- more tcp stuff (uses locking.h, hashtables, mostly untested)
[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         modules=0;
260 }
261
262 #ifdef NO_REVERSE_INIT
263
264 /*
265  * Initialize all loaded modules, the initialization
266  * is done *AFTER* the configuration file is parsed
267  */
268 int init_modules(void)
269 {
270         struct sr_module* t;
271         
272         for(t = modules; t; t = t->next) {
273                 if ((t->exports) && (t->exports->init_f))
274                         if (t->exports->init_f() != 0) {
275                                 LOG(L_ERR, "init_modules(): Error while initializing"
276                                                         " module %s\n", t->exports->name);
277                                 return -1;
278                         }
279         }
280         return 0;
281 }
282
283 /*
284  * per-child initialization
285  */
286 int init_child(int rank)
287 {
288         struct sr_module* t;
289
290         for(t = modules; t; t = t->next) {
291                 if (t->exports->init_child_f) {
292                         if ((t->exports->init_child_f(rank)) < 0) {
293                                 LOG(L_ERR, "init_child(): Initialization of child %d failed\n",
294                                                 rank);
295                                 return -1;
296                         }
297                 }
298         }
299         return 0;
300 }
301
302 #else
303
304
305 /* recursive module child initialization; (recursion is used to
306    process the module linear list in the same order in
307    which modules are loaded in config file
308 */
309
310 static int init_mod_child( struct sr_module* m, int rank )
311 {
312         if (m) {
313                 /* iterate through the list; if error occurs,
314                    propagate it up the stack
315                  */
316                 if (init_mod_child(m->next, rank)!=0) return -1;
317                 if (m->exports && m->exports->init_child_f) {
318                         DBG("DEBUG: init_mod_child (%d): %s\n", 
319                                         rank, m->exports->name);
320                         if (m->exports->init_child_f(rank)<0) {
321                                 LOG(L_ERR, "init_mod_child(): Error while initializing"
322                                                         " module %s\n", m->exports->name);
323                                 return -1;
324                         } else {
325                                 /* module correctly initialized */
326                                 return 0;
327                         }
328                 }
329                 /* no init function -- proceed with success */
330                 return 0;
331         } else {
332                 /* end of list */
333                 return 0;
334         }
335 }
336
337
338 /*
339  * per-child initialization
340  */
341 int init_child(int rank)
342 {
343         return init_mod_child(modules, rank);
344 }
345
346
347
348 /* recursive module initialization; (recursion is used to
349    process the module linear list in the same order in
350    which modules are loaded in config file
351 */
352
353 static int init_mod( struct sr_module* m )
354 {
355         if (m) {
356                 /* iterate through the list; if error occurs,
357                    propagate it up the stack
358                  */
359                 if (init_mod(m->next)!=0) return -1;
360                 if (m->exports && m->exports->init_f) {
361                         DBG("DEBUG: init_mod: %s\n", m->exports->name);
362                         if (m->exports->init_f()!=0) {
363                                 LOG(L_ERR, "init_mod(): Error while initializing"
364                                                         " module %s\n", m->exports->name);
365                                 return -1;
366                         } else {
367                                 /* module correctly initialized */
368                                 return 0;
369                         }
370                 }
371                 /* no init function -- proceed with success */
372                 return 0;
373         } else {
374                 /* end of list */
375                 return 0;
376         }
377 }
378
379 /*
380  * Initialize all loaded modules, the initialization
381  * is done *AFTER* the configuration file is parsed
382  */
383 int init_modules(void)
384 {
385         return init_mod(modules);
386 }
387
388 #endif