factory.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489
  1. /** BEGIN COPYRIGHT BLOCK
  2. * This Program is free software; you can redistribute it and/or modify it under
  3. * the terms of the GNU General Public License as published by the Free Software
  4. * Foundation; version 2 of the License.
  5. *
  6. * This Program is distributed in the hope that it will be useful, but WITHOUT
  7. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  8. * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  9. *
  10. * You should have received a copy of the GNU General Public License along with
  11. * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
  12. * Place, Suite 330, Boston, MA 02111-1307 USA.
  13. *
  14. * In addition, as a special exception, Red Hat, Inc. gives You the additional
  15. * right to link the code of this Program with code not covered under the GNU
  16. * General Public License ("Non-GPL Code") and to distribute linked combinations
  17. * including the two, subject to the limitations in this paragraph. Non-GPL Code
  18. * permitted under this exception must only link to the code of this Program
  19. * through those well defined interfaces identified in the file named EXCEPTION
  20. * found in the source code files (the "Approved Interfaces"). The files of
  21. * Non-GPL Code may instantiate templates or use macros or inline functions from
  22. * the Approved Interfaces without causing the resulting work to be covered by
  23. * the GNU General Public License. Only Red Hat, Inc. may make changes or
  24. * additions to the list of Approved Interfaces. You must obey the GNU General
  25. * Public License in all respects for all of the Program code and other code used
  26. * in conjunction with the Program except the Non-GPL Code covered by this
  27. * exception. If you modify this file, you may extend this exception to your
  28. * version of the file, but you are not obligated to do so. If you do not wish to
  29. * provide this exception without modification, you must delete this exception
  30. * statement from your version and license this file solely under the GPL without
  31. * exception.
  32. *
  33. *
  34. * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
  35. * Copyright (C) 2005 Red Hat, Inc.
  36. * All rights reserved.
  37. * END COPYRIGHT BLOCK **/
  38. #include "slap.h"
  39. /*
  40. * This module provides a mechanism for extending core server objects.
  41. * This functionality is provided to plugin writers so that they may
  42. * efficiently pass state information between plugin calls. Typically
  43. * a plugin might register both a pre-op and post-op call. It's very
  44. * convenient for the plugin to associate it's private data with the
  45. * operation object that's passed through the PBlock.
  46. *
  47. * --- An interface is made available to the core server.
  48. *
  49. * int factory_register_type(const char *name, size_t offset)
  50. * void *factory_create_extension(int type,void *object,void *parent)
  51. * void factory_destroy_extension(int type,void *object,void *parent,void **extension)
  52. *
  53. * An object that wishes to make itself available for extension must
  54. * register with the Factory. It passes it's name, say 'Operation',
  55. * and an offset into the structure of where the extension block
  56. * is to be stored. In return a type handle is passed back, which is
  57. * used in place of the name in the creation and destruction calls.
  58. *
  59. * When an object is created, which has registered as extensible, it
  60. * must call the factory_create_extension with its type handle so that
  61. * the extension block can be constructed. A pointer to the block is
  62. * returned that *must* be stored in the object structure at the offset
  63. * declared by the call to factory_register_type.
  64. *
  65. * When an extensible object is destroyed the extension block must also
  66. * be destroyed. The factory_destroy_extension call is provided to
  67. * tidy up and free any extenions created for this object.
  68. *
  69. * --- An interface is made available to the plugins.
  70. *
  71. * int slapi_register_object_extension(
  72. * const char* objectname,
  73. * slapi_extension_constructor_fnptr constructor,
  74. * slapi_extension_destructor_fnptr destructor,
  75. * int *objecttype,
  76. * int *extensionhandle)
  77. * void *slapi_get_object_extension(int objecttype,void *object,int extensionhandle)
  78. *
  79. * When the plugin is initialised it must register its object extensions.
  80. * It must provide the name of the object to be extended, say 'Operation',
  81. * and constructor and destructor functions. These functions are called
  82. * when the object is constructed and destroyed. The extension functions
  83. * would probably allocate some memory and initialise it for its
  84. * own use. The registration function will fail if any objects have already
  85. * been created. This is why the registration *must* happen during plugin
  86. * initialisation. In return the plugin will receive two handles, one for
  87. * the object type, and one for the object extension. These only have meaning
  88. * for the slapi_get_object_extension function.
  89. *
  90. * A plugin retrieves a pointer to its own extension by calling slapi_get_
  91. * object_extension with the object from which the extension is to be
  92. * retrieved. The factory uses the objecttype to find the offset into the
  93. * object of where the extension block is stored. The extension handle is
  94. * then used to find the appropriate extension within the block.
  95. *
  96. * Currently (Oct 98) the only supported objects are Operation and Connection.
  97. *
  98. * This documentation is available here...
  99. *
  100. * http://warp/server/directory-server/hydra/replication/objext.html
  101. */
  102. /* JCM: Could implement simple object leak detection here */
  103. /* ---------------------- Factory Extension ---------------------- */
  104. struct factory_extension
  105. {
  106. const char *pluginname;
  107. slapi_extension_constructor_fnptr constructor;
  108. slapi_extension_destructor_fnptr destructor;
  109. };
  110. static struct factory_extension*
  111. new_factory_extension(
  112. const char *pluginname,
  113. slapi_extension_constructor_fnptr constructor,
  114. slapi_extension_destructor_fnptr destructor)
  115. {
  116. struct factory_extension* fe= (struct factory_extension*)slapi_ch_malloc(sizeof(struct factory_extension));
  117. if(pluginname!=NULL)
  118. {
  119. fe->pluginname= slapi_ch_strdup(pluginname);
  120. }
  121. fe->constructor= constructor;
  122. fe->destructor= destructor;
  123. return fe;
  124. }
  125. static void
  126. delete_factory_extension(struct factory_extension **fe)
  127. {
  128. slapi_ch_free( (void **) &((*fe)->pluginname) );
  129. slapi_ch_free( (void **) fe);
  130. }
  131. /* ---------------------- Factory Type ---------------------- */
  132. #define MAX_EXTENSIONS 32
  133. struct factory_type
  134. {
  135. char *name; /* The name of the object that can be extended */
  136. int extension_count; /* The number of extensions registered for this object */
  137. PRLock *extension_lock; /* Protect the array of extensions */
  138. size_t extension_offset; /* The offset into the object where the extension pointer is */
  139. long existence_count; /* Keep track of how many extensions blocks are in existence */
  140. struct factory_extension *extensions[MAX_EXTENSIONS]; /* The extension registered for this object type */
  141. };
  142. static struct factory_type*
  143. new_factory_type(const char *name, size_t offset)
  144. {
  145. struct factory_type* ft= (struct factory_type*)slapi_ch_malloc(sizeof(struct factory_type));
  146. ft->name= slapi_ch_strdup(name);
  147. ft->extension_lock = PR_NewLock();
  148. ft->extension_count= 0;
  149. ft->extension_offset= offset;
  150. ft->existence_count= 0;
  151. return ft;
  152. }
  153. static void
  154. delete_factory_type(struct factory_type **ft)
  155. {
  156. slapi_ch_free( (void **) &((*ft)->name));
  157. PR_DestroyLock((*ft)->extension_lock);
  158. slapi_ch_free( (void **) ft);
  159. }
  160. static int
  161. factory_type_add_extension(struct factory_type *ft,struct factory_extension *fe)
  162. {
  163. int extensionhandle= -1;
  164. PR_Lock(ft->extension_lock);
  165. if(ft->existence_count>0)
  166. {
  167. /* Can't register an extension if there are objects already with extension blocks */
  168. LDAPDebug( LDAP_DEBUG_ANY, "ERROR: factory.c: Registration of %s extension by %s failed.\n", ft->name, fe->pluginname, 0);
  169. LDAPDebug( LDAP_DEBUG_ANY, "ERROR: factory.c: %lu %s objects already in existence.\n", ft->existence_count, ft->name, 0);
  170. }
  171. else
  172. {
  173. if(ft->extension_count<MAX_EXTENSIONS)
  174. {
  175. extensionhandle= ft->extension_count;
  176. ft->extensions[ft->extension_count]= fe;
  177. ft->extension_count++;
  178. }
  179. else
  180. {
  181. LDAPDebug( LDAP_DEBUG_ANY, "ERROR: factory.c: Registration of %s extension by %s failed.\n", ft->name, fe->pluginname, 0);
  182. LDAPDebug( LDAP_DEBUG_ANY, "ERROR: factory.c: %d extensions already registered. Max is %d\n", ft->extension_count, MAX_EXTENSIONS, 0);
  183. }
  184. }
  185. PR_Unlock(ft->extension_lock);
  186. return extensionhandle;
  187. }
  188. static void
  189. factory_type_increment_existence(struct factory_type *ft)
  190. {
  191. ft->existence_count++;
  192. }
  193. static void
  194. factory_type_decrement_existence(struct factory_type *ft)
  195. {
  196. ft->existence_count--;
  197. if(ft->existence_count<0)
  198. {
  199. /* This just shouldn't happen */
  200. LDAPDebug( LDAP_DEBUG_ANY, "ERROR: factory.c: %lu %s object extensions in existence.\n", ft->extension_count, ft->name, 0);
  201. }
  202. }
  203. /* ---------------------- Factory Type Store ---------------------- */
  204. #define MAX_TYPES 16
  205. static PRLock *factory_type_store_lock;
  206. static struct factory_type* factory_type_store[MAX_TYPES];
  207. static int number_of_types= 0;
  208. static void
  209. factory_type_store_init()
  210. {
  211. int i= 0;
  212. factory_type_store_lock= PR_NewLock(); /* JCM - Should really free this at shutdown */
  213. for(i=0;i<MAX_TYPES;i++)
  214. {
  215. factory_type_store[number_of_types]= NULL;
  216. }
  217. }
  218. static int
  219. factory_type_store_add(struct factory_type* ft)
  220. {
  221. int type= number_of_types;
  222. factory_type_store[type]= ft;
  223. number_of_types++;
  224. return type;
  225. }
  226. static void
  227. factory_type_store_remove(struct factory_type *ft)
  228. {
  229. int i;
  230. int found_it = 0;
  231. for (i = 0; i < number_of_types; i++)
  232. {
  233. if (!found_it)
  234. {
  235. if (factory_type_store[i] == ft)
  236. {
  237. found_it = 1;
  238. }
  239. }
  240. else
  241. {
  242. factory_type_store[i-1] = factory_type_store[i];
  243. }
  244. }
  245. if (found_it)
  246. {
  247. factory_type_store[i-1] = NULL;
  248. number_of_types--;
  249. }
  250. }
  251. static struct factory_type*
  252. factory_type_store_get_factory_type(int type)
  253. {
  254. if(type>=0 && type<number_of_types)
  255. {
  256. return factory_type_store[type];
  257. }
  258. else
  259. {
  260. return NULL;
  261. }
  262. }
  263. static int
  264. factory_type_store_name_to_type(const char* name)
  265. {
  266. int i;
  267. for(i=0;i<number_of_types;i++)
  268. {
  269. if(strcasecmp(factory_type_store[i]->name,name)==0)
  270. {
  271. return i;
  272. }
  273. }
  274. return -1;
  275. }
  276. /* ---------------------- Core Server Functions ---------------------- */
  277. /*
  278. * Function for core server usage.
  279. * See documentation at head of file.
  280. */
  281. int
  282. factory_register_type(const char *name, size_t offset)
  283. {
  284. int type= 0;
  285. if(number_of_types==0)
  286. {
  287. factory_type_store_init();
  288. }
  289. PR_Lock(factory_type_store_lock);
  290. if(number_of_types<MAX_TYPES)
  291. {
  292. struct factory_type* ft= new_factory_type(name,offset);
  293. type= factory_type_store_add(ft);
  294. }
  295. else
  296. {
  297. LDAPDebug( LDAP_DEBUG_ANY, "ERROR: factory.c: Registration of %s object failed.\n", name, 0, 0);
  298. LDAPDebug( LDAP_DEBUG_ANY, "ERROR: factory.c: %d objects already registered. Max is %d\n", number_of_types, MAX_TYPES, 0);
  299. type= -1;
  300. }
  301. PR_Unlock(factory_type_store_lock);
  302. return type;
  303. }
  304. /*
  305. * Function for core server usage.
  306. * See documentation at head of file.
  307. */
  308. void *
  309. factory_create_extension(int type,void *object,void *parent)
  310. {
  311. int n;
  312. void **extension= NULL;
  313. struct factory_type* ft= factory_type_store_get_factory_type(type);
  314. if(ft!=NULL)
  315. {
  316. PR_Lock(ft->extension_lock);
  317. if((n = ft->extension_count)>0)
  318. {
  319. int i;
  320. factory_type_increment_existence(ft);
  321. PR_Unlock(ft->extension_lock);
  322. extension= (void**)slapi_ch_malloc(n*sizeof(void*));
  323. for(i=0;i<n;i++)
  324. {
  325. slapi_extension_constructor_fnptr constructor= ft->extensions[i]->constructor;
  326. if(constructor!=NULL)
  327. {
  328. extension[i]= (*constructor)(object,parent);
  329. }
  330. }
  331. }
  332. else
  333. {
  334. /* No extensions registered. That's OK */
  335. PR_Unlock(ft->extension_lock);
  336. }
  337. }
  338. else
  339. {
  340. /* The type wasn't registered. Programming error? */
  341. LDAPDebug( LDAP_DEBUG_ANY, "ERROR: factory.c: Object type handle %d not valid. Object not registered?\n", type, 0, 0);
  342. }
  343. return (void*)extension;
  344. }
  345. /*
  346. * Function for core server usage.
  347. * See documentation at head of file.
  348. */
  349. void
  350. factory_destroy_extension(int type,void *object,void *parent,void **extension)
  351. {
  352. if(extension!=NULL && *extension!=NULL)
  353. {
  354. struct factory_type* ft= factory_type_store_get_factory_type(type);
  355. if(ft!=NULL)
  356. {
  357. int i,n;
  358. PR_Lock(ft->extension_lock);
  359. n=ft->extension_count;
  360. factory_type_decrement_existence(ft);
  361. PR_Unlock(ft->extension_lock);
  362. for(i=0;i<n;i++)
  363. {
  364. slapi_extension_destructor_fnptr destructor= ft->extensions[i]->destructor;
  365. if(destructor!=NULL)
  366. {
  367. void **extention_array= (void**)(*extension);
  368. (*destructor)(extention_array[i],object,parent);
  369. }
  370. }
  371. }
  372. else
  373. {
  374. /* The type wasn't registered. Programming error? */
  375. LDAPDebug( LDAP_DEBUG_ANY, "ERROR: factory.c: Object type handle %d not valid. Object not registered?\n", type, 0, 0);
  376. }
  377. slapi_ch_free(extension);
  378. }
  379. }
  380. /* ---------------------- Slapi Functions ---------------------- */
  381. /*
  382. * Function for plugin usage.
  383. * See documentation at head of file.
  384. */
  385. int
  386. slapi_register_object_extension(
  387. const char* pluginname,
  388. const char* objectname,
  389. slapi_extension_constructor_fnptr constructor,
  390. slapi_extension_destructor_fnptr destructor,
  391. int *objecttype,
  392. int *extensionhandle)
  393. {
  394. int rc= 0;
  395. struct factory_extension* fe;
  396. struct factory_type* ft;
  397. fe= new_factory_extension(pluginname,constructor, destructor);
  398. *objecttype= factory_type_store_name_to_type(objectname);
  399. ft= factory_type_store_get_factory_type(*objecttype);
  400. if(ft!=NULL)
  401. {
  402. *extensionhandle= factory_type_add_extension(ft,fe);
  403. if(*extensionhandle==-1)
  404. {
  405. delete_factory_extension(&fe);
  406. factory_type_store_remove(ft);
  407. delete_factory_type(&ft);
  408. }
  409. }
  410. else
  411. {
  412. LDAPDebug( LDAP_DEBUG_ANY, "ERROR: factory.c: Plugin %s failed to register extension for object %s.\n", pluginname, objectname, 0);
  413. rc= -1;
  414. }
  415. return rc;
  416. }
  417. /*
  418. * Function for plugin usage.
  419. * See documentation at head of file.
  420. */
  421. void *
  422. slapi_get_object_extension(int objecttype,void *object,int extensionhandle)
  423. {
  424. void *object_extension= NULL;
  425. struct factory_type* ft= factory_type_store_get_factory_type(objecttype);
  426. if(ft!=NULL)
  427. {
  428. char *object_base= (char*)object;
  429. void **o_extension= (void**)(object_base + ft->extension_offset);
  430. void **extension_array= (void**)(*o_extension);
  431. if ( extension_array != NULL ) {
  432. object_extension= extension_array[extensionhandle];
  433. }
  434. }
  435. return object_extension;
  436. }
  437. /*
  438. * sometimes a plugin would like to change its extension, too.
  439. */
  440. void
  441. slapi_set_object_extension(int objecttype, void *object, int extensionhandle,
  442. void *extension)
  443. {
  444. struct factory_type *ft = factory_type_store_get_factory_type(objecttype);
  445. if (ft != NULL) {
  446. char *object_base = (char *)object;
  447. void **o_extension = (void **)(object_base + ft->extension_offset);
  448. void **extension_array= (void**)(*o_extension);
  449. if (extension_array != NULL) {
  450. extension_array[extensionhandle] = extension;
  451. }
  452. }
  453. }