1/* BEGIN LICENSE BLOCK
2 * Version: CMPL 1.1
3 *
4 * The contents of this file are subject to the Cisco-style Mozilla Public
5 * License Version 1.1 (the "License"); you may not use this file except
6 * in compliance with the License.  You may obtain a copy of the License
7 * at www.eclipse-clp.org/license.
8 *
9 * Software distributed under the License is distributed on an "AS IS"
10 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See
11 * the License for the specific language governing rights and limitations
12 * under the License.
13 *
14 * The Original Code is  The ECLiPSe Constraint Logic Programming System.
15 * The Initial Developer of the Original Code is  Cisco Systems, Inc.
16 * Portions created by the Initial Developer are
17 * Copyright (C) 2001 - 2006 Cisco Systems, Inc.  All Rights Reserved.
18 *
19 * Contributor(s): ___________________________________.
20 *
21 * END LICENSE BLOCK
22 *
23 * ECLiPSe LIBRARY MODULE
24 *
25 * $Id: bip_pt.c,v 1.1 2006/09/23 01:53:18 snovello Exp $
26 *
27 *
28 * IDENTIFICATION:	bip_pt.c
29 *
30 * AUTHOR:		Joachim Schimpf, IC-Parc
31 *
32 * CONTENTS:
33 *
34 *  licence_checkout(+Feature, +Policy, +Version, +Path, -Message, -Status)
35 *  licence_heartbeat(+Feature, +Minutes, -Reconnects, -FailedReconnects)
36 *  licence_checkin(+Feature)
37 *  licence_held(+Feature)
38 *
39 * DESCRIPTION:
40 *
41 *  Interface to FLEXlm licence manager software
42 *
43 */
44
45
46#define EC_EXTERNAL
47
48#ifdef _WIN32
49#include <windows.h>
50#define Winapi WINAPI
51#else
52#define Winapi
53#endif
54
55#ifdef _WIN32
56#  include 	<stdlib.h>
57#  define MAX_PATH_LEN	_MAX_PATH
58#else
59#ifdef PATH_IN_LIMITS
60#  include 	<limits.h>
61#  define MAX_PATH_LEN	PATH_MAX
62#else
63#  include <sys/param.h>
64#  define MAX_PATH_LEN	MAXPATHLEN
65#endif
66#endif
67
68
69#include "external.h"
70
71int DLLEXP pteclipse_init(int flags);
72
73#ifdef HAVE_FLEXLM
74
75#undef PERROR	/* lmpolicy.h contains a redefinition  of this name */
76
77#include "lmpolicy.h"
78
79
80/* The handle for the checked out 'eclipse' feature */
81
82static LP_HANDLE *eclipse_lp_handle = 0;
83
84
85/* A list of all features checked out with licence_checkout/6 */
86
87struct checked_out_feature {
88    dident	feature;
89    dident	version;
90    int		policy;
91    LP_HANDLE	*lp_handle;
92    struct checked_out_feature *next;
93};
94
95static struct checked_out_feature *
96		checked_out_features = 0;
97
98
99#define MAX_FLEXLM_POLICIES	7
100
101static dident	lm_policy_name[MAX_FLEXLM_POLICIES];
102static int	lm_policy_flag[MAX_FLEXLM_POLICIES];
103
104static dident	d_ok, d_warning;
105
106
107#define Get_Name_Did(v, t, d) \
108    if (IsRef(t)) { Bip_Error(INSTANTIATION_FAULT); } \
109    else if (IsAtom(t)) { d = (v).did; } \
110    else if (IsString(t)) { d = ec_did(StringStart(v),0); } \
111    else { Bip_Error(TYPE_ERROR); }
112
113
114
115static int
116p_licence_checkout(value vfeature, type tfeature, value vpol, type tpol, value vversion, type tversion, value vlicloc, type tlicloc, value vmsg, type tmsg, value vstat, type tstat)
117{
118    LP_HANDLE *lp_handle;
119    char lic_path[MAX_PATH_LEN];
120    char *licloc;
121    dident feature, version;
122    struct checked_out_feature *cof;
123    int policy = LM_MANUAL_HEARTBEAT;
124    Prepare_Requests;
125
126    Get_Name_Did(vfeature, tfeature, feature);
127    Get_Name_Did(vversion, tversion, version);
128    Get_Name(vlicloc, tlicloc, licloc);
129    Check_List(tpol);
130    Check_Ref(tmsg);
131    Check_Ref(tstat);
132
133#ifdef REQUIRE_LICENCE
134    /* do a heartbeat for the 'eclipse' feature */
135    if (!eclipse_lp_handle || lp_heartbeat(eclipse_lp_handle, 0, 0))
136    {
137	pword pw;
138	Make_String(&pw, "ECLiPSe licence check failed\n");
139	Request_Unify_Pw(vmsg, tmsg, pw.val, pw.tag);
140	Request_Unify_Atom(vstat, tstat, d_.err);
141	Return_Unify;
142    }
143#endif
144
145    /* decode the policy option list */
146    if (IsList(tpol))
147    {
148	pword *car;
149	for(car=vpol.ptr;;)
150	{
151	    int i;
152	    pword *cdr = car+1;
153	    Dereference_(car);
154	    Check_Atom(car->tag);
155	    for(i=0; i<MAX_FLEXLM_POLICIES; ++i)
156	    {
157		if (lm_policy_name[i] == car->val.did)
158		    policy |= lm_policy_flag[i];
159	    }
160	    Dereference_(cdr);
161	    if (IsList(cdr->tag))
162		car = cdr->val.ptr;
163	    else if IsNil(cdr->tag)
164		break;
165	    else
166		{ Bip_Error(TYPE_ERROR); }
167	}
168    }
169    else
170    {
171    	policy |= LM_RESTRICTIVE;
172    }
173
174    /* We allow checking out multiple licences for the same feature, but only
175     * if they have the same version and policy. Because all checked out
176     * licences for one feature are then equivalent, we can use the feature
177     * name instead of a licence handle to identify it. When checking in,
178     * we just check in an arbitrary one.
179     */
180    for(cof=checked_out_features; cof; cof = cof->next)
181    {
182	if (cof->feature == feature &&
183	    ! (cof->version == version && cof->policy == policy))
184	{
185	    pword pw;
186	    Make_String(&pw, "Implementation restriction: Multiple checkout of the same\nfeature only allowed when version and policy are the same.");
187	    Request_Unify_Pw(vmsg, tmsg, pw.val, pw.tag);
188	    Request_Unify_Atom(vstat, tstat, d_.err);
189	    Return_Unify;
190	}
191    }
192
193    /* fill in the default licence path, if necessary */
194    if (*licloc == '\0')
195    {
196	char lic_path_canonical[MAX_PATH_LEN];
197	strcpy(lic_path_canonical, DidName(d_.eclipse_home));
198	strcat(lic_path_canonical, "/licence.dat");
199	licloc = os_filename(lic_path_canonical, lic_path);
200    }
201
202    /* check out and return the results */
203    if (lp_checkout(LPCODE, policy, DidName(feature), DidName(version),
204    			1, licloc, &lp_handle))
205    {
206	pword pw;
207	char *message = lp_errstring(lp_handle);
208	if (!message)		/* shouldn't happen */
209	    message = "";
210	Make_String(&pw, message);
211	Request_Unify_Pw(vmsg, tmsg, pw.val, pw.tag);
212	Request_Unify_Atom(vstat, tstat, d_.err);
213    }
214    else
215    {
216	char *message = lp_warning(lp_handle);
217
218	/* store the feature name and the checked out handle */
219	cof = (struct checked_out_feature *)
220		malloc(sizeof(struct checked_out_feature));
221	cof->feature = feature;
222	cof->version = version;
223	cof->policy = policy;
224	cof->lp_handle = lp_handle;
225	cof->next = checked_out_features;
226	checked_out_features = cof;
227
228	if (message)
229	{
230	    pword pw;
231	    Make_String(&pw, message);
232	    Request_Unify_Pw(vmsg, tmsg, pw.val, pw.tag);
233	    Request_Unify_Atom(vstat, tstat, d_warning);
234	}
235	else
236	{
237	    Request_Unify_Atom(vstat, tstat, d_ok);
238	}
239    }
240    Return_Unify;
241}
242
243
244static int
245p_licence_held(value vfeature, type tfeature)
246{
247    dident feature;
248    struct checked_out_feature *cof;
249    Get_Name_Did(vfeature, tfeature, feature);
250
251    for(cof=checked_out_features; cof; cof = cof->next)
252    {
253	if (cof->feature == feature)
254	    { Succeed_; }
255    }
256    Fail_;
257}
258
259
260static int
261p_licence_checkin(value vfeature, type tfeature)
262{
263    dident feature;
264    struct checked_out_feature *cof, **pcof;
265    Get_Name_Did(vfeature, tfeature, feature);
266
267    pcof = &checked_out_features;
268    for(cof=checked_out_features; cof; cof = cof->next)
269    {
270	if (cof->feature == feature)
271	{
272	    lp_checkin(cof->lp_handle);
273	    *pcof = cof->next;
274	    free(cof);
275	    break;
276	}
277	pcof = &cof->next;
278    }
279    Succeed_;
280}
281
282
283static int
284p_licence_heartbeat(value vfeature, type tfeature, value vminutes, type tminutes, value vrec, type trec, value vfrec, type tfrec)
285{
286    struct checked_out_feature *cof;
287    dident feature;
288    int rec_total = 0, frec_total = 0, found = 0;
289    Prepare_Requests;
290
291    Get_Name_Did(vfeature, tfeature, feature);
292    Check_Integer(tminutes);
293    for(cof=checked_out_features; cof; cof = cof->next)
294    {
295	if (cof->feature == feature)
296	{
297	    int rec;
298	    found = 1;
299	    frec_total += lp_heartbeat(cof->lp_handle, &rec, (int) vminutes.nint);
300	    rec_total += rec;
301	}
302    }
303    if (found)
304    {
305	Request_Unify_Integer(vrec, trec, rec_total);
306	Request_Unify_Integer(vfrec, tfrec, frec_total);
307	Return_Unify;
308    }
309    Fail_;
310}
311
312
313/*ARGSUSED*/
314int
315pteclipse_init(int flags)
316{
317#ifdef REQUIRE_LICENCE
318    extern char	ec_version[];
319    char lic_path[MAX_PATH_LEN];
320
321    strcpy(lic_path, DidName(d_.eclipse_home));
322    strcpy(lic_path+strlen(lic_path), "/licence.dat");
323    if (lp_checkout(LPCODE, LM_RESTRICTIVE|LM_MANUAL_HEARTBEAT,
324    	"eclipse", ec_version, 1, lic_path, &eclipse_lp_handle))
325    {
326	lp_perror(eclipse_lp_handle, "ECLiPSe");
327	eclipse_lp_handle = 0;
328	Fail_;
329    }
330#endif
331
332    (void) ec_external(ec_did("licence_checkout", 6), p_licence_checkout, d_.kernel_sepia);
333    (void) ec_external(ec_did("licence_checkin", 1), p_licence_checkin, d_.kernel_sepia);
334    (void) ec_external(ec_did("licence_heartbeat", 4), p_licence_heartbeat, d_.kernel_sepia);
335    (void) ec_external(ec_did("licence_held", 1), p_licence_held, d_.kernel_sepia);
336    lm_policy_name[0] = ec_did("restrictive",0); lm_policy_flag[0] = LM_RESTRICTIVE;
337    lm_policy_name[1] = ec_did("queue",0); lm_policy_flag[1] = LM_QUEUE;
338    lm_policy_name[2] = ec_did("failsafe",0); lm_policy_flag[2] = LM_FAILSAFE;
339    lm_policy_name[3] = ec_did("lenient",0); lm_policy_flag[3] = LM_LENIENT;
340    lm_policy_name[4] = ec_did("retry_restrictive",0); lm_policy_flag[4] = LM_RETRY_RESTRICTIVE;
341    lm_policy_name[5] = ec_did("check_baddate",0); lm_policy_flag[5] = LM_CHECK_BADDATE;
342    lm_policy_name[6] = ec_did("flexlock",0); lm_policy_flag[6] = LM_FLEXLOCK;
343    d_warning = ec_did("warning", 0);
344    d_ok = ec_did("ok", 0);
345    Succeed_;
346}
347
348#else
349
350/*ARGSUSED*/
351int
352pteclipse_init(int flags)
353{
354    Bip_Error(UNIMPLEMENTED);
355}
356
357#endif
358
359