1/* $OpenLDAP$ */ 2/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 3 * 4 * Copyright 2003-2011 The OpenLDAP Foundation. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted only as authorized by the OpenLDAP 9 * Public License. 10 * 11 * A copy of this license is available in the file LICENSE in the 12 * top-level directory of the distribution or, alternatively, at 13 * <http://www.OpenLDAP.org/license.html>. 14 */ 15/* (C) Copyright PADL Software Pty Ltd. 2003 16 * Redistribution and use in source and binary forms, with or without 17 * modification, are permitted provided that this notice is preserved 18 * and that due credit is given to PADL Software Pty Ltd. This software 19 * is provided ``as is'' without express or implied warranty. 20 */ 21/* ACKNOWLEDGEMENTS: 22 * This work was initially developed by Luke Howard for inclusion 23 * in OpenLDAP Software. 24 */ 25 26#include "portable.h" 27 28#include <ac/string.h> 29#include <ac/stdarg.h> 30#include <ac/ctype.h> 31#include <ac/unistd.h> 32 33#ifdef LDAP_SLAPI 34 35#include <slap.h> 36#include <slapi.h> 37 38/* 39 * Object extensions 40 * 41 * We only support two types -- connection and operation extensions. 42 * Define more types in slapi.h 43 */ 44 45/* global state */ 46struct slapi_registered_extension_set { 47 ldap_pvt_thread_mutex_t mutex; 48 struct slapi_registered_extension { 49 int active; 50 int count; 51 slapi_extension_constructor_fnptr *constructors; 52 slapi_extension_destructor_fnptr *destructors; 53 } extensions[SLAPI_X_EXT_MAX]; 54} registered_extensions; 55 56/* per-object state */ 57struct slapi_extension_block { 58 void **extensions; 59}; 60 61static int get_extension_block(int objecttype, void *object, struct slapi_extension_block **eblock, void **parent) 62{ 63 switch ((slapi_extension_t) objecttype) { 64 case SLAPI_X_EXT_CONNECTION: 65 *eblock = ((Connection *)object)->c_extensions; 66 *parent = NULL; 67 break; 68 case SLAPI_X_EXT_OPERATION: 69 *eblock = ((Operation *)object)->o_hdr->oh_extensions; 70 *parent = ((Operation *)object)->o_conn; 71 break; 72 default: 73 return -1; 74 break; 75 } 76 77 if ( *eblock == NULL ) { 78 return -1; 79 } 80 81 return 0; 82} 83 84static int map_extension_type(const char *objectname, slapi_extension_t *type) 85{ 86 if ( strcasecmp( objectname, SLAPI_EXT_CONNECTION ) == 0 ) { 87 *type = SLAPI_X_EXT_CONNECTION; 88 } else if ( strcasecmp( objectname, SLAPI_EXT_OPERATION ) == 0 ) { 89 *type = SLAPI_X_EXT_OPERATION; 90 } else { 91 return -1; 92 } 93 94 return 0; 95} 96 97static void new_extension(struct slapi_extension_block *eblock, 98 int objecttype, void *object, void *parent, 99 int extensionhandle ) 100{ 101 slapi_extension_constructor_fnptr constructor; 102 103 assert( objecttype < SLAPI_X_EXT_MAX ); 104 assert( extensionhandle < registered_extensions.extensions[objecttype].count ); 105 106 assert( registered_extensions.extensions[objecttype].constructors != NULL ); 107 constructor = registered_extensions.extensions[objecttype].constructors[extensionhandle]; 108 109 assert( eblock->extensions[extensionhandle] == NULL ); 110 111 if ( constructor != NULL ) { 112 eblock->extensions[extensionhandle] = (*constructor)( object, parent ); 113 } else { 114 eblock->extensions[extensionhandle] = NULL; 115 } 116} 117 118static void free_extension(struct slapi_extension_block *eblock, int objecttype, void *object, void *parent, int extensionhandle ) 119{ 120 slapi_extension_destructor_fnptr destructor; 121 122 assert( objecttype < SLAPI_X_EXT_MAX ); 123 assert( extensionhandle < registered_extensions.extensions[objecttype].count ); 124 125 if ( eblock->extensions[extensionhandle] != NULL ) { 126 assert( registered_extensions.extensions[objecttype].destructors != NULL ); 127 destructor = registered_extensions.extensions[objecttype].destructors[extensionhandle]; 128 if ( destructor != NULL ) { 129 (*destructor)( eblock->extensions[extensionhandle], object, parent ); 130 } 131 eblock->extensions[extensionhandle] = NULL; 132 } 133} 134 135void *slapi_get_object_extension(int objecttype, void *object, int extensionhandle) 136{ 137 struct slapi_extension_block *eblock; 138 void *parent; 139 140 if ( get_extension_block( objecttype, object, &eblock, &parent ) != 0 ) { 141 return NULL; 142 } 143 144 if ( extensionhandle < registered_extensions.extensions[objecttype].count ) { 145 return eblock->extensions[extensionhandle]; 146 } 147 148 return NULL; 149} 150 151void slapi_set_object_extension(int objecttype, void *object, int extensionhandle, void *extension) 152{ 153 struct slapi_extension_block *eblock; 154 void *parent; 155 156 if ( get_extension_block( objecttype, object, &eblock, &parent ) != 0 ) { 157 return; 158 } 159 160 if ( extensionhandle < registered_extensions.extensions[objecttype].count ) { 161 /* free the old one */ 162 free_extension( eblock, objecttype, object, parent, extensionhandle ); 163 164 /* constructed by caller */ 165 eblock->extensions[extensionhandle] = extension; 166 } 167} 168 169int slapi_register_object_extension( 170 const char *pluginname, 171 const char *objectname, 172 slapi_extension_constructor_fnptr constructor, 173 slapi_extension_destructor_fnptr destructor, 174 int *objecttype, 175 int *extensionhandle) 176{ 177 int rc; 178 slapi_extension_t type; 179 struct slapi_registered_extension *re; 180 181 ldap_pvt_thread_mutex_lock( ®istered_extensions.mutex ); 182 183 rc = map_extension_type( objectname, &type ); 184 if ( rc != 0 ) { 185 ldap_pvt_thread_mutex_unlock( ®istered_extensions.mutex ); 186 return rc; 187 } 188 189 *objecttype = (int)type; 190 191 re = ®istered_extensions.extensions[*objecttype]; 192 193 *extensionhandle = re->count; 194 195 if ( re->active ) { 196 /* can't add new extensions after objects have been created */ 197 ldap_pvt_thread_mutex_unlock( ®istered_extensions.mutex ); 198 return -1; 199 } 200 201 re->count++; 202 203 if ( re->constructors == NULL ) { 204 re->constructors = (slapi_extension_constructor_fnptr *)slapi_ch_calloc( re->count, 205 sizeof( slapi_extension_constructor_fnptr ) ); 206 } else { 207 re->constructors = (slapi_extension_constructor_fnptr *)slapi_ch_realloc( (char *)re->constructors, 208 re->count * sizeof( slapi_extension_constructor_fnptr ) ); 209 } 210 re->constructors[*extensionhandle] = constructor; 211 212 if ( re->destructors == NULL ) { 213 re->destructors = (slapi_extension_destructor_fnptr *)slapi_ch_calloc( re->count, 214 sizeof( slapi_extension_destructor_fnptr ) ); 215 } else { 216 re->destructors = (slapi_extension_destructor_fnptr *)slapi_ch_realloc( (char *)re->destructors, 217 re->count * sizeof( slapi_extension_destructor_fnptr ) ); 218 } 219 re->destructors[*extensionhandle] = destructor; 220 221 ldap_pvt_thread_mutex_unlock( ®istered_extensions.mutex ); 222 223 return 0; 224} 225 226int slapi_int_create_object_extensions(int objecttype, void *object) 227{ 228 int i; 229 struct slapi_extension_block *eblock; 230 void **peblock; 231 void *parent; 232 233 switch ((slapi_extension_t) objecttype) { 234 case SLAPI_X_EXT_CONNECTION: 235 peblock = &(((Connection *)object)->c_extensions); 236 parent = NULL; 237 break; 238 case SLAPI_X_EXT_OPERATION: 239 peblock = &(((Operation *)object)->o_hdr->oh_extensions); 240 parent = ((Operation *)object)->o_conn; 241 break; 242 default: 243 return -1; 244 break; 245 } 246 247 *peblock = NULL; 248 249 ldap_pvt_thread_mutex_lock( ®istered_extensions.mutex ); 250 if ( registered_extensions.extensions[objecttype].active == 0 ) { 251 /* 252 * once we've created some extensions, no new extensions can 253 * be registered. 254 */ 255 registered_extensions.extensions[objecttype].active = 1; 256 } 257 ldap_pvt_thread_mutex_unlock( ®istered_extensions.mutex ); 258 259 eblock = (struct slapi_extension_block *)slapi_ch_calloc( 1, sizeof(*eblock) ); 260 261 if ( registered_extensions.extensions[objecttype].count ) { 262 eblock->extensions = (void **)slapi_ch_calloc( registered_extensions.extensions[objecttype].count, sizeof(void *) ); 263 for ( i = 0; i < registered_extensions.extensions[objecttype].count; i++ ) { 264 new_extension( eblock, objecttype, object, parent, i ); 265 } 266 } else { 267 eblock->extensions = NULL; 268 } 269 270 *peblock = eblock; 271 272 return 0; 273} 274 275int slapi_int_free_object_extensions(int objecttype, void *object) 276{ 277 int i; 278 struct slapi_extension_block *eblock; 279 void **peblock; 280 void *parent; 281 282 switch ((slapi_extension_t) objecttype) { 283 case SLAPI_X_EXT_CONNECTION: 284 peblock = &(((Connection *)object)->c_extensions); 285 parent = NULL; 286 break; 287 case SLAPI_X_EXT_OPERATION: 288 peblock = &(((Operation *)object)->o_hdr->oh_extensions); 289 parent = ((Operation *)object)->o_conn; 290 break; 291 default: 292 return -1; 293 break; 294 } 295 296 eblock = (struct slapi_extension_block *)*peblock; 297 298 if ( eblock->extensions != NULL ) { 299 for ( i = registered_extensions.extensions[objecttype].count - 1; i >= 0; --i ) { 300 free_extension( eblock, objecttype, object, parent, i ); 301 } 302 303 slapi_ch_free( (void **)&eblock->extensions ); 304 } 305 306 slapi_ch_free( peblock ); 307 308 return 0; 309} 310 311/* for reusable object types */ 312int slapi_int_clear_object_extensions(int objecttype, void *object) 313{ 314 int i; 315 struct slapi_extension_block *eblock; 316 void *parent; 317 318 if ( get_extension_block( objecttype, object, &eblock, &parent ) != 0 ) { 319 return -1; 320 } 321 322 if ( eblock->extensions == NULL ) { 323 /* no extensions */ 324 return 0; 325 } 326 327 for ( i = registered_extensions.extensions[objecttype].count - 1; i >= 0; --i ) { 328 free_extension( eblock, objecttype, object, parent, i ); 329 } 330 331 for ( i = 0; i < registered_extensions.extensions[objecttype].count; i++ ) { 332 new_extension( eblock, objecttype, object, parent, i ); 333 } 334 335 return 0; 336} 337 338int slapi_int_init_object_extensions(void) 339{ 340 memset( ®istered_extensions, 0, sizeof( registered_extensions ) ); 341 342 if ( ldap_pvt_thread_mutex_init( ®istered_extensions.mutex ) != 0 ) { 343 return -1; 344 } 345 346 return 0; 347} 348 349#endif /* LDAP_SLAPI */ 350