summaryrefslogtreecommitdiffstats
path: root/lib/plugins/InterfaceMgr/generic.c
blob: 6ddad3b02a394df97ae78bf6fdea39c16b98c639 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
/*
 * 
 * Generic interface (implementation) manager
 *
 * Copyright 2001 Alan Robertson <alanr@unix.sh>
 * Licensed under the GNU Lesser General Public License
 *
 * This manager will manage any number of types of interfaces.
 *
 * This means that when any implementations of our client interfaces register
 * or unregister, it is us that makes their interfaces show up in the outside
 * world.
 *
 * And, of course, we have to do this in a very generic way, since we have
 * no idea about the client programs or interface types, or anything else.
 *
 * We do that by getting a parameter passed to us which tell us the names
 * of the interface types we want to manage, and the address of a GHashTable
 * for each type that we put the implementation in when they register
 * themselves.
 *
 * So, each type of interface that we manage gets its own private
 * GHashTable of the implementations of that type that are currently
 * registered.
 *
 * For example, if we manage communication modules, their exported
 * interfaces will be registered in a hash table.  If we manage
 * authentication modules, they'll have their (separate) hash table that
 * their exported interfaces are registered in.
 *
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */

#define	PIL_PLUGINTYPE		InterfaceMgr
#define PIL_PLUGINTYPE_S	"InterfaceMgr"
#define	PIL_PLUGIN		generic
#define PIL_PLUGIN_S		"generic"
#define PIL_PLUGINLICENSE	LICENSE_LGPL
#define PIL_PLUGINLICENSEURL	URL_LGPL

/* We are an interface manager... */
#define ENABLE_PLUGIN_MANAGER_PRIVATE
#define ENABLE_PIL_DEFS_PRIVATE

#include <lha_internal.h>
#include <pils/generic.h>

#include <stdio.h>

PIL_PLUGIN_BOILERPLATE("1.0", GenDebugFlag, CloseGeneralPluginManager)

/*
 * Key is interface type, value is a PILGenericIfMgmtRqst.
 * The key is g_strdup()ed, but the struct is not copied.
 */

static gboolean FreeAKey(gpointer key, gpointer value, gpointer data);

/*
 *	Places to store information gotten during registration.
 */
static const PILPluginImports*	GenPIImports;	/* Imported plugin fcns */
static PILPlugin*		GenPlugin;	/* Our plugin info */
static PILInterfaceImports*	GenIfImports;	/* Interface imported fcns */

/* Our exported generic interface management functions */
static PIL_rc RegisterGenIF(PILInterface* ifenv, void**	imports);

static PIL_rc UnregisterGenIF(PILInterface*iifinfo);

static PIL_rc CloseGenInterfaceManager(PILInterface*, void* info);

/*
 *	Our Interface Manager interfaces - exported to the universe!
 *
 *	(or at least to the interface management universe ;-).
 *
 *	These are the interfaces which are used to manage our
 *	client implementations
 */
static PILInterfaceOps		GenIfOps =
{	RegisterGenIF
,	UnregisterGenIF
};


PIL_rc PIL_PLUGIN_INIT(PILPlugin*us, PILPluginImports* imports, void*);

/*
 *	Our user_ptr is presumed to point to NULL-terminated array of
 *	PILGenericIfMgmtRqst structs.
 *
 *	These requests have pointers to GHashTables for us
 *	to put plugins into when they show up, and drop from when
 *	they disappear.
 *
 * 	Issues include:
 * 	- freeing all memory,
 * 	- making sure things are all cleaned up correctly
 * 	- Thread-safety?
 *
 * 	IMHO the global system should handle thread-safety.
 */
static PIL_rc AddAnInterfaceType(PILPlugin*us, GHashTable* MasterTable, PILGenericIfMgmtRqst* req);

PIL_rc
PIL_PLUGIN_INIT(PILPlugin*us, PILPluginImports* imports, void *user_ptr)
{
	PIL_rc			ret;
	PILGenericIfMgmtRqst*	user_req;
	PILGenericIfMgmtRqst*	curreq;
	GHashTable*	MasterTable = NULL;
	/*
	 * Force the compiler to check our parameters...
	 */
	PILPluginInitFun	fun = &PIL_PLUGIN_INIT; (void)fun;


	GenPIImports = imports;

	if (GenDebugFlag) {
		PILCallLog(GenPIImports->log, PIL_DEBUG
		,	"IF manager %s: initializing.", PIL_PLUGIN_S);
	}

	if (user_ptr == NULL) {
		PILCallLog(GenPIImports->log, PIL_CRIT
		,	"%s Interface Manager requires non-NULL "
		" PILGenericIfMgmtRqst user pointer at initialization."
		,	PIL_PLUGIN_S);
		return PIL_INVAL;
	}

	GenPlugin = us;

	if (GenDebugFlag) {
		PILCallLog(GenPIImports->log, PIL_DEBUG
		,	"IF manager %s: registering as a plugin."
		, PIL_PLUGIN_S);
	}

	user_req = user_ptr;
	MasterTable = g_hash_table_new(g_str_hash, g_str_equal);
	us->ud_plugin = MasterTable;	/* Override passed value */

	/* Register ourselves as a plugin */

	if ((ret = imports->register_plugin(us, &OurPIExports)) != PIL_OK) {
		PILCallLog(imports->log, PIL_CRIT
		,	"IF manager %s unable to register as plugin (%s)"
		,	PIL_PLUGIN_S, PIL_strerror(ret));

		return ret;
	}

	/*
	 * Register to manage implementations
	 * for all the interface types we've been asked to manage.
	 */

	for(curreq = user_req; curreq->iftype != NULL; ++curreq) {
		PIL_rc newret;

		newret = AddAnInterfaceType(us, MasterTable, curreq);

		if (newret != PIL_OK) {
			ret = newret;
		}
	}

	/*
	 * Our plugin and all our registered plugin types
	 * have ud_plugin pointing at MasterTable.
	 */

	return ret;
}

static PIL_rc
AddAnInterfaceType(PILPlugin*us, GHashTable* MasterTable, PILGenericIfMgmtRqst* req)
{
	PIL_rc	rc;
	PILInterface*		GenIf;		/* Our Generic Interface info*/

	g_assert(MasterTable != NULL);
	g_hash_table_insert(MasterTable, g_strdup(req->iftype), req);

	if (req->ifmap == NULL) {
		PILCallLog(GenPIImports->log, PIL_CRIT
		,	"IF manager %s: iftype %s has NULL"
		" ifmap pointer address."
		,	PIL_PLUGIN_S, req->iftype);
		return PIL_INVAL;
	}
	if ((*req->ifmap) != NULL) {
		PILCallLog(GenPIImports->log, PIL_CRIT
		,	"IF manager %s: iftype %s GHashTable pointer"
		" was not initialized to NULL"
		,	PIL_PLUGIN_S, req->iftype);
		return PIL_INVAL;
	}

	if (GenDebugFlag) {
		PILCallLog(GenPIImports->log, PIL_DEBUG
		,	"IF manager %s: registering ourselves"
		" to manage interface type %s"
		,	PIL_PLUGIN_S, req->iftype);
		PILCallLog(GenPIImports->log, PIL_DEBUG
		,	"%s IF manager: ifmap: 0x%lx callback: 0x%lx"
		" imports: 0x%lx"
		,	PIL_PLUGIN_S
		,	(unsigned long)req->ifmap
		,	(unsigned long)req->callback
		,	(unsigned long)req->importfuns);
	}

	/* Create the hash table to communicate with this client */
	*(req->ifmap) = g_hash_table_new(g_str_hash, g_str_equal);

	rc = GenPIImports->register_interface(us
	,	PIL_PLUGINTYPE_S
	,	req->iftype	/* the iftype we're managing here */
	,	&GenIfOps
	,	CloseGenInterfaceManager
	,	&GenIf
	,	(void*)&GenIfImports
	,	MasterTable);	/* Point ud_interface to MasterTable */

	/* We don't ever want to be unloaded... */
	GenIfImports->ModRefCount(GenIf, +100);

	if (rc != PIL_OK) {
		PILCallLog(GenPIImports->log, PIL_CRIT
		,	"Generic interface manager %s: unable to register"
		" to manage interface type %s: %s"
		,	PIL_PLUGIN_S, req->iftype
		,	PIL_strerror(rc));
	}
	return rc;
}

static void
CloseGeneralPluginManager(PILPlugin* us)
{
	
	GHashTable*	MasterTable = us->ud_plugin;
	int		count;

	g_assert(MasterTable != NULL);

	/*
	 * All our clients have already been shut down automatically
	 * This is the final shutdown for us...
	 */


	/* There *shouldn't* be any keys in there ;-) */

	if ((count=g_hash_table_size(MasterTable)) > 0) {

		/* But just in case there are... */
		g_hash_table_foreach_remove(MasterTable, FreeAKey, NULL);
	}
	g_hash_table_destroy(MasterTable);
	us->ud_plugin = NULL;
	return;
}

/*
 *	We get called for every time an implementation registers itself as
 *	implementing one of the kinds of interfaces we manage.
 *
 *	It's our job to make the implementation that's
 *	registering with us available to the system.
 *
 *	We do that by adding it to a GHashTable for its interface type
 *	Our users in the rest of the system takes it from there...
 *
 *	The key to the GHashTable is the implementation name, and the data is
 *	a pointer to the information the implementation exports.
 *
 *	It's a piece of cake ;-)
 */
static PIL_rc
RegisterGenIF(PILInterface* intf,  void** imports)
{
	PILGenericIfMgmtRqst*	ifinfo;
	GHashTable*	MasterTable = intf->ifmanager->ud_interface;

	g_assert(MasterTable != NULL);

	/* Reference count should now be one */
	if (GenDebugFlag) {
		PILCallLog(GenPIImports->log, PIL_DEBUG
		,	"%s IF manager: interface %s/%s registering."
		,	PIL_PLUGIN_S, intf->interfacetype->typename
		,	intf->interfacename);
	}
	g_assert(intf->refcnt == 1);
	/*
	 * We need to add it to the table that goes with this particular
	 * type of interface.
	 */
	if ((ifinfo = g_hash_table_lookup(MasterTable
	,	intf->interfacetype->typename)) !=	NULL)	{
		GHashTable*		ifmap = *(ifinfo->ifmap);

		g_hash_table_insert(ifmap, intf->interfacename,intf->exports);
		if (GenDebugFlag) {
			PILCallLog(GenPIImports->log, PIL_DEBUG
			, "%s IF manager: Inserted interface [%s] in hash"
			" table @ 0x%08lx"
			, PIL_PLUGIN_S, intf->interfacename
			, (unsigned long)ifmap);
			PILCallLog(GenPIImports->log, PIL_DEBUG
			, "%s IF manager: Exports are here: 0x%08x"
			, PIL_PLUGIN_S
			, GPOINTER_TO_UINT(intf->exports));
		}

		if (ifinfo->callback != NULL) {
			PILInterfaceType*	t = intf->interfacetype;

			if (GenDebugFlag) {
				PILCallLog(GenPIImports->log, PIL_DEBUG
				,	"%s IF manager: callback 0x%lx"
				,	PIL_PLUGIN_S
				,	(unsigned long)ifinfo->callback);
			}
			ifinfo->callback(PIL_REGISTER
			,	t->universe->piuniv, intf->interfacename
			,	t->typename, ifinfo->userptr);
		}

		*imports = ifinfo->importfuns;

		return PIL_OK;

	}else{
		PILCallLog(GenPIImports->log, PIL_WARN
		,	"RegisterGenIF: interface type %s not found"
		,	intf->interfacename);
	}
	return PIL_INVAL;
}

/* Unregister an implementation -
 * 	We get called from the interface management system when someone
 * 	has requested that an implementation of a client interface be
 * 	unregistered.
 */
static PIL_rc
UnregisterGenIF(PILInterface*intf)
{
	GHashTable*	MasterTable = intf->ifmanager->ud_interface;
	PILGenericIfMgmtRqst*	ifinfo;

	g_assert(MasterTable != NULL);
	g_assert(intf->refcnt >= 0);
	/*
	 * Go through the "master table" and find client table, 
	 * notify client we're about to remove this entry, then
	 * then remove this entry from it.
	 */
	if (GenDebugFlag) {
		PILCallLog(GenPIImports->log, PIL_DEBUG
		,	"%s IF manager: unregistering interface %s/%s."
		,	PIL_PLUGIN_S, intf->interfacetype->typename
		,	intf->interfacename);
	}
	if ((ifinfo = g_hash_table_lookup(MasterTable
	,	intf->interfacetype->typename)) != NULL)	{

		GHashTable*		ifmap = *(ifinfo->ifmap);

		if (ifinfo->callback != NULL) {
			PILInterfaceType*	t = intf->interfacetype;
			if (GenDebugFlag) {
				PILCallLog(GenPIImports->log, PIL_DEBUG
				,	"%s IF manager: callback 0x%lx"
				,	PIL_PLUGIN_S
				,	(unsigned long)ifinfo->callback);
			}
			ifinfo->callback(PIL_UNREGISTER
			,	t->universe->piuniv, intf->interfacename
			,	t->typename, ifinfo->userptr);
		}

		/* Remove the client entry from master table */
		g_hash_table_remove(ifmap, intf->interfacename);

	}else{
		PILCallLog(GenPIImports->log, PIL_WARN
		,	"UnregisterGenIF: interface type %s not found"
		,	intf->interfacename);
		return PIL_INVAL;
	}
	return PIL_OK;
}

/*
 *	Close down the generic interface manager.
 */
static PIL_rc
CloseGenInterfaceManager(PILInterface*intf, void* info)
{
	void*		key;
	void*		data;
	GHashTable*	MasterTable = intf->ud_interface;

	if (GenDebugFlag) {
		PILCallLog(GenPIImports->log, PIL_INFO
		,	"In CloseGenInterFaceManager on %s/%s (MasterTable: 0x%08lx)"
		,	intf->interfacetype->typename, intf->interfacename
		,	(unsigned long)MasterTable);
	}


	g_assert(MasterTable != NULL);
	if (g_hash_table_lookup_extended(MasterTable
	,	intf->interfacename, &key, &data)) {
		PILGenericIfMgmtRqst*	ifinfo = data;
		g_hash_table_destroy(*(ifinfo->ifmap));
		*(ifinfo->ifmap) = NULL;
		g_hash_table_remove(MasterTable, key);
		g_free(key);
	}else{
		g_assert_not_reached();
	}
	return PIL_OK;
}

static gboolean
FreeAKey(gpointer key, gpointer value, gpointer data)
{
	g_free(key);
	return TRUE;
}