10a7832c9032ec1170c3ed9213cb4e2ff1cfe324
[sip-router] / sr_module.c
1 /* $Id$
2  *
3  * Copyright (C) 2001-2003 Fhg Fokus
4  *
5  * This file is part of ser, a free SIP server.
6  *
7  * ser is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version
11  *
12  * For a license to use the ser software under conditions
13  * other than those described here, or to purchase support for this
14  * software, please contact iptel.org by e-mail at the following addresses:
15  *    info@iptel.org
16  *
17  * ser is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License 
23  * along with this program; if not, write to the Free Software 
24  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
25  */
26 /*
27  * History:
28  * --------
29  *  2003-03-10  switched to new module_exports format: updated find_export,
30  *               find_export_param, find_module (andrei)
31  *  2003-03-19  replaced all mallocs/frees w/ pkg_malloc/pkg_free (andrei)
32  *  2003-03-19  Support for flags in find_export (janakj)
33  *  2003-03-29  cleaning pkg_mallocs introduced (jiri)
34  *  2003-04-24  module version checking introduced (jiri)
35  */
36
37
38 #include "sr_module.h"
39 #include "dprint.h"
40 #include "error.h"
41 #include "mem/mem.h"
42
43 #include <dlfcn.h>
44 #include <strings.h>
45 #include <stdlib.h>
46 #include <string.h>
47
48
49 struct sr_module* modules=0;
50
51 #ifdef STATIC_EXEC
52         extern struct module_exports* exec_exports();
53 #endif
54 #ifdef STATIC_TM
55         extern struct module_exports* tm_exports();
56 #endif
57
58 #ifdef STATIC_MAXFWD
59         extern struct module_exports* maxfwd_exports();
60 #endif
61
62 #ifdef STATIC_AUTH
63         extern struct module_exports* auth_exports();
64 #endif
65
66 #ifdef STATIC_RR
67         extern struct module_exports* rr_exports();
68 #endif
69
70 #ifdef STATIC_USRLOC
71         extern struct module_exports* usrloc_exports();
72 #endif
73
74 #ifdef STATIC_SL
75         extern struct module_exports* sl_exports();
76 #endif
77
78
79 /* initializes statically built (compiled in) modules*/
80 int register_builtin_modules()
81 {
82         int ret;
83
84         ret=0;
85 #ifdef STATIC_TM
86         ret=register_module(tm_exports,"built-in", 0); 
87         if (ret<0) return ret;
88 #endif
89
90 #ifdef STATIC_EXEC
91         ret=register_module(exec_exports,"built-in", 0); 
92         if (ret<0) return ret;
93 #endif
94
95 #ifdef STATIC_MAXFWD
96         ret=register_module(maxfwd_exports, "built-in", 0);
97         if (ret<0) return ret;
98 #endif
99
100 #ifdef STATIC_AUTH
101         ret=register_module(auth_exports, "built-in", 0); 
102         if (ret<0) return ret;
103 #endif
104         
105 #ifdef STATIC_RR
106         ret=register_module(rr_exports, "built-in", 0);
107         if (ret<0) return ret;
108 #endif
109         
110 #ifdef STATIC_USRLOC
111         ret=register_module(usrloc_exports, "built-in", 0);
112         if (ret<0) return ret;
113 #endif
114
115 #ifdef STATIC_SL
116         ret=register_module(sl_exports, "built-in", 0);
117         if (ret<0) return ret;
118 #endif
119         
120         return ret;
121 }
122
123
124
125 /* registers a module,  register_f= module register  functions
126  * returns <0 on error, 0 on success */
127 int register_module(struct module_exports* e, char* path, void* handle)
128 {
129         int ret;
130         struct sr_module* mod;
131         
132         ret=-1;
133
134         /* add module to the list */
135         if ((mod=pkg_malloc(sizeof(struct sr_module)))==0){
136                 LOG(L_ERR, "load_module: memory allocation failure\n");
137                 ret=E_OUT_OF_MEM;
138                 goto error;
139         }
140         memset(mod,0, sizeof(struct sr_module));
141         mod->path=path;
142         mod->handle=handle;
143         mod->exports=e;
144         mod->next=modules;
145         modules=mod;
146         return 0;
147 error:
148         return ret;
149 }
150
151 #ifndef DLSYM_PREFIX
152 /* define it to null */
153 #define DLSYM_PREFIX
154 #endif
155
156 static inline int version_control(void *handle, char *path)
157 {
158         char **m_ver;
159         char* error;
160
161         m_ver=(char **)dlsym(handle, DLSYM_PREFIX "module_version");
162         if ((error=(char *)dlerror())!=0) {
163                 LOG(L_ERR, "ERROR: no version info in module <%s>: %s\n",
164                         path, error );
165                 return 0;
166         }
167         if (!m_ver || !(*m_ver)) {
168                 LOG(L_ERR, "ERROR: no version in module <%s>\n", path );
169                 return 0;
170         }
171         if (strcmp(VERSION,*m_ver)==0)
172                 return 1;
173         LOG(L_ERR, "ERROR: module version mismatch for %s; "
174                 "core: %s; module: %s\n", path, VERSION, *m_ver );
175         return 0;
176 }
177
178 /* returns 0 on success , <0 on error */
179 int load_module(char* path)
180 {
181         void* handle;
182         char* error;
183         struct module_exports* exp;
184         struct sr_module* t;
185         
186 #ifndef RTLD_NOW
187 /* for openbsd */
188 #define RTLD_NOW DL_LAZY
189 #endif
190         handle=dlopen(path, RTLD_NOW); /* resolve all symbols now */
191         if (handle==0){
192                 LOG(L_ERR, "ERROR: load_module: could not open module <%s>: %s\n",
193                                         path, dlerror() );
194                 goto error;
195         }
196         
197         for(t=modules;t; t=t->next){
198                 if (t->handle==handle){
199                         LOG(L_WARN, "WARNING: load_module: attempting to load the same"
200                                                 " module twice (%s)\n", path);
201                         goto skip;
202                 }
203         }
204         /* version control */
205         if (!version_control(handle, path)) {
206                 exit(0);
207         }
208         /* launch register */
209         exp = (struct module_exports*)dlsym(handle, DLSYM_PREFIX "exports");
210         if ( (error =(char*)dlerror())!=0 ){
211                 LOG(L_ERR, "ERROR: load_module: %s\n", error);
212                 goto error1;
213         }
214         if (register_module(exp, path, handle)<0) goto error1;
215         return 0;
216
217 error1:
218         dlclose(handle);
219 error:
220 skip:
221         return -1;
222 }
223
224
225
226 /* searches the module list and returns pointer to the "name" function or
227  * 0 if not found 
228  * flags parameter is OR value of all flags that must match
229  */
230 cmd_function find_export(char* name, int param_no, int flags)
231 {
232         struct sr_module* t;
233         cmd_export_t* cmd;
234
235         for(t=modules;t;t=t->next){
236                 for(cmd=t->exports->cmds; cmd && cmd->name; cmd++){
237                         if((strcmp(name, cmd->name)==0)&&
238                            (cmd->param_no==param_no) &&
239                            ((cmd->flags & flags) == flags)
240                           ){
241                                 DBG("find_export: found <%s> in module %s [%s]\n",
242                                     name, t->exports->name, t->path);
243                                 return cmd->function;
244                         }
245                 }
246         }
247         DBG("find_export: <%s> not found \n", name);
248         return 0;
249 }
250
251
252
253 /*
254  * searches the module list and returns pointer to "name" function in module "mod"
255  * 0 if not found
256  * flags parameter is OR value of all flags that must match
257  */
258 cmd_function find_mod_export(char* mod, char* name, int param_no, int flags)
259 {
260         struct sr_module* t;
261         cmd_export_t* cmd;
262
263         for (t = modules; t; t = t->next) {
264                 if (strcmp(t->exports->name, mod) == 0) {
265                         for (cmd = t->exports->cmds;  cmd && cmd->name; cmd++) {
266                                 if ((strcmp(name, cmd->name) == 0) &&
267                                     (cmd->param_no == param_no) &&
268                                     ((cmd->flags & flags) == flags)
269                                    ){
270                                         DBG("find_mod_export: found <%s> in module %s [%s]\n",
271                                             name, t->exports->name, t->path);
272                                         return cmd->function;
273                                 }
274                         }
275                 }
276         }
277
278         DBG("find_mod_export: <%s> in module %s not found\n", name, mod);
279         return 0;
280 }
281
282
283
284
285 void* find_param_export(char* mod, char* name, modparam_t type)
286 {
287         struct sr_module* t;
288         param_export_t* param;
289
290         for(t = modules; t; t = t->next) {
291                 if (strcmp(mod, t->exports->name) == 0) {
292                         for(param=t->exports->params;param && param->name ; param++) {
293                                 if ((strcmp(name, param->name) == 0) &&
294                                     (param->type == type)) {
295                                         DBG("find_param_export: found <%s> in module %s [%s]\n",
296                                             name, t->exports->name, t->path);
297                                         return param->param_pointer;
298                                 }
299                         }
300                 }
301         }
302         DBG("find_param_export: parameter <%s> or module <%s> not found\n",
303                         name, mod);
304         return 0;
305 }
306
307
308 /* finds a module, given a pointer to a module function *
309  * returns pointer to module, & if  c!=0, *c=pointer to the
310  * function cmd_export structure*/
311 struct sr_module* find_module(void* f, cmd_export_t  **c)
312 {
313         struct sr_module* t;
314         cmd_export_t* cmd;
315         
316         for (t=modules;t;t=t->next){
317                 for(cmd=t->exports->cmds; cmd && cmd->name; cmd++) 
318                         if (f==(void*)cmd->function) {
319                                 if (c) *c=cmd;
320                                 return t;
321                         }
322         }
323         return 0;
324 }
325
326
327
328 void destroy_modules()
329 {
330         struct sr_module* t, *foo;
331
332         t=modules;
333         while(t) {
334                 foo=t->next;
335                 if ((t->exports)&&(t->exports->destroy_f)) t->exports->destroy_f();
336                 pkg_free(t);
337                 t=foo;
338         }
339         modules=0;
340 }
341
342 #ifdef NO_REVERSE_INIT
343
344 /*
345  * Initialize all loaded modules, the initialization
346  * is done *AFTER* the configuration file is parsed
347  */
348 int init_modules(void)
349 {
350         struct sr_module* t;
351         
352         for(t = modules; t; t = t->next) {
353                 if ((t->exports) && (t->exports->init_f))
354                         if (t->exports->init_f() != 0) {
355                                 LOG(L_ERR, "init_modules(): Error while initializing"
356                                                         " module %s\n", t->exports->name);
357                                 return -1;
358                         }
359         }
360         return 0;
361 }
362
363 /*
364  * per-child initialization
365  */
366 int init_child(int rank)
367 {
368         struct sr_module* t;
369         char* type;
370
371         switch(rank) {
372         case PROC_MAIN:     type = "PROC_MAIN";     break;
373         case PROC_TIMER:    type = "PROC_TIMER";    break;
374         case PROC_FIFO:     type = "PROC_FIFO";     break;
375         case PROC_TCP_MAIN: type = "PROC_TCP_MAIN"; break;
376         default:            type = "CHILD";         break;
377         }
378         DBG("init_child: initializing %s with rank %d\n", type, rank);
379         
380
381         for(t = modules; t; t = t->next) {
382                 if (t->exports->init_child_f) {
383                         if ((t->exports->init_child_f(rank)) < 0) {
384                                 LOG(L_ERR, "init_child(): Initialization of child %d failed\n",
385                                                 rank);
386                                 return -1;
387                         }
388                 }
389         }
390         return 0;
391 }
392
393 #else
394
395
396 /* recursive module child initialization; (recursion is used to
397    process the module linear list in the same order in
398    which modules are loaded in config file
399 */
400
401 static int init_mod_child( struct sr_module* m, int rank )
402 {
403         if (m) {
404                 /* iterate through the list; if error occurs,
405                    propagate it up the stack
406                  */
407                 if (init_mod_child(m->next, rank)!=0) return -1;
408                 if (m->exports && m->exports->init_child_f) {
409                         DBG("DEBUG: init_mod_child (%d): %s\n", 
410                                         rank, m->exports->name);
411                         if (m->exports->init_child_f(rank)<0) {
412                                 LOG(L_ERR, "init_mod_child(): Error while initializing"
413                                                         " module %s\n", m->exports->name);
414                                 return -1;
415                         } else {
416                                 /* module correctly initialized */
417                                 return 0;
418                         }
419                 }
420                 /* no init function -- proceed with success */
421                 return 0;
422         } else {
423                 /* end of list */
424                 return 0;
425         }
426 }
427
428
429 /*
430  * per-child initialization
431  */
432 int init_child(int rank)
433 {
434         return init_mod_child(modules, rank);
435 }
436
437
438
439 /* recursive module initialization; (recursion is used to
440    process the module linear list in the same order in
441    which modules are loaded in config file
442 */
443
444 static int init_mod( struct sr_module* m )
445 {
446         if (m) {
447                 /* iterate through the list; if error occurs,
448                    propagate it up the stack
449                  */
450                 if (init_mod(m->next)!=0) return -1;
451                 if (m->exports && m->exports->init_f) {
452                         DBG("DEBUG: init_mod: %s\n", m->exports->name);
453                         if (m->exports->init_f()!=0) {
454                                 LOG(L_ERR, "init_mod(): Error while initializing"
455                                                         " module %s\n", m->exports->name);
456                                 return -1;
457                         } else {
458                                 /* module correctly initialized */
459                                 return 0;
460                         }
461                 }
462                 /* no init function -- proceed with success */
463                 return 0;
464         } else {
465                 /* end of list */
466                 return 0;
467         }
468 }
469
470 /*
471  * Initialize all loaded modules, the initialization
472  * is done *AFTER* the configuration file is parsed
473  */
474 int init_modules(void)
475 {
476         return init_mod(modules);
477 }
478
479 #endif