Selaa lähdekoodia

Merge commit 'origin/andrei/module_interface'

* commit 'origin/andrei/module_interface':
  tm makefile: declare SER_MOD_INTERFACE
  kamailio LM_* compatibility macros
  dual module interface support: ser and kamailio
  kamailio compatibility header files
  added .gitignore
  module interface: minor changes from kamailio
Andrei Pelinescu-Onciul 17 vuotta sitten
vanhempi
commit
8cc09737d9
12 muutettua tiedostoa jossa 834 lisäystä ja 135 poistoa
  1. 8 5
      action.c
  2. 6 2
      cfg.y
  3. 4 2
      core_cmd.c
  4. 21 0
      dprint.h
  5. 99 0
      mi/mi.h
  6. 7 5
      modparam.c
  7. 1 0
      modules/tm/Makefile
  8. 145 0
      pvar.h
  9. 4 4
      route.c
  10. 293 100
      sr_module.c
  11. 174 17
      sr_module.h
  12. 72 0
      statistics.h

+ 8 - 5
action.c

@@ -716,8 +716,9 @@ int do_action(struct run_act_ctx* h, struct action* a, struct sip_msg* msg)
 				}
 			break;
 		case MODULE_T:
-			if ( a->val[0].type==MODEXP_ST && a->val[0].u.data && ((cmd_export_t*)a->val[0].u.data)->function ){
-				ret=((cmd_export_t*)a->val[0].u.data)->function(msg,
+			if ( a->val[0].type==MODEXP_ST && a->val[0].u.data && 
+					((union cmd_export_u*)a->val[0].u.data)->c.function){
+				ret=((union cmd_export_u*)a->val[0].u.data)->c.function(msg,
 					(char*)a->val[2].u.data,
 					(char*)a->val[3].u.data
 				);
@@ -976,9 +977,11 @@ end:
 	/* process module onbreak handlers if present */
 	if (h->rec_lev==0 && ret==0)
 		for (mod=modules;mod;mod=mod->next)
-			if (mod->exports && mod->exports->onbreak_f) {
-				mod->exports->onbreak_f( msg );
-				DBG("DEBUG: %s onbreak handler called\n", mod->exports->name);
+			if ((mod->mod_interface_ver==0) && mod->exports && 
+					mod->exports->v0.onbreak_f) {
+				mod->exports->v0.onbreak_f( msg );
+				DBG("DEBUG: %s onbreak handler called\n",
+						mod->exports->c.name);
 			}
 	return ret;
 

+ 6 - 2
cfg.y

@@ -174,6 +174,7 @@ extern int yylex();
 static void yyerror(char* s);
 static char* tmp;
 static int i_tmp;
+static unsigned u_tmp;
 static struct socket_id* lst_tmp;
 static struct name_lst*  nl_tmp;
 static int rt;  /* Type of route block for find_export */
@@ -2359,9 +2360,12 @@ cmd:
 	}
 	| FORCE_SEND_SOCKET error {$$=0; yyerror("missing '(' or ')' ?"); }
 	| ID {mod_func_action = mk_action(MODULE_T, 2, MODEXP_ST, NULL, NUMBER_ST, 0); } LPAREN func_params RPAREN	{
-		mod_func_action->val[0].u.data = find_export_record($1, mod_func_action->val[1].u.number, rt);
+		mod_func_action->val[0].u.data = 
+			find_export_record($1, mod_func_action->val[1].u.number, rt,
+								&u_tmp);
 		if (mod_func_action->val[0].u.data == 0) {
-			if (find_export_record($1, mod_func_action->val[1].u.number, 0) ) {
+			if (find_export_record($1, mod_func_action->val[1].u.number, 0,
+									&u_tmp) ) {
 					yyerror("Command cannot be used in the block\n");
 			} else {
 				yyerror("unknown command, missing loadmodule?\n");

+ 4 - 2
core_cmd.c

@@ -198,7 +198,8 @@ static void system_listMethods(rpc_t* rpc, void* c)
 	}
 
 	for(t = modules; t; t = t->next) {
-		for(ptr = t->exports->rpc_methods; ptr && ptr->name; ptr++) {
+		if (t->mod_interface_ver!=0) continue;
+		for(ptr = t->exports->v0.rpc_methods; ptr && ptr->name; ptr++) {
 			if (rpc->add(c, "s", ptr->name) < 0) return;
 		}
 	}
@@ -232,7 +233,8 @@ static void system_methodHelp(rpc_t* rpc, void* c)
 	}
 
 	for(t = modules; t; t = t->next) {
-		for(ptr = t->exports->rpc_methods; ptr && ptr->name; ptr++) {
+		if (t->mod_interface_ver!=0) continue;
+		for(ptr = t->exports->v0.rpc_methods; ptr && ptr->name; ptr++) {
 			if (strcmp(name, ptr->name) == 0) {
 				if (ptr->doc_str && ptr->doc_str[0]) {
 					rpc->add(c, "s", ptr->doc_str[0]);

+ 21 - 0
dprint.h

@@ -244,13 +244,34 @@ int log_facility_fixup(void *handle, str *name, void **val);
 		#define WARN(...) LOG(L_WARN, "WARNING: " LOC_INFO __VA_ARGS__)
 		#define INFO(...) LOG(L_INFO, "INFO: "    LOC_INFO __VA_ARGS__)
 		#define BUG(...) LOG(L_CRIT, "BUG: "      LOC_INFO __VA_ARGS__)
+		#define NOTICE(...) LOG(L_NOTICE, "NOTICE: " LOC_INFO __VA_ARGS__)
+		#define ALERT(...) LOG(L_ALERT, "ALERT: " LOC_INFO __VA_ARGS__)
+		#define CRIT(...) LOG(L_CRIT, "CRITICAL: " LOC_INFO __VA_ARGS__)
 #else
 		#define DEBUG(fmt, args...) DBG("DEBUG: "       LOC_INFO fmt, ## args)
 		#define ERR(fmt, args...) LOG(L_ERR, "ERROR: "  LOC_INFO fmt, ## args)
 		#define WARN(fmt, args...) LOG(L_WARN, "WARN: " LOC_INFO fmt, ## args)
 		#define INFO(fmt, args...) LOG(L_INFO, "INFO: " LOC_INFO fmt, ## args)
 		#define BUG(fmt, args...) LOG(L_CRIT, "BUG: "   LOC_INFO fmt, ## args)
+		#define NOTICE(fmt, args...) \
+			LOG(L_NOTICE, "NOTICE: " LOC_INFO fmt, ## args)
+		#define ALERT(fmt, args...) \
+			LOG(L_ALERT, "ALERT: " LOC_INFO fmt, ## args)
+		#define CRIT(fmt, args...) \
+			LOG(L_CRIT, "CRITICAL: " LOC_INFO fmt, ## args)
 #endif
 
+/* kamailio/openser compatibility */
+
+#define LM_GEN1 LOG
+
+#define LM_ALERT ALERT
+#define LM_CRIT  CRIT
+#define LM_ERR ERR
+#define LM_WARN WARN
+#define LM_NOTICE
+#define LM_INFO INFO
+#define LM_DBG DEBUG
+
 
 #endif /* ifndef dprint_h */

+ 99 - 0
mi/mi.h

@@ -0,0 +1,99 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2008 iptelorg GmbH
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/*
+ * mi compatibility wrapper for kamailio
+ * for now it doesn't do anything, it just a compile helper
+ * (obsolete, do not use anymore)
+ *
+ * History:
+ * --------
+ *  2008-11-17  initial version compatible with kamailio mi/mi.h (andrei)
+ */
+
+#ifndef _mi_h_
+#define _mi_h_
+
+#include "../str.h"
+
+#define MI_DUP_NAME   (1<<0)
+#define MI_DUP_VALUE  (1<<1)
+
+#define MI_OK_S              "OK"
+#define MI_OK_LEN            (sizeof(MI_OK_S)-1)
+#define MI_INTERNAL_ERR_S    "Server Internal Error"
+#define MI_INTERNAL_ERR_LEN  (sizeof(MI_INTERNAL_ERR_S)-1)
+#define MI_MISSING_PARM_S    "Too few or too many arguments"
+#define MI_MISSING_PARM_LEN  (sizeof(MI_MISSING_PARM_S)-1)
+#define MI_BAD_PARM_S        "Bad parameter"
+#define MI_BAD_PARM_LEN      (sizeof(MI_BAD_PARM_S)-1)
+
+#define MI_SSTR(_s)           _s,(sizeof(_s)-1)
+#define MI_OK                 MI_OK_S
+#define MI_INTERNAL_ERR       MI_INTERNAL_ERR_S
+#define MI_MISSING_PARM       MI_MISSING_PARM_S
+#define MI_BAD_PARM           MI_BAD_PARM_S
+
+
+
+struct mi_attr{
+	str name;
+	str value;
+	struct mi_attr *next;
+};
+
+
+struct mi_node {
+	str value;
+	str name;
+	struct mi_node *kids;
+	struct mi_node *next;
+	struct mi_node *last;
+	struct mi_attr *attributes;
+};
+
+
+struct mi_root {
+	unsigned int       code;
+	str                reason;
+	struct mi_handler  *async_hdl;
+	struct mi_node     node;
+};
+
+typedef struct mi_root* (mi_cmd_f)(struct mi_root*, void *param);
+typedef int (mi_child_init_f)(void);
+
+
+typedef struct mi_export_ {
+	char *name;
+	mi_cmd_f *cmd;
+	unsigned int flags;
+	void *param;
+	mi_child_init_f *init_f;
+}mi_export_t;
+
+
+#define init_mi_tree(code, reason, reason_len) 0
+#define free_mi_tree(parent)
+#define add_mi_node_sibling(node, flags, name, name_len, val, val_len) 0
+#define add_mi_node_child(node, flags, name, name_len, val, val_len) 0
+#define addf_mi_node_child(node, flags, name, name_len, fmt, ...) 0
+
+
+#endif /* _mi_h_ */
+
+

+ 7 - 5
modparam.c

@@ -84,8 +84,9 @@ int set_mod_param_regex(char* regex, char* name, modparam_t type, void* val)
 
 	mod_found = 0;
 	for(t = modules; t; t = t->next) {
-		if (regexec(&preg, t->exports->name, 0, 0, 0) == 0) {
-			DBG("set_mod_param_regex: '%s' matches module '%s'\n", regex, t->exports->name);
+		if (regexec(&preg, t->exports->c.name, 0, 0, 0) == 0) {
+			DBG("set_mod_param_regex: '%s' matches module '%s'\n",
+					regex, t->exports->c.name);
 			mod_found = 1;
 			/* PARAM_STR (PARAM_STRING) may be assigned also to PARAM_STRING(PARAM_STR) so let get both module param */
 			ptr = find_param_export(t, name, type | ((type & (PARAM_STR|PARAM_STRING))?PARAM_STR|PARAM_STRING:0), &param_type);
@@ -100,7 +101,8 @@ int set_mod_param_regex(char* regex, char* name, modparam_t type, void* val)
 				} else {
 					val2 = val;
 				}
-				DBG("set_mod_param_regex: found <%s> in module %s [%s]\n", name, t->exports->name, t->path);
+				DBG("set_mod_param_regex: found <%s> in module %s [%s]\n",
+						name, t->exports->c.name, t->path);
 				if (param_type & PARAM_USE_FUNC) {
 					if ( ((param_func_t)(ptr))(param_type, val2) < 0) {
 						regfree(&preg);
@@ -137,8 +139,8 @@ int set_mod_param_regex(char* regex, char* name, modparam_t type, void* val)
 				}
 			}
 			else {
-				LOG(L_ERR, "set_mod_param_regex: parameter <%s> not found in module <%s>\n",
-				    name, t->exports->name);
+				LOG(L_ERR, "set_mod_param_regex: parameter <%s> not found in"
+							" module <%s>\n", name, t->exports->c.name);
 				regfree(&preg);
 				pkg_free(reg);
 				return -3;

+ 1 - 0
modules/tm/Makefile

@@ -9,5 +9,6 @@ include ../../Makefile.defs
 auto_gen=
 NAME=tm.so
 LIBS=
+DEFS+= -DSER_MOD_INTERFACE
 
 include ../../Makefile.modules

+ 145 - 0
pvar.h

@@ -0,0 +1,145 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2008 
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/*
+ * pvar compatibility wrapper for kamailio
+ * for now it doesn't do anything (feel free to rm & replace the file)
+ *
+ * History:
+ * --------
+ *  2008-11-17  initial version compatible with kamailio pvar.h (andrei)
+ */
+
+#ifndef _pvar_h_
+#define _pvar_h_
+
+#include "str.h"
+#include "usr_avp.h"
+#include "parser/msg_parser.h"
+
+
+
+
+enum _pv_type { 
+	PVT_NONE=0,           PVT_EMPTY,             PVT_NULL, 
+	PVT_MARKER,           PVT_AVP,               PVT_HDR,
+	PVT_PID,              PVT_RETURN_CODE,       PVT_TIMES,
+	PVT_TIMEF,            PVT_MSGID,             PVT_METHOD,
+	PVT_STATUS,           PVT_REASON,            PVT_RURI,
+	PVT_RURI_USERNAME,    PVT_RURI_DOMAIN,       PVT_RURI_PORT,
+	PVT_FROM,             PVT_FROM_USERNAME,     PVT_FROM_DOMAIN,
+	PVT_FROM_TAG,         PVT_TO,                PVT_TO_USERNAME,
+	PVT_TO_DOMAIN,        PVT_TO_TAG,            PVT_CSEQ,
+	PVT_CONTACT,          PVT_CALLID,            PVT_USERAGENT,
+	PVT_MSG_BUF,          PVT_MSG_LEN,           PVT_FLAGS,
+	PVT_HEXFLAGS,         PVT_SRCIP,             PVT_SRCPORT,
+	PVT_RCVIP,            PVT_RCVPORT,           PVT_REFER_TO,
+	PVT_DSET,             PVT_DSTURI,            PVT_COLOR,
+	PVT_BRANCH,           PVT_BRANCHES,          PVT_CONTENT_TYPE,
+	PVT_CONTENT_LENGTH,   PVT_MSG_BODY,          PVT_AUTH_USERNAME,
+	PVT_AUTH_REALM,       PVT_RURI_PROTOCOL,     PVT_DSTURI_DOMAIN,
+	PVT_DSTURI_PORT,      PVT_DSTURI_PROTOCOL,   PVT_FROM_DISPLAYNAME,
+	PVT_TO_DISPLAYNAME,   PVT_OURI,              PVT_OURI_USERNAME,
+	PVT_OURI_DOMAIN,      PVT_OURI_PORT,         PVT_OURI_PROTOCOL,
+	PVT_FORCE_SOCK,       PVT_RPID_URI,          PVT_DIVERSION_URI,
+	PVT_ACC_USERNAME,     PVT_PPI,               PVT_PPI_DISPLAYNAME,
+	PVT_PPI_DOMAIN,       PVT_PPI_USERNAME,      PVT_PAI_URI,
+	PVT_BFLAGS,           PVT_HEXBFLAGS,         PVT_SFLAGS,
+	PVT_HEXSFLAGS,        PVT_ERR_CLASS,         PVT_ERR_LEVEL,
+	PVT_ERR_INFO,         PVT_ERR_RCODE,         PVT_ERR_RREASON,
+	PVT_SCRIPTVAR,        PVT_PROTO,             PVT_AUTH_USERNAME_WHOLE,
+	PVT_AUTH_DURI,        PVT_DIV_REASON,        PVT_DIV_PRIVACY,
+	PVT_AUTH_DOMAIN,      PVT_EXTRA /* keep it last */
+};
+
+typedef enum _pv_type pv_type_t;
+typedef int pv_flags_t;
+
+typedef struct _pv_value
+{
+	str rs;    /*!< string value */
+	int ri;    /*!< integer value */
+	int flags; /*!< flags about the type of value */
+} pv_value_t, *pv_value_p;
+
+typedef struct _pv_name
+{
+	int type;             /*!< type of name */
+	union {
+		struct {
+			int type;     /*!< type of int_str name - compatibility with AVPs */
+			int_str name; /*!< the value of the name */
+		} isname;
+		void *dname;      /*!< PV value - dynamic name */
+	} u;
+} pv_name_t, *pv_name_p;
+
+typedef struct _pv_index
+{
+	int type; /*!< type of PV index */
+	union {
+		int ival;   /*!< integer value */
+		void *dval; /*!< PV value - dynamic index */
+	} u;
+} pv_index_t, *pv_index_p;
+
+typedef struct _pv_param
+{
+	pv_name_t    pvn; /*!< PV name */
+	pv_index_t   pvi; /*!< PV index */
+} pv_param_t, *pv_param_p;
+
+typedef int (*pv_getf_t) (struct sip_msg*,  pv_param_t*, pv_value_t*);
+typedef int (*pv_setf_t) (struct sip_msg*,  pv_param_t*, int, pv_value_t*);
+
+typedef struct _pv_spec {
+	pv_type_t    type;   /*!< type of PV */
+	pv_getf_t    getf;   /*!< get PV value function */
+	pv_setf_t    setf;   /*!< set PV value function */
+	pv_param_t   pvp;    /*!< parameter to be given to get/set functions */
+	void         *trans; /*!< transformations */
+} pv_spec_t, *pv_spec_p;
+
+
+
+typedef int (*pv_parse_name_f)(pv_spec_p sp, str *in);
+typedef int (*pv_parse_index_f)(pv_spec_p sp, str *in);
+typedef int (*pv_init_param_f)(pv_spec_p sp, int param);
+
+/*! \brief
+ * PV spec format:
+ * - $class_name
+ * - $class_name(inner_name)
+ * - $(class_name[index])
+ * - $(class_name(inner_name)[index])
+ * - $(class_name{transformation})
+ * - $(class_name(inner_name){transformation})
+ * - $(class_name[index]{transformation})
+ * - $(class_name(inner_name)[index]{transformation})
+ */
+typedef struct _pv_export {
+	str name;                      /*!< class name of PV */
+	pv_type_t type;                /*!< type of PV */
+	pv_getf_t  getf;               /*!< function to get the value */
+	pv_setf_t  setf;               /*!< function to set the value */
+	pv_parse_name_f parse_name;    /*!< function to parse the inner name */
+	pv_parse_index_f parse_index;  /*!< function to parse the index of PV */
+	pv_init_param_f init_param;    /*!< function to init the PV spec */
+	int iparam;                    /*!< parameter for the init function */
+} pv_export_t;
+
+#endif /* _pvar_h_ */

+ 4 - 4
route.c

@@ -386,7 +386,7 @@ static int fix_actions(struct action* a)
 	struct proxy_l* p;
 	char *tmp;
 	int ret;
-	cmd_export_t* cmd;
+	union cmd_export_u* cmd;
 	str s;
 	struct hostent* he;
 	struct ip_addr ip;
@@ -504,9 +504,9 @@ static int fix_actions(struct action* a)
 
 			case MODULE_T:
 				cmd = t->val[0].u.data;
-				if (cmd && cmd->fixup) {
+				if (cmd && cmd->c.fixup) {
 					int i;
-					DBG("fixing %s()\n", cmd->name);
+					DBG("fixing %s()\n", cmd->c.name);
 					/* type cast NUMBER to STRING, old modules may expect
 					 * all STRING params during fixup */
 					for (i=0; i<t->val[1].u.number; i++) {
@@ -527,7 +527,7 @@ static int fix_actions(struct action* a)
 					for (i=0; i<t->val[1].u.number; i++) {
 						void *p;
 						p = t->val[i+2].u.data;
-						ret = cmd->fixup(&t->val[i+2].u.data, i+1);
+						ret = cmd->c.fixup(&t->val[i+2].u.data, i+1);
 						if (t->val[i+2].u.data != p)
 							t->val[i+2].type = MODFIXUP_ST;
 						if (ret < 0)

+ 293 - 100
sr_module.c

@@ -37,6 +37,7 @@
  *               find_export_record
  *  2006-02-07  added fix_flag (andrei)
  *  2008-02-29  store all the reponse callbacks in their own array (andrei)
+ *  2008-11-17  support dual module interface: ser & kamailio (andrei)
  */
 
 
@@ -63,30 +64,30 @@
 struct sr_module* modules=0;
 
 #ifdef STATIC_EXEC
-	extern struct module_exports* exec_exports();
+	extern struct module_exports exec_exports;
 #endif
 #ifdef STATIC_TM
-	extern struct module_exports* tm_exports();
+	extern struct module_exports tm_exports;
 #endif
 
 #ifdef STATIC_MAXFWD
-	extern struct module_exports* maxfwd_exports();
+	extern struct module_exports maxfwd_exports;
 #endif
 
 #ifdef STATIC_AUTH
-	extern struct module_exports* auth_exports();
+	extern struct module_exports auth_exports;
 #endif
 
 #ifdef STATIC_RR
-	extern struct module_exports* rr_exports();
+	extern struct module_exports rr_exports;
 #endif
 
 #ifdef STATIC_USRLOC
-	extern struct module_exports* usrloc_exports();
+	extern struct module_exports usrloc_exports;
 #endif
 
 #ifdef STATIC_SL
-	extern struct module_exports* sl_exports();
+	extern struct module_exports sl_exports;
 #endif
 
 
@@ -101,37 +102,37 @@ int register_builtin_modules()
 
 	ret=0;
 #ifdef STATIC_TM
-	ret=register_module(tm_exports,"built-in", 0);
+	ret=register_module(MODULE_INTERFACE_VER, &tm_exports,"built-in", 0);
 	if (ret<0) return ret;
 #endif
 
 #ifdef STATIC_EXEC
-	ret=register_module(exec_exports,"built-in", 0);
+	ret=register_module(MODULE_INTERFACE_VER, &exec_exports,"built-in", 0);
 	if (ret<0) return ret;
 #endif
 
 #ifdef STATIC_MAXFWD
-	ret=register_module(maxfwd_exports, "built-in", 0);
+	ret=register_module(MODULE_INTERFACE_VER, &maxfwd_exports, "built-in", 0);
 	if (ret<0) return ret;
 #endif
 
 #ifdef STATIC_AUTH
-	ret=register_module(auth_exports, "built-in", 0);
+	ret=register_module(MODULE_INTERFACE_VER, &auth_exports, "built-in", 0);
 	if (ret<0) return ret;
 #endif
 
 #ifdef STATIC_RR
-	ret=register_module(rr_exports, "built-in", 0);
+	ret=register_module(MODULE_INTERFACE_VER, &rr_exports, "built-in", 0);
 	if (ret<0) return ret;
 #endif
 
 #ifdef STATIC_USRLOC
-	ret=register_module(usrloc_exports, "built-in", 0);
+	ret=register_module(MODULE_INTERFACE_VER, &usrloc_exports, "built-in", 0);
 	if (ret<0) return ret;
 #endif
 
 #ifdef STATIC_SL
-	ret=register_module(sl_exports, "built-in", 0);
+	ret=register_module(MODULE_INTERFACE_VER, &sl_exports, "built-in", 0);
 	if (ret<0) return ret;
 #endif
 
@@ -142,7 +143,8 @@ int register_builtin_modules()
 
 /* registers a module,  register_f= module register  functions
  * returns <0 on error, 0 on success */
-int register_module(struct module_exports* e, char* path, void* handle)
+static int register_module(unsigned ver, union module_exports_u* e,
+					char* path, void* handle)
 {
 	int ret;
 	struct sr_module* mod;
@@ -158,6 +160,7 @@ int register_module(struct module_exports* e, char* path, void* handle)
 	memset(mod,0, sizeof(struct sr_module));
 	mod->path=path;
 	mod->handle=handle;
+	mod->mod_interface_ver=ver;
 	mod->exports=e;
 	mod->next=modules;
 	modules=mod;
@@ -218,7 +221,8 @@ int load_module(char* path)
 {
 	void* handle;
 	char* error;
-	struct module_exports* exp;
+	union module_exports_u* exp;
+	unsigned* mod_if_ver;
 	struct sr_module* t;
 	struct stat stat_buf;
 	char* modname;
@@ -302,13 +306,20 @@ int load_module(char* path)
 	if (!version_control(handle, path)) {
 		exit(0);
 	}
+	mod_if_ver = (unsigned *)dlsym(handle,
+									DLSYM_PREFIX "module_interface_ver");
+	if ( (error =(char*)dlerror())!=0 ){
+		LOG(L_ERR, "ERROR: no module interface version in module <%s>\n",
+					path );
+		goto error1;
+	}
 	/* launch register */
-	exp = (struct module_exports*)dlsym(handle, DLSYM_PREFIX "exports");
+	exp = (union module_exports_u*)dlsym(handle, DLSYM_PREFIX "exports");
 	if ( (error =(char*)dlerror())!=0 ){
 		LOG(L_ERR, "ERROR: load_module: %s\n", error);
 		goto error1;
 	}
-	if (register_module(exp, path, handle)<0) goto error1;
+	if (register_module(*mod_if_ver, exp, path, handle)<0) goto error1;
 	return 0;
 
 error1:
@@ -321,25 +332,51 @@ skip:
 
 
 
-/* searches the module list and returns pointer to the "name" function record or
- * 0 if not found
+/* 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
+ * 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
  */
-cmd_export_t* find_export_record(char* name, int param_no, int flags)
+union cmd_export_u* find_mod_export_record(char* mod, char* name,
+											int param_no, int flags,
+											unsigned* mod_if_ver)
 {
 	struct sr_module* t;
-	cmd_export_t* cmd;
+	union cmd_export_u* cmd;
+	int i;
+	unsigned mver;
+
+#define FIND_EXPORT_IN_MOD(VER) \
+		if (t->exports->VER.cmds) \
+			for(i=0, cmd=(void*)&t->exports->VER.cmds[0]; cmd->VER.name; \
+					i++, cmd=(void*)&t->exports->VER.cmds[i]){\
+				if((strcmp(name, cmd->VER.name)==0)&& \
+					(cmd->VER.param_no==param_no) &&  \
+					((cmd->VER.flags & flags) == flags) \
+				){ \
+					DBG("find_export_record: found <%s> in module %s [%s]\n", \
+						name, t->exports->VER.name, t->path); \
+					*mod_if_ver=mver; \
+					return cmd; \
+				} \
+			}
 
 	for(t=modules;t;t=t->next){
-		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_export_record: found <%s> in module %s [%s]\n",
-				    name, t->exports->name, t->path);
-				return cmd;
-			}
+		if (mod!=0 && (strcmp(t->exports->c.name, mod) !=0))
+			continue;
+		mver=t->mod_interface_ver;
+		switch (mver){
+			case 0:
+				FIND_EXPORT_IN_MOD(v0);
+				break;
+			case 1:
+				FIND_EXPORT_IN_MOD(v1);
+				break;
+			default:
+				BUG("invalid module interface version %d for modules %s\n",
+						t->mod_interface_ver, t->path);
 		}
 	}
 	DBG("find_export_record: <%s> not found \n", name);
@@ -347,11 +384,30 @@ cmd_export_t* find_export_record(char* name, int param_no, int flags)
 }
 
 
+
+/* 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
+ */
+union cmd_export_u* find_export_record(char* name,
+											int param_no, int flags,
+											unsigned* mod_if_ver)
+{
+	return find_mod_export_record(0, name, param_no, flags, mod_if_ver);
+}
+
+
+
 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;
+	union cmd_export_u* cmd;
+	unsigned mver;
+	
+	cmd = find_export_record(name, param_no, flags, &mver);
+	return cmd?cmd->c.function:0;
 }
 
 
@@ -372,7 +428,8 @@ rpc_export_t* find_rpc_export(char* name, int flags)
 	}
 	     /* Continue with modules if not found */
 	for(t = modules; t; t = t->next) {
-		for(rpc = t->exports->rpc_methods; rpc && rpc->name; rpc++) {
+		if (t->mod_interface_ver!=0) continue;
+		for(rpc = t->exports->v0.rpc_methods; rpc && rpc->name; rpc++) {
 			if ((strcmp(name, rpc->name) == 0) &&
 			    ((rpc->flags & flags) == flags)
 			   ) {
@@ -385,30 +442,20 @@ rpc_export_t* find_rpc_export(char* name, int flags)
 
 
 /*
- * searches the module list and returns pointer to "name" function in module "mod"
+ * 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;
-				}
-			}
-		}
-	}
+	union cmd_export_u* cmd;
+	unsigned mver;
 
+	cmd=find_mod_export_record(mod, name, param_no, flags, &mver);
+	if (cmd)
+		return cmd->c.function;
+	
 	DBG("find_mod_export: <%s> in module <%s> not found\n", name, mod);
 	return 0;
 }
@@ -418,7 +465,7 @@ 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) {
+		if (strcmp(mod, t->exports->c.name) == 0) {
 			return t;
 		}
 	}
@@ -427,23 +474,37 @@ struct sr_module* find_module_by_name(char* mod) {
 }
 
 
-void* find_param_export(struct sr_module* mod, char* name, modparam_t type_mask, modparam_t *param_type)
+void* find_param_export(struct sr_module* mod, char* name,
+						modparam_t type_mask, modparam_t *param_type)
 {
 	param_export_t* param;
 
 	if (!mod)
 		return 0;
-	for(param=mod->exports->params;param && param->name ; param++) {
+	param=0;
+	switch(mod->mod_interface_ver){
+		case 0:
+			param=mod->exports->v0.params;
+			break;
+		case 1:
+			param=mod->exports->v1.params;
+			break;
+		default:
+			BUG("bad module interface version %d in module %s [%s]\n",
+					mod->mod_interface_ver, mod->exports->c.name, mod->path);
+			return 0;
+	}
+	for(;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);
+				name, mod->exports->c.name, mod->path);
 			*param_type = param->type;
 			return param->param_pointer;
 		}
 	}
 	DBG("find_param_export: parameter <%s> not found in module <%s>\n",
-			name, mod->exports->name);
+			name, mod->exports->c.name);
 	return 0;
 }
 
@@ -455,7 +516,20 @@ void destroy_modules()
 	t=modules;
 	while(t) {
 		foo=t->next;
-		if ((t->exports)&&(t->exports->destroy_f)) t->exports->destroy_f();
+		if (t->exports){
+			switch(t->mod_interface_ver){
+				case 0:
+					if ((t->exports->v0.destroy_f)) t->exports->v0.destroy_f();
+					break;
+				case 1:
+					if ((t->exports->v1.destroy_f)) t->exports->v1.destroy_f();
+					break;
+				default:
+					BUG("bad module interface version %d in module %s [%s]\n",
+						t->mod_interface_ver, t->exports->c.name,
+						t->path);
+			}
+		}
 		pkg_free(t);
 		t=foo;
 	}
@@ -477,14 +551,36 @@ 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) {
-				LOG(L_ERR, "init_modules(): Error while initializing"
-							" module %s\n", t->exports->name);
-				return -1;
+		if (t->exports){
+			switch(t->mod_interface_ver){
+				case 0:
+					if (t->exports->v0.init_f)
+						if (t->exports->v0.init_f() != 0) {
+							LOG(L_ERR, "init_modules(): Error while"
+										" initializing module %s\n",
+										t->exports->v0.name);
+							return -1;
+						}
+					if (t->exports->v0.response_f)
+						mod_response_cbk_no++;
+					break;
+				case 1:
+					if (t->exports->v1.init_f)
+						if (t->exports->v1.init_f() != 0) {
+							LOG(L_ERR, "init_modules(): Error while"
+										" initializing module %s\n",
+										t->exports->v1.name);
+							return -1;
+						}
+					if (t->exports->v1.response_f)
+						mod_response_cbk_no++;
+					break;
+				default:
+					BUG("bad module interface version %d in module %s [%s]\n",
+						t->exports->c.name, t->path);
+					return -1;
 			}
-		if ( t->exports && t->exports->response_f)
-			mod_response_cbk_no++;
+		}
 	}
 	mod_response_cbks=pkg_malloc(mod_response_cbk_no * 
 									sizeof(response_function));
@@ -494,9 +590,21 @@ int init_modules(void)
 		return -1;
 	}
 	for (t=modules, i=0; t && (i<mod_response_cbk_no); t=t->next){
-		if (t->exports && t->exports->response_f){
-			mod_response_cbks[i]=t->exports->response_f;
-			i++;
+		if (t->exports){
+			switch(t->mod_interface_ver){
+				case 0:
+					if (t->exports->v0.response_f){
+						mod_response_cbks[i]=t->exports->v0.response_f;
+						i++;
+					}
+					break;
+				case 1:
+					if (t->exports->v1.response_f){
+						mod_response_cbks[i]=t->exports->v1.response_f;
+						i++;
+					}
+					break;
+			}
 		}
 	}
 	return 0;
@@ -521,12 +629,30 @@ int init_child(int rank)
 
 
 	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);
+		switch(t->mod_interface_ver){
+			case 0:
+				if (t->exports->v0.init_child_f) {
+					if ((t->exports->v0.init_child_f(rank)) < 0) {
+						LOG(L_ERR, "init_child(): Initialization of child"
+									" %d failed\n", rank);
+						return -1;
+					}
+				}
+				break;
+			case 1:
+				if (t->exports->v1.init_child_f) {
+					if ((t->exports->v1.init_child_f(rank)) < 0) {
+						LOG(L_ERR, "init_child(): Initialization of child"
+									" %d failed\n", rank);
+						return -1;
+					}
+				}
+				break;
+			default:
+				BUG("bad module interface version %d in module %s [%s]\n",
+						t->mod_interface_ver, t->exports->c.name,
+						t->path);
 				return -1;
-			}
 		}
 	}
 	return 0;
@@ -547,19 +673,43 @@ static int init_mod_child( struct sr_module* m, int rank )
 		   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;
+		if (m->exports){
+			switch(m->mod_interface_ver){
+				case 0:
+					if (m->exports->v0.init_child_f) {
+						DBG("DEBUG: init_mod_child (%d): %s\n",
+								rank, m->exports->v0.name);
+						if (m->exports->v0.init_child_f(rank)<0) {
+							LOG(L_ERR, "init_mod_child(): Error while"
+										" initializing module %s\n",
+										m->exports->v0.name);
+							return -1;
+						} else {
+							/* module correctly initialized */
+							return 0;
+						}
+					}
+					/* no init function -- proceed with success */
+					return 0;
+				case 1:
+					if (m->exports->v1.init_child_f) {
+						DBG("DEBUG: init_mod_child (%d): %s\n",
+								rank, m->exports->v1.name);
+						if (m->exports->v1.init_child_f(rank)<0) {
+							LOG(L_ERR, "init_mod_child(): Error while"
+										" initializing module %s\n",
+										m->exports->v1.name);
+							return -1;
+						} else {
+							/* module correctly initialized */
+							return 0;
+						}
+					}
+					/* no init function -- proceed with success */
+					return 0;
 			}
 		}
-		/* no init function -- proceed with success */
+		/* no exports -- proceed with success */
 		return 0;
 	} else {
 		/* end of list */
@@ -590,18 +740,39 @@ static int init_mod( struct sr_module* m )
 		   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;
+		if (m->exports){
+			switch(m->mod_interface_ver){
+				case 0:
+					if ( m->exports->v0.init_f) {
+						DBG("DEBUG: init_mod: %s\n", m->exports->v0.name);
+						if (m->exports->v0.init_f()!=0) {
+							LOG(L_ERR, "init_mod(): Error while initializing"
+										" module %s\n", m->exports->v0.name);
+							return -1;
+						} else {
+							/* module correctly initialized */
+							return 0;
+						}
+					}
+					/* no init function -- proceed with success */
+					return 0;
+				case 1:
+					if ( m->exports->v1.init_f) {
+						DBG("DEBUG: init_mod: %s\n", m->exports->v1.name);
+						if (m->exports->v1.init_f()!=0) {
+							LOG(L_ERR, "init_mod(): Error while initializing"
+										" module %s\n", m->exports->v1.name);
+							return -1;
+						} else {
+							/* module correctly initialized */
+							return 0;
+						}
+					}
+					/* no init function -- proceed with success */
+					return 0;
 			}
 		}
-		/* no init function -- proceed with success */
+		/* no exports -- proceed with success */
 		return 0;
 	} else {
 		/* end of list */
@@ -619,8 +790,18 @@ int init_modules(void)
 	int i;
 	
 	for(t = modules; t; t = t->next)
-		if ( t->exports && t->exports->response_f)
-			mod_response_cbk_no++;
+		if (t->exports){
+			switch(t->mod_interface_ver){
+				case 0:
+					if (t->exports->v0.response_f)
+						mod_response_cbk_no++;
+					break;
+				case 1:
+					if (t->exports->v1.response_f)
+						mod_response_cbk_no++;
+					break;
+			}
+		}
 	mod_response_cbks=pkg_malloc(mod_response_cbk_no * 
 									sizeof(response_function));
 	if (mod_response_cbks==0){
@@ -629,9 +810,21 @@ int init_modules(void)
 		return -1;
 	}
 	for (t=modules, i=0; t && (i<mod_response_cbk_no); t=t->next){
-		if (t->exports && t->exports->response_f){
-			mod_response_cbks[i]=t->exports->response_f;
-			i++;
+		if (t->exports){
+			switch(t->mod_interface_ver){
+				case 0:
+					if (t->exports->v0.response_f){
+						mod_response_cbks[i]=t->exports->v0.response_f;
+						i++;
+					}
+					break;
+				case 1:
+					if (t->exports->v1.response_f){
+						mod_response_cbks[i]=t->exports->v1.response_f;
+						i++;
+					}
+					break;
+			}
 		}
 	}
 	

+ 174 - 17
sr_module.h

@@ -41,6 +41,14 @@
  *  2007-06-07  added PROC_INIT, called in the main process context
  *               (same as PROC_MAIN), buf guaranteed to be called before
  *               any other process is forked (andrei)
+ *  2008-11-17  sip-router version: includes some of the openser/kamailio
+ *               changes: f(void) instead of f(), free_fixup_function()
+ *              dual module interface support: ser & kamailio (andrei)
+ */
+
+/*!
+ * \file
+ * \brief modules/plug-in structures declarations
  */
 
 
@@ -53,12 +61,40 @@
 #include "route_struct.h"
 #include "str.h"
 
-typedef  struct module_exports* (*module_register)();
+/* kamailio compat */
+#include "statistics.h"
+#include "mi/mi.h"
+#include "pvar.h"
+
+
+
+#if defined KAMAILIO_MOD_INTERFACE || defined OPENSER_MOD_INTERFACE || \
+	defined MOD_INTERFACE_V1
+
+#define MODULE_INTERFACE_VER 1
+#define cmd_export_t kam_cmd_export_t
+#define module_exports kam_module_exports
+
+#elif defined SER_MOD_INTERFACE || defined MOD_INTERFACE_V0
+
+#define MODULE_INTERFACE_VER 0
+#define cmd_export_t ser_cmd_export_t
+#define module_exports ser_module_exports
+
+#else
+
+/* do nothing for core */
+
+#endif
+
+typedef  struct module_exports* (*module_register)(void);
 typedef  int (*cmd_function)(struct sip_msg*, char*, char*);
 typedef  int (*fixup_function)(void** param, int param_no);
+typedef  int (*free_fixup_function)(void** param, int param_no);
 typedef  int (*response_function)(struct sip_msg*);
 typedef  void (*onbreak_function)(struct sip_msg*);
-typedef void (*destroy_function)();
+typedef void (*destroy_function)(void);
+
 typedef int (*init_function)(void);
 typedef int (*child_init_function)(int rank);
 
@@ -82,7 +118,8 @@ typedef int (*param_func_t)( modparam_t type, void* val);
 #define FAILURE_ROUTE 2  /* Function can be used in reply route blocks */
 #define ONREPLY_ROUTE 4  /* Function can be used in on_reply */
 #define BRANCH_ROUTE  8  /* Function can be used in branch_route blocks */
-#define ONSEND_ROUTE   16  /* Function can be used in onsend_route blocks */
+#define ONSEND_ROUTE 16  /* Function can be used in onsend_route blocks */
+#define ERROR_ROUTE  32  /* Function can be used in an error route */ 
 
 /* Macros - used as rank in child_init function */
 #define PROC_MAIN      0  /* Main ser process */
@@ -107,11 +144,24 @@ typedef int (*param_func_t)( modparam_t type, void* val);
 
 #define PROC_MIN PROC_NOCHLDINIT /* Minimum process rank */
 
+
+#define DEFAULT_DLFLAGS	0 /* value that signals to module loader to
+							use default dlopen flags in Kamailio */
+#ifndef RTLD_NOW
+/* for openbsd */
+#define RTLD_NOW DL_LAZY
+#endif
+
+#define KAMAILIO_DLFLAGS	RTLD_NOW
+
+
 #define MODULE_VERSION \
 	char *module_version=SER_FULL_VERSION; \
-	char *module_flags=SER_COMPILE_FLAGS;
+	char *module_flags=SER_COMPILE_FLAGS; \
+	unsigned int module_interface_ver=MODULE_INTERFACE_VER; 
 
-struct cmd_export_ {
+/* ser version */
+struct ser_cmd_export_ {
 	char* name;             /* null terminated command name */
 	cmd_function function;  /* pointer to the corresponding function */
 	int param_no;           /* number of parameters used by the function */
@@ -121,6 +171,29 @@ struct cmd_export_ {
 };
 
 
+/* kamailo/openser version */
+struct kam_cmd_export_ {
+	char* name;             /* null terminated command name */
+	cmd_function function;  /* pointer to the corresponding function */
+	int param_no;           /* number of parameters used by the function */
+	fixup_function fixup;   /* pointer to the function called to "fix" the
+							   parameters */
+	free_fixup_function free_fixup; /* function called to free the "fixed"
+									   parameters */
+	int flags;              /* Function flags */
+};
+
+
+/* members situated at the same place in memory in both ser & kamailio
+   cmd_export */
+struct cmd_export_common_ {
+	char* name;
+	cmd_function function; 
+	int param_no;
+	fixup_function fixup;
+};
+
+
 struct param_export_ {
 	char* name;             /* null terminated param. name */
 	modparam_t type;        /* param. type */
@@ -157,18 +230,26 @@ typedef struct fparam {
 } fparam_t;
 
 
-typedef struct cmd_export_ cmd_export_t;
-typedef struct param_export_ param_export_t;
+typedef struct param_export_ param_export_t;  
+typedef struct ser_cmd_export_ ser_cmd_export_t;
+typedef struct kam_cmd_export_ kam_cmd_export_t;
+typedef struct cmd_export_common_ cmd_export_common_t;
 
-struct module_exports {
-	char* name;                     /* null terminated module name */
+union cmd_export_u{
+	cmd_export_common_t c; /* common members for everybody */
+	ser_cmd_export_t v0;
+	kam_cmd_export_t v1;
+};
 
-	cmd_export_t* cmds;             /* null terminated array of the exported
+
+/* ser module exports version */
+struct ser_module_exports {
+	char* name;                     /* null terminated module name */
+	ser_cmd_export_t* cmds;         /* null terminated array of the exported
 									   commands */
 	rpc_export_t* rpc_methods;      /* null terminated array of exported rpc methods */
 	param_export_t* params;         /* null terminated array of the exported
 									   module parameters */
-
 	init_function init_f;           /* Initialization function */
 	response_function response_f;   /* function used for responses,
 									   returns yes or no; can be null */
@@ -181,10 +262,69 @@ struct module_exports {
 };
 
 
+/* kamailio/openser proc_export (missing from ser) */
+typedef void (*mod_proc)(int no);
+
+typedef int (*mod_proc_wrapper)(void);
+
+struct proc_export_ {
+	char *name;
+	mod_proc_wrapper pre_fork_function;
+	mod_proc_wrapper post_fork_function;
+	mod_proc function;
+	unsigned int no;
+};
+
+typedef struct proc_export_ proc_export_t;
+
+
+/* kamailio/openser module exports version */
+struct kam_module_exports {
+	char* name;                     /* null terminated module name */
+	unsigned int dlflags;			/*!< flags for dlopen  */
+	kam_cmd_export_t* cmds;			/* null terminated array of the exported
+									   commands */
+	param_export_t* params;			/* null terminated array of the exported
+									   module parameters */
+	stat_export_t* stats;			/*!< null terminated array of the exported
+									  module statistics */
+	mi_export_t* mi_cmds;			/*!< null terminated array of the exported
+									  MI functions */
+	pv_export_t* items;				/*!< null terminated array of the exported
+									   module items (pseudo-variables) */
+	proc_export_t* procs;			/*!< null terminated array of the
+									  additional processes required by the
+									  module */
+	init_function init_f;           /* Initialization function */
+	response_function response_f;   /* function used for responses,
+									   returns yes or no; can be null */
+	destroy_function destroy_f;     /* function called when the module should
+									   be "destroyed", e.g: on ser exit;
+									   can be null */
+	child_init_function init_child_f;  /* function called by all processes
+										  after the fork */
+};
+
+
+
+/* module exports in the same place in memory in both ser & kamailio */
+struct module_exports_common{
+	char* name;
+};
+
+
+union module_exports_u {
+		struct module_exports_common c; /*common members for all the versions*/
+		struct ser_module_exports v0;
+		struct kam_module_exports v1;
+};
+
+
 struct sr_module{
 	char* path;
 	void* handle;
-	struct module_exports* exports;
+	unsigned int mod_interface_ver;
+	union module_exports_u* exports;
 	struct sr_module* next;
 };
 
@@ -193,19 +333,20 @@ extern struct sr_module* modules; /* global module list*/
 extern response_function* mod_response_cbks;/* response callback array */
 extern int mod_response_cbk_no;    /* size of reponse callbacks array */
 
-int register_builtin_modules();
-int register_module(struct module_exports*, char*,  void*);
+int register_builtin_modules(void);
+/*int register_module(unsigned , struct module_exports*, char*,  void*);*/
 int load_module(char* path);
-cmd_export_t* find_export_record(char* name, int param_no, int flags);
+union cmd_export_u* find_export_record(char* name, int param_no, int flags,
+										unsigned *ver);
 cmd_function find_export(char* name, int param_no, int flags);
 cmd_function find_mod_export(char* mod, char* name, int param_no, int flags);
 rpc_export_t* find_rpc_export(char* name, int flags);
-void destroy_modules();
+void destroy_modules(void);
 int init_child(int rank);
 int init_modules(void);
 struct sr_module* find_module_by_name(char* mod);
 
-/*
+/*! \brief
  * Find a parameter with given type and return it's
  * address in memory
  * If there is no such parameter, NULL is returned
@@ -329,4 +470,20 @@ int get_int_fparam(int* dst, struct sip_msg* msg, fparam_t* param);
  * @return: 0 for success, negative on error.
  */
 int get_regex_fparam(regex_t *dst, struct sip_msg* msg, fparam_t* param);
+
+
+/* functions needed for kamailio/openser compatibility */
+
+/*! \brief Check if module is loaded
+ * \return Returns 1 if the module with name 'name' is loaded, and zero otherwise. */
+int module_loaded(char *name);
+
+/*! \brief Counts the additional the number of processes
+ requested by modules */
+int count_module_procs(void);
+
+
+/*! \brief Forks and starts the additional processes required by modules */
+int start_module_procs(void);
+
 #endif /* sr_module_h */

+ 72 - 0
statistics.h

@@ -0,0 +1,72 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2008 iptelorg GmbH
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/*
+ * statistics compatibility wrapper for kamailio
+ * for now it doesn't do anything
+ * (obsolete, do not use anymore)
+ *
+ * History:
+ * --------
+ *  2008-11-17  initial version compatible with kamailio statistics.h (andrei)
+ */
+
+#ifndef _STATISTICS_H_
+#define _STATISTICS_H_
+
+#include "str.h"
+
+#define STAT_NO_RESET  1
+#define STAT_NO_SYNC   2
+#define STAT_SHM_NAME  4
+#define STAT_IS_FUNC   8
+
+
+
+typedef unsigned int stat_val;
+typedef unsigned long (*stat_function)(void);
+
+typedef struct stat_var_{
+	unsigned int mod_idx;
+	str name;
+	int flags;
+	union{
+		stat_val *val;
+		stat_function f;
+	}u;
+	struct stat_var_ *hnext;
+	struct stat_var_ *lnext;
+} stat_var;
+
+
+typedef struct stat_export_ {
+	char* name;                /* null terminated statistic name */
+	int flags;                 /* flags */
+	stat_var** stat_pointer;   /* pointer to the variable's shm mem location */
+} stat_export_t;
+
+#define get_stat(name)  0
+#define get_stat_val(v) 0
+#define update_stat(v, n)
+#define reset_stat(v)
+#define if_update_stat (cond, v, n)
+
+#ifdef STATISTICS
+#warning "sorry sip-router does not support STATISTICS"
+#endif
+
+#endif /* _STATISTICS_H_ */