3bf76e49 |
/* $Id$
|
7dd0b342 |
*
* Copyright (C) 2001-2003 Fhg Fokus
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* 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)
|
6419a43f |
*/
|
3bf76e49 |
|
7dd0b342 |
|
3bf76e49 |
#include "sr_module.h"
#include "dprint.h"
|
404073d3 |
#include "error.h"
|
e3dccdc9 |
#include "mem/mem.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
ret=register_module(tm_exports,"built-in", 0);
if (ret<0) return ret;
#endif
|
192ac55b |
|
e8df4b11 |
#ifdef STATIC_EXEC
|
30449150 |
ret=register_module(exec_exports,"built-in", 0);
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
ret=register_module(auth_exports, "built-in", 0);
if (ret<0) return ret;
#endif
|
192ac55b |
#ifdef STATIC_RR
|
57c9e572 |
ret=register_module(rr_exports, "built-in", 0);
if (ret<0) return ret;
|
192ac55b |
#endif
|
57c9e572 |
|
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
|
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;
|
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;
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;
}
if (!m_ver || !(*m_ver)) {
|
bae7e884 |
LOG(L_ERR, "ERROR: no version in module <%s>\n", path );
|
2dcb8b67 |
return 0;
}
if (strcmp(VERSION,*m_ver)==0)
return 1;
|
627b66ef |
LOG(L_ERR, "ERROR: module version mismatch for %s; "
|
2dcb8b67 |
"core: %s; module: %s\n", path, VERSION, *m_ver );
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;
|
3bf76e49 |
|
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;
}
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;
}
|
49b28ea4 |
/* searches the module list and returns pointer to the "name" function or
|
51c38611 |
* 0 if not found
|
49b28ea4 |
* flags parameter is OR value of all flags that must match
|
51c38611 |
*/
cmd_function find_export(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)
){
|
3bf76e49 |
DBG("find_export: found <%s> in module %s [%s]\n",
|
51c38611 |
name, t->exports->name, t->path);
|
6419a43f |
return cmd->function;
|
3bf76e49 |
}
}
}
DBG("find_export: <%s> not found \n", name);
return 0;
}
|
34fd2612 |
|
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;
}
}
}
}
DBG("find_mod_export: <%s> in module %s not found\n", name, mod);
return 0;
}
|
31309a3a |
void* find_param_export(char* mod, char* name, modparam_t type)
{
struct sr_module* t;
|
6419a43f |
param_export_t* param;
|
31309a3a |
for(t = modules; t; t = t->next) {
if (strcmp(mod, t->exports->name) == 0) {
|
6419a43f |
for(param=t->exports->params;param && param->name ; param++) {
if ((strcmp(name, param->name) == 0) &&
(param->type == type)) {
|
31309a3a |
DBG("find_param_export: found <%s> in module %s [%s]\n",
name, t->exports->name, t->path);
|
6419a43f |
return param->param_pointer;
|
31309a3a |
}
}
}
}
|
e3fc93f4 |
DBG("find_param_export: parameter <%s> or module <%s> not found\n",
name, mod);
|
31309a3a |
return 0;
}
|
34fd2612 |
/* finds a module, given a pointer to a module function *
|
6419a43f |
* returns pointer to module, & if c!=0, *c=pointer to the
* function cmd_export structure*/
struct sr_module* find_module(void* f, cmd_export_t **c)
|
34fd2612 |
{
struct sr_module* t;
|
6419a43f |
cmd_export_t* cmd;
|
34fd2612 |
for (t=modules;t;t=t->next){
|
6419a43f |
for(cmd=t->exports->cmds; cmd && cmd->name; cmd++)
if (f==(void*)cmd->function) {
if (c) *c=cmd;
|
34fd2612 |
return t;
}
}
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;
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);
|
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) {
DBG("DEBUG: init_mod_child (%d): %s\n",
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
|