e3d6fdff33271d804dae63c87abe71344988fadf
[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
28 #include "sr_module.h"
29 #include "dprint.h"
30 #include "error.h"
31
32 #include <dlfcn.h>
33 #include <strings.h>
34 #include <stdlib.h>
35 #include <string.h>
36
37
38 struct sr_module* modules=0;
39
40 #ifdef STATIC_EXEC
41         extern struct module_exports* exec_exports();
42 #endif
43 #ifdef STATIC_TM
44         extern struct module_exports* tm_exports();
45 #endif
46
47 #ifdef STATIC_MAXFWD
48         extern struct module_exports* maxfwd_exports();
49 #endif
50
51 #ifdef STATIC_AUTH
52         extern struct module_exports* auth_exports();
53 #endif
54
55 #ifdef STATIC_RR
56         extern struct module_exports* rr_exports();
57 #endif
58
59 #ifdef STATIC_USRLOC
60         extern struct module_exports* usrloc_exports();
61 #endif
62
63 #ifdef STATIC_SL
64         extern struct module_exports* sl_exports();
65 #endif
66
67
68 /* initializes statically built (compiled in) modules*/
69 int register_builtin_modules()
70 {
71         int ret;
72
73         ret=0;
74 #ifdef STATIC_TM
75         ret=register_module(tm_exports,"built-in", 0); 
76         if (ret<0) return ret;
77 #endif
78
79 #ifdef STATIC_EXEC
80         ret=register_module(exec_exports,"built-in", 0); 
81         if (ret<0) return ret;
82 #endif
83
84 #ifdef STATIC_MAXFWD
85         ret=register_module(maxfwd_exports, "built-in", 0);
86         if (ret<0) return ret;
87 #endif
88
89 #ifdef STATIC_AUTH
90         ret=register_module(auth_exports, "built-in", 0); 
91         if (ret<0) return ret;
92 #endif
93         
94 #ifdef STATIC_RR
95         ret=register_module(rr_exports, "built-in", 0);
96         if (ret<0) return ret;
97 #endif
98         
99 #ifdef STATIC_USRLOC
100         ret=register_module(usrloc_exports, "built-in", 0);
101         if (ret<0) return ret;
102 #endif
103
104 #ifdef STATIC_SL
105         ret=register_module(sl_exports, "built-in", 0);
106         if (ret<0) return ret;
107 #endif
108         
109         return ret;
110 }
111
112
113
114 /* registers a module,  register_f= module register  functions
115  * returns <0 on error, 0 on success */
116 int register_module(struct module_exports* e, char* path, void* handle)
117 {
118         int ret;
119         struct sr_module* mod;
120         
121         ret=-1;
122
123         /* add module to the list */
124         if ((mod=malloc(sizeof(struct sr_module)))==0){
125                 LOG(L_ERR, "load_module: memory allocation failure\n");
126                 ret=E_OUT_OF_MEM;
127                 goto error;
128         }
129         memset(mod,0, sizeof(struct sr_module));
130         mod->path=path;
131         mod->handle=handle;
132         mod->exports=e;
133         mod->next=modules;
134         modules=mod;
135         return 0;
136 error:
137         return ret;
138 }
139
140
141 /* returns 0 on success , <0 on error */
142 int load_module(char* path)
143 {
144         void* handle;
145         char* error;
146         struct module_exports* exp;
147         struct sr_module* t;
148         
149 #ifndef RTLD_NOW
150 /* for openbsd */
151 #define RTLD_NOW DL_LAZY
152 #endif
153 #ifndef DLSYM_PREFIX
154 /* define it to null */
155 #define DLSYM_PREFIX
156 #endif
157         handle=dlopen(path, RTLD_NOW); /* resolve all symbols now */
158         if (handle==0){
159                 LOG(L_ERR, "ERROR: load_module: could not open module <%s>: %s\n",
160                                         path, dlerror() );
161                 goto error;
162         }
163         
164         for(t=modules;t; t=t->next){
165                 if (t->handle==handle){
166                         LOG(L_WARN, "WARNING: load_module: attempting to load the same"
167                                                 " module twice (%s)\n", path);
168                         goto skip;
169                 }
170         }
171         /* launch register */
172         exp = (struct module_exports*)dlsym(handle, DLSYM_PREFIX "exports");
173         if ( (error =(char*)dlerror())!=0 ){
174                 LOG(L_ERR, "ERROR: load_module: %s\n", error);
175                 goto error1;
176         }
177         if (register_module(exp, path, handle)<0) goto error1;
178         return 0;
179
180 error1:
181         dlclose(handle);
182 error:
183 skip:
184         return -1;
185 }
186
187
188
189 /* searches the module list and returns a pointer to the "name" function or
190  * 0 if not found */
191 cmd_function find_export(char* name, int param_no)
192 {
193         struct sr_module* t;
194         int r;
195
196         for(t=modules;t;t=t->next){
197                 for(r=0;r<t->exports->cmd_no;r++){
198                         if((strcmp(name, t->exports->cmd_names[r])==0)&&
199                                 (t->exports->param_no[r]==param_no) ){
200                                 DBG("find_export: found <%s> in module %s [%s]\n",
201                                                 name, t->exports->name, t->path);
202                                 return t->exports->cmd_pointers[r];
203                         }
204                 }
205         }
206         DBG("find_export: <%s> not found \n", name);
207         return 0;
208 }
209
210
211 void* find_param_export(char* mod, char* name, modparam_t type)
212 {
213         struct sr_module* t;
214         int r;
215
216         for(t = modules; t; t = t->next) {
217                 if (strcmp(mod, t->exports->name) == 0) {
218                         for(r = 0; r < t->exports->par_no; r++) {
219                                 if ((strcmp(name, t->exports->param_names[r]) == 0) &&
220                                     (t->exports->param_types[r] == type)) {
221                                         DBG("find_param_export: found <%s> in module %s [%s]\n",
222                                             name, t->exports->name, t->path);
223                                         return t->exports->param_pointers[r];
224                                 }
225                         }
226                 }
227         }
228         DBG("find_param_export: parameter <%s> or module <%s> not found\n",
229                         name, mod);
230         return 0;
231 }
232
233
234
235 /* finds a module, given a pointer to a module function *
236  * returns pointer to module, & if i i!=0, *i=the function index */
237 struct sr_module* find_module(void* f, int *i)
238 {
239         struct sr_module* t;
240         int r;
241         for (t=modules;t;t=t->next){
242                 for(r=0;r<t->exports->cmd_no;r++) 
243                         if (f==(void*)t->exports->cmd_pointers[r]) {
244                                 if (i) *i=r;
245                                 return t;
246                         }
247         }
248         return 0;
249 }
250
251
252
253 void destroy_modules()
254 {
255         struct sr_module* t;
256
257         for(t=modules;t;t=t->next)
258                 if  ((t->exports)&&(t->exports->destroy_f)) t->exports->destroy_f();
259 }
260
261 #ifdef NO_REVERSE_INIT
262
263 /*
264  * Initialize all loaded modules, the initialization
265  * is done *AFTER* the configuration file is parsed
266  */
267 int init_modules(void)
268 {
269         struct sr_module* t;
270         
271         for(t = modules; t; t = t->next) {
272                 if ((t->exports) && (t->exports->init_f))
273                         if (t->exports->init_f() != 0) {
274                                 LOG(L_ERR, "init_modules(): Error while initializing"
275                                                         " module %s\n", t->exports->name);
276                                 return -1;
277                         }
278         }
279         return 0;
280 }
281
282 /*
283  * per-child initialization
284  */
285 int init_child(int rank)
286 {
287         struct sr_module* t;
288
289         for(t = modules; t; t = t->next) {
290                 if (t->exports->init_child_f) {
291                         if ((t->exports->init_child_f(rank)) < 0) {
292                                 LOG(L_ERR, "init_child(): Initialization of child %d failed\n",
293                                                 rank);
294                                 return -1;
295                         }
296                 }
297         }
298         return 0;
299 }
300
301 #else
302
303
304 /* recursive module child initialization; (recursion is used to
305    process the module linear list in the same order in
306    which modules are loaded in config file
307 */
308
309 static int init_mod_child( struct sr_module* m, int rank )
310 {
311         if (m) {
312                 /* iterate through the list; if error occurs,
313                    propagate it up the stack
314                  */
315                 if (init_mod_child(m->next, rank)!=0) return -1;
316                 if (m->exports && m->exports->init_child_f) {
317                         DBG("DEBUG: init_mod_child (%d): %s\n", 
318                                         rank, m->exports->name);
319                         if (m->exports->init_child_f(rank)<0) {
320                                 LOG(L_ERR, "init_mod_child(): Error while initializing"
321                                                         " module %s\n", m->exports->name);
322                                 return -1;
323                         } else {
324                                 /* module correctly initialized */
325                                 return 0;
326                         }
327                 }
328                 /* no init function -- proceed with success */
329                 return 0;
330         } else {
331                 /* end of list */
332                 return 0;
333         }
334 }
335
336
337 /*
338  * per-child initialization
339  */
340 int init_child(int rank)
341 {
342         return init_mod_child(modules, rank);
343 }
344
345
346
347 /* recursive module initialization; (recursion is used to
348    process the module linear list in the same order in
349    which modules are loaded in config file
350 */
351
352 static int init_mod( struct sr_module* m )
353 {
354         if (m) {
355                 /* iterate through the list; if error occurs,
356                    propagate it up the stack
357                  */
358                 if (init_mod(m->next)!=0) return -1;
359                 if (m->exports && m->exports->init_f) {
360                         DBG("DEBUG: init_mod: %s\n", m->exports->name);
361                         if (m->exports->init_f()!=0) {
362                                 LOG(L_ERR, "init_mod(): Error while initializing"
363                                                         " module %s\n", m->exports->name);
364                                 return -1;
365                         } else {
366                                 /* module correctly initialized */
367                                 return 0;
368                         }
369                 }
370                 /* no init function -- proceed with success */
371                 return 0;
372         } else {
373                 /* end of list */
374                 return 0;
375         }
376 }
377
378 /*
379  * Initialize all loaded modules, the initialization
380  * is done *AFTER* the configuration file is parsed
381  */
382 int init_modules(void)
383 {
384         return init_mod(modules);
385 }
386
387 #endif