* The Business of Software

A former community discussing the business of software, from the smallest shareware operation to Microsoft. A part of Joel on Software.

We're closed, folks!

Links:

» Business of Software FAQ
» The Business of Software Conference (held every fall, usually in Boston)
» Forum guidelines (Please read before posting!)

Moderators:

Andy Brice
Successful Software

Doug Nebeker ("Doug")

Jonathan Matthews
Creator of DeepTrawl, CloudTrawl, and LeapDoc

Nicholas Hebb
BreezeTree Software

Bob Walsh
host, Startup Success Podcast author of The Web Startup Success Guide and Micro-ISV: From Vision To Reality

Patrick McKenzie
Bingo Card Creator

Licensing dilemna

My windows desktop app requires one license per user and that applies to server installations. Until recently I relied solely on trust that customers would buy the number of licenses needed. A new version when run on a server  counts user names using Environment.Username, storing each unique user name in a license file, and compares the count with the number of licenses purchased, which are in the Registry. If customer does not have sufficient licenses  the application runs in trial mode for each user that is over the limit. A license is required for each unique user, regarless of the number of concurrent users.

A customer with one license said he often needs to login remotely through the service account the application runs under for troubleshooting, diagnostics, etc., with the result that he is in trial mode because the RDP user name is different from the user name already in the license file. Customer feels they should not have to buy a second license.

There are a number of ways to handle this, such as allowing two users for the first license purchased, requiring a minimum of two licenses for server instalations, allowing one RDP user to not be counted as a user, give one free license to customers that complain, etc.

What are your suggestions?
Bill Anonomist Send private email
Thursday, January 16, 2014
 
 
Do you have your definition of a user defined anywhere? This could be simply a case of what you think of a user is different from what the customer thinks a user is.

When I managed IT most user licensed software that I encountered was either per seat or per logged in user. With per seat only the number of licenses bought could be installed, virtual or on hardware. Per user (logged in user) the software could be installed many times but only used at anytime concurrently by the number licenses bought.

From you're description you seem to be doing per individualized user (actual person). If so what happens when there are personnel changes?

Find out how your customer defines a user if you don't define it for them. If it's not clear you may end up having to give some licenses out til what is a user is understood by existing customers.
TrippinOnIT Send private email
Thursday, January 16, 2014
 
 
My EULA states that each person using the application must have one license. So I have per seat licensing, but if the application is on a server then there is only one installation. The EULA does not address how users are identified, but how else than by their Windows user name[or sid]?

Most customers that installed the application on a server have only one person using the application at a given time, but several different[physical/actual] persons need to be able to use it. I knew this going in so that is why I chose per seat licensing.

But this particular customer is saying there is only one person using the application so we should only have to buy one license when the one person uses it concurrently under different user names. I think I agree with them, but need a way for my licensing algorithm to accommodate them and still enforce per seat licensing. Until I figure that out I think I need to give them one free license.
Bill Anonomist Send private email
Thursday, January 16, 2014
 
 
If it's intended to per seat then I would agree that you'd have to give them an additional license.

Perhaps you can use a machine identifier instead of the Windows user to track installed instances instead.
TrippinOnIT Send private email
Thursday, January 16, 2014
 
 
>> "The EULA does not address how users are identified, but how else than by their Windows user name[or sid]?"


Right, well, for all practical purposes "per-user" (per-human) identification is impossible with current technology. There's no good way for a computer to know what human is sitting in front of the computer. Username or Session ID are quick and dirty ways to identify users, but there are a number of flaws with that. A "user" (human) can have multiple user-names (especially in organizations with complex and not entirely integrated systems), and even in well-formed organizations the "user" (human) can be under multiple sessions (and thus have multiple session IDs).

And even if you the technology progresses such that per-human identification was reliable, would you really want it? "TrippinOnIT" raised this point in his first post. Namely, you'll have organizational changes. So CompanyX might buy 3 licenses of YourApp for Bob, Alice, and Sally, but organizations and projects change. So 7 months from now, maybe Alice moved to another project in the company (being replaced by Terry), and Bob got shit-canned (being replaced by Frank). If you could reliably do per-human identification then that means Terry & Frank wouldn't be able to use your app, even though 2 of the licenses for your app were sitting unused.


The closest you can get to per-user identification is to have floating licensing (a.k.a. concurrent licensing) that locks to both the machine and the session on the machine. This is how our floating licensing works (http://wyday.com/limelm/help/using-turbofloat/ ).

So if you sell 3 licenses to CompanyX, and you use floating licensing, then the "license leases" will be sitting in a pool. Meaning Bob, Alice, and Sally may be the primary users today, but even if the organization changes in 7 months (replacing Bob & Alice with Terry & Frank) then the new "users" will be able to user the "license slots" vacated by the former "users".




So it sounds like you need to do 2 things:

1. Clarify your EULA so "user" is defined to something that's actually enforceable & flexible for the customer (e.g. "user" = per session per machine).

2. Modify your concurrent licensing (or buy reliable 3rd party concurrent licensing) such that you can actually enforce this definition of "user".
Wyatt O'Day Send private email
Thursday, January 16, 2014
 
 
Maybehave each running instance periodically
update the license file with userid, current date/time and a  'session' id that is randomly generated when the program is opened.
On shutdown each instance should clear its entry in the license file.
In the event of the program crashing, if an ID/session combo's recorded date/time has not updated for a certain interval allow it to be overwritten by a new ID/session combo.
Drummer Send private email
Friday, January 17, 2014
 
 
Regardless of the precise details of what counts as a user (which yiu can nail down in this thread), I would suggest a scheme something like this:

If they purchase N licenses, set X=N, or if there is a margin for error in counting, set X = N+1 or N+2 etc.

If <= (X) users are running, everything runs fine

If <= (X+a few) are running,  everything runs fine, but you give a warning on screen that they need to purchase more licenses

If > (X+a few) are running, do not allow any more users to log-in and give a warning  on screen that they need to purchase more licenses to keep running
S. Tanna Send private email
Friday, January 17, 2014
 
 
@Drummer

You're quite literally describing floating licensing. Although you're misunderstanding a few things.


>> "'session' id that is randomly generated"

The "session ID" is a construct of operating systems. It's something the kernel controls, not something that can be randomly generated.

Plus, this idea is pointless with proper hardware-fingerprinting. Although, there is 1 exception where a unique GUID per-instance would be useful: clients running on VM/hypervisor instances. If you want I can explain why a GUID per-instance is only useful under those circumstances.


>> "On shutdown each instance should clear its entry in the license file."

I'm not aware of floating licensing that *doesn't* do that. That's the whole point of a "pool" of license leases I was describing. When a user is done using a "license lease" it's released back to the pool for someone else to use. This is literally the whole point of floating licensing.

Make sense?


>> "In the event of the program crashing, if an ID/session combo's recorded date/time has not updated for a certain interval allow it to be overwritten by a new ID/session combo."

Again, I'm not aware of floating licensing that *doesn't* do that. We call these type of unused, yet taken, slots as "zombie leases" (see: http://wyday.com/limelm/help/turbofloat-server/#config-lease ), but although the terminology differs between floating licensing products, any well designed floating licensing already does that.
Wyatt O'Day Send private email
Friday, January 17, 2014
 
 
>> "In the event of the program crashing, if an ID/session combo's recorded date/time has not updated for a certain interval allow it to be overwritten by a new ID/session combo."

Wyatt O'Day: "Again, I'm not aware of floating licensing that *doesn't* do that. We call these type of unused, yet taken, slots as "zombie leases" (see: http://wyday.com/limelm/help/turbofloat-server/#config-lease ), but although the terminology differs between floating licensing products, any well designed floating licensing already does that."

It was about twenty years ago.  I was working for a place that had a 10-user licence for Novell and 10 users.  Unfortunately, when a system crashed, the user could not reconnect.  Someone else would have to log off first.  Then, the crashed system could reconnect which would free up the user slot from the crash, and the other user could sign on again.  It was somewhat of a nuisance because I tested software.

Sincerely,

Gene Wirchenko
Gene Wirchenko Send private email
Friday, January 17, 2014
 
 
Thanks to all for your comments and suggestions. They give me a good idea on how to proceed with a better implementation of floating licenses. It appears every licensing model has at  least one downside and Gene pointed one out.
Bill Anonomist Send private email
Friday, January 17, 2014
 
 
@BillAnon
>> "It appears every licensing model has at  least one downside and Gene pointed one out."


A minor quibble: Gene pointed out a problem with a particular implementation of the model, not the model itself.
Wyatt O'Day Send private email
Friday, January 17, 2014
 
 
Regarding floating licenses, why not just use a counter stored and encrypted in a license file -increment it when the app is run, decrement when it is shut down? And allow one additional launch in case the app crashes.
Bill Anonomist Send private email
Friday, January 17, 2014
 
 
@Wyatt
I don't know much about licensing systems, thanks for the explanation.

@Bill
With regard to a simple counter that decrements on closing a program, when does the decrementing happen for crashes?
Drummer Send private email
Saturday, January 18, 2014
 
 
@Drummer

Two things:

1. If the user that crashed restarts and then exits normally, their name gets removed from the pool.

2. If another user starts the app and is blocked,  the app will get the user sid of all running instances, identify the user that crashed and remove their name from the pool. this requires admin rights so if the user is not an admin they are told to have an admin run the app.  I may lso provide the admin a tool to directly edit the user list.

I spoke with the customer that alerted me to this issue and he [who is a system admin] is OK with this.
Bill Anonomist Send private email
Saturday, January 18, 2014
 
 
>> "Regarding floating licenses, why not just use a counter stored and encrypted in a license file -increment it when the app is run, decrement when it is shut down?"

Why not use a file instead of a "server app" that manages everything? Well, there are several huge reasons that you should avoid a "file" that each instance of your app tries to manipulate.

But first, for anyone else following along, let me describe the 2 broad differences between your proposed method, and how typical floating licensing (like our TurboFloat) works:


Typical floating licensing consists of 2 parts:

1. The "server" application which manages all of the "slots" (number of allowed concurrent users). This "server" is just a process that sits there and waits for "clients" to talk to it (requesting a slot, saying it no longer needs a slot, etc.). There's a bit more to it than that (removing zombie slots, etc., etc.), but those are the broad strokes.

2. The "client" (your application) talks to the "floating license server" and requests a "license lease" (one of the empty slots), and the server responds with either "no, sorry, no more leases left" or "yep, here's a cryptographically signed lease that can only work on that one machine and that one session for the next N minutes).



Your proposed method doesn't use a "server", which is a huge mistake, but I'll get to that in a minute. In your method each of the "clients" (your application instances) tries to modify a single file -- a file which, under ideal circumstances, contains a list of other running "client" instances.



I'll just go over a few big reasons why this is a bad idea:


* Big Reason #1: You're stuck on a single computer

One of the big main advantages of typical floating licensing is that a customer can run your app on any computer they want. They don't need to run all the instances on a single computer / server. Why? Because a "server" process listens for your app to talk to it (giving it the fingerprint, waiting for the response, etc.).


With your method all "clients" (instances of your app) *must* be on the same machine because all of these "clients" are forced to write to the same file.


----------
* Big Reason #2: No VM/Hypervisor support

Let's say you have good VM/Hypervisor detection (which is a huge, hard problem in itself). You won't be able to make use of this information in any way that counts (namely, making money from customers that try to clone the VM instance X times). Why? Because, again, you're stuck on a single computer. That is, you can't separate out the "floating license server" onto a real computer, and then let instances of your app run on either real computers or VM instances.

Properly designed floating licensing can do this. At last count there were 2 companies that actually implement this correctly (us, and one other company).

For more information about what I'm talking about read this: http://wyday.com/limelm/help/vm-hypervisor-licensing/

I can delve further in depth if you want.


--------
* Big Reason #3: Lock contention

With your method all of your app instances are fighting for control of a single file. Every time an instance of your app runs it needs exclusive read/write control over the file. Simple enough, right? Well, yes, if you only have a handful of your app instances running.

Once you start getting into large number of instances of your app running, now suddenly all of the instances of your app are fighting for exclusive control over a file without "knowing" when the other processes are done with it (or, who's "next in line").

Let's say you implemented this exclusive locking intelligently (e.g. try-lock, followed by increasing back off if locking fails), then, depending on how many instances of your app is running some instances will never be able to get a "free slot".

(Lock contention is a huge topic in computer science, if you're a little fuzzy on what I'm talking about and why it's a problem I can explain it in greater detail.)


In proper floating licenses the "floating license server" handles all of the flow control. The instances of your app just talk to the floating license server and the server handles the requests one, by, one. Your app instances don't need to be aware of the inevitable "locks" that must be handled -- the server handles it. And because the server is in full control of the "locks", it never has to worry about "outside" lock-contention problems (all the locks are handled inside the process).

Again, I'll explain this more if you don't see why this is a problem.




----------
* Big Reason #4: (response to your idea)
>> "And allow one additional launch in case the app crashes."

Who says just one instance will crash? In fact, the file will continue to "rot" until all of the available "slots" are taken up. You're setting yourself up to reproduce the exact problem that Gene described.



>> "If another user starts the app and is blocked,  the app will get the user sid of all running instances, identify the user that crashed and remove their name from the pool."


Yikes, this is a terrible idea. You've just neutered your floating licensing. The user can just start as many instances of your app as they want. If you limit the user to running 10 instances of your app, then they want to start the 11th (12th, 13th, 14th, etc.) instance of your app all they have to do is click one of the other instances they want to remove from your "list".

Do you see what I'm saying?



This problem doesn't exist if you use a proper floating license server. If you're intent on building this yourself, then do something like what we've done (see: http://wyday.com/limelm/help/turbofloat-server/#config-lease ).
Wyatt O'Day Send private email
Wednesday, January 29, 2014
 
 

This topic is archived. No further replies will be accepted.

Other recent topics Other recent topics
 
Powered by FogBugz