Synchronized LexActivator state from within multiple plugins

We’re using Cryptlex as a static lib in our plugins (Windows and OSX), and we allow the user to manage his license from within the plugins. All plugins share the same product ID, since we sell them in bundles. Once the license state is altered from within one plugin, it triggers a sync of the new state to the other loaded plugins within the same host application.

We however noticed that when we let the host application load two of our plugins at once, and then activate a license from one of the loaded plugins, and then try to deactivate it from the other loaded plugin (so in the same session), we get an LA_FAIL returned.

When we however let the host load up only one plugin, activate a license from that plugin, and then let the host load in a second plugin, this second plugin is now able to deactivate the license just fine.

I guess this is as expected, since in the first scenario LexActivator’s internal state in the 2nd plugin doesn’t know what the 1st one has been up to, so when asked to deactivate the license it sees it isn’t even activated and thus returns LA_FAIL. (then again I’d expect a LA_E_ACTIVATION_NOT_FOUND instead?)

In the second scenario the 2nd plugin does a call to SetProductData, SetProductId, SetAppVersion, and finally SetLicenseCallback as part of it’s startup code, and I guess that before the host has fully given control back to the user, the server sync has already happened and the 2nd plugin’s cached state is now up-to-speed on the current license state, and can thus successfully perform a license deactivation.

What is the best way to let all plugins update their internal LexActivator state once one of them performs an activation, deactivation, or actually any license state altering action? Do we need to wait for the server check thread in the other plugins to do it’s thing once every hour? Or do we need to mirror the calls to SetLicenseKey / ActivateLicense in the other plugins as well? Then again: doesn’t that bump up the activation count for that installation manyfold? This also because we also use the same code for controlling hosted and on-premise floating licenses. Plus that the user could potentially have up to 80 distinct plugins loaded at once, so if they all perform a simultaneous server sync… Or is this problem fixed if we use the dll version of LexActivator? Then again we’d rather have only static dependencies, since depending on external dlls is tricky when you’re a plugin dll without control over e.g. PATH and cannot call any CHDIR command at load time (the OS thus just won’t find auxiliary dlls, even if they’re right next to our dll). Or is a single call to IsLicenseGenuine / IsLicenseValid / IsTrialGenuine (/ non-existing-IsTrialValid?) enough to reliably sync the internal LexActivator state? Or is there maybe another LexActivator function we can call which effectively just lets it refresh it’s internal state?

Hi Carl,

The issue you are facing is most probably due to the stale cache. We fixed a related issue in v3.12.2 of LexActivator. Try using the latest version and see if it fixes your issue.

Hi Adnan,

13.12.2 on Windows didn’t fix it. I also tried some older versions, up to 3.8.1 (from nov 2018?), but they all work the same way.

To be honest I actually didn’t think it would work out-of-the-box in our situation (because each loaded plugin indeed probably has a stale internal cache once one of 'em does some LexActivator magic), so I guess the real question is: how is the cache most easily updated from plugin to plugin, without having undesirable side effects like bumping up floating license activation counts and such?

I tried calling IsLicenseGenuine from the other plugins, but that seems to just read back the cache too.

Hi Carl,

In the case of v3.12.2 if the license is not activated/invalid it always reads from the disk and not from the memory cache.

What is the leasing strategy you are using? What permission flag did you pass to SetProductid() function?

Hi Adnan,

For node locked licenses we use LA_USER for SetProductId, and for floating licenses (hosted and on premise) we intend to use per-machine leasing.

Though for now we’re just interested in getting LexActivator to work nicely.
In our set-up the LexActivator / node locked licenses are intended for individual end users, and they can only manage their license from within the product itself, so the whole suite (all already loaded plugins) needs to catch up on license changes dynamically.
For floating licenses we use a different strategy where a sysadmin places a config file in a dedicated place, all plugins use the info in it from the start, and the end users are not even allowed to alter the details at runtime, so we don’t need much cross-plugin synchronization there.

To illustrate our setup:

  • Each plugin has it’s own statically linked LexActivator lib, and each does it’s own SetProductData / SetProductId(LA_USER) / SetAppVersion / SetLicenseCallback when it is loaded.
  • The first plugin to be loaded by each host (unique process) starts a worker thread, and on that thread it calls IsLicenseGenuine (possibly followed by IsTrialGenuine if there was no license). After that, if either a license or a trial is detected, it reads out all the details and then syncs the result to all other loaded plugins. We do this due to efficiency reasons; while under normal situations these Cryptlex calls are fast enough at about 1-2 seconds each, we might have to do them up to 80-fold, all at host startup, which just adds up too much, and all the while it’s our plugins being iterated to the user in the host’s splash screen.
  • The user can manage their license from within any plugin’s GUI, and the updated license state is then again synced to all already loaded plugins. Maybe this is relevant: these callbacks all come from arbitrary threads, so another thread than the startup code ran from.
  • Plugins loaded later on also get synced by already loaded plugins so they always all share the same state.
  • Because we do our own license state syncing, when a license state change happens in one of the loaded plugins, the LexActivator libs in all other plugins are kept in the dark about this.

A scenario where this breaks is:

  • The user starts the host application, which in turn loads several of our plugins.
  • The user didn’t activate a license yet, so all plugins load up blank and there is nothing to sync.
  • The user uses one of the plugins to activate a node locked license.
  • That plugin does the ActivateLicense etc. calls, and broadcasts the result to the other loaded plugins.
  • The user switches to one of the other plugins; it now shows the license that was activated (though it’s LexActivator doesn’t know of it).
  • The user uses this other plugin to deactivate the license again. This plugin calls DeactivateLicense, and gets served off with an LA_FAIL.

Where this does work out OK is:

  • Were the user to deactivate the license again from the original plugin, the call succeeds (of course)
  • Were the user to load in a yet unloaded plugin instead and use that one to deactivate his license, DeactivateLicense succeeds; most probably because that plugin called SetProductID etc. during it’s startup process and activation was already done at that time, so the LexActivator lib picked up the details from disk.
  • Were the user to load plugins A and B, then activate from A, deactivate from B (gives LA_FAIL), then deactivate from A (succeeds), then activate from B (succeeds) and finally deactivate from A, this last deactivate now also succeeds! But then on the next startup, when asked for IsLicenseGenuine we get returned an LA_E_LICENSE_KEY. Activating that same license again in a next host session gives LA_OK and the license is recognized again, but from then on (no matter how many host startups), whenever the license is deactivated, LA_E_LICENSE_KEY is returned again from IsLicenseGenuine. Even a LexActivator’s Reset, rebooting the machine, nor nuking the LexActivator registry keys together with deactivating all activations for this machine from Cryptlex’ web site doesn’t get it out of this state. So this is clearly not an optimal strategy :slight_smile: I finally fixed it by going back to LexActivator 3.9.0, nuking everything from there, and then going to 3.12.2 again.

Doing a new activation from an already activated machine won’t increase the activation count. So, calling Activate again before deactivating should fix your issue.