/* * * Generic interface (implementation) manager * * Copyright 2001 Alan Robertson * 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 #include #include 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; }