]> git.sur5r.net Git - openldap/blob - servers/slapd/slapi/slapi_ext.c
Happy New Year
[openldap] / servers / slapd / slapi / slapi_ext.c
1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 2003-2018 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 */
46 struct 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 */
57 struct slapi_extension_block {
58         void **extensions;
59 };
60
61 static 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
84 static 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
97 static 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
118 static 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
135 void *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
151 void 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
169 int 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( &registered_extensions.mutex );
182
183         rc = map_extension_type( objectname, &type );
184         if ( rc != 0 ) {
185                 ldap_pvt_thread_mutex_unlock( &registered_extensions.mutex );
186                 return rc;
187         }
188
189         *objecttype = (int)type;
190
191         re = &registered_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( &registered_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( &registered_extensions.mutex );
222
223         return 0;
224 }
225
226 int 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( &registered_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( &registered_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
275 int 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 */
312 int 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
338 int slapi_int_init_object_extensions(void)
339 {
340         memset( &registered_extensions, 0, sizeof( registered_extensions ) );
341
342         if ( ldap_pvt_thread_mutex_init( &registered_extensions.mutex ) != 0 ) {
343                 return -1;
344         }
345
346         return 0;
347 }
348
349 #endif /* LDAP_SLAPI */