More information is needed. Exact version numbers, code youre using including parameters passed in, whether this can be consistently reproduced on different machines.
Hi,
We recently updated to TurboActivate 4.1 (from 4.0) in the development branch of our product.
For reasons we're not able to ascertain, after the update, TA_TrialDaysRemaining has started returning TA_FAIL (1) for at least expired verified trials, and possibly for other situations as well.
As it's not one of the error codes with an explanation (such as TA_E_INVALID_HANDLE, etc.), we are not sure how to diagnose the failure. Some things we have tried:
1) Removing the state folders in /var/lib/.local2) Running an strace while TA_TrialDaysRemaining is executed to see if it's encountering permissions errors, etc.
Neither of these have been helpful. The error is returned regardless of whether the state folders are present. The strace is probably not helpful either, but just in case, here are the last few system calls before TA_TrialDaysRemaining emits an error. It looks like the last thing it does is read the state folders (successfully), then check /etc/localtime (also successfully).
[pid 2132] stat("/var/lib/.local/.c773c155981f38032a617.51222781", {st_mode=S_IFREG|0777, st_size=0, ...}) = 0[pid 2132] open("/var/lib/.local/.c773c155981f38032a617.51222781", O_RDONLY) = 3[pid 2132] read(3, "", 8191) = 0[pid 2132] close(3) = 0[pid 2132] ioctl(2, TCGETS, 0x7ffca525abf0) = -1 ENOTTY (Inappropriate ioctl for device)[pid 2132] open("/etc/localtime", O_RDONLY|O_CLOEXEC) = 3[pid 2132] fstat(3, {st_mode=S_IFREG|0644, st_size=127, ...}) = 0[pid 2132] fstat(3, {st_mode=S_IFREG|0644, st_size=127, ...}) = 0[pid 2132] read(3, "TZif2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1\0\0\0\1\0\0\0\0"..., 4096) = 127[pid 2132] lseek(3, -71, SEEK_CUR) = 56[pid 2132] read(3, "TZif2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1\0\0\0\1\0\0\0\0"..., 4096) = 71[pid 2132] close(3) = 0
What else might cause TA_TrialDaysRemaining to return a generic TA_FAIL?
More information is needed. Exact version numbers, code youre using including parameters passed in, whether this can be consistently reproduced on different machines.
> Exact version numbers
We have reproduced this with TurboActivate 4.1.5.0 and 4.1.8.1 on Linux.
> code youre using including parameters passed in
Here's the actual invocation from our source code:
HRESULT hr = ::TA_TrialDaysRemaining(handle(), trialFlags_, pDaysRemaining);
handle() returns the handle (obviously) trialFlags_ is TA_VERIFIED_TRIAL in this case, and pDaysRemaining is a pointer to a uint32_t.
> whether this can be consistently reproduced on different machines.
Yes, we have reproduced the problem on three different machines running a variety of Linux operating systems (one on Fedora 28, one on Ubuntu 16, not sure about the last).
If I were to guess I'd say it has to deal with messing with internal state files. Don't change them, delete them, replace them, etc. Why? Because there are a handful of files modified in-tandem. And the internal details change.
If you mess with things in unexpected ways, TurboActivate won't try to guess what you did. It will just throw up its hands and say "no trial for you" (TA_FAIL or TA_E_EXPIRED). Which is what you would want in the real world anyway.
Wyatt wrote:> If I were to guess I'd say it has to deal with messing with internal state> files. Don't change them, delete them, replace them, etc.
This can't be the problem because we've observed it on 2 systems with almost-pristine configurations. Only after getting the error repeatedly on multiple systems did we try removing the files (thinking that perhaps something in them might have become corrupted or invalid).
We're getting the same error after trying to upgrade from TurboActivate v4.0.9.7 to TurboActivate v4.1.9.0.
We've reproduced the error in macOS 10.14.6, Windows 7, and CentOS 7.6. The macOS system was in a state where a trial started by TurboActivate v4.0.9.7 was already expired. The latter two systems were both in a pristine state where no version of TurboActivate had been used previously and no trial had been started.
We're using the static version of TurboActivate as our software is a plug-in that runs within the context of another application.
So far we've only been using node locked licenses and trials, but we're starting to implement floating licenses. It seems like the current version of TurboFloat is incompatable with TurboActivate v4.0.9.7, but because of this issue we're unable upgrade TurboActivate.
Until we can figure out why we're unable to successfully call TA_TrialDaysRemaining in the latest version of TurboActivate, we're not able to make progress on floating licensing.
As a stopgap, is there somewhere we can download TurboFloat v4.0.9.7?
Firstly, exactly the parameters and error codes you get are needed. Also, sample code. See: https://wyday.com/limelm/help/faq/#useful-reports
When we get a partial picture we need to fill in a bunch of holes with assumptions which may or may not be correct.
>> "We're getting the same error after trying to upgrade from TurboActivate v4.0.9.7 to TurboActivate v4.1.9.0."
>> "We've reproduced the error in macOS 10.14.6, Windows 7, and CentOS 7.6. The macOS system was in a state where a trial started by TurboActivate v4.0.9.7 was already expired. "
The error code handling internally in TA 4.0 vs 4.1+ is slightly different. Namely, if you have an expired trial, TurboActivate will tell you about it earlier.
So... it sounds like everything is working correctly. You'll just need to alter the code in your app to handle the "expired" error code.
But, again, tell us the code you're using, the parameters you're passing, the return codes for every function called, what you expect to happen, etc., etc. and we can tell you exactly what to fix.
I think I now have an idea of what we were doing wrong. We were relying on some undocumented behavior of TurboActivate v4.0.9.7 that no longer works in 4.1.
We need to determine whether or not the user has already started a trial before we call TA_UseTrial. Our software has a free mode and a paid mode with additional features. We want to allow users of the free mode to begin a trial of the paid mode at any time, possibly after using the free mode for quite a while.
When the software launches, if the user has started the trial, we want to remove the option to start a trial and display how many days they have remaining.
However, if we call TA_UseTrial at startup, that will start the trial if it hasn't started yet.
The way we dealt with this with TurboActivate v4.0.9.7 was with the following function:
/// Code begins here
#define LIME_TRIAL_FLAGS (TA_VERIFIED_TRIAL | TA_USER)
bool isTrial() { uint32_t ignored = 0;
// NB: limeHandle() returns a valid handle HRESULT result = TA_TrialDaysRemaining(limeHandle(), LIME_TRIAL_FLAGS, &ignored);
if (result != TA_OK && result != TA_E_MUST_USE_TRIAL) { // handle unexpected error here }
return result == TA_OK;}
/// Code ends here
We were relying on the fact that TA_TrialDaysRemaining would return TA_E_MUST_USE_TRIAL when the trial has not started. In TurboActivate v4.0.9.7, TA_TrialDaysRemaining returned TA_OK if a trial has been started by a previous instance of our software but TA_UseTrial had not yet been called for the current instance.
In TurboActivate 4.1.x, it seems that TA_TrialDaysRemaining returns TA_FAIL if TA_UseTrial has not been called for the current instance of our software, regardless of whether a trial has been started by a previous instance.
And, if TA_UseTrial has been called and returned TA_E_TRIAL_EXPIRED, TA_TrialDaysRemaining seems to return TA_FAIL.
Are both of these intended behavior? If so, then I'm confused about the circumstances in which TA_TrialDaysRemaining would return TA_E_MUST_USE_TRIAL. Also, it seems to contradict the documentation which states that TA_TrialDaysRemaining indicates there are 0 days remaining if the trial has expired.
In fact, if I recall correctly, we knew we were relying on undocumented behavior here. But we do need to know whether or not the user has started a trial without having to call TA_UseTrial and we couldn't figure out any other way to determine that.
Is there a recommended way for us to find out if a trial has started without using TA_UseTrial?
>> "Is there a recommended way for us to find out if a trial has started without using TA_UseTrial?"
No, there's currently no way to determine that. We just recommend following the examples. Namely, check if activated / genuine, if not check trial days remaining, and show some combination of interface options depending on the needs for your business.
>> "TA_E_MUST_USE_TRIAL when the trial has not started"
You were depending on undefined internal behavior. TurboActivate did / does return TA_E_MUST_USE_TRIAL, but it doesn't *just* return that.
>> "And, if TA_UseTrial has been called and returned TA_E_TRIAL_EXPIRED, TA_TrialDaysRemaining seems to return TA_FAIL."
Under certain circumstances, yes. So, you'll need to handle the TA_E_TRIAL_EXPIRED rather than just barreling through to TA_TrialDaysRemaining().
Thanks for the response. We've dealt with this issue by storing a flag in a separate settings file that determines whether or not the trial has started. We're a little concerned that it might in some cases get out of sync with TurboActivate's state but that's not too big of a deal since it won't actually allow the user to reset their trial.
Would you consider adding a function to TurboActivate that checks to see whether the trial has started? That would be very helpful for our use case, and likely other use cases as well.
Hi,
Sorry for opening this one again after quite some time…
We are experiencing the same problem as described above: TA_TrialDaysRemaining
is returning TA_FAIL (when the trial is expired). It seems to do so regardless of whether TA_UseTrial
is called prior to it or not. TA_UseTrial
does return TA_E_TRIAL_EXPIRED
, but we cannot use that, as we don't want to start the trial immediately.
We are using TurboActivate version 4.4.4.0 (and the same version of TurboFloat).
Here's our sample code snippet:
_serverResp = TA_IsGenuineEx(_handle, &_GenuineOpts);
if (_serverResp != TA_OK && _serverResp != TA_E_FEATURES_CHANGED &&
_serverResp != TA_E_INET && _serverResp != TA_E_INET_DELAYED &&
TA_IsActivated(_handle) != TA_OK)
{
if (TA_TrialDaysRemaining(_handle, TA_VERIFIED_TRIAL | TA_SYSTEM, &_remTrialDays) != TA_E_MUST_USE_TRIAL)
{
_serverResp = TA_UseTrial(_handle, TA_VERIFIED_TRIAL | TA_SYSTEM, nullptr); // will return TA_E_TRIAL_EXPIRED if this is the case.
}
As I understand from the answers above, it is not unexpected that - “under certain circumstances” -TA_TrialDaysRemaining
returns TA_FAIL
.if the trial has actually expired. The reason to re-raise this issue is that this is not what the documentation of TA_TrialDaysRemaining
states, or at least it's rather misleading:
/*
Get the number of trial days remaining.
0 days if the trial has expired or has been tampered with
(1 day means *at most* 1 day, that is it could be 30 seconds)You must call TA_UseTrial() at least once in the past before calling this function.
And you must call this function with the same flags you used with TA_UseTrial().
Returns: TA_OK on success. Handle all other return codes as failures.Possible return codes: TA_OK, TA_FAIL, TA_E_INVALID_HANDLE, TA_E_ALREADY_VERIFIED_TRIAL,
TA_E_MUST_USE_TRIAL, TA_E_MUST_SPECIFY_TRIAL_TYPE
*/
TURBOACTIVATE_API HRESULT TA_CC TA_TrialDaysRemaining(uint32_t handle, uint32_t useTrialFlags, uint32_t * DaysRemaining);
So my question I guess is, when does TA_TrialDaysRemaining
ever set the “DaysRemaining” output parameter to 0 (and return TA_OK) if it returns TA_FAIL when the trial has expired?
Thank you in advance,
Joris
Always use TA_UseTrial before you use any other trial functionality. We say that in the example, and the docs.
And if any of the functions “error out” then none of the parameters can be used.
Shorter answer: follow the examples.
Hi,
Thank you for your swift reply!
I do have three small follow-up questions then, though:
TA_UseTrial
prior to TA_TrialDaysRemaining
(although I know in my tests that it has been called before on that machine - see question 1). TA_UseTrial
prior to it, TA_TrialDaysRemaining
is still returning TA_FAIL
, as opposed to what one (or at least I :) would expect from the documentation (namely "0 days if the trial has expired or has been tampered with"). TA_UseTrial
must have returned TA_OK
” (and would it not be helpful to make that explicit in the docs)?TA_TrialDaysRemaining
if TA_UseTrial
returns TA_E_TRIAL_EXPIRED
, is it then actually ever possible for TA_TrialDaysRemaining
to return zero as “DaysRemaining”?Thanks again (and in advance :) for your quick answers!
Joris
“before -- as in prior to and within the same run of the program”
Yes.
However, even if I do call
TA_UseTrial
prior to it,TA_TrialDaysRemaining
is still returningTA_FAIL
, as opposed to what one (or at least I :) would expect from the documentation (namely "0 days if the trial has expired or has been tampered with").
If TA_UseTrial()
has already told you the trial has expired, then barreling ahead to get the trial days remaining will give you a failure.
So when the documentation is saying “You must call TA_UseTrial() at least once in the past before calling this function”, is that then actually implicitly also implying “AND
TA_UseTrial
must have returnedTA_OK
” (and would it not be helpful to make that explicit in the docs)?
Yes, that is implied in the docs, and explicitly shown in the examples. Barreling past an error has always been a bad practice in programming (no matter what library you use).
If you should not use
TA_TrialDaysRemaining
ifTA_UseTrial
returnsTA_E_TRIAL_EXPIRED
, is it then actually ever possible forTA_TrialDaysRemaining
to return zero as “DaysRemaining”?
Yes, it is possible. It depends on a number of conditions. That's why the example code handles that case too.
All very clear, thank you! 🙏
One last thing I was wondering about (then I'll stop, promise! 😊):
Under what circumstances does TA_TrialDaysRemaining
return TA_E_MUST_USE_TRIAL
(seeing that I did not get it when - erroneously! - calling it without TA_UseTrial
in front)?
Could that perhaps be if TA_UseTrial
has never been called on that machine? And if not, then when?
Could that perhaps be if
TA_UseTrial
has never been called on that machine?
It depends on a number of factors, but yes, that's one of them. Long story short: it's internal behavior that has changed / will change. Don't depend on it to try to “read” some internal state.
Got it, thx! 🙏
Out of my interest, is lazy trialing (i.e. to be able to check whether a machine has already used up it's verified trial, without having to start one in case it hadn't) something that is “on the table” to be added in some version of TurboActivate in the near (or distant) future?
Out of my interest, is lazy trialing (i.e. to be able to check whether a machine has already used up it's verified trial, without having to start one in case it hadn't) something that is “on the table” to be added in some version of TurboActivate in the near (or distant) future?
No. The plan limits are designed such that you'll sell more copies of your software than you'll use verified trials. (We used business case-studies and internal studies to design the best verified trial to activation ratio).
And real-life usage has proven that design out.
So, don't be afraid to use verified trials. You can always extend a person's trial at any time and as many times as you need.
OK, thanks for your insights!