Chapter 4. Incorporating FLEXlm Into Your Application

To incorporate FLEXlm into your application, you will add function calls to your application program, build your application, and build a custom vendor daemon as discussed in the following sections.

FLEXlm Naming Conventions

All FLEXlm client routines and variables adhere to certain naming conventions. These conventions are:

  • All client routine names start with either “l_” or “lc_”. In general, the “lc_” routines are the routines which are to be used by FLEXlm vendors, whereas the “l_” routines are internal support routines (note that a few “l_” routines will be described in the next section). These routines are contained in the library file liblmgr.a (lmgr.dll/lmgr.lib for Windows and lmgr32.dll/lmgr32.lib for Windows NT and Win32s, and lmgr.olb for VMS platforms).

  • All FLEXlm server function and global data names will start with “ls_”. These routines are contained in the library files liblmgr_s.a and liblmgr_as.a, as well as in lmgrd.a. These routines will not be linked into your application.

FLEXlm Example Applications

The FLEXlm distribution kit contains an example client application program in the machind directory called lmclient.c. For Windows and Windows NT systems, this file is located in the test directory. lmclient.c is a small stand-alone licensed program and is a good place to start to learn how to integrate FLEXlm with your application.

For Windows and Windows NT systems the WINTEST directory contains a second example application which uses Microsoft Visual C++ to build a slightly more complicated example program to demonstrate the usage of UDP, LSAPI, etc.

The create_license and lmcrypter programs can be used to generate licenses for your customers, or they can be used as examples of license generation programs. Source to the create_license and lmcrypter programs is in the machind directory—called create_lic.c and lmcrypter.c in the /lmgr/machind directory. For Windows and Windows NT systems, these files are located in the utils directory with the file name CREATE_L.C and LMCRYPTE.C.

The create_license and lmcrypter programs generate the same license keys on all FLEXlm supported platforms for all FLEXlm versions, thus allowing you to create codes for any supported platform on any other supported platform.

FLEXlm kits also contain an examples directory at the top-level of the kit hierarchy. The examples directory contains example programs, which have been put on the kit in order to illustrate how to perform various operations with FLEXlm. These programs are not supported, and Globetrotter Software may not include them in future FLEXlm releases.

Client Heartbeats and License Server Failures

Your client application will need to communicate regularly with the server via lc_timer() “heartbeats”, to ensure the server is still running. How the heartbeats occur and what action takes place when the server is not running are the most important part of incorporating FLEXlm in an application. This is addressed in the following sections:

Internationalization

A message file for localization of FLEXlm messages has been provided for Solaris 2.x in FLEXlm v3.0 and later. The message file is FLEXlm.po, and it is contained in the machind directory. The text domain is “FLEXlm”. All messages from lmgrd, the vendor daemons, and lmutil are contained in this message file. Since the client library does not output any messages, and the create_license, lmcrypter and lmfeatset programs are example programs for the ISV's use only (which are shipped in source form, anyway), these have not been internationalized. All FLEXlm client library messages are contained in the file machind/lm_errors.h. In order to build a localized version of the daemons and utilities, do the following:

  1. Edit FLEXlm.po to contain the text translations.

  2. Run msgfmt on FLEXlm.po (produces FLEXlm.mo).

  3. Put FLEXlm.mo into the appropriate message directory. For example, if you were doing a french translation:

    % cp FLEXlm.mo /usr/lib/locale/fr/LC_MESSAGES
    

  4. Set your language environment:

    % setenv LANG fr
    

  5. Run lmgrd or the utility program. You should see the translated messages.

Lingering Licenses

A lingering license allows you to specify how long a license will remained checked out beyond either an lc_checkin() call or program exit (whichever comes first). To use this feature, call lc_set_attr() before checking out the feature that should linger:

lc_set_attr(LM_A_LINGER, x)

where:  

is the:

(long) x  

number of seconds to make the license linger.

In addition, the end-user can specify a longer linger interval in his daemon options file, as such:

LINGER f1 100

The longer of the developer-specified and user-specified times will be used. The actual time of checkin will vary somewhat since the vendor daemon checks all lingering licenses once per minute. If however, a new license request is made that would otherwise be denied, a check of the lingering licenses is made immediately to attempt to satisfy the new request. Linger is useful for programs that normally take under a minute to complete. Linger is generally only useful if DUP_GROUP is also set.

TLI vs. Sockets

By default, all UNIX FLEXlm implementations use sockets. On Solaris 2.x FLEXlm gives you the option to use TLI instead of the socket networking interfaces. There is no good reason to force the FLEXlm client library to use TLI, since the Solaris sockets implementation uses TLI internally. However, if you want to use TLI, do the following:

  • replace “-lsocket” with “l_tli.o” in the makefile

  • re-build your application.

Globetrotter Software does not recommend building lmgrd and the vendor daemons with TLI. Using TLI may make administration more difficult for your customer's license administrator. If, however, you wish to do this, keep the following in mind:

  • You CANNOT mix a TLI and a non-TLI lmgrd and vendor daemon.

  • If the daemons are built with TLI, then only ONE copy of any vendor daemon will be able to run. Additional vendor daemons that are started will fail. This is a permanent restriction.

If you want to use TLI for your daemons, you will need a source kit. Start by re-building the kit, setting the “USE_TLI” compile-time switch in lm_machdep.h. (This switch is surrounded with a #if 0/#endif in the kit, as shipped). Next, change “-lsocket” to “l_tli.o” in the XTRALIB macro in the makefile. Re-build your vendor daemon. Finally, to re-build lmgrd with TLI, do the following:

% ar x lmgrd.a ls_lmgrd.o
% cc -o lmgrd ls_lmgrd.o lmgrd.a liblmgr_s.a liblmgr.a l_tli.o \
-lnsl -lintl

If you do not rebuild any of the programs this way, they will use the default system socket library (-lsocket).

Multiple Jobs

lc_init(job, x, y, &job_handle) function calls enable applications to support more than one FLEXlm job in a single binary. Each job has a separate connection to a license server, as well as a independent set of job attributes. When a new job is created, with lc_init(), all the FLEXlm attributes are set to defaults, and attributes can be set completely independently for this new job. For example, one job could use TCP, and another job UDP, running simultaneously, although this is not a significant reason for multiple jobs.

Multiple jobs may be desirable for the following reasons:

  • If $LM_LICENSE_FILE is a colon-separated list (vertical-bar-separated list on Windows or Windows NT or a space separated list on VMS platforms) with more than one server supporting features for the client, and if the application needs to check out more than one feature, it may be necessary to communicate with two servers to check out the necessary licenses. This can only be done with multiple jobs, since a separate connection is required for each server.

  • It may be convenient to have a single process manage licenses for other processes. It is usually convenient to manage each process's license as a separate job.

  • lc_checkin() checks in all licenses for a given name. If the application needs to check-in only some of the licenses, this can be done with multiple jobs, where groups of checkouts are done in separate jobs, and checked in separately from each job.

The first item can be important as an alternative way of supporting server redundancy. Following is a program excerpt that illustrates how to support this:

LM_HANDLE *job1, *job2, *feature_2_job;
lc_init((LM_HANDLE *)0, "demo", code, &job1);
set_all_my_attr(job1); /* do all necessary lc_set_attr() calls */
if (lc_checkout(job1, "feature1",...))
/* error processing */
/*fs got one feature successfully checked out, so we're connected
 *to a server already. In order to connect to another server, we 
 *would need another job
 */
if (lc_checkout(feature_2_job = job1, "feature2",...))
{
lc_init(job1, "demo", code, &job2); /* try another server */
/*
 *reset attributes for this new job 
 */
set_all_my_attr(job2); 
if (lc_checkout(feature_2_job = job2, "feature2",...)
{
feature_2_job = (LM_HANDLE *)0;
 /* error processing */
}
}

/* . . . */
lc_checkin(job1, "feature1"); /* have to checkin from job1 */
lc_free_job(job1); /* not really necessary, but shown for illustration */
if (feature_2_job)
{
lc_checkin(feature_2_job, "feature2");
}

If the application is managing many jobs, you may need to free jobs with lc_free_job() to save memory. When doing so, make sure that you do not delete a job which still has a license checked out—this can result in a core dump.

Jobs can be found and managed using lc_first_job() and lc_next_job(), which are used to walk the list of jobs.

Attributes for jobs are set and retrieved with lc_set_attr() and lc_get_attr().