Răsfoiți Sursa

dual module interface support: ser and kamailio

Added support for both ser and kamailio module interfaces: a module
just needs to define its module interface prior to including sr_module.h
(e.g. by adding EXTRA_DEFS+=-DSER_MOD_INTERFACE for a ser module or
 EXTRA_DEFS+=-DKAMAILIO_MOD_INTERFACE to the module Makefile).
This way ser and kamailio modules can be mixed at will with only one
Makefile change.
Under the hood, now each module declares its interface version (by
exporting a global symbol named module_interface_ver) and the internal
module loader and module export finder were updated to take the interface
version into account.
Internally the core works now with a generic module_export_u union.
Andrei Pelinescu-Onciul 17 ani în urmă
părinte
comite
2873d3842c
7 a modificat fișierele cu 482 adăugiri și 130 ștergeri
  1. 8 5
      action.c
  2. 6 2
      cfg.y
  3. 4 2
      core_cmd.c
  4. 7 5
      modparam.c
  5. 4 4
      route.c
  6. 293 100
      sr_module.c
  7. 160 12
      sr_module.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]);

+ 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;

+ 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;
+			}
 		}
 	}
 	

+ 160 - 12
sr_module.h

@@ -43,6 +43,7 @@
  *               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)
  */
 
 /*!
@@ -60,6 +61,32 @@
 #include "route_struct.h"
 #include "str.h"
 
+/* 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);
@@ -91,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 */
@@ -116,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 */
@@ -130,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 */
@@ -166,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;
+
+union cmd_export_u{
+	cmd_export_common_t c; /* common members for everybody */
+	ser_cmd_export_t v0;
+	kam_cmd_export_t v1;
+};
 
-struct module_exports {
-	char* name;                     /* null terminated module name */
 
-	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 */
@@ -190,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;
 };
 
@@ -203,9 +334,10 @@ extern response_function* mod_response_cbks;/* response callback array */
 extern int mod_response_cbk_no;    /* size of reponse callbacks array */
 
 int register_builtin_modules(void);
-int register_module(struct module_exports*, char*,  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);
@@ -338,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 */