diff options
Diffstat (limited to 'ldap/servers/slapd/factory.c')
| -rw-r--r-- | ldap/servers/slapd/factory.c | 458 |
1 files changed, 458 insertions, 0 deletions
diff --git a/ldap/servers/slapd/factory.c b/ldap/servers/slapd/factory.c new file mode 100644 index 00000000..b4ef0585 --- /dev/null +++ b/ldap/servers/slapd/factory.c @@ -0,0 +1,458 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ + +#include "slap.h" + +/* + * This module provides a mechanism for extending core server objects. + * This functionality is provided to plugin writers so that they may + * efficiently pass state information between plugin calls. Typically + * a plugin might register both a pre-op and post-op call. It's very + * convenient for the plugin to associate it's private data with the + * operation object that's passed through the PBlock. + * + * --- An interface is made available to the core server. + * + * int factory_register_type(const char *name, size_t offset) + * void *factory_create_extension(int type,void *object,void *parent) + * void factory_destroy_extension(int type,void *object,void *parent,void **extension) + * + * An object that wishes to make itself available for extension must + * register with the Factory. It passes it's name, say 'Operation', + * and an offset into the structure of where the extension block + * is to be stored. In return a type handle is passed back, which is + * used in place of the name in the creation and destruction calls. + * + * When an object is created, which has registered as extensible, it + * must call the factory_create_extension with its type handle so that + * the extension block can be constructed. A pointer to the block is + * returned that *must* be stored in the object structure at the offset + * declared by the call to factory_register_type. + * + * When an extensible object is destroyed the extension block must also + * be destroyed. The factory_destroy_extension call is provided to + * tidy up and free any extenions created for this object. + * + * --- An interface is made available to the plugins. + * + * int slapi_register_object_extension( + * const char* objectname, + * slapi_extension_constructor_fnptr constructor, + * slapi_extension_destructor_fnptr destructor, + * int *objecttype, + * int *extensionhandle) + * void *slapi_get_object_extension(int objecttype,void *object,int extensionhandle) + * + * When the plugin is initialised it must register its object extensions. + * It must provide the name of the object to be extended, say 'Operation', + * and constructor and destructor functions. These functions are called + * when the object is constructed and destroyed. The extension functions + * would probably allocate some memory and initialise it for its + * own use. The registration function will fail if any objects have already + * been created. This is why the registration *must* happen during plugin + * initialisation. In return the plugin will receive two handles, one for + * the object type, and one for the object extension. These only have meaning + * for the slapi_get_object_extension function. + * + * A plugin retrieves a pointer to its own extension by calling slapi_get_ + * object_extension with the object from which the extension is to be + * retrieved. The factory uses the objecttype to find the offset into the + * object of where the extension block is stored. The extension handle is + * then used to find the appropriate extension within the block. + * + * Currently (Oct 98) the only supported objects are Operation and Connection. + * + * This documentation is available here... + * + * http://warp/server/directory-server/hydra/replication/objext.html + */ + +/* JCM: Could implement simple object leak detection here */ + + +/* ---------------------- Factory Extension ---------------------- */ + +struct factory_extension +{ + const char *pluginname; + slapi_extension_constructor_fnptr constructor; + slapi_extension_destructor_fnptr destructor; +}; + +static struct factory_extension* +new_factory_extension( + const char *pluginname, + slapi_extension_constructor_fnptr constructor, + slapi_extension_destructor_fnptr destructor) +{ + struct factory_extension* fe= (struct factory_extension*)slapi_ch_malloc(sizeof(struct factory_extension)); + if(pluginname!=NULL) + { + fe->pluginname= slapi_ch_strdup(pluginname); + } + fe->constructor= constructor; + fe->destructor= destructor; + return fe; +} + +static void +delete_factory_extension(struct factory_extension **fe) +{ + slapi_ch_free( (void **) &((*fe)->pluginname) ); + slapi_ch_free( (void **) fe); +} + +/* ---------------------- Factory Type ---------------------- */ + +#define MAX_EXTENSIONS 32 + +struct factory_type +{ + char *name; /* The name of the object that can be extended */ + int extension_count; /* The number of extensions registered for this object */ + PRLock *extension_lock; /* Protect the array of extensions */ + size_t extension_offset; /* The offset into the object where the extension pointer is */ + long existence_count; /* Keep track of how many extensions blocks are in existence */ + struct factory_extension *extensions[MAX_EXTENSIONS]; /* The extension registered for this object type */ +}; + +static struct factory_type* +new_factory_type(const char *name, size_t offset) +{ + struct factory_type* ft= (struct factory_type*)slapi_ch_malloc(sizeof(struct factory_type)); + ft->name= slapi_ch_strdup(name); + ft->extension_lock = PR_NewLock(); + ft->extension_count= 0; + ft->extension_offset= offset; + ft->existence_count= 0; + return ft; +} + +static void +delete_factory_type(struct factory_type **ft) +{ + slapi_ch_free( (void **) &((*ft)->name)); + PR_DestroyLock((*ft)->extension_lock); + slapi_ch_free( (void **) ft); +} + +static int +factory_type_add_extension(struct factory_type *ft,struct factory_extension *fe) +{ + int extensionhandle= -1; + PR_Lock(ft->extension_lock); + if(ft->existence_count>0) + { + /* Can't register an extension if there are objects already with extension blocks */ + LDAPDebug( LDAP_DEBUG_ANY, "ERROR: factory.c: Registration of %s extension by %s failed.\n", ft->name, fe->pluginname, 0); + LDAPDebug( LDAP_DEBUG_ANY, "ERROR: factory.c: %lu %s objects already in existence.\n", ft->existence_count, ft->name, 0); + } + else + { + if(ft->extension_count<MAX_EXTENSIONS) + { + extensionhandle= ft->extension_count; + ft->extensions[ft->extension_count]= fe; + ft->extension_count++; + } + else + { + LDAPDebug( LDAP_DEBUG_ANY, "ERROR: factory.c: Registration of %s extension by %s failed.\n", ft->name, fe->pluginname, 0); + LDAPDebug( LDAP_DEBUG_ANY, "ERROR: factory.c: %d extensions already registered. Max is %d\n", ft->extension_count, MAX_EXTENSIONS, 0); + } + } + PR_Unlock(ft->extension_lock); + return extensionhandle; +} + +static void +factory_type_increment_existence(struct factory_type *ft) +{ + ft->existence_count++; +} + +static void +factory_type_decrement_existence(struct factory_type *ft) +{ + ft->existence_count--; + if(ft->existence_count<0) + { + /* This just shouldn't happen */ + LDAPDebug( LDAP_DEBUG_ANY, "ERROR: factory.c: %lu %s object extensions in existence.\n", ft->extension_count, ft->name, 0); + } +} + +/* ---------------------- Factory Type Store ---------------------- */ + +#define MAX_TYPES 16 + +static PRLock *factory_type_store_lock; +static struct factory_type* factory_type_store[MAX_TYPES]; +static int number_of_types= 0; + +static void +factory_type_store_init() +{ + int i= 0; + factory_type_store_lock= PR_NewLock(); /* JCM - Should really free this at shutdown */ + for(i=0;i<MAX_TYPES;i++) + { + factory_type_store[number_of_types]= NULL; + } +} + +static int +factory_type_store_add(struct factory_type* ft) +{ + int type= number_of_types; + factory_type_store[type]= ft; + number_of_types++; + return type; +} + +static void +factory_type_store_remove(struct factory_type *ft) +{ + int i; + int found_it = 0; + + for (i = 0; i < number_of_types; i++) + { + if (!found_it) + { + if (factory_type_store[i] == ft) + { + found_it = 1; + } + } + else + { + factory_type_store[i-1] = factory_type_store[i]; + } + } + + if (found_it) + { + factory_type_store[i-1] = NULL; + number_of_types--; + } +} + +static struct factory_type* +factory_type_store_get_factory_type(int type) +{ + if(type>=0 && type<number_of_types) + { + return factory_type_store[type]; + } + else + { + return NULL; + } +} + +static int +factory_type_store_name_to_type(const char* name) +{ + int i; + for(i=0;i<number_of_types;i++) + { + if(strcasecmp(factory_type_store[i]->name,name)==0) + { + return i; + } + } + return -1; +} + +/* ---------------------- Core Server Functions ---------------------- */ + +/* + * Function for core server usage. + * See documentation at head of file. + */ +int +factory_register_type(const char *name, size_t offset) +{ + int type= 0; + if(number_of_types==0) + { + factory_type_store_init(); + } + PR_Lock(factory_type_store_lock); + if(number_of_types<MAX_TYPES) + { + struct factory_type* ft= new_factory_type(name,offset); + type= factory_type_store_add(ft); + } + else + { + LDAPDebug( LDAP_DEBUG_ANY, "ERROR: factory.c: Registration of %s object failed.\n", name, 0, 0); + LDAPDebug( LDAP_DEBUG_ANY, "ERROR: factory.c: %d objects already registered. Max is %d\n", number_of_types, MAX_TYPES, 0); + type= -1; + } + PR_Unlock(factory_type_store_lock); + return type; +} + +/* + * Function for core server usage. + * See documentation at head of file. + */ +void * +factory_create_extension(int type,void *object,void *parent) +{ + int n; + void **extension= NULL; + struct factory_type* ft= factory_type_store_get_factory_type(type); + + if(ft!=NULL) + { + PR_Lock(ft->extension_lock); + if((n = ft->extension_count)>0) + { + int i; + factory_type_increment_existence(ft); + PR_Unlock(ft->extension_lock); + extension= (void**)slapi_ch_malloc(n*sizeof(void*)); + for(i=0;i<n;i++) + { + slapi_extension_constructor_fnptr constructor= ft->extensions[i]->constructor; + if(constructor!=NULL) + { + extension[i]= (*constructor)(object,parent); + } + } + } + else + { + /* No extensions registered. That's OK */ + PR_Unlock(ft->extension_lock); + } + } + else + { + /* The type wasn't registered. Programming error? */ + LDAPDebug( LDAP_DEBUG_ANY, "ERROR: factory.c: Object type handle %d not valid. Object not registered?\n", type, 0, 0); + } + return (void*)extension; +} + +/* + * Function for core server usage. + * See documentation at head of file. + */ +void +factory_destroy_extension(int type,void *object,void *parent,void **extension) +{ + if(extension!=NULL && *extension!=NULL) + { + struct factory_type* ft= factory_type_store_get_factory_type(type); + if(ft!=NULL) + { + int i,n; + + PR_Lock(ft->extension_lock); + n=ft->extension_count; + factory_type_decrement_existence(ft); + PR_Unlock(ft->extension_lock); + for(i=0;i<n;i++) + { + slapi_extension_destructor_fnptr destructor= ft->extensions[i]->destructor; + if(destructor!=NULL) + { + void **extention_array= (void**)(*extension); + (*destructor)(extention_array[i],object,parent); + } + } + } + else + { + /* The type wasn't registered. Programming error? */ + LDAPDebug( LDAP_DEBUG_ANY, "ERROR: factory.c: Object type handle %d not valid. Object not registered?\n", type, 0, 0); + } + slapi_ch_free(extension); + } +} + +/* ---------------------- Slapi Functions ---------------------- */ + +/* + * Function for plugin usage. + * See documentation at head of file. + */ +int +slapi_register_object_extension( + const char* pluginname, + const char* objectname, + slapi_extension_constructor_fnptr constructor, + slapi_extension_destructor_fnptr destructor, + int *objecttype, + int *extensionhandle) +{ + int rc= 0; + struct factory_extension* fe; + struct factory_type* ft; + fe= new_factory_extension(pluginname,constructor, destructor); + *objecttype= factory_type_store_name_to_type(objectname); + ft= factory_type_store_get_factory_type(*objecttype); + if(ft!=NULL) + { + *extensionhandle= factory_type_add_extension(ft,fe); + if(*extensionhandle==-1) + { + delete_factory_extension(&fe); + factory_type_store_remove(ft); + delete_factory_type(&ft); + } + } + else + { + LDAPDebug( LDAP_DEBUG_ANY, "ERROR: factory.c: Plugin %s failed to register extension for object %s.\n", pluginname, objectname, 0); + rc= -1; + } + return rc; +} + +/* + * Function for plugin usage. + * See documentation at head of file. + */ +void * +slapi_get_object_extension(int objecttype,void *object,int extensionhandle) +{ + void *object_extension= NULL; + struct factory_type* ft= factory_type_store_get_factory_type(objecttype); + if(ft!=NULL) + { + char *object_base= (char*)object; + void **o_extension= (void**)(object_base + ft->extension_offset); + void **extension_array= (void**)(*o_extension); + if ( extension_array != NULL ) { + object_extension= extension_array[extensionhandle]; + } + } + return object_extension; +} + +/* + * sometimes a plugin would like to change its extension, too. + */ +void +slapi_set_object_extension(int objecttype, void *object, int extensionhandle, + void *extension) +{ + void *object_extension = NULL; + struct factory_type *ft = factory_type_store_get_factory_type(objecttype); + if (ft != NULL) { + char *object_base = (char *)object; + void **o_extension = (void **)(object_base + ft->extension_offset); + void **extension_array= (void**)(*o_extension); + if (extension_array != NULL) { + extension_array[extensionhandle] = extension; + } + } +} |
