Chapter 6. Controlling Licensing Behavior Of Your Application With lc_set_attr

FLEXlm allows you to control the licensing behavior of your application with a set of attributes. FLEXlm attributes allow you control over licensing policy, internal operations of FLEXlm (e.g. use of timers, etc), and control of the licensing parameters of your process (e.g., define how FLEXlm will define “username”, “hostname”, and “display name,” etc. for managed license distribution.)

To set FLEXlm attributes, use the lc_set_attr call, described in “lc_set_attr”.

The following parameters can be changed with lc_set_attr() and queried with lc_get_attr(). The section heading is the attribute name. The first line of each section is the data type of the attribute. All attribute definitions are in lm_attr.h.

When using these attributes with lc_set_attr(), the argument must be of the correct type (each item below lists its associated type), and must then be cast to LM_A_VAL_TYPE. When using them with lc_get_attr(), the pointer argument should point to a value of the correct type (noting that short and int are different in this case), and must be cast to a (short *).

LM_A_ALLOW_SET_TRANSPORT

Type: int

This option allows you to disable the end-user selection of communications transport, which they can do with either the daemon options file, or the FLEXLM_COMM_TRANSPORT environment variable.

Default: On(1), i.e., end-users can select communications transport.

LM_A_ALT_ENCRYPTION

Type: (VENDORCODE *)

This option allows a vendor to more easily migrate to a new set of encryption seeds while still supporting old license files in the field. This option would be used in new applications until all the old license files in the field were replaced.

Here's an example of the use of ALT_ENCRYPTION:

Your company has 3 products, which are widely available, and you want eventually to make the old license files obsolete. You could do this by generating new license files with a new set of encryption seeds (the two hexadecimal numbers in lm_code.h that your company defines), but you might want to phase this in, since the 3 products will not all be re-released with the new encryption seeds for a year and you want the old versions to continue to work.

The solution is to make the new products support both old and new license files, shipping with new vendor daemons that will accept both old and new license files. At this point, license files would be shipped generated with the new encryption seeds.

Once all three new products become available, and all new license files are generated with the new encryption seeds; later versions of the products and vendor daemons can be released that will only accept the new encryption seeds.

Here is an excerpt from the interim client code:

lm_code.h:
/* newcode */
LM_CODE(newcode, ENCRYPTION_CODE_1,
ENCRYPTION_CODE_2, VENDOR_KEY1, VENDOR_KEY2,
                        VENDOR_KEY3, VENDOR_KEY4, VENDOR_KEY5);
/* oldcode */
LM_CODE(oldcode, OLD_ENCRYPTION_CODE_1,
                        OLD_ENCRYPTION_CODE_2, VENDOR_KEY1, VENDOR_KEY2,
                        VENDOR_KEY3, VENDOR_KEY4, VENDOR_KEY5);
application.c:
rc = lc_init((LM_HANDLE *)0, VENDOR_NAME, &newcode, &lm_job);
lc_set_attr(lm_job, LM_A_ALT_ENCRYPTION, &oldcode);

/* lc_checkout will try both newcode and oldcode */
rc = lc_checkout(lm_job, feature, version, checkout_cnt,
LM_CO_NOWAIT, &newcode, LM_DUP_NONE);

Also, in the ls_vendor.c file, the first version of the vendor daemon would need to support both encryption seeds, as follows:

/*
 * Read license files using either vendorkeys and
 * accept connections from clients using either
 * vendorkeys
 */
VENDORCODE vendorkeys[] = {
   {VENDORCODE_4, ENCRYPTION_CODE_1, ENCRYPTION_CODE_2,
 VENDOR_KEY1, VENDOR_KEY2, VENDOR_KEY3, 
VENDOR_KEY4,FLEXLM_VERSION, FLEXLM_REVISION},
  {VENDORCODE_4, OLD_ENCRYPTION_CODE_1, 
OLD_ENCRYPTION_CODE_2,
  VENDOR_KEY1, VENDOR_KEY2, VENDOR_KEY3, VENDOR_KEY4,
FLEXLM_VERSION, FLEXLM_REVISION}};

The final version of the vendor daemon, (the one that would no longer support old license files) would have the second vendor key (the one with OLD_ENCRYPT_CODE_n) removed, and the next release of the applications would have the lc_set_attr(LM_A_ALT_ENCRYPTION,...) call removed.

Default: None

LM_A_ANY_ENABLED

Type: short

This option controls whether the “ANY” hostid type will be allowed by your application.

Default: 1 (enabled)

LM_A_CHECK_INTERVAL

Type: int

LM_A_CHECK_INTERVAL controls the client's detection of daemon failures. FLEXlm client routines will install a SIGALRM handler or no handler at all, based on LM_A_CHECK_INTERVAL. The minimum value for LM_A_CHECK_INTERVAL is 30 seconds.

Default: 120 second interval.

The results of possible settings of this variable is:

Table 6-1. LM_A_CHECK_INTERVAL Settings

Variable

Setting

Result

check_interval

< 0

No SIGALRM timer installed.[a]

check_interval

>= 0, < 30

Old interval unchanged.

check_interval

>= 30

Timer interval.

[a] If you do not enable FLEXlm's timer, you must call lc_timer() periodically to check the status of the license. You cannot set check_interval to less than 30 seconds with lc_set_attr().

The timer handler remembers any other handler that was installed, and calls the previously installed handler when it has checked the socket. If it is unacceptable to have handlers installed for either of these signals (or to have the intervals changed), then set check_interval < 0. If you set check_interval < 0, then no checking of the daemon will be done unless you call lc_timer periodically. You could, of course, do this from your own timer signal handler.

LM_A_CHECKOUT_DATA

Type: (char *)

This option allows you to send some vendor-specific data to the vendor daemon in addition to the normal USER/HOST/DISPLAY data which is sent. This checkout data can be used to group duplicates in addition to the USER/HOST/DISPLAY by setting the LM_DUP_VENDOR bit in the duplicate grouping bitmask passed to lc_checkout(). The checkout data can be modified before each individual lc_checkout() or lc_checkin() call. This makes it possible for a process to check out several different independent licenses (if LM_DUP_VENDOR is in the duplicate mask), and to checkin the licenses independently by setting the vendor-defined field each time before calling lc_checkin(). The vendor-defined data is a character string, with a maximum size of MAX_VENDOR_CHECKOUT_DATA bytes (32).

You have the option in your vendor daemon of allowing this data to be visible or not. The daemon variable ls_show_vendor_def controls whether the vendor-defined field is visible to your end-users via lmstat (or any utility which calls lc_userlist()).

Each checkout or checkin request uses the value of the vendor-defined data from the last lc_set_attr() call. Checkins will only be performed for features on which the vendor-defined field matches.

Default: None

LM_A_CHECKOUTFILTER

Type: Pointer to a function returning int.

The checkout filter allows you to examine the FEATURE line which is going to be used in an lc_checkout() request, and either allow the checkout to proceed or reject this particular FEATURE line. This filter function will be called with a pointer to the CONFIG struct which is about to be checked out. If this function returns 0, then checkout proceeds, otherwise if this function returns a non-zero value, then the checkout proceeds to the next available FEATURE line. If this function returns a non-zero value and sets the error obtainable from lc_get_errno(), then this value will be the return of lc_checkout(), otherwise, if lc_get_errno() is set to 0 by this function, then the result of lc_checkout() would be LM_LOCALFILTER (assuming the checkout was not attempted on further FEATURE lines, or that another FEATURE line did not produce a LM_MAXUSERS result).

Default: None

LM_A_COMM_TRANSPORT

Type: short

Communications transport to use, one of LM_TCP or LM_UDP. It is recommended that this be set by the end-user (license administrator), not set in the application.

Default: LM_TCP.


Note: Not supported on VMS.


LM_A_CONN_TIMEOUT

Type: int

If specified as a positive integer, conn_timeout will set the timeout for connection to a vendor daemon, as well as subsequent reads from the daemon. For connect(), this timeout overrides the TCP/IP default of 45 seconds. lc_set_attr() will return LM_BADPARAM, while will also be returned from lc_get_errno(), if this value is <0.


Note: Prior to FLEXlm v4.0, this timeout only applied to connect().

Default: 10 seconds

LM_A_CRYPT_CASE_SENSITIVE

Type: short

If specified as a non-zero integer, LM_A_CRYPT_CASE_SENSITIVE will cause the output of the encryption routine to be compared to the code in the license file with a case-sensitive comparison.

Default: Case-insensitive comparison.

LM_A_DIAGS_ENABLED

Type: short

This option allows FLEXlm to produce some diagnostic output for failures of the lc_checkout() call if the environment variable FLEXLM_DIAGNOSTICS is set. If LM_A_DIAGS_ENABLED is set to 0, this diagnostic information is unconditionally disabled.

The FLEXLM_DIAGNOSTICS environment variable can be used by your end-users to obtain more information if a checkout fails. If FLEXLM_DIAGNOSTICS is set, an lc_perror() call is made. If FLEXLM_DIAGNOSTICS is set to “2”, then in addition to the lc_perror() call, the arguments to lc_checkout() (except for the KEY information) are printed to stderr, also.

The diagnostics are enabled by default. Globetrotter Software recommends that this be left enabled. This will allow us to help you debug your end-users' problems with error messages more explicit than, “can't get license”. In these situations, we are unable to help. We developed and distributed the FLEXLM_DIAGNOSTICS to enable us (and your support people) to help your end-users more effectively.

Default: On (1).

LM_A_DISABLE_ENV

Type: short

If set to a non-zero value, disable_env will force the FLEXlm client routines to disregard the setting of the LM_LICENSE_FILE environment variable.

Globetrotter Software strongly recommends that this default not be changed. If you disable the environment variable, see the FLEXlm Style Guide, which is available on-line with the GLOBEhelp browser.

Default: LM_LICENSE_FILE environment variable enabled.

LM_A_DISPLAY_OVERRIDE

Type: (char *)

This string, if specified, will be used to override the display name as derived from the UNIX ttyname() system call.


Note: This value cannot be changed for a job after the initial connection to the vendor daemon.

Default: No override of display name.

The most common use of this attribute is for setting the display to the X-Display name. Unfortunately, the only reliable way of obtaining the name of the X-Display is via an X call. Therefore, this can only be done by the X-based application, after XOpenDisplay (or XtAppInitialize) has been called.

DisplayString(<display>)

In addition, it is essential to note that there are at least three possible aliases for using the monitor attached to the computer in use: “localhost:0”, “UNIX:0” and “:0”. If any of these are used, the lc_set_attr(LM_A_DISPLAY_OVERRIDE) should use the result of gethostname() instead. Finally, it may be safest to use the IP address as a string, to avoid the problem of aliases for a particular display host.

The following example code can be used for this purpose:

/* 
 * assume XOpenDisplay or XtAppInitialize has already been called 
 */
#include <netdb.h>
char display_name[50], *cp, display_ip[9];
struct hostent *he;
/*...*/
strncpy(display_name, DisplayString(display), 49);
if (!(strncmp(display_name, ":0", 2)) ||
                        !(strncmp(display_name, "UNIX:0", 6)) ||
                        !(strncmp(display_name, "localhost:0", 12)))
{
  static char d[50];
gethostname(d, 47);
if (*d)
{
strcat(d, ":0");
display_name = d;
}
}
he = gethostbyname(display_name)
sprintf(display_ip, "%x", *((int *)he->h_addr));
lc_set_attr(LM_A_DISPLAY_OVERRIDE, display_ip);

LM_A_EF_1, LM_A_EF_2, LM_A_EF_3, LM_A_EF_4, LM_A_EF_5

Type: int

These five event flags are used on VMS only. FLEXlm client routines assign these event flags dynamically. You can reassign the event flags used by FLEXlm by calling lc_set_attr() for the attributes LM_A_EF_1, LM_A_EF_2, LM_A_EF_3., LM_A_EF_4, or LM_A_EF_5. The only restriction is that flag #1 and flag #2 must be in the same event flag cluster. If you reset them, do it before calling any FLEXlm routines. You can use lib$get_ef and lib$free_ef to assign event flag numbers, if desired.

Default: Event flags assigned with lib$get_ef()

LM_A_ETHERNET_BOARDS

Type: (char **)

This table of ethernet devices, if specified, will be searched before the standard FLEXlm ethernet device table is searched. This can be used either to override the FLEXlm device order, or to add new devices that are not built into the FLEXlm table. This table is used for both Ultrix and VMS systems but not for Windows and Windows NT systems. The table should be specified as a NULL-terminated array of character string pointers, as in the following example (this example is the standard Ultrix table):

char *our_ethernet_boards[] =
"qe0",
"de0",
"se0",
"ni0",
"ln0",
"xna0",
"ne0",
0};
lc_set_attr(LM_A_ETHERNET_BOARDS, our_ethernet_boards);

For VMS systems, be sure to include each interface in the table four times as xxa0:, xxa1:, xxa2:, and xxa3: (for device xx). The following example is the FLEXlm standard ethernet device table for VMS:

{"flexlm_hostid0", "flexlm_hostid1", "flexlm_hostid2", "flexlm_hostid3",
"_xqa0:", "_xqa1:", "_xqa2:", "_xqa3:",  /* DELQA, DEQNA, DESQA */
"_xea0:", "_xea1:", "_xea2:", "_xea3:",  /* DEUNA, DELUA */
"_esa0:", "_esa1:", "_esa2:", "_esa3:",  /* DESVA */
"_eta0:", "_eta1:", "_eta2:", "_eta3:",  /* DEBNA */
"_eza0:", "_eza1:", "_eza2:", "_eza3:",  /* uVAX 4000 */
"_exa0:", "_exa1:", "_exa2:", "_exa3:",  /* VAX 9000 */
"_ewa0:", "_ewa1:", "_ewa2:", "_ewa3:",  /* Alpha */
0 };

In order to update your daemon for a new set of ethernet addresses, you will need to put this call to lc_set_attr() into an initialization routine and set ls_user_init1 to the name of your initialization routine, as in the following example:

In any source module:

void daemon_init()
{
static char *new_board[] = {"new_board", 0};

lc_set_attr(LM_A_ETHERNET_BOARDS, new_board);
}

In ls_vendor.c:

extern void daemon_init();
void (*ls_user_init1)() = daemon_init;

Then, modify the makefile for the daemon to include your module with daemon_init(), or put this module into the liblmgr_as.a archive. On Ultrix systems, CONFIG_DAEMON will automatically make the edit to ls_vendor.c if you answer “daemon_init” to the daemon initialization (START) question.

Default: Only standard FLEXlm table searched.

LM_A_HOST_OVERRIDE

Type: (char *)

This string, if specified, will be used to override the hostname as derived from the UNIX gethostname() system call.


Note: This value cannot be changed for a job after the initial connection to the vendor daemon.

Default: No override of host name.

LM_A_HOSTID_PARSE

Type: Pointer to a function returning int.

int parse_id(HOSTID *id, char *hostid)

LM_A_HOSTID_PARSE, LM_A_VENDOR_GETHOSTID, LM_A_VENDOR_PRINTHOSTID, and LM_A_VENDOR_CHECKID are used by vendors who want to install their own vendor-defined hostid to extend the types of hostids which FLEXlm can support.

The hostid parsing routine takes the input “hostid” character string and returns the structure pointed to by “id”. If successful, parse_id returns zero, otherwise a non-zero value.

Default: None

LM_A_LF_LIST

Type: pointer to (char **)

List of all license files searched for features. Useful for failure messages for debugging. Note that lc_lic_where() only prints one file, the one last searched. For example:

#include "lm_attr.h"
/*...*/
char **cp;
lc_get_attr(job, LM_A_LF_LIST, (LM_A_VAL_TYPE)&cp);
if (cp)
{
puts("files searched are: ");
while (*cp)
printf("\t%s\n",*cp++);
}

LM_A_LICENSE_FILE

Type: (char *)

It is recommended that LM_A_LICENSE_FILE_PTR be used instead of LM_A_LICENSE_FILE.


Note: In FLEXlm v3.0 and later, Globetrotter Software strongly recommends the use of LM_A_LICENSE_FILE_PTR rather than LM_A_LICENSE_FILE. Globetrotter Software strongly recommends that all code of the form:


char path[MAXPATHLEN+1];
lc_get_attr(LM_A_LICENSE_FILE, path);

be changed to:

char *path;
lc_get_attr(LM_A_LICENSE_FILE, &path);

LM_A_LICENSE_FILE_PTR

Type: (char *), lc_set_attr,
 or pointer to (char *), lc_get_attr

This string will be used as the default license file pathname, overriding /usr/local/flexlm/licenses/license.dat (or C:\FLEXLM\LICENSE.DAT for Windows and Windows NT), unless the LM_LICENSE_FILE environment variable is set. To override LM_LICENSE_FILE, use LM_A_DISABLE_ENV.

lc_get_attr() expects an address of a (char *) pointer; the pointer's value will be set to the license file, but no data will be copied. If you want to modify the data, you should make a private copy. For example:

char *path;
lc_get_attr(job, LM_A_LICENSE_FILE_PTR, (short *)&path);

In practice, it is recommended that if you use LM_A_LICENSE_FILE_PTR with LM_A_DISABLE_ENV, you should do it in a manner similar to the following, to preserve the existing value of the LM_LICENSE_FILE environment variable:

char *currenv;
char newenv[LM_MAXPATHLEN];
char *desired_license_location = "/usr/product/license.dat"; 
currenv = getenv("LM_LICENSE_FILE");
if (!currenv) 
strcpy(newenv, desired_license_location);
else
/*
 *Create a colon-separated list, with our location last
 */
sprintf(newenv, "%s:%s", crrrenv, desired_license_location);
lc_set_attr(LM_A_DISABLE_ENV, (LM_A_VAL_TYPE) 1);
lc_set_attr(LM_A_LICENSE_FILE_PTR, newenv);


Note: On VMS systems, the default license file is SYS$COMMON:[SYSMGR]flexlm.dat


LM_A_LINGER

Type: long

This option controls the license linger time for your application. Any checkout performed after setting LINGER to a non-zero value will cause the license to be held by the vendor daemon for the specified number of seconds after either a checkin or your process dies. The vendor daemon only checks for lingering licenses once per minute, which will define the limit the granularity of this setting.

Default: 0 (No linger).

LM_A_MASTER

Type: (char *)

Gets the name of the master server when redundant servers are being used. This must only be used after the client is already connected to a server, via lm_userlist(), lm_checkout(), or lc_get_attr(LM_A_VD_*...).

Error returns

LM_BADPARAM 


connection not established yet.

LM_A_MAX_TIMEDIFF

Type: int

This field allows you to specify the maximum number of minutes that the client system's clock and the server systems's clock can differ. If set to a negative number, no check is performed. If set > 0, then the client and server's system clocks must agree within the specified number of minutes.


Note: You cannot set this parameter to 0 with lc_set_attr().

Default: -1, No check performed.

LM_A_NO_DEMO

Type: short

This field allows you to defeat the license file DEMO capability. If LM_A_NO_DEMO is set to 0, DEMO license files are allowed; if no_demo is set to a non-zero value, then DEMO license files are disallowed.

Default: 0, Demo is allowed.

LM_A_NO_TRAFFIC_ENCRYPT

Type: short

This field allows you to defeat the encryption of traffic that happens between client and server programs. If you set this parameter to a non-zero value, client-server communications will be unencrypted, as they were in V1.x FLEXlm.

Default: 0, Traffic is encrypted.

LM_A_PERIODIC_CALL

Type: Pointer to a function returning int. Return value not used.

This function, if specified, will be called each LM_A_PERIODIC_COUNT times that lc_timer() is called. lc_timer() is called directly or automatically depending on the value of LM_A_CHECK_INTERVAL.

Default: No periodic call.

LM_A_PERIODIC_COUNT

Type: int

This is the count of how many times lc_timer() must be called before the function specified by LM_A_PERIODIC_CALL is called. lc_timer() is called directly or automatically depending on the value of LM_A_CHECK_INTERVAL.

Default: 0 (No PERIODIC_CALL).

LM_A_RETRY_COUNT, LM_A_RETRY_INTERVAL

Type: int

Together, LM_A_RETRY_COUNT and LM_A_RETRY_INTERVAL are used for automatic reconnection to a daemon. Once daemon failure is detected, the client library routines will attempt to re-connect to a daemon. If reconnection fails, then the reconnect will be re-attempted LM_A_RETRY_COUNT times at intervals of LM_A_RETRY_INTERVAL. This timing will be done with the same timer that detects the daemon's failure. If no FLEXlm timers (SIGALRM) are desired, set LM_A_RETRY_INTERVAL to a negative value. The minimum value for LM_A_RETRY_INTERVAL is 30 seconds.

The default for LM_A_RETRY_COUNT is 5; the default for LM_A_RETRY_INTERVAL is 60.

LM_A_SETITIMER

Type: Pointer to a function returning void.

This option allows you to replace setitimer() with a routine of your choice. This might be done, for example, if your application uses XView or Sunview, where alarm() and setitimer() are not allowed.

The FLEXlm routine that connects to the daemon (l_basic_conn()) uses SIGALRM and the real timer even if the standard FLEXlm timer routines have been disabled by setting LM_A_CHECK_INTERVAL and LM_A_RETRY_INTERVAL to -1. Although l_basic_conn() replaces the old values for the SIGALRM handler and the old timer interval, this operation is incompatible with the Xview function notify_setitimer(). As a result, you may replace the timer/signal handling in l_basic_conn() (so that you can use notify_setitimer) with the following two calls:

lc_set_attr(LM_A_SETITIMER, new_setitimer_func);
lc_set_attr(LM_A_SIGNAL, new_signal_func);

where:  

is the:

new_setitimer_func 


is a function to replace setitimer. It must take the same parameters as setitimer and return void.

new_signal_func 


is a function to replace signal. It must take the same parameters as signal and return a pointer to a function returning either an int or void, depending on the platform. (it should return the same type as signal() returns on the platform).


Note: The FLEXlm implementation of setitimer() uses the sys$setimr() call on VMS.

Default: setitimer().

LM_A_SIGNAL

Type: Pointer to a function returning (pointer to function returning void).

This option allows you to replace “signal() with a routine of your choice. This would be done, for example, if your application uses XView or Sunview, where SIGALRM is not allowed, or if you want to replace signal with sigaction. Make sure your replacement function takes the same arguments as signal. This function is not supported on VMS, Windows, or Windows NT systems.

Default: signal().

LM_A_UDP_TIMEOUT

Type: int

This sets the amount of time (in seconds) during which a client must communicate with the vendor daemon for the UDP communications transport. If the client does not communicate within this interval (by calling lc_timer()), then the vendor daemon will release the license just as if an lc_checkin() call had been made.

Default: 45 minutes (2700).

LM_A_USE_START_DATE

Type: short

This field allows you to use the start date that is built into the license file for each feature. If the current system date is earlier than the start date, then checkouts of the feature will be disabled. If set to a non-zero value, the start date will be used. LM_A_USE_START_DATE can only be turned off with lc_set_attr().


Note: If you use your own encryption routine, you must either disable the use of the start date, or create an license key which contains a valid start date. See the description of the LM_A_USER_CRYPT attribute.

Default: 1, Use start date.

LM_A_USER_CRYPT

Type: Pointer to a function returning (char *). Return value is the license key.

The function pointer crypt can be set to point to a vendor-supplied encryption routine to be used in place of the default routine.

Default: FLEXlm standard encryption routine. (See “LM_CODE” for more information.)

The crypt routine is called as follows:

(*crypt)(conf,sdate, key);

where:  

is the:

(CONFIG *) conf 


CONFIG structure pointer.

(char *) sdate 

4-byte encoded start date.

(VENDORCODE *) key 


Pointer to the 1st argument to the LM_CODE macro in lm_code.h, where code.data[0] and code.data[1] have been XOR'd with VENDOR_KEY5, so that the encryption seeds are as specified in lm_code.h.

The function must return a character string (maximum length of MAX_CRYPT_LEN, minimum length of 8 characters), which is the encrypted code that should be in the license file. If you use your own encryption routine, then modify create_lic.c and lmcrypter.c to call it, so that it can generate the correct license keys for your customers. You must also specify the same encryption routine when building your vendor daemon. The standard encryption routine encrypts and encodes the sdate parameter into the features code. sdate can be extracted from a license file FEATURE line's code field as follows:

l_extract_date(code)

where code is the output of the (standard) encryption routine. l_extract_date() returns char *.


Note: If your encryption routine has any order dependencies, it should sort the hostid's of the servers, so that you will obtain repeatable results when the end-user re-orders the SERVER lines to bias the master node selection.


LM_A_USER_EXITCALL

Type:Pointer to a function returning int. Return value unused.

The function pointer LM_A_USER_EXITCALL can be set to point to the routine that is to receive control if reconnection fails after LM_A__RETRY_COUNT attempts. If no routine is specified, then lc_perror is called, and the program will exit. If the LM_A_USER_EXITCALL function returns control to its caller, program operation will continue as if no license had been checked out. The LM_A_USER_EXITCALL routine is called as follows:

(*exitcall)(feature)

Default: No user exit handler (program exits).

The exitcall() function will be called for each feature that the program had checked out, if that feature's license is lost. If the exitcall() function returns, it will be called again for the next feature. After it has been called for all features, control will return to the program at the point where detection of loss of licenses occurred.

See also

LM_A_USER_OVERRIDE

Type: (char *)

This string, if specified, will be used to override the username as derived from the UNIX password file. Vendors of software for Apollo systems might want to use this field to avoid the /etc/passwd lookup for Aegis-only sites.


Note: This value cannot be changed after the initial connection to the vendor daemon.

Default: No override of username.

LM_A_USER_RECONNECT

Type: Pointer to a function returning int. Return value unused.

This reconnection routine is called each time just before a reconnection is attempted, either automatically as a result of the timer set by LM_A_CHECK_INTERVAL, or as a result of the application program calling lc_timer.

Default: No user reconnection handler.

The reconnection routine is called as follows:

(*reconnect)(feature, pass, total_attempts, interval)

where:  

is the:

(char *)feature 

Feature name.

(int)pass  

Current attempt #.

(int)total_attempts 


Maximum number of passes that will be attempted.

(int)interval 

Time in seconds between reconnection attempts.

If LM_A_RETRY_COUNT is set to a value <=0, then the reconnect handler will not be called.

LM_A_USER_RECONNECT_DONE

Type: Pointer to a function returning int. Return value unused.

This function will be called when reconnection is successfully completed.

Default: No user reconnect_done handler.

The reconnection done handler is called as follows:

(*reconnect_done)(feature, tries, total_attempts, interval)

where:  

is the:

(char *)feature  

feature name.

(int)tries 

number of attempts that were required to re-connect for this feature.

(int)total_attempts 


maximum number of retry attempts that would be made.

(int)interval 

interval in seconds between reconnection attempts.

LM_A_VD_GENERIC_INFO, LM_A_VD_FEATURE_INFO

Type: Pointer to LM_VD_GENERIC_INFO or pointer to LM_VD_FEATURE_INFO

Both attributes get information from your vendor daemon. LM_A_VD_GENERIC_INFO gets information which is not specific to a feature, and which is mostly found in ls_vendor.c.

LM_A_VD_FEATURE_INFO gets information about a particular feature, and provides an accurate count of licenses used, users queued, etc., and works correctly when a license file has more than one FEATURE or INCREMENT line for the same feature name.

These attributes will only work on your vendor daemon. If a request is made for a feature only served by a different vendor daemon, then lc_get_errno() is set to LM_NOADMINAPI.

A pointer to a struct is given as an argument to lc_get_attr, and upon successful return, this struct is filled with the appropriate information. The following example illustrates the use of both attributes:

#include "lm_client.h"
#include "lm_code.h"
#include "lm_attr.h"
/* ... */
/* 
 * Print out GENERIC and FEATURE information for every
 * license file line for a given feature name
 */
void
vendor_daemon_info(job, feature)
LM_HANDLE *job; /* if you want to use lc_* functions instead */
char *feature;
{
  CONFIG *conf, *c;
  LM_VD_GENERIC_INFO gi;
  LM_VD_FEATURE_INFO fi;
  int first = 1;

c = (CONFIG *)0; 

for (conf = lc_next_conf(job, feature, &c);conf; 
conf=lc_next_conf(job, feature, &c))
{
if (first)
{
/* 
 * get generic daemon info
 */
gi.feat = conf;
if (lc_get_attr(job, LM_A_VD_GENERIC_INFO,
(short *)&gi))
{
lc_perror(job, "LM_A_VD_GENERIC_INFO");
}
else 
{
printf("conn-timeout = %d\n", 
gi.conn_timeout);
printf(" user_init1 %d\n", gi.user_init1);
printf(" user_init2 %d\n", gi.user_init2);
printf(" outfilter %d\n", gi.outfilter);
printf(" infilter %d\n", gi.infilter);
printf(" callback %d\n", gi.callback);
printf(" vendor_msg %d\n", gi.vendor_msg);
printf(" vendor_challenge %d\n", 
gi.vendor_challenge);
printf(" lockfile %d\n", gi.lockfile);
printf(" read_wait %d\n", gi.read_wait);
printf(" dump_send_data %d\n", 
gi.dump_send_data);
printf(" normal_hostid %d\n",
gi.normal_hostid);
printf(" conn_timeout %d\n", 
gi.conn_timeout);
printf(" enforce_startdate %d\n", 
gi.enforce_startdate);
printf(" tell_startdate %d\n", 
gi.tell_startdate);
printf(" minimum_user_timeout %d\n", 
   gi.minimum_user_timeout);
printf(" min_lmremove %d\n", 
gi.min_lmremove);
printf(" use_featset %d\n", 
gi.use_featset);
printf(" dup_sel 0x%x\n", gi.dup_sel);
printf(" use_all_feature_lines %d\n",
    gi.use_all_feature_lines);
printf(" do_checkroot %d\n", 
gi.do_checkroot);
printf(" show_vendor_def %d\n", 
gi.show_vendor_def);
printf(" allow_borrow %d\n", 
gi.allow_borrow);
}
first = 0;
}
fi.feat = conf;
if (lc_get_attr(job, LM_A_VD_FEATURE_INFO, (short *)&fi))
{
lc_perror(job, "LM_A_VD_FEATURE_INFO");
}
else
{
/* 
 * get specific feature info
 */
printf("lowwater %d\n", fi.lowwater);
printf("timeout %d\n", fi.timeout);
printf("linger %d\n", fi.linger);
printf("dup_select 0x%x\n", fi.dup_select);
printf("res %d\n", fi.res);
printf("maxborrow %d\n", fi.maxborrow);
printf("lic_in_use %d\n", fi.lic_in_use);
printf("user_cnt %d\n", fi.user_cnt);
printf("lic_avail %d\n", fi.lic_avail);
printf("queue_cnt %d\n", fi.queue_cnt);
printf("overdraft %d\n", fi.overdraft);
}
}
}

LM_A_VENDOR_CHECKID

Type: Pointer to a function returning int.

int check_id(HOSTID *id1, HOSTID *id2)

The vendor_checkid routine takes two HOSTID pointers, and returns 0 if they are different; 1 if they are the same. This is for supporting vendor-defined hostid.

Default: None.

LM_A_VENDOR_GETHOSTID

Type: Pointer to a function returning (HOSTID *).

HOSTID *get_hostid(short idtype)

The vendor_gethostid routine returns a pointer to a HOSTID struct after retrieving the hostid of type “idtype”. This is for supporting vendor-defined hostid.

Default: None.

LM_A_VENDOR_PRINTHOSTID

Type: Pointer to a function returning (char *).

char *print_id(HOSTID *id)

The print_id routine takes the input “id” struct and returns a pointer to the corresponding string. This is for supporting vendor-defined hostid.

This string should be <= MAX_HOSTID_LEN bytes

Default: None.

LM_A_VERSION and LM_A_REVISION

Type: short

FLEXlm version. Cannot be set. Only for use with lc_get_attr().

Default: Version and revision of the libraries you have linked with.