3c5a8364 |
/* |
53c7e0f1 |
* Copyright (C) 2001-2003 FhG Fokus |
7dd0b342 |
* |
6a0f4382 |
* This file is part of Kamailio, a free SIP server. |
7dd0b342 |
* |
6a0f4382 |
* Kamailio is free software; you can redistribute it and/or modify |
7dd0b342 |
* 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
* |
6a0f4382 |
* Kamailio is distributed in the hope that it will be useful, |
7dd0b342 |
* 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 |
9e1ff448 |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
3bf76e49 |
*/ |
a7524985 |
/**
* @file |
6a0f4382 |
* @brief Kamailio core :: modules loading, structures declarations and utilities |
a5b499a4 |
* @ingroup core |
a7524985 |
* Module: \ref core |
1d0661db |
*/ |
7dd0b342 |
|
a7524985 |
|
3bf76e49 |
#include "sr_module.h" |
0b52bcff |
#include "mod_fix.h" |
3bf76e49 |
#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" |
2f292107 |
#include "pvapi.h" |
f4194f69 |
#include "globals.h" |
5099fd64 |
#include "rpc_lookup.h" |
b25e31aa |
#include "sr_compat.h" |
14525efb |
#include "ppcfg.h" |
d5a22ca8 |
#include "async_task.h" |
3bf76e49 |
|
f4194f69 |
#include <sys/stat.h> |
f6712967 |
#include <regex.h> |
3bf76e49 |
#include <dlfcn.h>
#include <strings.h>
#include <stdlib.h> |
e22bbdb8 |
#include <string.h> |
b2383262 |
#include <stddef.h> /* for offsetof */ |
3bf76e49 |
|
031e278e |
struct sr_module* modules=0; |
3bf76e49 |
|
577585de |
/*We need to define this symbol on Solaris becuase libcurl relies on libnspr which looks for this symbol.
If it is not defined, dynamic module loading (dlsym) fails */
#ifdef __OS_solaris
int nspr_use_zone_allocator = 0;
#endif
|
30449150 |
#ifdef STATIC_EXEC |
2873d384 |
extern struct module_exports exec_exports; |
30449150 |
#endif |
404073d3 |
#ifdef STATIC_TM |
2873d384 |
extern struct module_exports tm_exports; |
404073d3 |
#endif |
57c9e572 |
|
6eb22d94 |
#ifdef STATIC_MAXFWD |
2873d384 |
extern struct module_exports maxfwd_exports; |
6eb22d94 |
#endif |
57c9e572 |
|
192ac55b |
#ifdef STATIC_AUTH |
2873d384 |
extern struct module_exports auth_exports; |
192ac55b |
#endif |
57c9e572 |
|
192ac55b |
#ifdef STATIC_RR |
2873d384 |
extern struct module_exports rr_exports; |
192ac55b |
#endif |
57c9e572 |
|
192ac55b |
#ifdef STATIC_USRLOC |
2873d384 |
extern struct module_exports usrloc_exports; |
192ac55b |
#endif |
404073d3 |
|
a50f3f89 |
#ifdef STATIC_SL |
2873d384 |
extern struct module_exports sl_exports; |
a50f3f89 |
#endif
|
b4c42f7b |
#ifndef offsetof
#warning "use null pointer dereference for offsetof"
#define offsetof(st, m) \
((size_t) ( (char *)&((st *)(0))->m - (char *)0 ))
#endif |
404073d3 |
|
55faef7d |
int mod_response_cbk_no=0;
response_function* mod_response_cbks=0;
|
52d33940 |
/* number of usec to wait before initializing a module */
static unsigned int modinit_delay = 0;
unsigned int set_modinit_delay(unsigned int v)
{
unsigned int r;
r = modinit_delay;
modinit_delay = v;
return r;
}
|
37db0ca7 |
/** |
df1958c0 |
* if bit 1 set, SIP worker processes handle RPC commands as well
* if bit 2 set, RPC worker processes handle SIP commands as well |
37db0ca7 |
*/
static int child_sip_rpc_mode = 0;
|
df1958c0 |
#define CHILD_SIP_RPC 1<<0
#define CHILD_RPC_SIP 1<<1
void set_child_sip_rpc_mode(void) |
37db0ca7 |
{ |
df1958c0 |
child_sip_rpc_mode |= CHILD_SIP_RPC; |
37db0ca7 |
}
|
df1958c0 |
void set_child_rpc_sip_mode(void) |
37db0ca7 |
{ |
df1958c0 |
child_sip_rpc_mode |= CHILD_RPC_SIP; |
37db0ca7 |
}
int is_rpc_worker(int rank)
{ |
df1958c0 |
if(rank==PROC_RPC
|| (rank>PROC_MAIN && (child_sip_rpc_mode&CHILD_SIP_RPC)!=0))
return 1;
return 0;
}
int is_sip_worker(int rank)
{
if(rank>PROC_MAIN
|| ((rank==PROC_RPC || rank==PROC_NOCHLDINIT)
&& (child_sip_rpc_mode&CHILD_RPC_SIP)!=0)) |
37db0ca7 |
return 1;
return 0;
}
|
404073d3 |
/* initializes statically built (compiled in) modules*/ |
31309a3a |
int register_builtin_modules() |
404073d3 |
{ |
e22bbdb8 |
int ret;
ret=0; |
57c9e572 |
#ifdef STATIC_TM |
2873d384 |
ret=register_module(MODULE_INTERFACE_VER, &tm_exports,"built-in", 0); |
57c9e572 |
if (ret<0) return ret;
#endif |
192ac55b |
|
e8df4b11 |
#ifdef STATIC_EXEC |
2873d384 |
ret=register_module(MODULE_INTERFACE_VER, &exec_exports,"built-in", 0); |
30449150 |
if (ret<0) return ret;
#endif
|
57c9e572 |
#ifdef STATIC_MAXFWD |
2873d384 |
ret=register_module(MODULE_INTERFACE_VER, &maxfwd_exports, "built-in", 0); |
57c9e572 |
if (ret<0) return ret; |
192ac55b |
#endif
|
57c9e572 |
#ifdef STATIC_AUTH |
2873d384 |
ret=register_module(MODULE_INTERFACE_VER, &auth_exports, "built-in", 0); |
57c9e572 |
if (ret<0) return ret;
#endif |
fb851d7e |
|
192ac55b |
#ifdef STATIC_RR |
2873d384 |
ret=register_module(MODULE_INTERFACE_VER, &rr_exports, "built-in", 0); |
57c9e572 |
if (ret<0) return ret; |
192ac55b |
#endif |
fb851d7e |
|
192ac55b |
#ifdef STATIC_USRLOC |
2873d384 |
ret=register_module(MODULE_INTERFACE_VER, &usrloc_exports, "built-in", 0); |
57c9e572 |
if (ret<0) return ret; |
192ac55b |
#endif |
a50f3f89 |
#ifdef STATIC_SL |
2873d384 |
ret=register_module(MODULE_INTERFACE_VER, &sl_exports, "built-in", 0); |
a50f3f89 |
if (ret<0) return ret;
#endif |
fb851d7e |
|
e22bbdb8 |
return ret; |
404073d3 |
}
|
dee21fff |
/** convert cmd exports to current format.
* @param ver - module interface versions (0 == ser, 1 == kam).
* @param src - null terminated array of cmd exports
* (either ser_cmd_export_t or kam_cmd_export_t, depending
* on ver).
* @param mod - pointer to module exports structure.
* @return - pkg_malloc'ed null terminated sr_cmd_export_v31_t array with
* the converted cmd exports or 0 on error.
*/
static sr31_cmd_export_t* sr_cmd_exports_convert(unsigned ver,
void* src, void* mod)
{
int i, n;
ser_cmd_export_t* ser_cmd;
kam_cmd_export_t* kam_cmd;
sr31_cmd_export_t* ret;
ser_cmd = 0;
kam_cmd = 0;
ret = 0;
n = 0;
/* count the number of elements */
if (ver == 0) {
ser_cmd = src;
for (; ser_cmd[n].name; n++);
} else if (ver == 1) {
kam_cmd = src;
for (; kam_cmd[n].name; n++);
} else goto error; /* unknown interface version */
/* alloc & init new array */
ret = pkg_malloc(sizeof(*ret)*(n+1));
memset(ret, 0, sizeof(*ret)*(n+1));
/* convert/copy */
for (i=0; i < n; i++) {
if (ver == 0) {
ret[i].name = ser_cmd[i].name;
ret[i].function = ser_cmd[i].function;
ret[i].param_no = ser_cmd[i].param_no;
ret[i].fixup = ser_cmd[i].fixup;
ret[i].free_fixup = 0; /* no present in ser <= 2.1 */
ret[i].flags = ser_cmd[i].flags;
} else {
ret[i].name = kam_cmd[i].name;
ret[i].function = kam_cmd[i].function;
ret[i].param_no = kam_cmd[i].param_no;
ret[i].fixup = kam_cmd[i].fixup;
ret[i].free_fixup = kam_cmd[i].free_fixup;
ret[i].flags = kam_cmd[i].flags;
}
/* 3.1+ specific stuff */
ret[i].fixup_flags = 0;
ret[i].module_exports = mod; |
d709a720 |
/* fill known free fixups */
if (ret[i].fixup && ret[i].free_fixup == 0)
ret[i].free_fixup = get_fixup_free(ret[i].fixup); |
dee21fff |
}
return ret;
error:
return 0;
}
|
404073d3 |
/* registers a module, register_f= module register functions
* returns <0 on error, 0 on success */ |
2873d384 |
static int register_module(unsigned ver, union module_exports_u* e,
char* path, void* handle) |
404073d3 |
{ |
5099fd64 |
int ret, i; |
e22bbdb8 |
struct sr_module* mod; |
14525efb |
char defmod[64]; |
fb851d7e |
|
404073d3 |
ret=-1; |
31309a3a |
|
404073d3 |
/* add module to the list */ |
e3dccdc9 |
if ((mod=pkg_malloc(sizeof(struct sr_module)))==0){ |
153ab772 |
LM_ERR("memory allocation failure\n"); |
404073d3 |
ret=E_OUT_OF_MEM;
goto error;
}
memset(mod,0, sizeof(struct sr_module));
mod->path=path;
mod->handle=handle; |
dee21fff |
mod->orig_mod_interface_ver=ver;
/* convert exports to sr31 format */
if (ver == 0) {
/* ser <= 3.0 */
mod->exports.name = e->v0.name;
if (e->v0.cmds) {
mod->exports.cmds = sr_cmd_exports_convert(ver, e->v0.cmds, mod);
if (mod->exports.cmds == 0) { |
153ab772 |
LM_ERR("failed to convert module command exports to 3.1 format" |
dee21fff |
" for module \"%s\" (%s), interface version %d\n",
mod->exports.name, mod->path, ver);
ret = E_UNSPEC;
goto error;
}
}
mod->exports.params = e->v0.params;
mod->exports.init_f = e->v0.init_f;
mod->exports.response_f = e->v0.response_f;
mod->exports.destroy_f = e->v0.destroy_f;
mod->exports.onbreak_f = e->v0.onbreak_f;
mod->exports.init_child_f = e->v0.init_child_f;
mod->exports.dlflags = 0; /* not used in ser <= 3.0 */
mod->exports.rpc_methods = e->v0.rpc_methods;
/* the rest are 0, not used in ser */
} else if (ver == 1) {
/* kamailio <= 3.0 */
mod->exports.name = e->v1.name;
if (e->v1.cmds) {
mod->exports.cmds = sr_cmd_exports_convert(ver, e->v1.cmds, mod);
if (mod->exports.cmds == 0) { |
153ab772 |
LM_ERR("failed to convert module command exports to 3.1 format" |
dee21fff |
" for module \"%s\" (%s), interface version %d\n",
mod->exports.name, mod->path, ver);
ret = E_UNSPEC;
goto error;
}
}
mod->exports.params = e->v1.params;
mod->exports.init_f = e->v1.init_f;
mod->exports.response_f = e->v1.response_f;
mod->exports.destroy_f = e->v1.destroy_f;
mod->exports.onbreak_f = 0; /* not used in k <= 3.0 */
mod->exports.init_child_f = e->v1.init_child_f;
mod->exports.dlflags = e->v1.dlflags;
mod->exports.rpc_methods = 0; /* not used in k <= 3.0 */
mod->exports.stats = e->v1.stats;
mod->exports.mi_cmds = e->v1.mi_cmds;
mod->exports.items = e->v1.items;
mod->exports.procs = e->v1.procs;
} else { |
153ab772 |
LM_ERR("unsupported module interface version %d\n", ver); |
dee21fff |
ret = E_UNSPEC;
goto error;
} |
d79388b3 |
|
dee21fff |
if (mod->exports.items) { |
5099fd64 |
/* register module pseudo-variables for kamailio modules */ |
dee21fff |
LM_DBG("register PV from: %s\n", mod->exports.name);
if (register_pvars_mod(mod->exports.name, mod->exports.items)!=0) {
LM_ERR("failed to register pseudo-variables for module %s (%s)\n",
mod->exports.name, path);
ret = E_UNSPEC;
goto error; |
d79388b3 |
} |
dee21fff |
}
if (mod->exports.rpc_methods){ |
5099fd64 |
/* register rpcs for ser modules */ |
dee21fff |
i=rpc_register_array(mod->exports.rpc_methods); |
5099fd64 |
if (i<0){ |
153ab772 |
LM_ERR("failed to register RPCs for module %s (%s)\n", |
dee21fff |
mod->exports.name, path);
ret = E_UNSPEC; |
5099fd64 |
goto error;
}else if (i>0){ |
153ab772 |
LM_ERR("%d duplicate RPCs name detected while registering RPCs" |
dee21fff |
" declared in module %s (%s)\n",
i, mod->exports.name, path);
ret = E_UNSPEC; |
5099fd64 |
goto error;
}
/* i==0 => success */ |
d79388b3 |
}
|
14525efb |
/* add cfg define for each module: MOD_modulename */
if(strlen(mod->exports.name)>=60) {
LM_ERR("too long module name: %s\n", mod->exports.name);
goto error;
}
strcpy(defmod, "MOD_");
strcat(defmod, mod->exports.name);
pp_define_set_type(0);
if(pp_define(strlen(defmod), defmod)<0) {
LM_ERR("unable to set cfg define for module: %s\n",
mod->exports.name);
goto error;
}
|
dee21fff |
/* link module in the list */
mod->next=modules;
modules=mod; |
404073d3 |
return 0;
error: |
dee21fff |
if (mod)
pkg_free(mod); |
404073d3 |
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) { |
153ab772 |
LM_ERR("no version info in module <%s>: %s\n", path, error); |
2dcb8b67 |
return 0;
} |
dd0e65a8 |
m_flags=(char **)dlsym(handle, DLSYM_PREFIX "module_flags");
if ((error=(char *)dlerror())!=0) { |
153ab772 |
LM_ERR("no compile flags info in module <%s>: %s\n", path, error); |
dd0e65a8 |
return 0;
} |
2dcb8b67 |
if (!m_ver || !(*m_ver)) { |
153ab772 |
LM_ERR("no version in module <%s>\n", path ); |
2dcb8b67 |
return 0;
} |
dd0e65a8 |
if (!m_flags || !(*m_flags)) { |
153ab772 |
LM_ERR("no compile flags in module <%s>\n", path ); |
dd0e65a8 |
return 0;
} |
fb851d7e |
|
dd0e65a8 |
if (strcmp(SER_FULL_VERSION, *m_ver)==0){
if (strcmp(SER_COMPILE_FLAGS, *m_flags)==0)
return 1;
else { |
153ab772 |
LM_ERR("module compile flags mismatch for %s " |
dd0e65a8 |
" \ncore: %s \nmodule: %s\n",
path, SER_COMPILE_FLAGS, *m_flags);
return 0;
}
} |
153ab772 |
LM_ERR("module version mismatch for %s; " |
dd0e65a8 |
"core: %s; module: %s\n", path, SER_FULL_VERSION, *m_ver ); |
2dcb8b67 |
return 0;
} |
3bf76e49 |
|
3c5a8364 |
/**
* \brief load a sr module
* |
c9c181f8 |
* tries to load the module specified by mod_path.
* If mod_path is 'modname' or 'modname.so' then |
3c5a8364 |
* \<MODS_DIR\>/\<modname\>.so will be tried and if this fails
* \<MODS_DIR\>/\<modname\>/\<modname\>.so |
c9c181f8 |
* If mod_path contain a '/' it is assumed to be the
* path to the module and tried first. If fails and mod_path is not
* absolute path (not starting with '/') then will try: |
3c5a8364 |
* \<MODS_DIR\>/mod_path
* @param mod_path path or module name |
ea31876f |
* @return 0 on success , <0 on error
*/ |
fdbb341c |
int load_module(char* mod_path) |
3bf76e49 |
{
void* handle;
char* error; |
ea31876f |
mod_register_function mr; |
2873d384 |
union module_exports_u* exp;
unsigned* mod_if_ver; |
404073d3 |
struct sr_module* t; |
f4194f69 |
struct stat stat_buf; |
b27dfba5 |
str modname; |
fdbb341c |
char* mdir;
char* nxt_mdir;
char* path;
int mdir_len; |
f4194f69 |
int len; |
ea31876f |
int dlflags;
int new_dlflags;
int retries; |
b27dfba5 |
int path_type; |
fb851d7e |
|
087d0976 |
#ifndef RTLD_NOW |
e61f4ba3 |
/* for openbsd */ |
087d0976 |
#define RTLD_NOW DL_LAZY
#endif |
fdbb341c |
path=mod_path; |
b27dfba5 |
path_type = 0;
modname.s = path;
modname.len = strlen(mod_path);
if(modname.len>3 && strcmp(modname.s+modname.len-3, ".so")==0) {
path_type = 1;
modname.len -= 3;
}
if (!strchr(path, '/'))
path_type |= 2;
if((path_type&2) || path[0] != '/') { |
f4194f69 |
/* module name was given, we try to construct the path */ |
fdbb341c |
mdir=mods_dir; /* search path */
do{
nxt_mdir=strchr(mdir, ':');
if (nxt_mdir) mdir_len=(int)(nxt_mdir-mdir);
else mdir_len=strlen(mdir);
|
b27dfba5 |
if(path_type&2) {
/* try path <MODS_DIR>/<modname>.so */
path = (char*)pkg_malloc(mdir_len + 1 /* "/" */ +
modname.len + 3 /* ".so" */ + 1); |
fdbb341c |
if (path==0) goto error;
memcpy(path, mdir, mdir_len);
len = mdir_len; |
b27dfba5 |
if (len != 0 && path[len - 1] != '/'){ |
fdbb341c |
path[len]='/';
len++;
}
path[len]=0; |
b27dfba5 |
strcat(path, modname.s);
if(!(path_type&1))
strcat(path, ".so"); |
fdbb341c |
if (stat(path, &stat_buf) == -1) { |
c6a1ba6d |
LM_DBG("module file not found <%s>\n", path); |
fdbb341c |
pkg_free(path); |
b27dfba5 |
/* try path <MODS_DIR>/<modname>/<modname>.so */
path = (char*)pkg_malloc(
mdir_len + 1 /* "/" */ +
modname.len + 1 /* "/" */ +
modname.len + 3 /* ".so" */ + 1);
if (path==0) goto error;
memcpy(path, mdir, mdir_len);
len = mdir_len;
if (len != 0 && path[len - 1] != '/') {
path[len]='/';
len++;
}
path[len]=0;
strncat(path, modname.s, modname.len);
strcat(path, "/");
strcat(path, modname.s);
if(!(path_type&1))
strcat(path, ".so");
if (stat(path, &stat_buf) == -1) { |
c6a1ba6d |
LM_DBG("module file not found <%s>\n", path); |
b27dfba5 |
pkg_free(path);
path=0;
}
}
} else {
/* try mod_path - S compat */
if(path==mod_path) {
if (stat(path, &stat_buf) == -1) { |
c6a1ba6d |
LM_DBG("module file not found <%s>\n", path); |
b27dfba5 |
path=0;
}
}
if(path==0) {
/* try path <MODS_DIR>/mod_path - K compat */
path = (char*)pkg_malloc(mdir_len + 1 /* "/" */ +
strlen(mod_path) + 1);
if (path==0) goto error;
memcpy(path, mdir, mdir_len);
len = mdir_len;
if (len != 0 && path[len - 1] != '/'){
path[len]='/';
len++;
}
path[len]=0;
strcat(path, mod_path);
if (stat(path, &stat_buf) == -1) { |
c6a1ba6d |
LM_DBG("module file not found <%s>\n", path); |
b27dfba5 |
pkg_free(path);
path=0;
} |
fdbb341c |
} |
f4194f69 |
} |
fdbb341c |
mdir=nxt_mdir?nxt_mdir+1:0;
}while(path==0 && mdir);
if (path==0){ |
153ab772 |
LM_ERR("could not find module <%.*s> in <%s>\n",
modname.len, modname.s, mods_dir); |
fdbb341c |
goto error; |
f4194f69 |
}
} |
c6a1ba6d |
LM_DBG("trying to load <%s>\n", path); |
b27dfba5 |
|
ea31876f |
retries=2;
dlflags=RTLD_NOW;
reload: |
f4d2f91c |
handle=dlopen(path, dlflags); /* resolve all symbols now */ |
3bf76e49 |
if (handle==0){ |
153ab772 |
LM_ERR("could not open module <%s>: %s\n", path, dlerror()); |
3bf76e49 |
goto error;
} |
fb851d7e |
|
3bf76e49 |
for(t=modules;t; t=t->next){
if (t->handle==handle){ |
153ab772 |
LM_WARN("attempting to load the same module twice (%s)\n", path); |
3bf76e49 |
goto skip;
}
} |
2dcb8b67 |
/* version control */ |
bae7e884 |
if (!version_control(handle, path)) { |
c4f7356f |
exit(-1); |
bae7e884 |
} |
2873d384 |
mod_if_ver = (unsigned *)dlsym(handle,
DLSYM_PREFIX "module_interface_ver");
if ( (error =(char*)dlerror())!=0 ){ |
153ab772 |
LM_ERR("no module interface version in module <%s>\n", path ); |
2873d384 |
goto error1;
} |
3bf76e49 |
/* launch register */ |
ea31876f |
mr = (mod_register_function)dlsym(handle, DLSYM_PREFIX "mod_register");
if (((error =(char*)dlerror())==0) && mr) {
/* no error call it */
new_dlflags=dlflags; |
931bd29d |
if (mr(path, &new_dlflags, 0, 0)!=0) { |
153ab772 |
LM_ERR("%s: mod_register failed\n", path); |
ea31876f |
goto error1;
}
if (new_dlflags!=dlflags && new_dlflags!=0) {
/* we have to reload the module */
dlclose(handle);
dlflags=new_dlflags;
retries--;
if (retries>0) goto reload; |
153ab772 |
LM_ERR("%s: cannot agree on the dlflags\n", path); |
ea31876f |
goto error;
}
} |
2873d384 |
exp = (union module_exports_u*)dlsym(handle, DLSYM_PREFIX "exports"); |
381659ac |
if ( (error =(char*)dlerror())!=0 ){ |
153ab772 |
LM_ERR("%s\n", error); |
3bf76e49 |
goto error1;
} |
ea31876f |
/* hack to allow for kamailio style dlflags inside exports */
if (*mod_if_ver == 1) {
new_dlflags = exp->v1.dlflags;
if (new_dlflags!=dlflags && new_dlflags!=DEFAULT_DLFLAGS) {
/* we have to reload the module */
dlclose(handle); |
a7876417 |
DEBUG("%s: exports dlflags interface is deprecated and it will not" |
d70215e5 |
" be supported in newer versions; consider using" |
207f7c6f |
" mod_register() instead\n", path); |
ea31876f |
dlflags=new_dlflags;
retries--;
if (retries>0) goto reload; |
153ab772 |
LM_ERR("%s: cannot agree on the dlflags\n", path); |
ea31876f |
goto error;
}
} |
2873d384 |
if (register_module(*mod_if_ver, exp, path, handle)<0) goto error1; |
3bf76e49 |
return 0;
error1:
dlclose(handle);
error:
skip: |
fdbb341c |
if (path && path!=mod_path)
pkg_free(path); |
3bf76e49 |
return -1;
}
|
2873d384 |
/* searches the module list for function name in module mod and returns
* a pointer to the "name" function record union or 0 if not found |
dee21fff |
* sets also *mod_if_ver to the original module interface version. |
2873d384 |
* mod==0 is a wildcard matching all modules |
49b28ea4 |
* flags parameter is OR value of all flags that must match |
51c38611 |
*/ |
dee21fff |
sr31_cmd_export_t* find_mod_export_record(char* mod, char* name, |
2873d384 |
int param_no, int flags,
unsigned* mod_if_ver) |
3bf76e49 |
{
struct sr_module* t; |
dee21fff |
sr31_cmd_export_t* cmd; |
3bf76e49 |
for(t=modules;t;t=t->next){ |
dee21fff |
if (mod!=0 && (strcmp(t->exports.name, mod) !=0)) |
2873d384 |
continue; |
dee21fff |
if (t->exports.cmds)
for(cmd=&t->exports.cmds[0]; cmd->name; cmd++) {
if((strcmp(name, cmd->name) == 0) &&
((cmd->param_no == param_no) ||
(cmd->param_no==VAR_PARAM_NO)) &&
((cmd->flags & flags) == flags)
){ |
c6a1ba6d |
LM_DBG("find_export_record: found <%s> in module %s [%s]\n", |
dee21fff |
name, t->exports.name, t->path);
*mod_if_ver=t->orig_mod_interface_ver;
return cmd;
}
} |
3bf76e49 |
} |
c6a1ba6d |
LM_DBG("find_export_record: <%s> not found \n", name); |
3bf76e49 |
return 0;
}
|
34fd2612 |
|
2873d384 |
/* searches the module list for function name and returns
* a pointer to the "name" function record union or 0 if not found
* sets also *mod_if_ver to the module interface version (needed to know
* which member of the union should be accessed v0 or v1)
* mod==0 is a wildcard matching all modules
* flags parameter is OR value of all flags that must match
*/ |
dee21fff |
sr31_cmd_export_t* find_export_record(char* name, |
2873d384 |
int param_no, int flags,
unsigned* mod_if_ver)
{
return find_mod_export_record(0, name, param_no, flags, mod_if_ver);
}
|
f141bc93 |
cmd_function find_export(char* name, int param_no, int flags)
{ |
dee21fff |
sr31_cmd_export_t* cmd; |
2873d384 |
unsigned mver;
cmd = find_export_record(name, param_no, flags, &mver); |
dee21fff |
return cmd?cmd->function:0; |
f141bc93 |
}
|
300b0f50 |
rpc_export_t* find_rpc_export(char* name, int flags)
{ |
5099fd64 |
return rpc_lookup((char*)name, strlen(name)); |
300b0f50 |
}
|
49b28ea4 |
/* |
2873d384 |
* searches the module list and returns pointer to "name" function in module
* "mod" |
49b28ea4 |
* 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)
{ |
dee21fff |
sr31_cmd_export_t* cmd; |
2873d384 |
unsigned mver; |
49b28ea4 |
|
2873d384 |
cmd=find_mod_export_record(mod, name, param_no, flags, &mver);
if (cmd) |
dee21fff |
return cmd->function; |
2873d384 |
|
c6a1ba6d |
LM_DBG("<%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) { |
dee21fff |
if (strcmp(mod, t->exports.name) == 0) { |
fb851d7e |
return t;
}
} |
c6a1ba6d |
LM_DBG("module <%s> not found\n", mod); |
fb851d7e |
return 0;
} |
49b28ea4 |
|
a7524985 |
/*!
* \brief Find a parameter with given type
* \param mod module
* \param name parameter name
* \param type_mask parameter mask
* \param param_type parameter type
* \return parameter address in memory, if there is no such parameter, NULL is returned
*/ |
2873d384 |
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; |
dee21fff |
for(param = mod->exports.params ;param && param->name ; param++) { |
fb851d7e |
if ((strcmp(name, param->name) == 0) &&
((param->type & PARAM_TYPE_MASK(type_mask)) != 0)) { |
c6a1ba6d |
LM_DBG("found <%s> in module %s [%s]\n", |
dee21fff |
name, mod->exports.name, mod->path); |
fb851d7e |
*param_type = param->type;
return param->param_pointer; |
31309a3a |
}
} |
c6a1ba6d |
LM_DBG("parameter <%s> not found in module <%s>\n", |
dee21fff |
name, mod->exports.name); |
31309a3a |
return 0;
}
|
bf08223a |
void destroy_modules()
{ |
3c8bd369 |
struct sr_module* t, *foo;
|
2396dde7 |
/* call first destroy function from each module */ |
3c8bd369 |
t=modules;
while(t) {
foo=t->next; |
dee21fff |
if (t->exports.destroy_f){
t->exports.destroy_f(); |
2873d384 |
} |
2396dde7 |
t=foo;
}
/* free module exports structures */
t=modules;
while(t) {
foo=t->next; |
3c8bd369 |
pkg_free(t);
t=foo;
} |
8aeb47e2 |
modules=0; |
55faef7d |
if (mod_response_cbks){
pkg_free(mod_response_cbks);
mod_response_cbks=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 |
|
d5a22ca8 |
if(async_task_init()<0)
return -1;
|
31309a3a |
for(t = modules; t; t = t->next) { |
52d33940 |
if (t->exports.init_f) { |
dee21fff |
if (t->exports.init_f() != 0) { |
153ab772 |
LM_ERR("Error while initializing module %s\n", t->exports.name); |
dee21fff |
return -1; |
31309a3a |
} |
52d33940 |
/* delay next module init, if configured */
if(unlikely(modinit_delay>0))
sleep_us(modinit_delay);
} |
dee21fff |
if (t->exports.response_f)
mod_response_cbk_no++; |
55faef7d |
}
mod_response_cbks=pkg_malloc(mod_response_cbk_no *
sizeof(response_function));
if (mod_response_cbks==0){ |
153ab772 |
LM_ERR("memory allocation failure for %d response_f callbacks\n",
mod_response_cbk_no); |
55faef7d |
return -1;
} |
dee21fff |
for (t=modules, i=0; t && (i<mod_response_cbk_no); t=t->next) {
if (t->exports.response_f) {
mod_response_cbks[i]=t->exports.response_f;
i++; |
55faef7d |
} |
31309a3a |
}
return 0;
} |
9243edb9 |
|
dee21fff |
|
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;
} |
c6a1ba6d |
LM_DBG("initializing %s with rank %d\n", type, rank); |
fb851d7e |
|
d5a22ca8 |
if(async_task_child_init(rank)<0)
return -1; |
9243edb9 |
for(t = modules; t; t = t->next) { |
dee21fff |
if (t->exports.init_child_f) {
if ((t->exports.init_child_f(rank)) < 0) { |
153ab772 |
LM_ERR("Initialization of child %d failed\n", rank); |
9243edb9 |
return -1; |
dee21fff |
} |
9243edb9 |
}
}
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; |
dee21fff |
if (m->exports.init_child_f) { |
c6a1ba6d |
LM_DBG("rank %d: %s\n", rank, m->exports.name); |
dee21fff |
if (m->exports.init_child_f(rank)<0) { |
153ab772 |
LM_ERR("Error while initializing module %s (%s)\n", |
dee21fff |
m->exports.name, m->path);
return -1;
} else {
/* module correctly initialized */
return 0; |
9243edb9 |
}
} |
dee21fff |
/* no init function -- proceed with success */ |
9243edb9 |
return 0;
} else {
/* end of list */
return 0;
}
}
/*
* per-child initialization
*/
int init_child(int rank)
{ |
d5a22ca8 |
if(async_task_child_init(rank)<0)
return -1;
|
9243edb9 |
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; |
dee21fff |
if (m->exports.init_f) { |
c6a1ba6d |
LM_DBG("%s\n", m->exports.name); |
dee21fff |
if (m->exports.init_f()!=0) { |
153ab772 |
LM_ERR("Error while initializing module %s (%s)\n", |
dee21fff |
m->exports.name, m->path);
return -1;
} else {
/* module correctly initialized */ |
2873d384 |
return 0; |
dee21fff |
} |
9243edb9 |
} |
dee21fff |
/* no init function -- proceed with success */
return 0; |
9243edb9 |
} else {
/* end of list */
return 0;
}
}
/*
* Initialize all loaded modules, the initialization
* is done *AFTER* the configuration file is parsed
*/
int init_modules(void)
{ |
55faef7d |
struct sr_module* t;
int i;
|
d5a22ca8 |
if(async_task_init()<0)
return -1;
|
e958eaf6 |
i = init_mod(modules);
if(i!=0)
return i;
|
55faef7d |
for(t = modules; t; t = t->next) |
dee21fff |
if (t->exports.response_f)
mod_response_cbk_no++; |
55faef7d |
mod_response_cbks=pkg_malloc(mod_response_cbk_no *
sizeof(response_function));
if (mod_response_cbks==0){ |
153ab772 |
LM_ERR("memory allocation failure for %d response_f callbacks\n", mod_response_cbk_no); |
55faef7d |
return -1;
} |
dee21fff |
for (t=modules, i=0; t && (i<mod_response_cbk_no); t=t->next)
if (t->exports.response_f) {
mod_response_cbks[i]=t->exports.response_f;
i++; |
55faef7d |
}
|
e958eaf6 |
return 0; |
9243edb9 |
}
#endif |
bb6575cd |
|
f2f12966 |
action_u_t *fixup_get_param(void **cur_param, int cur_param_no,
int required_param_no)
{ |
b2383262 |
action_u_t *a; |
f4194f69 |
/* cur_param points to a->u.string, get pointer to a */ |
b2383262 |
a = (void*) ((char *)cur_param - offsetof(action_u_t, u.string)); |
f141bc93 |
return a + required_param_no - cur_param_no;
}
|
f2f12966 |
int fixup_get_param_count(void **cur_param, int cur_param_no)
{ |
f141bc93 |
action_u_t *a;
a = fixup_get_param(cur_param, cur_param_no, 0);
if (a)
return a->u.number;
else
return -1;
} |
6d35d70e |
|
35657139 |
/** get a pointer to a parameter internal type.
* @param param
* @return pointer to the parameter internal type.
*/
action_param_type* fixup_get_param_ptype(void** param)
{
action_u_t* a; |
b2383262 |
a = (void*)((char*)param - offsetof(action_u_t, u.string)); |
35657139 |
return &a->type;
}
/** get a parameter internal type.
* @see fixup_get_param_ptype().
* @return paramter internal type.
*/
action_param_type fixup_get_param_type(void** param)
{
return *fixup_get_param_ptype(param);
}
|
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; |
f4194f69 |
|
6d35d70e |
if ((type & PARAM_STRING)==0){ |
153ab772 |
LM_CRIT("%s: fix_flag(%s): bad parameter type\n", |
6d35d70e |
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){ |
153ab772 |
LM_ERR("%s: invalid %s format: \"%s\"",
mod_name, param_name, s); |
6d35d70e |
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){ |
153ab772 |
LM_ERR("%s: bad %s %s\n", mod_name, param_name, s); |
6d35d70e |
return -1;
} else if ((f>0) && (num!=f)){ |
153ab772 |
LM_ERR("%s: flag %s already defined" |
6d35d70e |
" 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 |
|
f2f12966 |
/** Generic parameter fixup function.
* Creates a fparam_t structure.
* @param type contains allowed parameter types
* @param param is the parameter that will be fixed-up |
cd892e69 |
* |
f2f12966 |
* @return |
cd892e69 |
* 0 on success,
* 1 if the param doesn't match the specified type
* <0 on failure |
b91364c6 |
*/
int fix_param(int type, void** param) |
f4194f69 |
{ |
f2f12966 |
fparam_t* p;
str name, s; |
67436c8f |
int num; |
f2f12966 |
int err; |
f4194f69 |
|
f2f12966 |
p = (fparam_t*)pkg_malloc(sizeof(fparam_t));
if (!p) { |
153ab772 |
LM_ERR("No memory left\n"); |
f2f12966 |
return E_OUT_OF_MEM; |
d0ce0ebd |
} |
f2f12966 |
memset(p, 0, sizeof(fparam_t));
p->orig = *param;
switch(type) {
case FPARAM_UNSPEC: |
153ab772 |
LM_ERR("Invalid type value\n"); |
f2f12966 |
goto error;
case FPARAM_STRING:
p->v.asciiz = *param; |
b25e31aa |
/* no break */ |
f2f12966 |
case FPARAM_STR:
p->v.str.s = (char*)*param;
p->v.str.len = strlen(p->v.str.s); |
235a9c07 |
p->fixed = &p->v; |
f2f12966 |
break;
case FPARAM_INT:
s.s = (char*)*param;
s.len = strlen(s.s); |
67436c8f |
err = str2sint(&s, &num); |
f2f12966 |
if (err == 0) {
p->v.i = (int)num;
} else {
/* Not a number */
pkg_free(p);
return 1;
} |
235a9c07 |
p->fixed = (void*)(long)num; |
f2f12966 |
break;
case FPARAM_REGEX:
if ((p->v.regex = pkg_malloc(sizeof(regex_t))) == 0) { |
153ab772 |
LM_ERR("No memory left\n"); |
235a9c07 |
goto error; |
f2f12966 |
}
if (regcomp(p->v.regex, *param,
REG_EXTENDED|REG_ICASE|REG_NEWLINE)) {
pkg_free(p->v.regex); |
ad4f08c9 |
p->v.regex=0; |
b25e31aa |
/* not a valid regex */
goto no_match; |
f2f12966 |
} |
15d47d5c |
p->fixed = p->v.regex; |
f2f12966 |
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 */ |
b25e31aa |
goto no_match; |
f2f12966 |
}
name.s++;
name.len--;
if (parse_avp_ident(&name, &p->v.avp) < 0) { |
b25e31aa |
/* invalid avp identifier (=> no match) */
goto no_match; |
f2f12966 |
} |
235a9c07 |
p->fixed = &p->v; |
f2f12966 |
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 */ |
b25e31aa |
goto no_match; |
f2f12966 |
}
if (parse_select(&name.s, &p->v.select) < 0) { |
153ab772 |
LM_ERR("Error while parsing select identifier\n"); |
f2f12966 |
goto error;
} |
235a9c07 |
p->fixed = &p->v; |
f2f12966 |
break;
case FPARAM_SUBST:
s.s = *param;
s.len = strlen(s.s);
p->v.subst = subst_parser(&s);
if (!p->v.subst) { |
153ab772 |
LM_ERR("Error while parsing regex substitution\n"); |
ad4f08c9 |
goto error;
} |
235a9c07 |
p->fixed = &p->v; |
ad4f08c9 |
break;
case FPARAM_PVS:
name.s = (char*)*param;
name.len = strlen(name.s);
trim(&name);
if (!name.len || name.s[0] != '$'){
/* not a pvs identifier */ |
b25e31aa |
goto no_match; |
ad4f08c9 |
}
p->v.pvs=pkg_malloc(sizeof(pv_spec_t));
if (p->v.pvs==0){ |
153ab772 |
LM_ERR("out of memory while parsing pv_spec_t\n"); |
ad4f08c9 |
goto error;
} |
b25e31aa |
if (pv_parse_spec2(&name, p->v.pvs, 1)==0){
/* not a valid pvs identifier (but it might be an avp) */ |
ad4f08c9 |
pkg_free(p->v.pvs);
p->v.pvs=0; |
b25e31aa |
goto no_match; |
ad4f08c9 |
} |
d64c1c71 |
p->fixed = p->v.pvs; |
ad4f08c9 |
break;
case FPARAM_PVE:
name.s = (char*)*param;
name.len = strlen(name.s);
if (pv_parse_format(&name, &p->v.pve)<0){ |
153ab772 |
LM_ERR("bad PVE format: \"%.*s\"\n", name.len, name.s); |
ad4f08c9 |
goto error; |
f2f12966 |
} |
235a9c07 |
p->fixed = &p->v; |
f2f12966 |
break; |
b91364c6 |
} |
f2f12966 |
p->type = type;
*param = (void*)p;
return 0;
|
b25e31aa |
no_match:
pkg_free(p);
return 1; |
f2f12966 |
error:
pkg_free(p);
return E_UNSPEC; |
d0ce0ebd |
} |
b91364c6 |
|
ad4f08c9 |
/** fparam_t free function.
* Frees the "content" of a fparam, but not the fparam itself. |
6a40b4bd |
* Note: it doesn't free fp->orig! |
ad4f08c9 |
* Assumes pkg_malloc'ed content.
* @param fp - fparam to be freed
*
*/
void fparam_free_contents(fparam_t* fp)
{
if (fp==0)
return;
switch(fp->type) {
case FPARAM_UNSPEC:
case FPARAM_STRING: /* asciiz string, not str */
case FPARAM_INT:
case FPARAM_STR:
/* nothing to do */ |
af8f3e15 |
break; |
ad4f08c9 |
case FPARAM_REGEX:
if (fp->v.regex){
regfree(fp->v.regex);
pkg_free(fp->v.regex);
fp->v.regex=0;
}
break;
case FPARAM_AVP:
free_avp_name(&fp->v.avp.flags, &fp->v.avp.name);
break;
case FPARAM_SELECT:
if (fp->v.select){
free_select(fp->v.select);
fp->v.select=0;
}
break;
case FPARAM_SUBST:
if (fp->v.subst){
subst_expr_free(fp->v.subst);
fp->v.subst=0;
}
break;
case FPARAM_PVS:
if (fp->v.pvs){
pv_spec_free(fp->v.pvs);
fp->v.pvs=0;
}
break;
case FPARAM_PVE:
if (fp->v.pve){
pv_elem_free_all(fp->v.pve);
fp->v.pve=0;
}
break;
} |
6a40b4bd |
}
|
a7524985 |
/**
* @brief Generic free fixup type function for a fixed fparam
*
* Generic free fixup type function for a fixed fparam. It will free whatever
* was allocated during the initial fparam fixup and restore the original param
* value.
* @param param freed parameters |
6a40b4bd |
*/
void fparam_free_restore(void** param)
{
fparam_t *fp;
void *orig;
fp = *param;
orig = fp->orig;
fp->orig = 0;
fparam_free_contents(fp);
pkg_free(fp);
*param = orig; |
ad4f08c9 |
}
|
bf9d1c43 |
/** fix a param to one of the given types (mask).
*
* @param types - bitmap of the allowed types (e.g. FPARAM_INT|FPARAM_STR)
* @param param - value/result
* @return - 0 on success, -1 on error, 1 if param doesn't
* match any of the types
*/
int fix_param_types(int types, void** param)
{
int ret;
int t;
|
35657139 |
if (fixup_get_param_type(param) == STRING_RVE_ST &&
(types & (FPARAM_INT|FPARAM_STR|FPARAM_STRING))) {
/* if called with a RVE already converted to string =>
don't try AVP, PVAR or SELECT (to avoid double
deref., e.g.: $foo="$bar"; f($foo) ) */
types &= ~ (FPARAM_AVP|FPARAM_PVS|FPARAM_SELECT|FPARAM_PVE);
} |
bf9d1c43 |
for (t=types & ~(types-1); types; types&=(types-1), t=types & ~(types-1)){
if ((ret=fix_param(t, param))<=0) return ret;
}
return E_UNSPEC;
}
|
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)
{ |
f2f12966 |
int ret; |
35657139 |
if (fixup_get_param_type(param) != STRING_RVE_ST) {
/* if called with a RVE already converted to string =>
don't try AVP, PVAR or SELECT (to avoid double
deref., e.g.: $foo="$bar"; f($foo) ) */ |
99cff510 |
if ((ret = fix_param(FPARAM_PVS, param)) <= 0) return ret; |
35657139 |
if ((ret = fix_param(FPARAM_AVP, param)) <= 0) return ret;
if ((ret = fix_param(FPARAM_SELECT, param)) <= 0) return ret;
} |
f2f12966 |
if ((ret = fix_param(FPARAM_STR, param)) <= 0) return ret; |
153ab772 |
LM_ERR("Error while fixing parameter, PV, AVP, SELECT, and str conversions" |
f2f12966 |
" failed\n");
return -1; |
d0ce0ebd |
} |
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)
{ |
f2f12966 |
if (param_no == 1) return fixup_var_str_12(param, param_no);
else return 0; |
d0ce0ebd |
} |
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)
{ |
f2f12966 |
if (param_no == 2) return fixup_var_str_12(param, param_no);
else return 0; |
d0ce0ebd |
} |
b91364c6 |
|
4c52cf05 |
/** fixup variable-pve-only-string.
* The parameter can be a PVE (pv based format string)
* or string.
* non-static PVEs identifiers will be resolved to
* their values during runtime.
* The parameter value will be converted to fparam structure
* @param param - double pointer to param, as for normal fixup functions.
* @param param_no - parameter number, ignored.
* @return -1 on an error, 0 on success.
*/
int fixup_var_pve_12(void** param, int param_no)
{
int ret;
fparam_t* fp;
if (fixup_get_param_type(param) != STRING_RVE_ST) {
/* if called with a RVE already converted to string =>
don't try PVE again (to avoid double
deref., e.g.: $foo="$bar"; f($foo) ) */
if ((ret = fix_param(FPARAM_PVE, param)) <= 0) {
if (ret < 0)
return ret;
/* check if it resolved to a dynamic or "static" PVE.
If the resulting PVE is static (normal string), discard
it and use the normal string fixup (faster at runtime) */
fp = (fparam_t*)*param; |
2895dbdc |
if (fp->v.pve->spec == 0 || fp->v.pve->spec->getf == 0) |
4c52cf05 |
fparam_free_restore(param); /* fallback to STR below */
else
return ret; /* dynamic PVE => return */
}
}
if ((ret = fix_param(FPARAM_STR, param)) <= 0) return ret; |
153ab772 |
LM_ERR("Error while fixing parameter - PVE or str conversions failed\n"); |
4c52cf05 |
return -1;
}
|
b91364c6 |
|
a5b499a4 |
/** fixup variable-pve-string.
* The parameter can be a PVAR, AVP, SELECT, PVE (pv based format string)
* or string.
* PVAR, AVP and select and non-static PVEs identifiers will be resolved to
* their values during runtime.
* The parameter value will be converted to fparam structure
* @param param - double pointer to param, as for normal fixup functions.
* @param param_no - parameter number, ignored.
* @return -1 on an error, 0 on success.
*/
int fixup_var_pve_str_12(void** param, int param_no)
{
int ret;
fparam_t* fp;
if (fixup_get_param_type(param) != STRING_RVE_ST) {
/* if called with a RVE already converted to string =>
don't try AVP, PVAR, SELECT or PVE again (to avoid double
deref., e.g.: $foo="$bar"; f($foo) ) */
if ((ret = fix_param(FPARAM_PVS, param)) <= 0) return 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_PVE, param)) <= 0) {
if (ret < 0)
return ret;
/* check if it resolved to a dynamic or "static" PVE.
If the resulting PVE is static (normal string), discard
it and use the normal string fixup (faster at runtime) */
fp = (fparam_t*)*param; |
2895dbdc |
if (fp->v.pve->spec == 0 || fp->v.pve->spec->getf == 0) |
a5b499a4 |
fparam_free_restore(param); /* fallback to STR below */
else
return ret; /* dynamic PVE => return */
}
}
if ((ret = fix_param(FPARAM_STR, param)) <= 0) return ret; |
153ab772 |
LM_ERR("Error while fixing parameter, PV, AVP, SELECT, and str conversions" |
a5b499a4 |
" failed\n");
return -1;
}
/* Same as fixup_var_pve_str_12 but applies to the 1st parameter only */
int fixup_var_pve_str_1(void** param, int param_no)
{
if (param_no == 1) return fixup_var_pve_str_12(param, param_no);
else return 0;
}
/* Same as fixup_var_pve_str_12 but applies to the 2nd parameter only */
int fixup_var_pve_str_2(void** param, int param_no)
{
if (param_no == 2) return fixup_var_pve_str_12(param, param_no);
else return 0;
}
|
d0ce0ebd |
/*
* Fixup variable integer, the parameter can be
* AVP, SELECT, or ordinary integer. AVP and select |
f4194f69 |
* identifiers will be resolved to their values and |
d0ce0ebd |
* 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)
{ |
f2f12966 |
int ret; |
35657139 |
if (fixup_get_param_type(param) != STRING_RVE_ST) {
/* if called with a RVE already converted to string =>
don't try AVP, PVAR or SELECT (to avoid double
deref., e.g.: $foo="$bar"; f($foo) ) */ |
99cff510 |
if ((ret = fix_param(FPARAM_PVS, param)) <= 0) return ret; |
35657139 |
if ((ret = fix_param(FPARAM_AVP, param)) <= 0) return ret;
if ((ret = fix_param(FPARAM_SELECT, param)) <= 0) return ret;
} |
f2f12966 |
if ((ret = fix_param(FPARAM_INT, param)) <= 0) return ret; |
153ab772 |
LM_ERR("Error while fixing parameter, PV, AVP, SELECT, and int conversions" |
f2f12966 |
" failed\n");
return -1; |
d0ce0ebd |
}
/* Same as fixup_var_int_12 but applies to the 1st parameter only */
int fixup_var_int_1(void** param, int param_no)
{ |
f2f12966 |
if (param_no == 1) return fixup_var_int_12(param, param_no);
else return 0; |
d0ce0ebd |
}
/* Same as fixup_var_int_12 but applies to the 2nd parameter only */
int fixup_var_int_2(void** param, int param_no)
{ |
f2f12966 |
if (param_no == 2) return fixup_var_int_12(param, param_no);
else return 0; |
d0ce0ebd |
}
/*
* 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)
{ |
f2f12966 |
int ret; |
d0ce0ebd |
|
f2f12966 |
if ((ret = fix_param(FPARAM_REGEX, param)) <= 0) return ret; |
153ab772 |
LM_ERR("Error while compiling regex in function parameter\n"); |
f2f12966 |
return -1; |
d0ce0ebd |
}
/* Same as fixup_regex_12 but applies to the 1st parameter only */
int fixup_regex_1(void** param, int param_no)
{ |
f2f12966 |
if (param_no == 1) return fixup_regex_12(param, param_no);
else return 0; |
d0ce0ebd |
}
/* Same as fixup_regex_12 but applies to the 2nd parameter only */
int fixup_regex_2(void** param, int param_no)
{ |
f2f12966 |
if (param_no == 2) return fixup_regex_12(param, param_no);
else return 0; |
d0ce0ebd |
}
/*
* The string parameter will be converted to integer
*/
int fixup_int_12(void** param, int param_no)
{ |
f2f12966 |
int ret; |
d0ce0ebd |
|
f2f12966 |
if ((ret = fix_param(FPARAM_INT, param)) <= 0) return ret; |
153ab772 |
LM_ERR("Cannot function parameter to integer\n"); |
f2f12966 |
return -1; |
d0ce0ebd |
}
/* Same as fixup_int_12 but applies to the 1st parameter only */
int fixup_int_1(void** param, int param_no)
{ |
f2f12966 |
if (param_no == 1) return fixup_int_12(param, param_no);
else return 0; |
d0ce0ebd |
}
/* Same as fixup_int_12 but applies to the 2nd parameter only */
int fixup_int_2(void** param, int param_no)
{ |
f2f12966 |
if (param_no == 2) return fixup_int_12(param, param_no);
else return 0; |
d0ce0ebd |
}
/*
* 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)
{ |
f2f12966 |
int ret; |
d0ce0ebd |
|
f2f12966 |
if ((ret = fix_param(FPARAM_STR, param)) <= 0) return ret; |
153ab772 |
LM_ERR("Cannot function parameter to string\n"); |
f2f12966 |
return -1; |
d0ce0ebd |
}
/* Same as fixup_str_12 but applies to the 1st parameter only */
int fixup_str_1(void** param, int param_no)
{ |
f2f12966 |
if (param_no == 1) return fixup_str_12(param, param_no);
else return 0; |
d0ce0ebd |
}
/* Same as fixup_str_12 but applies to the 2nd parameter only */
int fixup_str_2(void** param, int param_no)
{ |
f2f12966 |
if (param_no == 2) return fixup_str_12(param, param_no);
else return 0; |
b91364c6 |
} |
c16e9887 |
|
8f281796 |
|
39af8f24 |
/** Get the function parameter value as string.
* @return 0 - Success
* -1 - Cannot get value |
c16e9887 |
*/
int get_str_fparam(str* dst, struct sip_msg* msg, fparam_t* param)
{ |
f2f12966 |
int_str val;
int ret;
avp_t* avp; |
39af8f24 |
pv_value_t pv_val; |
f2f12966 |
switch(param->type) {
case FPARAM_REGEX:
case FPARAM_UNSPEC:
case FPARAM_INT:
return -1;
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); |
39af8f24 |
if (unlikely(!avp)) { |
c6a1ba6d |
LM_DBG("Could not find AVP from function parameter '%s'\n", |
f2f12966 |
param->orig);
return -1;
} |
39af8f24 |
if (likely(avp->flags & AVP_VAL_STR)) { |
f2f12966 |
*dst = val.s;
} else {
/* 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);
}
break;
case FPARAM_SELECT:
ret = run_select(dst, param->v.select, msg); |
39af8f24 |
if (unlikely(ret < 0 || ret > 0)) return -1;
break;
case FPARAM_PVS:
if (likely((pv_get_spec_value(msg, param->v.pvs, &pv_val)==0) &&
((pv_val.flags&(PV_VAL_NULL|PV_VAL_STR))==PV_VAL_STR))){
*dst=pv_val.rs;
}else{ |
153ab772 |
LM_ERR("Could not convert PV to str\n"); |
39af8f24 |
return -1;
}
break;
case FPARAM_PVE: |
2f292107 |
dst->s=pv_get_buffer();
dst->len=pv_get_buffer_size(); |
8f281796 |
if (unlikely(pv_printf(msg, param->v.pve, dst->s, &dst->len)!=0)){ |
153ab772 |
LM_ERR("Could not convert the PV-formated string to str\n"); |
39af8f24 |
dst->len=0;
return -1;
}; |
f2f12966 |
break; |
c16e9887 |
} |
f2f12966 |
return 0; |
c16e9887 |
}
|
d0ce0ebd |
|
39af8f24 |
/** Get the function parameter value as integer.
* @return 0 - Success
* -1 - Cannot get value |
d0ce0ebd |
*/
int get_int_fparam(int* dst, struct sip_msg* msg, fparam_t* param)
{ |
f2f12966 |
int_str val;
int ret;
avp_t* avp;
str tmp; |
39af8f24 |
pv_value_t pv_val; |
f4194f69 |
|
f2f12966 |
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); |
39af8f24 |
if (unlikely(!avp)) { |
c6a1ba6d |
LM_DBG("Could not find AVP from function parameter '%s'\n", |
f2f12966 |
param->orig);
return -1;
}
if (avp->flags & AVP_VAL_STR) {
if (str2int(&val.s, (unsigned int*)dst) < 0) { |
153ab772 |
LM_ERR("Could not convert AVP string value to int\n"); |
f2f12966 |
return -1;
}
} else {
*dst = val.n;
}
break;
case FPARAM_SELECT:
ret = run_select(&tmp, param->v.select, msg); |
39af8f24 |
if (unlikely(ret < 0 || ret > 0)) return -1;
if (unlikely(str2int(&tmp, (unsigned int*)dst) < 0)) { |
153ab772 |
LM_ERR("Could not convert select result to int\n"); |
f2f12966 |
return -1;
}
break; |
39af8f24 |
case FPARAM_PVS:
if (likely((pv_get_spec_value(msg, param->v.pvs, &pv_val)==0) &&
((pv_val.flags&(PV_VAL_NULL|PV_VAL_INT))==PV_VAL_INT))){
*dst=pv_val.ri;
}else{ |
153ab772 |
LM_ERR("Could not convert PV to int\n"); |
39af8f24 |
return -1;
}
break;
case FPARAM_PVE:
return -1; |
d0ce0ebd |
} |
f2f12966 |
return 0; |
d0ce0ebd |
} |
44c65404 |
|
8a334551 |
/** Get the function parameter value as string or/and integer (if possible).
* @return 0 - Success
* -1 - Cannot get value
*/
int get_is_fparam(int* i_dst, str* s_dst, struct sip_msg* msg, fparam_t* param, unsigned int *flags)
{
int_str val;
int ret;
avp_t* avp;
str tmp;
pv_value_t pv_val;
*flags = 0;
switch(param->type) {
case FPARAM_INT:
*i_dst = param->v.i;
*flags |= PARAM_INT;
return 0;
case FPARAM_REGEX:
case FPARAM_UNSPEC:
case FPARAM_STRING:
s_dst->s = param->v.asciiz;
s_dst->len = strlen(param->v.asciiz);
*flags |= PARAM_STR;
break;
case FPARAM_STR:
*s_dst = param->v.str;
*flags |= PARAM_STR;
break;
case FPARAM_AVP:
avp = search_first_avp(param->v.avp.flags, param->v.avp.name,
&val, 0);
if (unlikely(!avp)) { |
c6a1ba6d |
LM_DBG("Could not find AVP from function parameter '%s'\n", |
8a334551 |
param->orig);
return -1;
}
if (avp->flags & AVP_VAL_STR) {
*s_dst = val.s;
*flags |= PARAM_STR;
if (str2int(&val.s, (unsigned int*)i_dst) < 0) { |
153ab772 |
LM_ERR("Could not convert AVP string value to int\n"); |
8a334551 |
return -1;
}
} else {
*i_dst = val.n;
*flags |= PARAM_INT;
}
break;
case FPARAM_SELECT:
ret = run_select(&tmp, param->v.select, msg);
if (unlikely(ret < 0 || ret > 0)) return -1;
if (unlikely(str2int(&tmp, (unsigned int*)i_dst) < 0)) { |
153ab772 |
LM_ERR("Could not convert select result to int\n"); |
8a334551 |
return -1;
}
*flags |= PARAM_INT;
break;
case FPARAM_PVS:
if (likely(pv_get_spec_value(msg, param->v.pvs, &pv_val)==0)) {
if ((pv_val.flags&(PV_VAL_NULL|PV_VAL_INT))==PV_VAL_INT){
*i_dst=pv_val.ri;
*flags |= PARAM_INT;
}
if ((pv_val.flags&(PV_VAL_NULL|PV_VAL_STR))==PV_VAL_STR){
*s_dst=pv_val.rs;
*flags |= PARAM_STR;
}
}else{ |
153ab772 |
LM_ERR("Could not get PV\n"); |
8a334551 |
return -1;
}
break;
case FPARAM_PVE:
s_dst->s=pv_get_buffer();
s_dst->len=pv_get_buffer_size();
if (unlikely(pv_printf(msg, param->v.pve, s_dst->s, &s_dst->len)!=0)){ |
153ab772 |
LM_ERR("Could not convert the PV-formated string to str\n"); |
8a334551 |
s_dst->len=0;
return -1;
}
*flags |= PARAM_STR;
break;
}
/* Let's convert to int, if possible */
if (!(*flags & PARAM_INT) && (*flags & PARAM_STR) && str2sint(s_dst, i_dst) == 0)
*flags |= PARAM_INT;
if (!*flags) return -1;
return 0;
}
|
44c65404 |
/**
* Retrieve the compiled RegExp.
* @return: 0 for success, negative on error.
*/
int get_regex_fparam(regex_t *dst, struct sip_msg* msg, fparam_t* param)
{
switch (param->type) {
case FPARAM_REGEX:
*dst = *param->v.regex;
return 0;
default: |
153ab772 |
LM_ERR("unexpected parameter type (%d), instead of regexp.\n", |
44c65404 |
param->type);
}
return -1;
} |
8f3db98b |
|
6a40b4bd |
/** generic free fixup function for "pure" fparam type fixups.
* @param param - double pointer to param, as for normal fixup functions.
* @param param_no - parameter number, ignored.
* @return 0 on success (always).
*/
int fixup_free_fparam_all(void** param, int param_no)
{
fparam_free_restore(param);
return 0;
}
/** generic free fixup function for "pure" first parameter fparam type fixups.
* @param param - double pointer to param, as for normal fixup functions.
* @param param_no - parameter number: the function will work only for
* param_no == 1 (first parameter).
* @return 0 on success (always).
*/
int fixup_free_fparam_1(void** param, int param_no)
{
if (param_no == 1)
fparam_free_restore(param);
return 0;
}
/** generic free fixup function for "pure" 2nd parameter fparam type fixups.
* @param param - double pointer to param, as for normal fixup functions.
* @param param_no - parameter number: the function will work only for
* param_no == 2 (2nd parameter).
* @return 0 on success (always).
*/
int fixup_free_fparam_2(void** param, int param_no)
{
if (param_no == 2)
fparam_free_restore(param);
return 0;
}
|
8f3db98b |
/** returns true if a fixup is a fparam_t* one. |
0b52bcff |
* Used to automatically detect "pure" fparam fixups that can be used with non |
8f3db98b |
* contant RVEs.
* @param f - function pointer
* @return 1 for fparam fixups, 0 for others.
*/
int is_fparam_rve_fixup(fixup_function f)
{
if (f == fixup_var_str_12 ||
f == fixup_var_str_1 ||
f == fixup_var_str_2 || |
a5b499a4 |
f == fixup_var_pve_str_12 ||
f == fixup_var_pve_str_1 ||
f == fixup_var_pve_str_2 || |
8f3db98b |
f == fixup_var_int_12 ||
f == fixup_var_int_1 ||
f == fixup_var_int_2 ||
f == fixup_int_12 ||
f == fixup_int_1 ||
f == fixup_int_2 ||
f == fixup_str_12 ||
f == fixup_str_1 || |
0b52bcff |
f == fixup_str_2 ||
f == fixup_regex_12 ||
f == fixup_regex_1 ||
f == fixup_regex_2
) |
8f3db98b |
return 1;
return 0;
} |
0b52bcff |
|
a7524985 |
/**
* @brief returns the corresponding fixup_free* for various known fixup types
*
* Returns the corresponding fixup_free* for various known fixup types. |
0b52bcff |
* Used to automatically fill in free_fixup* functions. |
a7524985 |
* @param f fixup function pointer
* @return free fixup function pointer on success, 0 on failure (unknown
* fixup or no free fixup function). |
0b52bcff |
*/
free_fixup_function get_fixup_free(fixup_function f)
{
free_fixup_function ret;
/* "pure" fparam, all parameters */
if (f == fixup_var_str_12 || |
a5b499a4 |
f == fixup_var_pve_str_12 || |
0b52bcff |
f == fixup_var_int_12 ||
f == fixup_int_12 ||
f == fixup_str_12 ||
f == fixup_regex_12)
return fixup_free_fparam_all;
/* "pure" fparam, 1st parameter */
if (f == fixup_var_str_1 || |
a5b499a4 |
f == fixup_var_pve_str_1 || |
0b52bcff |
f == fixup_var_int_1 ||
f == fixup_int_1 ||
f == fixup_str_1 ||
f == fixup_regex_1)
return fixup_free_fparam_1;
/* "pure" fparam, 2nd parameters */
if (f == fixup_var_str_2 || |
a5b499a4 |
f == fixup_var_pve_str_2 || |
0b52bcff |
f == fixup_var_int_2 ||
f == fixup_int_2 ||
f == fixup_str_2 ||
f == fixup_regex_2)
return fixup_free_fparam_2;
/* mod_fix.h kamailio style fixups */
if ((ret = mod_fix_get_fixup_free(f)) != 0)
return ret;
/* unknown */
return 0;
} |