sr_module.c
3bf76e49
 /* $Id$
7dd0b342
  *
53c7e0f1
  * Copyright (C) 2001-2003 FhG Fokus
7dd0b342
  *
  * This file is part of ser, a free SIP server.
  *
  * ser is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version
  *
  * For a license to use the ser software under conditions
  * other than those described here, or to purchase support for this
  * software, please contact iptel.org by e-mail at the following addresses:
  *    info@iptel.org
  *
  * ser is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  *
fb851d7e
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
7dd0b342
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
3bf76e49
  */
6419a43f
 /*
  * History:
  * --------
  *  2003-03-10  switched to new module_exports format: updated find_export,
  *               find_export_param, find_module (andrei)
e3dccdc9
  *  2003-03-19  replaced all mallocs/frees w/ pkg_malloc/pkg_free (andrei)
51c38611
  *  2003-03-19  Support for flags in find_export (janakj)
3c8bd369
  *  2003-03-29  cleaning pkg_mallocs introduced (jiri)
2dcb8b67
  *  2003-04-24  module version checking introduced (jiri)
dd0e65a8
  *  2004-09-19  compile flags are checked too (andrei)
6d35d70e
  *  2005-01-07  removed find_module-overloading problems, added 
  *               find_export_record
  *  2006-02-07  added fix_flag (andrei)
6419a43f
  */
3bf76e49
 
7dd0b342
 
3bf76e49
 #include "sr_module.h"
 #include "dprint.h"
404073d3
 #include "error.h"
e3dccdc9
 #include "mem/mem.h"
300b0f50
 #include "core_cmd.h"
bb6575cd
 #include "ut.h"
d0ce0ebd
 #include "re.h"
f141bc93
 #include "route_struct.h"
6d35d70e
 #include "flags.h"
b91364c6
 #include "trim.h"
3bf76e49
 
f6712967
 #include <regex.h>
3bf76e49
 #include <dlfcn.h>
 #include <strings.h>
 #include <stdlib.h>
e22bbdb8
 #include <string.h>
3bf76e49
 
 
031e278e
 struct sr_module* modules=0;
3bf76e49
 
30449150
 #ifdef STATIC_EXEC
 	extern struct module_exports* exec_exports();
 #endif
404073d3
 #ifdef STATIC_TM
57c9e572
 	extern struct module_exports* tm_exports();
404073d3
 #endif
57c9e572
 
6eb22d94
 #ifdef STATIC_MAXFWD
57c9e572
 	extern struct module_exports* maxfwd_exports();
6eb22d94
 #endif
57c9e572
 
192ac55b
 #ifdef STATIC_AUTH
57c9e572
         extern struct module_exports* auth_exports();
192ac55b
 #endif
57c9e572
 
192ac55b
 #ifdef STATIC_RR
57c9e572
         extern struct module_exports* rr_exports();
192ac55b
 #endif
57c9e572
 
192ac55b
 #ifdef STATIC_USRLOC
57c9e572
         extern struct module_exports* usrloc_exports();
192ac55b
 #endif
404073d3
 
a50f3f89
 #ifdef STATIC_SL
         extern struct module_exports* sl_exports();
 #endif
 
404073d3
 
 /* initializes statically built (compiled in) modules*/
31309a3a
 int register_builtin_modules()
404073d3
 {
e22bbdb8
 	int ret;
 
 	ret=0;
57c9e572
 #ifdef STATIC_TM
fb851d7e
 	ret=register_module(tm_exports,"built-in", 0);
57c9e572
 	if (ret<0) return ret;
 #endif
192ac55b
 
e8df4b11
 #ifdef STATIC_EXEC
fb851d7e
 	ret=register_module(exec_exports,"built-in", 0);
30449150
 	if (ret<0) return ret;
 #endif
 
57c9e572
 #ifdef STATIC_MAXFWD
 	ret=register_module(maxfwd_exports, "built-in", 0);
 	if (ret<0) return ret;
192ac55b
 #endif
 
57c9e572
 #ifdef STATIC_AUTH
fb851d7e
 	ret=register_module(auth_exports, "built-in", 0);
57c9e572
 	if (ret<0) return ret;
 #endif
fb851d7e
 
192ac55b
 #ifdef STATIC_RR
57c9e572
 	ret=register_module(rr_exports, "built-in", 0);
 	if (ret<0) return ret;
192ac55b
 #endif
fb851d7e
 
192ac55b
 #ifdef STATIC_USRLOC
57c9e572
 	ret=register_module(usrloc_exports, "built-in", 0);
 	if (ret<0) return ret;
192ac55b
 #endif
a50f3f89
 
 #ifdef STATIC_SL
 	ret=register_module(sl_exports, "built-in", 0);
 	if (ret<0) return ret;
 #endif
fb851d7e
 
e22bbdb8
 	return ret;
404073d3
 }
 
 
 
 /* registers a module,  register_f= module register  functions
  * returns <0 on error, 0 on success */
31309a3a
 int register_module(struct module_exports* e, char* path, void* handle)
404073d3
 {
 	int ret;
e22bbdb8
 	struct sr_module* mod;
fb851d7e
 
404073d3
 	ret=-1;
31309a3a
 
404073d3
 	/* add module to the list */
e3dccdc9
 	if ((mod=pkg_malloc(sizeof(struct sr_module)))==0){
404073d3
 		LOG(L_ERR, "load_module: memory allocation failure\n");
 		ret=E_OUT_OF_MEM;
 		goto error;
 	}
 	memset(mod,0, sizeof(struct sr_module));
 	mod->path=path;
 	mod->handle=handle;
 	mod->exports=e;
 	mod->next=modules;
 	modules=mod;
 	return 0;
 error:
 	return ret;
 }
 
2dcb8b67
 #ifndef DLSYM_PREFIX
 /* define it to null */
 #define DLSYM_PREFIX
 #endif
 
 static inline int version_control(void *handle, char *path)
 {
 	char **m_ver;
dd0e65a8
 	char **m_flags;
2dcb8b67
 	char* error;
 
 	m_ver=(char **)dlsym(handle, DLSYM_PREFIX "module_version");
 	if ((error=(char *)dlerror())!=0) {
bae7e884
 		LOG(L_ERR, "ERROR: no version info in module <%s>: %s\n",
2dcb8b67
 			path, error );
 		return 0;
 	}
dd0e65a8
 	m_flags=(char **)dlsym(handle, DLSYM_PREFIX "module_flags");
 	if ((error=(char *)dlerror())!=0) {
 		LOG(L_ERR, "ERROR: no compile flags info in module <%s>: %s\n",
 			path, error );
 		return 0;
 	}
2dcb8b67
 	if (!m_ver || !(*m_ver)) {
bae7e884
 		LOG(L_ERR, "ERROR: no version in module <%s>\n", path );
2dcb8b67
 		return 0;
 	}
dd0e65a8
 	if (!m_flags || !(*m_flags)) {
 		LOG(L_ERR, "ERROR: no compile flags in module <%s>\n", path );
 		return 0;
 	}
fb851d7e
 
dd0e65a8
 	if (strcmp(SER_FULL_VERSION, *m_ver)==0){
 		if (strcmp(SER_COMPILE_FLAGS, *m_flags)==0)
 			return 1;
 		else {
 			LOG(L_ERR, "ERROR: module compile flags mismatch for %s "
 						" \ncore: %s \nmodule: %s\n",
 						path, SER_COMPILE_FLAGS, *m_flags);
 			return 0;
 		}
 	}
627b66ef
 	LOG(L_ERR, "ERROR: module version mismatch for %s; "
dd0e65a8
 		"core: %s; module: %s\n", path, SER_FULL_VERSION, *m_ver );
2dcb8b67
 	return 0;
 }
3bf76e49
 
 /* returns 0 on success , <0 on error */
 int load_module(char* path)
 {
 	void* handle;
 	char* error;
31309a3a
 	struct module_exports* exp;
404073d3
 	struct sr_module* t;
fb851d7e
 
087d0976
 #ifndef RTLD_NOW
e61f4ba3
 /* for openbsd */
087d0976
 #define RTLD_NOW DL_LAZY
 #endif
9148ad98
 	handle=dlopen(path, RTLD_NOW); /* resolve all symbols now */
3bf76e49
 	if (handle==0){
 		LOG(L_ERR, "ERROR: load_module: could not open module <%s>: %s\n",
 					path, dlerror() );
 		goto error;
 	}
fb851d7e
 
3bf76e49
 	for(t=modules;t; t=t->next){
 		if (t->handle==handle){
 			LOG(L_WARN, "WARNING: load_module: attempting to load the same"
 						" module twice (%s)\n", path);
 			goto skip;
 		}
 	}
2dcb8b67
 	/* version control */
bae7e884
 	if (!version_control(handle, path)) {
 		exit(0);
 	}
3bf76e49
 	/* launch register */
e61f4ba3
 	exp = (struct module_exports*)dlsym(handle, DLSYM_PREFIX "exports");
381659ac
 	if ( (error =(char*)dlerror())!=0 ){
3bf76e49
 		LOG(L_ERR, "ERROR: load_module: %s\n", error);
 		goto error1;
 	}
31309a3a
 	if (register_module(exp, path, handle)<0) goto error1;
3bf76e49
 	return 0;
 
 error1:
 	dlclose(handle);
 error:
 skip:
 	return -1;
 }
 
 
 
f141bc93
 
 /* searches the module list and returns pointer to the "name" function record or
fb851d7e
  * 0 if not found
49b28ea4
  * flags parameter is OR value of all flags that must match
51c38611
  */
f141bc93
 cmd_export_t* find_export_record(char* name, int param_no, int flags)
3bf76e49
 {
 	struct sr_module* t;
6419a43f
 	cmd_export_t* cmd;
3bf76e49
 
 	for(t=modules;t;t=t->next){
6419a43f
 		for(cmd=t->exports->cmds; cmd && cmd->name; cmd++){
 			if((strcmp(name, cmd->name)==0)&&
51c38611
 			   (cmd->param_no==param_no) &&
 			   ((cmd->flags & flags) == flags)
 			  ){
f141bc93
 				DBG("find_export_record: found <%s> in module %s [%s]\n",
51c38611
 				    name, t->exports->name, t->path);
f141bc93
 				return cmd;
3bf76e49
 			}
 		}
 	}
f141bc93
 	DBG("find_export_record: <%s> not found \n", name);
3bf76e49
 	return 0;
 }
 
34fd2612
 
f141bc93
 cmd_function find_export(char* name, int param_no, int flags)
 {
 	cmd_export_t* cmd;
 	cmd = find_export_record(name, param_no, flags);
 	return cmd?cmd->function:0;
 }
 
 
300b0f50
 rpc_export_t* find_rpc_export(char* name, int flags)
 {
 	struct sr_module* t;
 	rpc_export_t* rpc;
 
 	     /* Scan the list of core methods first, they are always
 	      * present
 	      */
 	for(rpc = core_rpc_methods; rpc && rpc->name; rpc++) {
 		if ((strcmp(name, rpc->name) == 0) &&
 		    ((rpc->flags & flags) == flags)
 		    ) {
 			return rpc;
 		}
 	}
 	     /* Continue with modules if not found */
 	for(t = modules; t; t = t->next) {
 		for(rpc = t->exports->rpc_methods; rpc && rpc->name; rpc++) {
 			if ((strcmp(name, rpc->name) == 0) &&
 			    ((rpc->flags & flags) == flags)
 			   ) {
 				return rpc;
 			}
 		}
 	}
 	return 0;
 }
 
49b28ea4
 
 /*
  * searches the module list and returns pointer to "name" function in module "mod"
  * 0 if not found
  * flags parameter is OR value of all flags that must match
  */
 cmd_function find_mod_export(char* mod, char* name, int param_no, int flags)
 {
 	struct sr_module* t;
 	cmd_export_t* cmd;
 
 	for (t = modules; t; t = t->next) {
 		if (strcmp(t->exports->name, mod) == 0) {
 			for (cmd = t->exports->cmds;  cmd && cmd->name; cmd++) {
 				if ((strcmp(name, cmd->name) == 0) &&
 				    (cmd->param_no == param_no) &&
 				    ((cmd->flags & flags) == flags)
 				   ){
 					DBG("find_mod_export: found <%s> in module %s [%s]\n",
 					    name, t->exports->name, t->path);
 					return cmd->function;
 				}
 			}
 		}
 	}
 
fb851d7e
 	DBG("find_mod_export: <%s> in module <%s> not found\n", name, mod);
49b28ea4
 	return 0;
 }
 
 
fb851d7e
 struct sr_module* find_module_by_name(char* mod) {
 	struct sr_module* t;
 
 	for(t = modules; t; t = t->next) {
 		if (strcmp(mod, t->exports->name) == 0) {
 			return t;
 		}
 	}
 	DBG("find_module_by_name: module <%s> not found\n", mod);
 	return 0;
 }
49b28ea4
 
 
fb851d7e
 void* find_param_export(struct sr_module* mod, char* name, modparam_t type_mask, modparam_t *param_type)
31309a3a
 {
6419a43f
 	param_export_t* param;
31309a3a
 
fb851d7e
 	if (!mod)
 		return 0;
 	for(param=mod->exports->params;param && param->name ; param++) {
 		if ((strcmp(name, param->name) == 0) &&
 			((param->type & PARAM_TYPE_MASK(type_mask)) != 0)) {
 			DBG("find_param_export: found <%s> in module %s [%s]\n",
 				name, mod->exports->name, mod->path);
 			*param_type = param->type;
 			return param->param_pointer;
31309a3a
 		}
 	}
fb851d7e
 	DBG("find_param_export: parameter <%s> not found in module <%s>\n",
 			name, mod->exports->name);
31309a3a
 	return 0;
 }
 
 
bf08223a
 void destroy_modules()
 {
3c8bd369
 	struct sr_module* t, *foo;
 
 	t=modules;
 	while(t) {
 		foo=t->next;
 		if ((t->exports)&&(t->exports->destroy_f)) t->exports->destroy_f();
 		pkg_free(t);
 		t=foo;
 	}
8aeb47e2
 	modules=0;
bf08223a
 }
31309a3a
 
9243edb9
 #ifdef NO_REVERSE_INIT
31309a3a
 
 /*
  * Initialize all loaded modules, the initialization
  * is done *AFTER* the configuration file is parsed
  */
 int init_modules(void)
 {
 	struct sr_module* t;
fb851d7e
 
31309a3a
 	for(t = modules; t; t = t->next) {
 		if ((t->exports) && (t->exports->init_f))
 			if (t->exports->init_f() != 0) {
e3fc93f4
 				LOG(L_ERR, "init_modules(): Error while initializing"
 							" module %s\n", t->exports->name);
31309a3a
 				return -1;
 			}
 	}
 	return 0;
 }
9243edb9
 
 /*
  * per-child initialization
  */
 int init_child(int rank)
 {
 	struct sr_module* t;
cb87691a
 	char* type;
 
 	switch(rank) {
 	case PROC_MAIN:     type = "PROC_MAIN";     break;
 	case PROC_TIMER:    type = "PROC_TIMER";    break;
 	case PROC_FIFO:     type = "PROC_FIFO";     break;
 	case PROC_TCP_MAIN: type = "PROC_TCP_MAIN"; break;
 	default:            type = "CHILD";         break;
 	}
 	DBG("init_child: initializing %s with rank %d\n", type, rank);
fb851d7e
 
9243edb9
 
 	for(t = modules; t; t = t->next) {
 		if (t->exports->init_child_f) {
 			if ((t->exports->init_child_f(rank)) < 0) {
 				LOG(L_ERR, "init_child(): Initialization of child %d failed\n",
 						rank);
 				return -1;
 			}
 		}
 	}
 	return 0;
 }
 
 #else
 
 
 /* recursive module child initialization; (recursion is used to
    process the module linear list in the same order in
    which modules are loaded in config file
 */
 
 static int init_mod_child( struct sr_module* m, int rank )
 {
 	if (m) {
 		/* iterate through the list; if error occurs,
 		   propagate it up the stack
 		 */
 		if (init_mod_child(m->next, rank)!=0) return -1;
 		if (m->exports && m->exports->init_child_f) {
fb851d7e
 			DBG("DEBUG: init_mod_child (%d): %s\n",
9243edb9
 					rank, m->exports->name);
 			if (m->exports->init_child_f(rank)<0) {
 				LOG(L_ERR, "init_mod_child(): Error while initializing"
 							" module %s\n", m->exports->name);
 				return -1;
 			} else {
 				/* module correctly initialized */
 				return 0;
 			}
 		}
 		/* no init function -- proceed with success */
 		return 0;
 	} else {
 		/* end of list */
 		return 0;
 	}
 }
 
 
 /*
  * per-child initialization
  */
 int init_child(int rank)
 {
 	return init_mod_child(modules, rank);
 }
 
 
 
 /* recursive module initialization; (recursion is used to
    process the module linear list in the same order in
    which modules are loaded in config file
 */
 
 static int init_mod( struct sr_module* m )
 {
 	if (m) {
 		/* iterate through the list; if error occurs,
 		   propagate it up the stack
 		 */
 		if (init_mod(m->next)!=0) return -1;
 		if (m->exports && m->exports->init_f) {
 			DBG("DEBUG: init_mod: %s\n", m->exports->name);
 			if (m->exports->init_f()!=0) {
 				LOG(L_ERR, "init_mod(): Error while initializing"
 							" module %s\n", m->exports->name);
 				return -1;
 			} else {
 				/* module correctly initialized */
 				return 0;
 			}
 		}
 		/* no init function -- proceed with success */
 		return 0;
 	} else {
 		/* end of list */
 		return 0;
 	}
 }
 
 /*
  * Initialize all loaded modules, the initialization
  * is done *AFTER* the configuration file is parsed
  */
 int init_modules(void)
 {
 	return init_mod(modules);
 }
 
 #endif
bb6575cd
 
 
f141bc93
 action_u_t *fixup_get_param(void **cur_param, int cur_param_no, int required_param_no) {
 	action_u_t *a, a2;
         /* cur_param points to a->u.string, get pointer to a */
 	a = (void*) ((char *)cur_param - ((char *)&a2.u.string-(char *)&a2));
 	return a + required_param_no - cur_param_no;
 }
 
 int fixup_get_param_count(void **cur_param, int cur_param_no) {
 	action_u_t *a;
 	a = fixup_get_param(cur_param, cur_param_no, 0);
 	if (a)
 		return a->u.number;
 	else
 		return -1;
 }
6d35d70e
 
 
 /* fixes flag params (resolves possible named flags)
  * use PARAM_USE_FUNC|PARAM_STRING as a param. type and create
  * a wrapper function that does just:
  * return fix_flag(type, val, "my_module", "my_param", &flag_var)
  * see also param_func_t.
  */
 int fix_flag( modparam_t type, void* val,
 					char* mod_name, char* param_name, int* flag)
 {
 	int num;
 	int err;
 	int f, len;
 	char* s;
 	char *p;
 	
 	if ((type & PARAM_STRING)==0){
 		LOG(L_CRIT, "BUG: %s: fix_flag(%s): bad parameter type\n",
 					mod_name, param_name);
 		return -1;
 	}
 	s=(char*)val;
 	len=strlen(s);
 	f=-1;
 	/* try to see if it's a number */
 	num = str2s(s, len, &err);
 	if (err != 0) {
 		/* see if it's in the name:<no> format */
 		p=strchr(s, ':');
 		if (p){
 			f= str2s(p+1, strlen(p+1), &err);
 			if (err!=0){
 				LOG(L_ERR, "ERROR: %s: invalid %s format:"
 						" \"%s\"", mod_name, param_name, s);
 				return -1;
 			}
 			*p=0;
 		}
 		if ((num=get_flag_no(s, len))<0){
 			/* not declared yet, declare it */
 			num=register_flag(s, f);
 		}
 		if (num<0){
 			LOG(L_ERR, "ERROR: %s: bad %s %s\n", mod_name, param_name, s);
 			return -1;
 		} else if ((f>0) && (num!=f)){
 			LOG(L_ERR, "WARNING: %s: flag %s already defined"
 					" as %d (and not %d), using %s:%d\n",
 					mod_name, s, num, f, s, num);
 		}
 	}
 	*flag=num;
 	return 0;
 }
b91364c6
 
d0ce0ebd
 /*
  * Common function parameter fixups
  */
b91364c6
 
 /*
  * Generic parameter fixup function which creates
  * fparam_t structure. type parameter contains allowed
  * parameter types
  */
 int fix_param(int type, void** param)
 {	
d0ce0ebd
     fparam_t* p;
     str name, s;
     unsigned long num;
     int err;
     
     p = (fparam_t*)pkg_malloc(sizeof(fparam_t));
     if (!p) {
 	ERR("No memory left\n");
 	return E_OUT_OF_MEM;
     }
     memset(p, 0, sizeof(fparam_t));
     p->orig = *param;
     
     switch(type) {
     case FPARAM_UNSPEC:
 	ERR("Invalid type value\n");
 	goto error;
 	
     case FPARAM_STRING:
 	p->v.asciiz = *param;
 	break;
 	
     case FPARAM_STR:
 	p->v.str.s = (char*)*param;
 	p->v.str.len = strlen(p->v.str.s);
 	break;
 	
     case FPARAM_INT:
 	num = str2s(*param, strlen(*param), &err);
 	if (err == 0) {
 	    p->v.i = num;
 	} else {
 		 /* Not a number */
 	    pkg_free(p);
 	    return 1;
 	}
 	break;
 	
     case FPARAM_REGEX:
 	if ((p->v.regex = pkg_malloc(sizeof(regex_t))) == 0) {
 	    ERR("No memory left\n");
 	    goto error;
 	}
 	if (regcomp(p->v.regex, *param, REG_EXTENDED|REG_ICASE|REG_NEWLINE)) {
 	    pkg_free(p->v.regex);
 	    ERR("Bad regular expression '%s'\n", (char*)*param);
 	    goto error;
 	}
 	break;
 	
     case FPARAM_AVP:
 	name.s = (char*)*param;
 	name.len = strlen(name.s);
 	trim(&name);
 	if (!name.len || name.s[0] != '$') {
 		 /* Not an AVP identifier */
 	    pkg_free(p);
 	    return 1;
 	}
 	name.s++;
 	name.len--;
 	
 	if (parse_avp_ident(&name, &p->v.avp) < 0) {
 	    ERR("Error while parsing attribute name\n");
 	    goto error;
 	}
 	break;
 	
     case FPARAM_SELECT:
 	name.s = (char*)*param;
 	name.len = strlen(name.s);
 	trim(&name);
 	if (!name.len || name.s[0] != '@') {
 		 /* Not a select identifier */
 	    pkg_free(p);
 	    return 1;
 	}
 	
 	if (parse_select(&name.s, &p->v.select) < 0) {
 	    ERR("Error while parsing select identifier\n");
 	    goto error;
 	}
 	break;
b91364c6
 
d0ce0ebd
     case FPARAM_SUBST:
 	s.s = *param;
 	s.len = strlen(s.s);
 	p->v.subst = subst_parser(&s);
 	if (!p->v.subst) {
 	    ERR("Error while parsing regex substitution\n");
 	    return -1;
b91364c6
 	}
d0ce0ebd
 	break;
     }
     
     p->type = type;
     *param = (void*)p;
     return 0;
     
  error:
     pkg_free(p);
     return E_UNSPEC;
 }
b91364c6
 
 
d0ce0ebd
 /*
  * Fixup variable string, the parameter can be
  * AVP, SELECT, or ordinary string. AVP and select
  * identifiers will be resolved to their values during
  * runtime
  *
  * The parameter value will be converted to fparam structure
  * This function returns -1 on an error
  */
 int fixup_var_str_12(void** param, int param_no)
 {
     int ret;
     if ((ret = fix_param(FPARAM_AVP, param)) <= 0) return ret;
     if ((ret = fix_param(FPARAM_SELECT, param)) <= 0) return ret;
     if ((ret = fix_param(FPARAM_STR, param)) <= 0) return ret;
     ERR("Error while fixing parameter, AVP, SELECT, and str conversions failed\n");
     return -1;
 }
b91364c6
 
d0ce0ebd
 /* Same as fixup_var_str_12 but applies to the 1st parameter only */
 int fixup_var_str_1(void** param, int param_no)
 {
     if (param_no == 1) return fixup_var_str_12(param, param_no);
     else return 0;
 }
c16e9887
 
d0ce0ebd
 /* Same as fixup_var_str_12 but applies to the 2nd parameter only */
 int fixup_var_str_2(void** param, int param_no)
 {
     if (param_no == 2) return fixup_var_str_12(param, param_no);
     else return 0;
 }
b91364c6
 
 
d0ce0ebd
 /*
  * Fixup variable integer, the parameter can be
  * AVP, SELECT, or ordinary integer. AVP and select
  * identifiers will be resolved to their values and 
  * converted to int if necessary during runtime
  *
  * The parameter value will be converted to fparam structure
  * This function returns -1 on an error
  */
 int fixup_var_int_12(void** param, int param_no)
 {
     int ret;
     if ((ret = fix_param(FPARAM_AVP, param)) <= 0) return ret;
     if ((ret = fix_param(FPARAM_SELECT, param)) <= 0) return ret;
     if ((ret = fix_param(FPARAM_INT, param)) <= 0) return ret;
     ERR("Error while fixing parameter, AVP, SELECT, and int conversions failed\n");
     return -1;
 }
 
 /* Same as fixup_var_int_12 but applies to the 1st parameter only */
 int fixup_var_int_1(void** param, int param_no)
 {
     if (param_no == 1) return fixup_var_int_12(param, param_no);
     else return 0;
 }
 
 /* Same as fixup_var_int_12 but applies to the 2nd parameter only */
 int fixup_var_int_2(void** param, int param_no)
 {
     if (param_no == 2) return fixup_var_int_12(param, param_no);
     else return 0;
 }
 
 
 /*
  * The parameter must be a regular expression which must compile, the
  * parameter will be converted to compiled regex
  */
 int fixup_regex_12(void** param, int param_no)
 {
     int ret;
 
     if ((ret = fix_param(FPARAM_REGEX, param)) <= 0) return ret;
     ERR("Error while compiling regex in function parameter\n");
     return -1;
 }
 
 /* Same as fixup_regex_12 but applies to the 1st parameter only */
 int fixup_regex_1(void** param, int param_no)
 {
     if (param_no == 1) return fixup_regex_12(param, param_no);
     else return 0;
 }
 
 /* Same as fixup_regex_12 but applies to the 2nd parameter only */
 int fixup_regex_2(void** param, int param_no)
 {
     if (param_no == 2) return fixup_regex_12(param, param_no);
     else return 0;
 }
 
 /*
  * The string parameter will be converted to integer
  */
 int fixup_int_12(void** param, int param_no)
 {
     int ret;
 
     if ((ret = fix_param(FPARAM_INT, param)) <= 0) return ret;
     ERR("Cannot function parameter to integer\n");
     return -1;
 
 }
 
 /* Same as fixup_int_12 but applies to the 1st parameter only */
 int fixup_int_1(void** param, int param_no)
 {
     if (param_no == 1) return fixup_int_12(param, param_no);
     else return 0;
 }
 
 /* Same as fixup_int_12 but applies to the 2nd parameter only */
 int fixup_int_2(void** param, int param_no)
 {
     if (param_no == 2) return fixup_int_12(param, param_no);
     else return 0;
 }
 
 /*
  * Parse the parameter as static string, do not resolve
  * AVPs or selects, convert the parameter to str structure
  */
 int fixup_str_12(void** param, int param_no)
 {
     int ret;
 
     if ((ret = fix_param(FPARAM_STR, param)) <= 0) return ret;
c70b2eb5
     ERR("Cannot function parameter to string\n");
d0ce0ebd
     return -1;
 }
 
 /* Same as fixup_str_12 but applies to the 1st parameter only */
 int fixup_str_1(void** param, int param_no)
 {
     if (param_no == 1) return fixup_str_12(param, param_no);
     else return 0;
 }
 
 /* Same as fixup_str_12 but applies to the 2nd parameter only */
 int fixup_str_2(void** param, int param_no)
 {
     if (param_no == 2) return fixup_str_12(param, param_no);
     else return 0;
b91364c6
 }
c16e9887
 
 
 /*
  * Get the function parameter value as string
  * Return values:  0 - Success
  *                -1 - Cannot get value
  */
 int get_str_fparam(str* dst, struct sip_msg* msg, fparam_t* param)
 {
     int_str val;
     int ret;
     avp_t* avp;
 
     switch(param->type) {
     case FPARAM_REGEX:
     case FPARAM_UNSPEC:
d0ce0ebd
     case FPARAM_INT:
 	return -1;
c16e9887
 
     case FPARAM_STRING:
 	dst->s = param->v.asciiz;
 	dst->len = strlen(param->v.asciiz);
 	break;
 
     case FPARAM_STR:
 	*dst = param->v.str;
 	break;
 
     case FPARAM_AVP:
 	avp = search_first_avp(param->v.avp.flags, param->v.avp.name, &val, 0);
d0ce0ebd
 	if (!avp) {
 	    DBG("Could not find AVP from function parameter '%s'\n", param->orig);
 	    return -1;
 	}
 	if (avp->flags & AVP_VAL_STR) {
c16e9887
 	    *dst = val.s;
 	} else {
d0ce0ebd
 		 /* The caller does not know of what type the AVP will be so
 		  * convert int AVPs into string here
 		  */
 	    dst->s = int2str(val.n, &dst->len);
c16e9887
 	}
 	break;
 
     case FPARAM_SELECT:
 	ret = run_select(dst, param->v.select, msg);
 	if (ret < 0 || ret > 0) return -1;
 	break;
     }
 
     return 0;
 }
 
d0ce0ebd
 
 /*
  * Get the function parameter value as integer
  * Return values:  0 - Success
  *                -1 - Cannot get value
  */
 int get_int_fparam(int* dst, struct sip_msg* msg, fparam_t* param)
 {
     int_str val;
     int ret;
     avp_t* avp;
     str tmp;
 
     switch(param->type) {
     case FPARAM_INT:
 	*dst = param->v.i;
 	return 0;
 	
     case FPARAM_REGEX:
     case FPARAM_UNSPEC:
     case FPARAM_STRING:
     case FPARAM_STR:
 	return -1;
 	
     case FPARAM_AVP:
 	avp = search_first_avp(param->v.avp.flags, param->v.avp.name, &val, 0);
 	if (!avp) {
 	    DBG("Could not find AVP from function parameter '%s'\n", param->orig);
 	    return -1;
 	}
 	if (avp->flags & AVP_VAL_STR) {
 	    if (str2int(&val.s, (unsigned int*)dst) < 0) {
 		ERR("Could not convert AVP string value to int\n");
 		return -1;
 	    }
 	} else {
 	    *dst = val.n;
 	}
 	break;
 
     case FPARAM_SELECT:
 	ret = run_select(&tmp, param->v.select, msg);
 	if (ret < 0 || ret > 0) return -1;
 	if (str2int(&tmp, (unsigned int*)dst) < 0) {
 	    ERR("Could not convert select result to int\n");
 	    return -1;
 	}
 	break;
     }
 
     return 0;
 }