b7291024bf74d50b489e2eadbb34594131b4af26
[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  *  2004-09-19  compile flags are checked too (andrei)
36  *  2005-01-07  removed find_module-overloading problems, added
37  *               find_export_record
38  *  2006-02-07  added fix_flag (andrei)
39  *  2008-02-29  store all the reponse callbacks in their own array (andrei)
40  *  2008-11-17  support dual module interface: ser & kamailio (andrei)
41  *  2008-11-26  added fparam_free_contents() and fix_param_types (andrei)
42  */
43
44 /*!
45  * \file
46  * \brief SIP-router core :: 
47  * \ingroup core
48  * Module: \ref core
49  */
50
51 #include "sr_module.h"
52 #include "dprint.h"
53 #include "error.h"
54 #include "mem/mem.h"
55 #include "core_cmd.h"
56 #include "ut.h"
57 #include "re.h"
58 #include "route_struct.h"
59 #include "flags.h"
60 #include "trim.h"
61 #include "globals.h"
62 #include "rpc_lookup.h"
63 #include "sr_compat.h"
64
65 #include <sys/stat.h>
66 #include <regex.h>
67 #include <dlfcn.h>
68 #include <strings.h>
69 #include <stdlib.h>
70 #include <string.h>
71
72
73 struct sr_module* modules=0;
74
75 #ifdef STATIC_EXEC
76         extern struct module_exports exec_exports;
77 #endif
78 #ifdef STATIC_TM
79         extern struct module_exports tm_exports;
80 #endif
81
82 #ifdef STATIC_MAXFWD
83         extern struct module_exports maxfwd_exports;
84 #endif
85
86 #ifdef STATIC_AUTH
87         extern struct module_exports auth_exports;
88 #endif
89
90 #ifdef STATIC_RR
91         extern struct module_exports rr_exports;
92 #endif
93
94 #ifdef STATIC_USRLOC
95         extern struct module_exports usrloc_exports;
96 #endif
97
98 #ifdef STATIC_SL
99         extern struct module_exports sl_exports;
100 #endif
101
102
103 int mod_response_cbk_no=0;
104 response_function* mod_response_cbks=0;
105
106
107 /* initializes statically built (compiled in) modules*/
108 int register_builtin_modules()
109 {
110         int ret;
111
112         ret=0;
113 #ifdef STATIC_TM
114         ret=register_module(MODULE_INTERFACE_VER, &tm_exports,"built-in", 0);
115         if (ret<0) return ret;
116 #endif
117
118 #ifdef STATIC_EXEC
119         ret=register_module(MODULE_INTERFACE_VER, &exec_exports,"built-in", 0);
120         if (ret<0) return ret;
121 #endif
122
123 #ifdef STATIC_MAXFWD
124         ret=register_module(MODULE_INTERFACE_VER, &maxfwd_exports, "built-in", 0);
125         if (ret<0) return ret;
126 #endif
127
128 #ifdef STATIC_AUTH
129         ret=register_module(MODULE_INTERFACE_VER, &auth_exports, "built-in", 0);
130         if (ret<0) return ret;
131 #endif
132
133 #ifdef STATIC_RR
134         ret=register_module(MODULE_INTERFACE_VER, &rr_exports, "built-in", 0);
135         if (ret<0) return ret;
136 #endif
137
138 #ifdef STATIC_USRLOC
139         ret=register_module(MODULE_INTERFACE_VER, &usrloc_exports, "built-in", 0);
140         if (ret<0) return ret;
141 #endif
142
143 #ifdef STATIC_SL
144         ret=register_module(MODULE_INTERFACE_VER, &sl_exports, "built-in", 0);
145         if (ret<0) return ret;
146 #endif
147
148         return ret;
149 }
150
151
152
153 /** convert cmd exports to current format.
154   * @param ver - module interface versions (0 == ser, 1 == kam).
155   * @param src - null terminated array of cmd exports
156   *              (either ser_cmd_export_t or kam_cmd_export_t, depending
157   *               on ver).
158   * @param mod - pointer to module exports structure.
159   * @return - pkg_malloc'ed null terminated sr_cmd_export_v31_t array with
160   *           the converted cmd exports  or 0 on error.
161   */
162 static sr31_cmd_export_t* sr_cmd_exports_convert(unsigned ver,
163                                                                                                         void* src, void* mod)
164 {
165         int i, n;
166         ser_cmd_export_t* ser_cmd;
167         kam_cmd_export_t* kam_cmd;
168         sr31_cmd_export_t* ret;
169         
170         ser_cmd = 0;
171         kam_cmd = 0;
172         ret = 0;
173         n = 0;
174         /* count the number of elements */
175         if (ver == 0) {
176                 ser_cmd = src;
177                 for (; ser_cmd[n].name; n++);
178         } else if (ver == 1) {
179                 kam_cmd = src;
180                 for (; kam_cmd[n].name; n++);
181         } else goto error; /* unknown interface version */
182         /* alloc & init new array */
183         ret = pkg_malloc(sizeof(*ret)*(n+1));
184         memset(ret, 0, sizeof(*ret)*(n+1));
185         /* convert/copy */
186         for (i=0; i < n; i++) {
187                 if (ver == 0) {
188                         ret[i].name = ser_cmd[i].name;
189                         ret[i].function = ser_cmd[i].function;
190                         ret[i].param_no = ser_cmd[i].param_no;
191                         ret[i].fixup = ser_cmd[i].fixup;
192                         ret[i].free_fixup = 0; /* no present in ser  <= 2.1 */
193                         ret[i].flags = ser_cmd[i].flags;
194                 } else {
195                         ret[i].name = kam_cmd[i].name;
196                         ret[i].function = kam_cmd[i].function;
197                         ret[i].param_no = kam_cmd[i].param_no;
198                         ret[i].fixup = kam_cmd[i].fixup;
199                         ret[i].free_fixup = kam_cmd[i].free_fixup;
200                         ret[i].flags = kam_cmd[i].flags;
201                 }
202                 /* 3.1+ specific stuff */
203                 ret[i].fixup_flags = 0;
204                 ret[i].module_exports = mod;
205         }
206         return ret;
207 error:
208         return 0;
209 }
210
211
212
213 /* registers a module,  register_f= module register  functions
214  * returns <0 on error, 0 on success */
215 static int register_module(unsigned ver, union module_exports_u* e,
216                                         char* path, void* handle)
217 {
218         int ret, i;
219         struct sr_module* mod;
220
221         ret=-1;
222
223         /* add module to the list */
224         if ((mod=pkg_malloc(sizeof(struct sr_module)))==0){
225                 LOG(L_ERR, "load_module: memory allocation failure\n");
226                 ret=E_OUT_OF_MEM;
227                 goto error;
228         }
229         memset(mod,0, sizeof(struct sr_module));
230         mod->path=path;
231         mod->handle=handle;
232         mod->orig_mod_interface_ver=ver;
233         /* convert exports to sr31 format */
234         if (ver == 0) {
235                 /* ser <= 3.0 */
236                 mod->exports.name = e->v0.name;
237                 if (e->v0.cmds) {
238                         mod->exports.cmds = sr_cmd_exports_convert(ver, e->v0.cmds, mod);
239                         if (mod->exports.cmds == 0) {
240                                 ERR("failed to convert module command exports to 3.1 format"
241                                                 " for module \"%s\" (%s), interface version %d\n",
242                                                 mod->exports.name, mod->path, ver);
243                                 ret = E_UNSPEC;
244                                 goto error;
245                         }
246                 }
247                 mod->exports.params = e->v0.params;
248                 mod->exports.init_f = e->v0.init_f;
249                 mod->exports.response_f = e->v0.response_f;
250                 mod->exports.destroy_f = e->v0.destroy_f;
251                 mod->exports.onbreak_f = e->v0.onbreak_f;
252                 mod->exports.init_child_f = e->v0.init_child_f;
253                 mod->exports.dlflags = 0; /* not used in ser <= 3.0 */
254                 mod->exports.rpc_methods = e->v0.rpc_methods;
255                 /* the rest are 0, not used in ser */
256         } else if (ver == 1) {
257                 /* kamailio <= 3.0 */
258                 mod->exports.name = e->v1.name;
259                 if (e->v1.cmds) {
260                         mod->exports.cmds = sr_cmd_exports_convert(ver, e->v1.cmds, mod);
261                         if (mod->exports.cmds == 0) {
262                                 ERR("failed to convert module command exports to 3.1 format"
263                                                 " for module \"%s\" (%s), interface version %d\n",
264                                                 mod->exports.name, mod->path, ver);
265                                 ret = E_UNSPEC;
266                                 goto error;
267                         }
268                 }
269                 mod->exports.params = e->v1.params;
270                 mod->exports.init_f = e->v1.init_f;
271                 mod->exports.response_f = e->v1.response_f;
272                 mod->exports.destroy_f = e->v1.destroy_f;
273                 mod->exports.onbreak_f = 0; /* not used in k <= 3.0 */
274                 mod->exports.init_child_f = e->v1.init_child_f;
275                 mod->exports.dlflags = e->v1.dlflags;
276                 mod->exports.rpc_methods = 0; /* not used in k <= 3.0 */
277                 mod->exports.stats = e->v1.stats;
278                 mod->exports.mi_cmds = e->v1.mi_cmds;
279                 mod->exports.items = e->v1.items;
280                 mod->exports.procs = e->v1.procs;
281         } else {
282                 ERR("unsupported module interface version %d\n", ver);
283                 ret = E_UNSPEC;
284                 goto error;
285         }
286
287         if (mod->exports.items) {
288                 /* register module pseudo-variables for kamailio modules */
289                 LM_DBG("register PV from: %s\n", mod->exports.name);
290                 if (register_pvars_mod(mod->exports.name, mod->exports.items)!=0) {
291                         LM_ERR("failed to register pseudo-variables for module %s (%s)\n",
292                                 mod->exports.name, path);
293                         ret = E_UNSPEC;
294                         goto error;
295                 }
296         }
297         if (mod->exports.rpc_methods){
298                 /* register rpcs for ser modules */
299                 i=rpc_register_array(mod->exports.rpc_methods);
300                 if (i<0){
301                         ERR("failed to register RPCs for module %s (%s)\n",
302                                         mod->exports.name, path);
303                         ret = E_UNSPEC;
304                         goto error;
305                 }else if (i>0){
306                         ERR("%d duplicate RPCs name detected while registering RPCs"
307                                         " declared in module %s (%s)\n",
308                                         i, mod->exports.name, path);
309                         ret = E_UNSPEC;
310                         goto error;
311                 }
312                 /* i==0 => success */
313         }
314
315         /* link module in the list */
316         mod->next=modules;
317         modules=mod;
318         return 0;
319 error:
320         if (mod)
321                 pkg_free(mod);
322         return ret;
323 }
324
325 #ifndef DLSYM_PREFIX
326 /* define it to null */
327 #define DLSYM_PREFIX
328 #endif
329
330 static inline int version_control(void *handle, char *path)
331 {
332         char **m_ver;
333         char **m_flags;
334         char* error;
335
336         m_ver=(char **)dlsym(handle, DLSYM_PREFIX "module_version");
337         if ((error=(char *)dlerror())!=0) {
338                 LOG(L_ERR, "ERROR: no version info in module <%s>: %s\n",
339                         path, error );
340                 return 0;
341         }
342         m_flags=(char **)dlsym(handle, DLSYM_PREFIX "module_flags");
343         if ((error=(char *)dlerror())!=0) {
344                 LOG(L_ERR, "ERROR: no compile flags info in module <%s>: %s\n",
345                         path, error );
346                 return 0;
347         }
348         if (!m_ver || !(*m_ver)) {
349                 LOG(L_ERR, "ERROR: no version in module <%s>\n", path );
350                 return 0;
351         }
352         if (!m_flags || !(*m_flags)) {
353                 LOG(L_ERR, "ERROR: no compile flags in module <%s>\n", path );
354                 return 0;
355         }
356
357         if (strcmp(SER_FULL_VERSION, *m_ver)==0){
358                 if (strcmp(SER_COMPILE_FLAGS, *m_flags)==0)
359                         return 1;
360                 else {
361                         LOG(L_ERR, "ERROR: module compile flags mismatch for %s "
362                                                 " \ncore: %s \nmodule: %s\n",
363                                                 path, SER_COMPILE_FLAGS, *m_flags);
364                         return 0;
365                 }
366         }
367         LOG(L_ERR, "ERROR: module version mismatch for %s; "
368                 "core: %s; module: %s\n", path, SER_FULL_VERSION, *m_ver );
369         return 0;
370 }
371
372 /** load a sr module.
373  * tries to load the module specified by mod_path.
374  * If mod_path is 'modname' or 'modname.so' then
375  *  <MODS_DIR>/<modname>.so will be tried and if this fails
376  *  <MODS_DIR>/<modname>/<modname>.so
377  * If mod_path contain a '/' it is assumed to be the 
378  * path to the module and tried first. If fails and mod_path is not
379  * absolute path (not starting with '/') then will try:
380  *   <MODS_DIR>/mod_path
381  * @param modname - path or module name
382  * @return 0 on success , <0 on error
383  */
384 int load_module(char* mod_path)
385 {
386         void* handle;
387         char* error;
388         mod_register_function mr;
389         union module_exports_u* exp;
390         unsigned* mod_if_ver;
391         struct sr_module* t;
392         struct stat stat_buf;
393         str modname;
394         char* mdir;
395         char* nxt_mdir;
396         char* path;
397         int mdir_len;
398         int len;
399         int dlflags;
400         int new_dlflags;
401         int retries;
402         int path_type;
403
404 #ifndef RTLD_NOW
405 /* for openbsd */
406 #define RTLD_NOW DL_LAZY
407 #endif
408         path=mod_path;
409         path_type = 0;
410         modname.s = path;
411         modname.len = strlen(mod_path);
412         if(modname.len>3 && strcmp(modname.s+modname.len-3, ".so")==0) {
413                 path_type = 1;
414                 modname.len -= 3;
415         }
416         if (!strchr(path, '/'))
417                 path_type |= 2;
418         if((path_type&2) || path[0] != '/') {
419                 /* module name was given, we try to construct the path */
420                 mdir=mods_dir; /* search path */
421                 do{
422                         nxt_mdir=strchr(mdir, ':');
423                         if (nxt_mdir) mdir_len=(int)(nxt_mdir-mdir);
424                         else mdir_len=strlen(mdir);
425                         
426                         if(path_type&2) {
427                                 /* try path <MODS_DIR>/<modname>.so */
428                                 path = (char*)pkg_malloc(mdir_len + 1 /* "/" */ +
429                                                                         modname.len + 3 /* ".so" */ + 1);
430                                 if (path==0) goto error;
431                                 memcpy(path, mdir, mdir_len);
432                                 len = mdir_len;
433                                 if (len != 0 && path[len - 1] != '/'){
434                                         path[len]='/';
435                                         len++;
436                                 }
437                                 path[len]=0;
438                                 strcat(path, modname.s);
439                                 if(!(path_type&1))
440                                         strcat(path, ".so");
441
442                                 if (stat(path, &stat_buf) == -1) {
443                                         DBG("load_module: module file not found <%s>\n", path);
444                                         pkg_free(path);
445
446                                         /* try path <MODS_DIR>/<modname>/<modname>.so */
447                                         path = (char*)pkg_malloc(
448                                                 mdir_len + 1 /* "/" */ +
449                                                 modname.len + 1 /* "/" */ +
450                                                 modname.len + 3 /* ".so" */ + 1);
451                                         if (path==0) goto error;
452                                         memcpy(path, mdir, mdir_len);
453                                         len = mdir_len;
454                                         if (len != 0 && path[len - 1] != '/') {
455                                                 path[len]='/';
456                                                 len++;
457                                         }
458                                         path[len]=0;
459                                         strncat(path, modname.s, modname.len);
460                                         strcat(path, "/");
461                                         strcat(path, modname.s);
462                                         if(!(path_type&1))
463                                                 strcat(path, ".so");
464
465                                         if (stat(path, &stat_buf) == -1) {
466                                                 DBG("load_module: module file not found <%s>\n", path);
467                                                 pkg_free(path);
468                                                 path=0;
469                                         }
470                                 }
471                         } else {
472                                 /* try mod_path - S compat */
473                                 if(path==mod_path) {
474                                         if (stat(path, &stat_buf) == -1) {
475                                                 DBG("load_module: module file not found <%s>\n", path);
476                                                 path=0;
477                                         }
478                                 }
479                                 if(path==0) {
480                                         /* try path <MODS_DIR>/mod_path - K compat */
481                                         path = (char*)pkg_malloc(mdir_len + 1 /* "/" */ +
482                                                                         strlen(mod_path) + 1);
483                                         if (path==0) goto error;
484                                         memcpy(path, mdir, mdir_len);
485                                         len = mdir_len;
486                                         if (len != 0 && path[len - 1] != '/'){
487                                                 path[len]='/';
488                                                 len++;
489                                         }
490                                         path[len]=0;
491                                         strcat(path, mod_path);
492
493                                         if (stat(path, &stat_buf) == -1) {
494                                                 DBG("load_module: module file not found <%s>\n", path);
495                                                 pkg_free(path);
496                                                 path=0;
497                                         }
498                                 }
499                         }
500                         mdir=nxt_mdir?nxt_mdir+1:0;
501                 }while(path==0 && mdir);
502                 if (path==0){
503                         LOG(L_ERR, "ERROR: load_module: could not find module <%.*s> in"
504                                                 " <%s>\n", modname.len, modname.s, mods_dir);
505                         goto error;
506                 }
507         }
508         DBG("load_module: trying to load <%s>\n", path);
509
510         retries=2;
511         dlflags=RTLD_NOW;
512 reload:
513         handle=dlopen(path, dlflags); /* resolve all symbols now */
514         if (handle==0){
515                 LOG(L_ERR, "ERROR: load_module: could not open module <%s>: %s\n",
516                         path, dlerror());
517                 goto error;
518         }
519
520         for(t=modules;t; t=t->next){
521                 if (t->handle==handle){
522                         LOG(L_WARN, "WARNING: load_module: attempting to load the same"
523                                                 " module twice (%s)\n", path);
524                         goto skip;
525                 }
526         }
527         /* version control */
528         if (!version_control(handle, path)) {
529                 exit(0);
530         }
531         mod_if_ver = (unsigned *)dlsym(handle,
532                                                                         DLSYM_PREFIX "module_interface_ver");
533         if ( (error =(char*)dlerror())!=0 ){
534                 LOG(L_ERR, "ERROR: no module interface version in module <%s>\n",
535                                         path );
536                 goto error1;
537         }
538         /* launch register */
539         mr = (mod_register_function)dlsym(handle, DLSYM_PREFIX "mod_register");
540         if (((error =(char*)dlerror())==0) && mr) {
541                 /* no error call it */
542                 new_dlflags=dlflags;
543                 if (mr(path, &dlflags, 0, 0)!=0) {
544                         LOG(L_ERR, "ERROR: load_module: %s: mod_register failed\n", path);
545                         goto error1;
546                 }
547                 if (new_dlflags!=dlflags && new_dlflags!=0) {
548                         /* we have to reload the module */
549                         dlclose(handle);
550                         dlflags=new_dlflags;
551                         retries--;
552                         if (retries>0) goto reload;
553                         LOG(L_ERR, "ERROR: load_module: %s: cannot agree"
554                                         " on the dlflags\n", path);
555                         goto error;
556                 }
557         }
558         exp = (union module_exports_u*)dlsym(handle, DLSYM_PREFIX "exports");
559         if ( (error =(char*)dlerror())!=0 ){
560                 LOG(L_ERR, "ERROR: load_module: %s\n", error);
561                 goto error1;
562         }
563         /* hack to allow for kamailio style dlflags inside exports */
564         if (*mod_if_ver == 1) {
565                 new_dlflags = exp->v1.dlflags;
566                 if (new_dlflags!=dlflags && new_dlflags!=DEFAULT_DLFLAGS) {
567                         /* we have to reload the module */
568                         dlclose(handle);
569                         WARN("%s: exports dlflags interface is deprecated and it will not"
570                                         "be supported in newer versions; consider using"
571                                         " mod_register() instead", path);
572                         dlflags=new_dlflags;
573                         retries--;
574                         if (retries>0) goto reload;
575                         LOG(L_ERR, "ERROR: load_module: %s: cannot agree"
576                                         " on the dlflags\n", path);
577                         goto error;
578                 }
579         }
580         if (register_module(*mod_if_ver, exp, path, handle)<0) goto error1;
581         return 0;
582
583 error1:
584         dlclose(handle);
585 error:
586 skip:
587         if (path && path!=mod_path)
588                 pkg_free(path);
589         return -1;
590 }
591
592
593
594 /* searches the module list for function name in module mod and returns 
595  *  a pointer to the "name" function record union or 0 if not found
596  * sets also *mod_if_ver to the original module interface version.
597  * mod==0 is a wildcard matching all modules
598  * flags parameter is OR value of all flags that must match
599  */
600 sr31_cmd_export_t* find_mod_export_record(char* mod, char* name,
601                                                                                         int param_no, int flags,
602                                                                                         unsigned* mod_if_ver)
603 {
604         struct sr_module* t;
605         sr31_cmd_export_t* cmd;
606
607         for(t=modules;t;t=t->next){
608                 if (mod!=0 && (strcmp(t->exports.name, mod) !=0))
609                         continue;
610                 if (t->exports.cmds)
611                         for(cmd=&t->exports.cmds[0]; cmd->name; cmd++) {
612                                 if((strcmp(name, cmd->name) == 0) &&
613                                         ((cmd->param_no == param_no) ||
614                                          (cmd->param_no==VAR_PARAM_NO)) &&
615                                         ((cmd->flags & flags) == flags)
616                                 ){
617                                         DBG("find_export_record: found <%s> in module %s [%s]\n",
618                                                 name, t->exports.name, t->path);
619                                         *mod_if_ver=t->orig_mod_interface_ver;
620                                         return cmd;
621                                 }
622                         }
623         }
624         DBG("find_export_record: <%s> not found \n", name);
625         return 0;
626 }
627
628
629
630 /* searches the module list for function name and returns 
631  *  a pointer to the "name" function record union or 0 if not found
632  * sets also *mod_if_ver to the module interface version (needed to know
633  * which member of the union should be accessed v0 or v1)
634  * mod==0 is a wildcard matching all modules
635  * flags parameter is OR value of all flags that must match
636  */
637 sr31_cmd_export_t* find_export_record(char* name,
638                                                                                         int param_no, int flags,
639                                                                                         unsigned* mod_if_ver)
640 {
641         return find_mod_export_record(0, name, param_no, flags, mod_if_ver);
642 }
643
644
645
646 cmd_function find_export(char* name, int param_no, int flags)
647 {
648         sr31_cmd_export_t* cmd;
649         unsigned mver;
650         
651         cmd = find_export_record(name, param_no, flags, &mver);
652         return cmd?cmd->function:0;
653 }
654
655
656 rpc_export_t* find_rpc_export(char* name, int flags)
657 {
658         return rpc_lookup((char*)name, strlen(name));
659 }
660
661
662 /*
663  * searches the module list and returns pointer to "name" function in module
664  * "mod"
665  * 0 if not found
666  * flags parameter is OR value of all flags that must match
667  */
668 cmd_function find_mod_export(char* mod, char* name, int param_no, int flags)
669 {
670         sr31_cmd_export_t* cmd;
671         unsigned mver;
672
673         cmd=find_mod_export_record(mod, name, param_no, flags, &mver);
674         if (cmd)
675                 return cmd->function;
676         
677         DBG("find_mod_export: <%s> in module <%s> not found\n", name, mod);
678         return 0;
679 }
680
681
682 struct sr_module* find_module_by_name(char* mod) {
683         struct sr_module* t;
684
685         for(t = modules; t; t = t->next) {
686                 if (strcmp(mod, t->exports.name) == 0) {
687                         return t;
688                 }
689         }
690         DBG("find_module_by_name: module <%s> not found\n", mod);
691         return 0;
692 }
693
694
695 void* find_param_export(struct sr_module* mod, char* name,
696                                                 modparam_t type_mask, modparam_t *param_type)
697 {
698         param_export_t* param;
699
700         if (!mod)
701                 return 0;
702         for(param = mod->exports.params ;param && param->name ; param++) {
703                 if ((strcmp(name, param->name) == 0) &&
704                         ((param->type & PARAM_TYPE_MASK(type_mask)) != 0)) {
705                         DBG("find_param_export: found <%s> in module %s [%s]\n",
706                                 name, mod->exports.name, mod->path);
707                         *param_type = param->type;
708                         return param->param_pointer;
709                 }
710         }
711         DBG("find_param_export: parameter <%s> not found in module <%s>\n",
712                         name, mod->exports.name);
713         return 0;
714 }
715
716
717 void destroy_modules()
718 {
719         struct sr_module* t, *foo;
720
721         t=modules;
722         while(t) {
723                 foo=t->next;
724                 if (t->exports.destroy_f){
725                         t->exports.destroy_f();
726                 }
727                 pkg_free(t);
728                 t=foo;
729         }
730         modules=0;
731         if (mod_response_cbks){
732                 pkg_free(mod_response_cbks);
733                 mod_response_cbks=0;
734         }
735 }
736
737 #ifdef NO_REVERSE_INIT
738
739 /*
740  * Initialize all loaded modules, the initialization
741  * is done *AFTER* the configuration file is parsed
742  */
743 int init_modules(void)
744 {
745         struct sr_module* t;
746
747         for(t = modules; t; t = t->next) {
748                 if (t->exports.init_f)
749                         if (t->exports.init_f() != 0) {
750                                 LOG(L_ERR, "init_modules(): Error while"
751                                                 " initializing module %s\n", t->exports.name);
752                                 return -1;
753                         }
754                 if (t->exports.response_f)
755                         mod_response_cbk_no++;
756         }
757         mod_response_cbks=pkg_malloc(mod_response_cbk_no * 
758                                                                         sizeof(response_function));
759         if (mod_response_cbks==0){
760                 LOG(L_ERR, "init_modules(): memory allocation failure"
761                                         " for %d response_f callbacks\n", mod_response_cbk_no);
762                 return -1;
763         }
764         for (t=modules, i=0; t && (i<mod_response_cbk_no); t=t->next) {
765                 if (t->exports.response_f) {
766                         mod_response_cbks[i]=t->exports.response_f;
767                         i++;
768                 }
769         }
770         return 0;
771 }
772
773
774
775 /*
776  * per-child initialization
777  */
778 int init_child(int rank)
779 {
780         struct sr_module* t;
781         char* type;
782
783         switch(rank) {
784         case PROC_MAIN:     type = "PROC_MAIN";     break;
785         case PROC_TIMER:    type = "PROC_TIMER";    break;
786         case PROC_FIFO:     type = "PROC_FIFO";     break;
787         case PROC_TCP_MAIN: type = "PROC_TCP_MAIN"; break;
788         default:            type = "CHILD";         break;
789         }
790         DBG("init_child: initializing %s with rank %d\n", type, rank);
791
792
793         for(t = modules; t; t = t->next) {
794                 if (t->exports.init_child_f) {
795                         if ((t->exports.init_child_f(rank)) < 0) {
796                                 LOG(L_ERR, "init_child(): Initialization of child"
797                                                         " %d failed\n", rank);
798                                 return -1;
799                         }
800                 }
801         }
802         return 0;
803 }
804
805 #else
806
807
808 /* recursive module child initialization; (recursion is used to
809    process the module linear list in the same order in
810    which modules are loaded in config file
811 */
812
813 static int init_mod_child( struct sr_module* m, int rank )
814 {
815         if (m) {
816                 /* iterate through the list; if error occurs,
817                    propagate it up the stack
818                  */
819                 if (init_mod_child(m->next, rank)!=0) return -1;
820                 if (m->exports.init_child_f) {
821                         DBG("DEBUG: init_mod_child (%d): %s\n", rank, m->exports.name);
822                         if (m->exports.init_child_f(rank)<0) {
823                                 LOG(L_ERR, "init_mod_child(): Error while"
824                                                         " initializing module %s (%s)\n",
825                                                         m->exports.name, m->path);
826                                 return -1;
827                         } else {
828                                 /* module correctly initialized */
829                                 return 0;
830                         }
831                 }
832                 /* no init function -- proceed with success */
833                 return 0;
834         } else {
835                 /* end of list */
836                 return 0;
837         }
838 }
839
840
841 /*
842  * per-child initialization
843  */
844 int init_child(int rank)
845 {
846         return init_mod_child(modules, rank);
847 }
848
849
850
851 /* recursive module initialization; (recursion is used to
852    process the module linear list in the same order in
853    which modules are loaded in config file
854 */
855
856 static int init_mod( struct sr_module* m )
857 {
858         if (m) {
859                 /* iterate through the list; if error occurs,
860                    propagate it up the stack
861                  */
862                 if (init_mod(m->next)!=0) return -1;
863                         if (m->exports.init_f) {
864                                 DBG("DEBUG: init_mod: %s\n", m->exports.name);
865                                 if (m->exports.init_f()!=0) {
866                                         LOG(L_ERR, "init_mod(): Error while initializing"
867                                                                 " module %s (%s)\n",
868                                                                 m->exports.name, m->path);
869                                         return -1;
870                                 } else {
871                                         /* module correctly initialized */
872                                         return 0;
873                                 }
874                         }
875                         /* no init function -- proceed with success */
876                         return 0;
877         } else {
878                 /* end of list */
879                 return 0;
880         }
881 }
882
883 /*
884  * Initialize all loaded modules, the initialization
885  * is done *AFTER* the configuration file is parsed
886  */
887 int init_modules(void)
888 {
889         struct sr_module* t;
890         int i;
891         
892         i = init_mod(modules);
893         if(i!=0)
894                 return i;
895
896         for(t = modules; t; t = t->next)
897                 if (t->exports.response_f)
898                         mod_response_cbk_no++;
899         mod_response_cbks=pkg_malloc(mod_response_cbk_no * 
900                                                                         sizeof(response_function));
901         if (mod_response_cbks==0){
902                 LOG(L_ERR, "init_modules(): memory allocation failure"
903                                         " for %d response_f callbacks\n", mod_response_cbk_no);
904                 return -1;
905         }
906         for (t=modules, i=0; t && (i<mod_response_cbk_no); t=t->next)
907                 if (t->exports.response_f) {
908                         mod_response_cbks[i]=t->exports.response_f;
909                         i++;
910                 }
911         
912         return 0;
913 }
914
915 #endif
916
917
918 action_u_t *fixup_get_param(void **cur_param, int cur_param_no,
919                                                         int required_param_no)
920 {
921         action_u_t *a, a2;
922         /* cur_param points to a->u.string, get pointer to a */
923         a = (void*) ((char *)cur_param - ((char *)&a2.u.string-(char *)&a2));
924         return a + required_param_no - cur_param_no;
925 }
926
927 int fixup_get_param_count(void **cur_param, int cur_param_no)
928 {
929         action_u_t *a;
930         a = fixup_get_param(cur_param, cur_param_no, 0);
931         if (a)
932                 return a->u.number;
933         else
934                 return -1;
935 }
936
937
938
939 /** get a pointer to a parameter internal type.
940  * @param param
941  * @return pointer to the parameter internal type.
942  */
943 action_param_type* fixup_get_param_ptype(void** param)
944 {
945         action_u_t* a;
946         a = (void*)((char*)param - (char*)&(((action_u_t*)(0))->u.string));
947         return &a->type;
948 }
949
950
951 /** get a parameter internal type.
952  * @see fixup_get_param_ptype().
953  * @return paramter internal type.
954  */
955 action_param_type fixup_get_param_type(void** param)
956 {
957         return *fixup_get_param_ptype(param);
958 }
959
960
961
962 /* fixes flag params (resolves possible named flags)
963  * use PARAM_USE_FUNC|PARAM_STRING as a param. type and create
964  * a wrapper function that does just:
965  * return fix_flag(type, val, "my_module", "my_param", &flag_var)
966  * see also param_func_t.
967  */
968 int fix_flag( modparam_t type, void* val,
969                                         char* mod_name, char* param_name, int* flag)
970 {
971         int num;
972         int err;
973         int f, len;
974         char* s;
975         char *p;
976
977         if ((type & PARAM_STRING)==0){
978                 LOG(L_CRIT, "BUG: %s: fix_flag(%s): bad parameter type\n",
979                                         mod_name, param_name);
980                 return -1;
981         }
982         s=(char*)val;
983         len=strlen(s);
984         f=-1;
985         /* try to see if it's a number */
986         num = str2s(s, len, &err);
987         if (err != 0) {
988                 /* see if it's in the name:<no> format */
989                 p=strchr(s, ':');
990                 if (p){
991                         f= str2s(p+1, strlen(p+1), &err);
992                         if (err!=0){
993                                 LOG(L_ERR, "ERROR: %s: invalid %s format:"
994                                                 " \"%s\"", mod_name, param_name, s);
995                                 return -1;
996                         }
997                         *p=0;
998                 }
999                 if ((num=get_flag_no(s, len))<0){
1000                         /* not declared yet, declare it */
1001                         num=register_flag(s, f);
1002                 }
1003                 if (num<0){
1004                         LOG(L_ERR, "ERROR: %s: bad %s %s\n", mod_name, param_name, s);
1005                         return -1;
1006                 } else if ((f>0) && (num!=f)){
1007                         LOG(L_ERR, "WARNING: %s: flag %s already defined"
1008                                         " as %d (and not %d), using %s:%d\n",
1009                                         mod_name, s, num, f, s, num);
1010                 }
1011         }
1012         *flag=num;
1013         return 0;
1014 }
1015
1016 /*
1017  * Common function parameter fixups
1018  */
1019
1020 /** Generic parameter fixup function.
1021  *  Creates a fparam_t structure.
1022  *  @param type  contains allowed parameter types
1023  *  @param param is the parameter that will be fixed-up
1024  *
1025  * @return
1026  *    0 on success, 
1027  *    1 if the param doesn't match the specified type
1028  *    <0 on failure
1029  */
1030 int fix_param(int type, void** param)
1031 {
1032         fparam_t* p;
1033         str name, s;
1034         unsigned int num;
1035         int err;
1036
1037         p = (fparam_t*)pkg_malloc(sizeof(fparam_t));
1038         if (!p) {
1039                 ERR("No memory left\n");
1040                 return E_OUT_OF_MEM;
1041         }
1042         memset(p, 0, sizeof(fparam_t));
1043         p->orig = *param;
1044         
1045         switch(type) {
1046                 case FPARAM_UNSPEC:
1047                         ERR("Invalid type value\n");
1048                         goto error;
1049                 case FPARAM_STRING:
1050                         p->v.asciiz = *param;
1051                         /* no break */
1052                 case FPARAM_STR:
1053                         p->v.str.s = (char*)*param;
1054                         p->v.str.len = strlen(p->v.str.s);
1055                         p->fixed = &p->v;
1056                         break;
1057                 case FPARAM_INT:
1058                         s.s = (char*)*param;
1059                         s.len = strlen(s.s);
1060                         err = str2int(&s, &num);
1061                         if (err == 0) {
1062                                 p->v.i = (int)num;
1063                         } else {
1064                                 /* Not a number */
1065                                 pkg_free(p);
1066                                 return 1;
1067                         }
1068                         p->fixed = (void*)(long)num;
1069                         break;
1070                 case FPARAM_REGEX:
1071                         if ((p->v.regex = pkg_malloc(sizeof(regex_t))) == 0) {
1072                                 ERR("No memory left\n");
1073                                 goto error;
1074                         }
1075                         if (regcomp(p->v.regex, *param,
1076                                                 REG_EXTENDED|REG_ICASE|REG_NEWLINE)) {
1077                                 pkg_free(p->v.regex);
1078                                 p->v.regex=0;
1079                                 /* not a valid regex */
1080                                 goto no_match;
1081                         }
1082                         p->fixed = p->v.regex;
1083                         break;
1084                 case FPARAM_AVP:
1085                         name.s = (char*)*param;
1086                         name.len = strlen(name.s);
1087                         trim(&name);
1088                         if (!name.len || name.s[0] != '$') {
1089                                 /* Not an AVP identifier */
1090                                 goto no_match;
1091                         }
1092                         name.s++;
1093                         name.len--;
1094                         if (parse_avp_ident(&name, &p->v.avp) < 0) {
1095                                 /* invalid avp identifier (=> no match) */
1096                                 goto no_match;
1097                         }
1098                         p->fixed = &p->v;
1099                         break;
1100                 case FPARAM_SELECT:
1101                         name.s = (char*)*param;
1102                         name.len = strlen(name.s);
1103                         trim(&name);
1104                         if (!name.len || name.s[0] != '@') {
1105                                 /* Not a select identifier */
1106                                 goto no_match;
1107                         }
1108                         if (parse_select(&name.s, &p->v.select) < 0) {
1109                                 ERR("Error while parsing select identifier\n");
1110                                 goto error;
1111                         }
1112                         p->fixed = &p->v;
1113                         break;
1114                 case FPARAM_SUBST:
1115                         s.s = *param;
1116                         s.len = strlen(s.s);
1117                         p->v.subst = subst_parser(&s);
1118                         if (!p->v.subst) {
1119                                 ERR("Error while parsing regex substitution\n");
1120                                 goto error;
1121                         }
1122                         p->fixed = &p->v;
1123                         break;
1124                 case FPARAM_PVS:
1125                         name.s = (char*)*param;
1126                         name.len = strlen(name.s);
1127                         trim(&name);
1128                         if (!name.len || name.s[0] != '$'){
1129                                 /* not a pvs identifier */
1130                                 goto no_match;
1131                         }
1132                         p->v.pvs=pkg_malloc(sizeof(pv_spec_t));
1133                         if (p->v.pvs==0){
1134                                 ERR("out of memory while parsing pv_spec_t\n");
1135                                 goto error;
1136                         }
1137                         if (pv_parse_spec2(&name, p->v.pvs, 1)==0){
1138                                 /* not a valid pvs identifier (but it might be an avp) */
1139                                 pkg_free(p->v.pvs);
1140                                 p->v.pvs=0;
1141                                 goto no_match;
1142                         }
1143                         p->fixed = p->v.pvs;
1144                         break;
1145                 case FPARAM_PVE:
1146                         name.s = (char*)*param;
1147                         name.len = strlen(name.s);
1148                         if (pv_parse_format(&name, &p->v.pve)<0){
1149                                 ERR("bad PVE format: \"%.*s\"\n", name.len, name.s);
1150                                 goto error;
1151                         }
1152                         p->fixed = &p->v;
1153                         break;
1154         }
1155         
1156         p->type = type;
1157         *param = (void*)p;
1158         return 0;
1159         
1160 no_match:
1161         pkg_free(p);
1162         return 1;
1163 error:
1164         pkg_free(p);
1165         return E_UNSPEC;
1166 }
1167
1168
1169
1170 /** fparam_t free function.
1171  *  Frees the "content" of a fparam, but not the fparam itself.
1172  *  Assumes pkg_malloc'ed content.
1173  *  @param fp -  fparam to be freed
1174  *
1175  */
1176 void fparam_free_contents(fparam_t* fp)
1177 {
1178
1179         if (fp==0)
1180                 return;
1181         switch(fp->type) {
1182                 case FPARAM_UNSPEC:
1183                 case FPARAM_STRING: /* asciiz string, not str */
1184                 case FPARAM_INT:
1185                 case FPARAM_STR:
1186                         /* nothing to do */
1187                         break;
1188                 case FPARAM_REGEX:
1189                         if (fp->v.regex){
1190                                 regfree(fp->v.regex);
1191                                 pkg_free(fp->v.regex);
1192                                 fp->v.regex=0;
1193                         }
1194                         break;
1195                 case FPARAM_AVP:
1196                         free_avp_name(&fp->v.avp.flags, &fp->v.avp.name);
1197                         break;
1198                 case FPARAM_SELECT:
1199                         if (fp->v.select){
1200                                 free_select(fp->v.select);
1201                                 fp->v.select=0;
1202                         }
1203                         break;
1204                 case FPARAM_SUBST:
1205                         if (fp->v.subst){
1206                                 subst_expr_free(fp->v.subst);
1207                                 fp->v.subst=0;
1208                         }
1209                         break;
1210                 case FPARAM_PVS:
1211                         if (fp->v.pvs){
1212                                 pv_spec_free(fp->v.pvs);
1213                                 fp->v.pvs=0;
1214                         }
1215                         break;
1216                 case FPARAM_PVE:
1217                         if (fp->v.pve){
1218                                 pv_elem_free_all(fp->v.pve);
1219                                 fp->v.pve=0;
1220                         }
1221                         break;
1222         }
1223         if (fp->orig){
1224                 pkg_free(fp->orig);
1225                 fp->orig=0;
1226         }
1227 }
1228
1229
1230
1231 /** fix a param to one of the given types (mask).
1232   *
1233   * @param types - bitmap of the allowed types (e.g. FPARAM_INT|FPARAM_STR)
1234   * @param param - value/result
1235   * @return - 0 on success, -1 on error, 1 if param doesn't
1236   *           match any of the types
1237   */
1238 int fix_param_types(int types, void** param)
1239 {
1240         int ret;
1241         int t;
1242         
1243         if (fixup_get_param_type(param) == STRING_RVE_ST &&
1244                         (types & (FPARAM_INT|FPARAM_STR|FPARAM_STRING))) {
1245                 /* if called with a RVE already converted to string =>
1246                    don't try AVP, PVAR or SELECT (to avoid double
1247                    deref., e.g.: $foo="$bar"; f($foo) ) */
1248                 types &= ~ (FPARAM_AVP|FPARAM_PVS|FPARAM_SELECT|FPARAM_PVE);
1249         }
1250         for (t=types & ~(types-1); types; types&=(types-1), t=types & ~(types-1)){
1251                 if ((ret=fix_param(t, param))<=0) return ret;
1252         }
1253         return E_UNSPEC;
1254 }
1255
1256
1257
1258 /*
1259  * Fixup variable string, the parameter can be
1260  * AVP, SELECT, or ordinary string. AVP and select
1261  * identifiers will be resolved to their values during
1262  * runtime
1263  *
1264  * The parameter value will be converted to fparam structure
1265  * This function returns -1 on an error
1266  */
1267 int fixup_var_str_12(void** param, int param_no)
1268 {
1269         int ret;
1270         if (fixup_get_param_type(param) != STRING_RVE_ST) {
1271                 /* if called with a RVE already converted to string =>
1272                    don't try AVP, PVAR or SELECT (to avoid double
1273                    deref., e.g.: $foo="$bar"; f($foo) ) */
1274                 if ((sr_cfg_compat!=SR_COMPAT_SER) &&
1275                         ((ret = fix_param(FPARAM_PVS, param)) <= 0)) return ret;
1276                 if ((ret = fix_param(FPARAM_AVP, param)) <= 0) return ret;
1277                 if ((ret = fix_param(FPARAM_SELECT, param)) <= 0) return ret;
1278         }
1279         if ((ret = fix_param(FPARAM_STR, param)) <= 0) return ret;
1280         ERR("Error while fixing parameter, AVP, SELECT, and str conversions"
1281                         " failed\n");
1282         return -1;
1283 }
1284
1285 /* Same as fixup_var_str_12 but applies to the 1st parameter only */
1286 int fixup_var_str_1(void** param, int param_no)
1287 {
1288         if (param_no == 1) return fixup_var_str_12(param, param_no);
1289         else return 0;
1290 }
1291
1292 /* Same as fixup_var_str_12 but applies to the 2nd parameter only */
1293 int fixup_var_str_2(void** param, int param_no)
1294 {
1295         if (param_no == 2) return fixup_var_str_12(param, param_no);
1296         else return 0;
1297 }
1298
1299
1300 /*
1301  * Fixup variable integer, the parameter can be
1302  * AVP, SELECT, or ordinary integer. AVP and select
1303  * identifiers will be resolved to their values and
1304  * converted to int if necessary during runtime
1305  *
1306  * The parameter value will be converted to fparam structure
1307  * This function returns -1 on an error
1308  */
1309 int fixup_var_int_12(void** param, int param_no)
1310 {
1311         int ret;
1312         if (fixup_get_param_type(param) != STRING_RVE_ST) {
1313                 /* if called with a RVE already converted to string =>
1314                    don't try AVP, PVAR or SELECT (to avoid double
1315                    deref., e.g.: $foo="$bar"; f($foo) ) */
1316                 if ((sr_cfg_compat!=SR_COMPAT_SER) &&
1317                         ((ret = fix_param(FPARAM_PVS, param)) <= 0)) return ret;
1318                 if ((ret = fix_param(FPARAM_AVP, param)) <= 0) return ret;
1319                 if ((ret = fix_param(FPARAM_SELECT, param)) <= 0) return ret;
1320         }
1321         if ((ret = fix_param(FPARAM_INT, param)) <= 0) return ret;
1322         ERR("Error while fixing parameter, AVP, SELECT, and int conversions"
1323                         " failed\n");
1324         return -1;
1325 }
1326
1327 /* Same as fixup_var_int_12 but applies to the 1st parameter only */
1328 int fixup_var_int_1(void** param, int param_no)
1329 {
1330         if (param_no == 1) return fixup_var_int_12(param, param_no);
1331         else return 0;
1332 }
1333
1334 /* Same as fixup_var_int_12 but applies to the 2nd parameter only */
1335 int fixup_var_int_2(void** param, int param_no)
1336 {
1337         if (param_no == 2) return fixup_var_int_12(param, param_no);
1338         else return 0;
1339 }
1340
1341
1342 /*
1343  * The parameter must be a regular expression which must compile, the
1344  * parameter will be converted to compiled regex
1345  */
1346 int fixup_regex_12(void** param, int param_no)
1347 {
1348         int ret;
1349
1350         if ((ret = fix_param(FPARAM_REGEX, param)) <= 0) return ret;
1351         ERR("Error while compiling regex in function parameter\n");
1352         return -1;
1353 }
1354
1355 /* Same as fixup_regex_12 but applies to the 1st parameter only */
1356 int fixup_regex_1(void** param, int param_no)
1357 {
1358         if (param_no == 1) return fixup_regex_12(param, param_no);
1359         else return 0;
1360 }
1361
1362 /* Same as fixup_regex_12 but applies to the 2nd parameter only */
1363 int fixup_regex_2(void** param, int param_no)
1364 {
1365         if (param_no == 2) return fixup_regex_12(param, param_no);
1366         else return 0;
1367 }
1368
1369 /*
1370  * The string parameter will be converted to integer
1371  */
1372 int fixup_int_12(void** param, int param_no)
1373 {
1374         int ret;
1375
1376         if ((ret = fix_param(FPARAM_INT, param)) <= 0) return ret;
1377         ERR("Cannot function parameter to integer\n");
1378         return -1;
1379
1380 }
1381
1382 /* Same as fixup_int_12 but applies to the 1st parameter only */
1383 int fixup_int_1(void** param, int param_no)
1384 {
1385         if (param_no == 1) return fixup_int_12(param, param_no);
1386         else return 0;
1387 }
1388
1389 /* Same as fixup_int_12 but applies to the 2nd parameter only */
1390 int fixup_int_2(void** param, int param_no)
1391 {
1392         if (param_no == 2) return fixup_int_12(param, param_no);
1393         else return 0;
1394 }
1395
1396 /*
1397  * Parse the parameter as static string, do not resolve
1398  * AVPs or selects, convert the parameter to str structure
1399  */
1400 int fixup_str_12(void** param, int param_no)
1401 {
1402         int ret;
1403
1404         if ((ret = fix_param(FPARAM_STR, param)) <= 0) return ret;
1405         ERR("Cannot function parameter to string\n");
1406         return -1;
1407 }
1408
1409 /* Same as fixup_str_12 but applies to the 1st parameter only */
1410 int fixup_str_1(void** param, int param_no)
1411 {
1412         if (param_no == 1) return fixup_str_12(param, param_no);
1413         else return 0;
1414 }
1415
1416 /* Same as fixup_str_12 but applies to the 2nd parameter only */
1417 int fixup_str_2(void** param, int param_no)
1418 {
1419         if (param_no == 2) return fixup_str_12(param, param_no);
1420         else return 0;
1421 }
1422
1423
1424
1425 #define PV_PRINT_BUF_SIZE  1024
1426 #define PV_PRINT_BUF_NO    3
1427 /** Get the function parameter value as string.
1428  *  @return  0 - Success
1429  *          -1 - Cannot get value
1430  */
1431 int get_str_fparam(str* dst, struct sip_msg* msg, fparam_t* param)
1432 {
1433         int_str val;
1434         int ret;
1435         avp_t* avp;
1436         pv_value_t pv_val;
1437         static int buf_itr = 0; /* ugly hack needed for PVE */
1438         static char pve_buf[PV_PRINT_BUF_NO][PV_PRINT_BUF_SIZE];
1439         
1440         switch(param->type) {
1441                 case FPARAM_REGEX:
1442                 case FPARAM_UNSPEC:
1443                 case FPARAM_INT:
1444                         return -1;
1445                 case FPARAM_STRING:
1446                         dst->s = param->v.asciiz;
1447                         dst->len = strlen(param->v.asciiz);
1448                         break;
1449                 case FPARAM_STR:
1450                         *dst = param->v.str;
1451                         break;
1452                 case FPARAM_AVP:
1453                         avp = search_first_avp(param->v.avp.flags, param->v.avp.name,
1454                                                                         &val, 0);
1455                         if (unlikely(!avp)) {
1456                                 DBG("Could not find AVP from function parameter '%s'\n",
1457                                                 param->orig);
1458                                 return -1;
1459                         }
1460                         if (likely(avp->flags & AVP_VAL_STR)) {
1461                                 *dst = val.s;
1462                         } else {
1463                                 /* The caller does not know of what type the AVP will be so
1464                                  * convert int AVPs into string here
1465                                  */
1466                                 dst->s = int2str(val.n, &dst->len);
1467                         }
1468                         break;
1469                 case FPARAM_SELECT:
1470                         ret = run_select(dst, param->v.select, msg);
1471                         if (unlikely(ret < 0 || ret > 0)) return -1;
1472                         break;
1473                 case FPARAM_PVS:
1474                         if (likely((pv_get_spec_value(msg, param->v.pvs, &pv_val)==0) &&
1475                                            ((pv_val.flags&(PV_VAL_NULL|PV_VAL_STR))==PV_VAL_STR))){
1476                                         *dst=pv_val.rs;
1477                         }else{
1478                                 ERR("Could not convert PV to str\n");
1479                                 return -1;
1480                         }
1481                         break;
1482                 case FPARAM_PVE:
1483                         dst->s=pve_buf[buf_itr];
1484                         dst->len=PV_PRINT_BUF_SIZE;
1485                         buf_itr = (buf_itr+1)%PV_PRINT_BUF_NO;
1486                         if (unlikely(pv_printf(msg, param->v.pve, dst->s, &dst->len)!=0)){
1487                                 ERR("Could not convert the PV-formated string to str\n");
1488                                 dst->len=0;
1489                                 return -1;
1490                         };
1491                         break;
1492         }
1493         return 0;
1494 }
1495
1496
1497 /** Get the function parameter value as integer.
1498  *  @return  0 - Success
1499  *          -1 - Cannot get value
1500  */
1501 int get_int_fparam(int* dst, struct sip_msg* msg, fparam_t* param)
1502 {
1503         int_str val;
1504         int ret;
1505         avp_t* avp;
1506         str tmp;
1507         pv_value_t pv_val;
1508
1509         switch(param->type) {
1510                 case FPARAM_INT:
1511                         *dst = param->v.i;
1512                         return 0;
1513                 case FPARAM_REGEX:
1514                 case FPARAM_UNSPEC:
1515                 case FPARAM_STRING:
1516                 case FPARAM_STR:
1517                         return -1;
1518                 case FPARAM_AVP:
1519                         avp = search_first_avp(param->v.avp.flags, param->v.avp.name,
1520                                                                         &val, 0);
1521                         if (unlikely(!avp)) {
1522                                 DBG("Could not find AVP from function parameter '%s'\n",
1523                                                 param->orig);
1524                                 return -1;
1525                         }
1526                         if (avp->flags & AVP_VAL_STR) {
1527                                 if (str2int(&val.s, (unsigned int*)dst) < 0) {
1528                                         ERR("Could not convert AVP string value to int\n");
1529                                         return -1;
1530                                 }
1531                         } else {
1532                                 *dst = val.n;
1533                         }
1534                         break;
1535                 case FPARAM_SELECT:
1536                         ret = run_select(&tmp, param->v.select, msg);
1537                         if (unlikely(ret < 0 || ret > 0)) return -1;
1538                         if (unlikely(str2int(&tmp, (unsigned int*)dst) < 0)) {
1539                                 ERR("Could not convert select result to int\n");
1540                                 return -1;
1541                         }
1542                         break;
1543                 case FPARAM_PVS:
1544                         if (likely((pv_get_spec_value(msg, param->v.pvs, &pv_val)==0) &&
1545                                            ((pv_val.flags&(PV_VAL_NULL|PV_VAL_INT))==PV_VAL_INT))){
1546                                         *dst=pv_val.ri;
1547                         }else{
1548                                 ERR("Could not convert PV to int\n");
1549                                 return -1;
1550                         }
1551                         break;
1552                 case FPARAM_PVE:
1553                         return -1;
1554         }
1555         return 0;
1556 }
1557
1558 /**
1559  * Retrieve the compiled RegExp.
1560  * @return: 0 for success, negative on error.
1561  */
1562 int get_regex_fparam(regex_t *dst, struct sip_msg* msg, fparam_t* param)
1563 {
1564         switch (param->type) {
1565                 case FPARAM_REGEX:
1566                         *dst = *param->v.regex;
1567                         return 0;
1568                 default:
1569                         ERR("unexpected parameter type (%d), instead of regexp.\n", 
1570                                         param->type);
1571         }
1572         return -1;
1573 }
1574
1575
1576
1577 /** returns true if a fixup is a fparam_t* one.
1578  * Used to automatically detect fparam fixups that can be used with non
1579  * contant RVEs.
1580  * @param f - function pointer
1581  * @return 1 for fparam fixups, 0 for others.
1582  */
1583 int is_fparam_rve_fixup(fixup_function f)
1584 {
1585         if (f == fixup_var_str_12 ||
1586                 f == fixup_var_str_1 ||
1587                 f == fixup_var_str_2 ||
1588                 f == fixup_var_int_12 ||
1589                 f == fixup_var_int_1 ||
1590                 f == fixup_var_int_2 ||
1591                 f == fixup_int_12 ||
1592                 f == fixup_int_1 ||
1593                 f == fixup_int_2 ||
1594                 f == fixup_str_12 ||
1595                 f == fixup_str_1 ||
1596                 f == fixup_str_2)
1597                 return 1;
1598         return 0;
1599 }