- new mod_register function added to the module interface
(separate from exports structure):
If a module exports a mod_register function it will be called
immediately after loading the module and checking the module
version and module interface (this means way before calling
mod_init).
The mod_register function prototype is:
int mod_register(char* path, int* dlflags, void* r1, void* r2)
where path is the module path including the filename, dlflags
is a pointer to the dlflags used when loading the module (If
the value is changed to a different and non-zero value, the
module will be reloaded with the new flags), and r1 and r2 are
parameters reserved for future use.
A 0 return means success and -1 means error (the module will not
be loaded).
This new function can be used to register new parsing functions,
alter dynamically the mod_exports structure contents a.s.o.
- kamailio compatible mod exports dlflags handling (but a warning
will be printed saying this is deprecated and the preferred way
is using mod_register().
... | ... |
@@ -216,17 +216,29 @@ static inline int version_control(void *handle, char *path) |
216 | 216 |
return 0; |
217 | 217 |
} |
218 | 218 |
|
219 |
-/* returns 0 on success , <0 on error */ |
|
219 |
+/** load a sr module. |
|
220 |
+ * tries to load the module specified by path. |
|
221 |
+ * If modname does contain a '/' or a '.' it would be assumed to contain a |
|
222 |
+ * path to the module and it will be used as give. |
|
223 |
+ * else <MODS_DIR>/<modname>.so will be tried and if this fails |
|
224 |
+ * <MODS_DIR>/<modname>/<modname>.so |
|
225 |
+ * @param modname - path or module name |
|
226 |
+ * @return 0 on success , <0 on error |
|
227 |
+ */ |
|
220 | 228 |
int load_module(char* path) |
221 | 229 |
{ |
222 | 230 |
void* handle; |
223 | 231 |
char* error; |
232 |
+ mod_register_function mr; |
|
224 | 233 |
union module_exports_u* exp; |
225 | 234 |
unsigned* mod_if_ver; |
226 | 235 |
struct sr_module* t; |
227 | 236 |
struct stat stat_buf; |
228 | 237 |
char* modname; |
229 | 238 |
int len; |
239 |
+ int dlflags; |
|
240 |
+ int new_dlflags; |
|
241 |
+ int retries; |
|
230 | 242 |
|
231 | 243 |
#ifndef RTLD_NOW |
232 | 244 |
/* for openbsd */ |
... | ... |
@@ -287,7 +299,9 @@ int load_module(char* path) |
287 | 299 |
} |
288 | 300 |
#endif /* !EXTRA_DEBUG */ |
289 | 301 |
} |
290 |
- |
|
302 |
+ retries=2; |
|
303 |
+ dlflags=RTLD_NOW; |
|
304 |
+reload: |
|
291 | 305 |
handle=dlopen(path, RTLD_NOW); /* resolve all symbols now */ |
292 | 306 |
if (handle==0){ |
293 | 307 |
LOG(L_ERR, "ERROR: load_module: could not open module <%s>: %s\n", |
... | ... |
@@ -314,11 +328,47 @@ int load_module(char* path) |
314 | 328 |
goto error1; |
315 | 329 |
} |
316 | 330 |
/* launch register */ |
331 |
+ mr = (mod_register_function)dlsym(handle, DLSYM_PREFIX "mod_register"); |
|
332 |
+ if (((error =(char*)dlerror())==0) && mr) { |
|
333 |
+ /* no error call it */ |
|
334 |
+ new_dlflags=dlflags; |
|
335 |
+ if (mr(path, &dlflags, 0, 0)!=0) { |
|
336 |
+ LOG(L_ERR, "ERROR: load_module: %s: mod_register failed\n", path); |
|
337 |
+ goto error1; |
|
338 |
+ } |
|
339 |
+ if (new_dlflags!=dlflags && new_dlflags!=0) { |
|
340 |
+ /* we have to reload the module */ |
|
341 |
+ dlclose(handle); |
|
342 |
+ dlflags=new_dlflags; |
|
343 |
+ retries--; |
|
344 |
+ if (retries>0) goto reload; |
|
345 |
+ LOG(L_ERR, "ERROR: load_module: %s: cannot agree" |
|
346 |
+ " on the dlflags\n", path); |
|
347 |
+ goto error; |
|
348 |
+ } |
|
349 |
+ } |
|
317 | 350 |
exp = (union module_exports_u*)dlsym(handle, DLSYM_PREFIX "exports"); |
318 | 351 |
if ( (error =(char*)dlerror())!=0 ){ |
319 | 352 |
LOG(L_ERR, "ERROR: load_module: %s\n", error); |
320 | 353 |
goto error1; |
321 | 354 |
} |
355 |
+ /* hack to allow for kamailio style dlflags inside exports */ |
|
356 |
+ if (*mod_if_ver == 1) { |
|
357 |
+ new_dlflags = exp->v1.dlflags; |
|
358 |
+ if (new_dlflags!=dlflags && new_dlflags!=DEFAULT_DLFLAGS) { |
|
359 |
+ /* we have to reload the module */ |
|
360 |
+ dlclose(handle); |
|
361 |
+ WARN("%s: exports dlflags interface is deprecated and it will not" |
|
362 |
+ "be supported in newer versions; consider using" |
|
363 |
+ " mod_register() instead", path); |
|
364 |
+ dlflags=new_dlflags; |
|
365 |
+ retries--; |
|
366 |
+ if (retries>0) goto reload; |
|
367 |
+ LOG(L_ERR, "ERROR: load_module: %s: cannot agree" |
|
368 |
+ " on the dlflags\n", path); |
|
369 |
+ goto error; |
|
370 |
+ } |
|
371 |
+ } |
|
322 | 372 |
if (register_module(*mod_if_ver, exp, path, handle)<0) goto error1; |
323 | 373 |
return 0; |
324 | 374 |
|
... | ... |
@@ -89,6 +89,20 @@ |
89 | 89 |
|
90 | 90 |
#endif |
91 | 91 |
|
92 |
+/** type used for the mod_register function export. |
|
93 |
+ * mod_register is a function called when loading a module |
|
94 |
+ * (if present), prior to registering the module exports. |
|
95 |
+ * @param path - path to the module, including file name |
|
96 |
+ * @param dlflags - pointer to the dlflags used when loading the module. |
|
97 |
+ * If the value is changed to a different and non-zero |
|
98 |
+ * value, the module will be reloaded with the new flags. |
|
99 |
+ * @param reserved1 - reserved for future use. |
|
100 |
+ * @param reserved2 - reserver for future use |
|
101 |
+ * @return 0 on success, -1 on error, all the other values are reserved |
|
102 |
+ * for future use (<0 meaning error and >0 success) |
|
103 |
+ */ |
|
104 |
+typedef int (*mod_register_function)(char*, int*, void*, void*); |
|
105 |
+ |
|
92 | 106 |
typedef struct module_exports* (*module_register)(void); |
93 | 107 |
typedef int (*cmd_function)(struct sip_msg*, char*, char*); |
94 | 108 |
typedef int (*cmd_function3)(struct sip_msg*, char*, char*, char*); |