We were asked to build a server-based licensing manager that was to control the concurrent use of application licenses by networked workstations. The service component of the product was to reside on one or more networked servers running a variety of operating systems (Netware, Windows NT, Solaris, BSD). The clients of the service were to run on numerous networked workstations running several operating systems (Windows 95/98, NT, Mac OS, OS/2, Unix, DOS).
The initial product requirements specified a system that would employ a database maintained by the licensing service that would track all of the information contained in a software license (including but not limited to manufacturer, number of copies, usage restrictions and suite membership). Through whatever means necessary, the clients would contact the service and obtain a license for a particular piece of software, when it executed that piece of software. When execution of the software terminated, the licensing service would again be contacted to release the license for reuse by another workstation.
Upon the request for a license by a workstation client, the license, if available, was to be granted to that workstation until the maximum number of licenses was given out. Otherwise, if a license existed by was unavailable, the license request was to be queued and notification was to be given to the requester when a license became available. Furthermore, for license requests in the queue, the system was to acquire the license on behalf of the requester and convey it to them when they asked for it, to ensure that other requesters would not usurp the initial requesters position in the queue.
To initiate the requests for licenses from the clients, a number of wrapping and hooking techniques were to be employed so that executable files could be wrapped, whereupon the wrapper could initiate a license request when the executable was run and non-executable files could be hooked in the workstation file system, whereupon an open for the file could initiate a license request. The wrapping and/or hooking techniques had to be applicable across all of the workstation platforms specified by the design.
BSM was to be responsible for all system architecture, design, establishment of the development team, coding of the majority of the components, selection of the product delivery method and packaging/delivery of the product. Documentation and one platform's wrapper code was to be handled by independent contractors.
The architecture of the product was, to a certain extent, dictated by the requirement that the licensing service run on a server platform and the clients run on networked workstations. The service needed to be able to establish multiple connections with the requesting workstations and some sort of keep-alive mechanism would be needed to permit releasing of acquired licenses should a workstation die. Other than that, requests for licenses and to release them were transactional in nature. Two kinds of databases would be necessary, one to keep long-term licensing information and a second to keep track of license allocations in the short-term.
Based on the architecture, our designer decided to create a platform-independent set of generic client RPC routines layered on top of Novell NCP, TCP/IP and Microsoft Named Pipes to present client requests to the licensing service. This RPC mechanism could also be used among the various services running in the system to communicate with one another. Communication of workstation viability would be through one of a number of out-of-band mechanisms, depending on the platform upon which the client was running. The actual RPC clients implemented ran on DOS, Windows, Windows NT, Unix, Macintosh (using a proprietary lower-level transport mechanism built by an independant contractor) and Netware.
To provide a portable environment in which to implement the licensing services, we built a base set of services (shared memory manager, balanced binary tree, event scheduler, database interface and RPC service) to run on top of Novell Netware (both 3.1 and NDS), BSD Unix and Solaris and Windows NT. Anything built on top of these base services was fully platform independent and portable.
We implemented all licensing service functions on top of the base services (mentioned above). A single code base was used for all three operating system implementations. Functions included license allocation and tracking, reporting and logging, reservation at specified times throughout the day, remote check out and borrowing. All administrative functions such as license security and maintenance were provided as service functions too. On NT, the licensing service was set up as a system service under the auspices of the Service Manager while on Netware it was run as an NLM. Unix did not require any special operational mode.
Two databases were chosen to provide long-term licensing information storage. Since there existed a portable database access layer through which the services accessed the database, selection of either of the two underlying databases was transparent to the service code. One of the databases chosen was a commercial, high-performance database and the other was a readily available freeware database, thus giving the customers a choice as to which route they'd like to take when installing the product.
Short-term license management was done using a balanced binary tree, which was implemented as a platform-independent service. This tree served as persistent memory for all of the licensing requests received by the service. On the Unix systems, a shared memory manager had to be implemented to allow the balanced binary tree to be persistent across tasks, since a new task was assigned to process each service request.
On the workstation side, we built the OS interfaces necessary to transparently license all types of files (not just executables) by using hooks in file open and close. These interfaces required Netware file system hooks and, on NT, a filter device driver and an LSA subauthorization filter. They were built with the Netware SDK and the NT SDK/DDK/IFS Kit. Their operation was such that, whenever a licensed file was opened, a license would be requested from the appropriate service before the open was allowed to complete.
A second approach to altering an executable program, so that it would acquire/release a license upon execution, applied wrapping technology. Essentially, the program was modified by the insertion of a small fragment of code into it which would make the request to the licensing service. As can be imagined, this code was extremely specific to the execution platform targeted by the program and required different approaches for each one. A module was produced that would insert and remove wrappers for a half dozen different executable formats. This technique rendered programs that could be copied from place to place and still request a license upon execution.
To control the operation of the licensing service as well as manage licenses themselves, two administrative user interfaces were developed. First, a UI that ran directly on the most common workstation platform was created. It was able to use the existing RPC mechanism to send service requests to the licensing service, just as did the workstations requesting licenses. Second, a platform-independent administrative UI was created to run under a Web browser. Using any browser, running on any platform, an administrator could control the service from anywhere on the Internet.
The product turned out to be a difficult one to install, due to its being supported on multiple platforms. It needed to have a database installed and there was the additional requirement that licenses and wrapped programs be migrated from a preexisting system. BSM Development produced an install program that automatically took care of all of the different variations of the install, database installation, and setup and license/wrapper migration. Operation by the user was very simple. This allowed the product to be installed by a full range of users with very few calls to the client's Tech Support department.
A sound architecture, robust design, attention to detail during implementation, a well-designed installation program and our working together with the customer's QA department to produce test cases that exercised all of the product's features yielded a product that was very solid in operation, over a wide range of loads, and well received by the ultimate users.