소스 검색

Merge branch 'master' of ssh://git.sip-router.org/sip-router

Carsten Bock 14 년 전
부모
커밋
905894f66f
90개의 변경된 파일2576개의 추가작업 그리고 679개의 파일을 삭제
  1. 9 2
      Makefile
  2. 4 1
      Makefile.defs
  3. 2 0
      cfg.lex
  4. 3 0
      cfg.y
  5. 4 1
      cfg_core.c
  6. 1 0
      cfg_core.h
  7. 51 2
      daemonize.c
  8. 1 1
      daemonize.h
  9. 36 0
      dprint.c
  10. 8 3
      dprint.h
  11. 20 1
      etc/kamailio.cfg
  12. 1 1
      forward.c
  13. 12 1
      lib/kcore/parse_sst.c
  14. 1 0
      lib/kcore/parse_sst.h
  15. 21 0
      lib/kcore/parse_supported.c
  16. 3 7
      lib/kcore/parse_supported.h
  17. 1 1
      lib/srdb1/db_id.c
  18. 3 3
      lvalue.c
  19. 3 0
      modules/dialplan/README
  20. 1 1
      modules/dialplan/dialplan.c
  21. 4 0
      modules/dialplan/doc/dialplan_admin.xml
  22. 29 15
      modules/dialplan/dp_repl.c
  23. 4 4
      modules/pipelimit/README
  24. 4 4
      modules/pipelimit/doc/pipelimit_admin.xml
  25. 14 0
      modules/sdpops/Makefile
  26. 137 0
      modules/sdpops/README
  27. 4 0
      modules/sdpops/doc/Makefile
  28. 37 0
      modules/sdpops/doc/sdpops.xml
  29. 145 0
      modules/sdpops/doc/sdpops_admin.xml
  30. 413 0
      modules/sdpops/sdpops_mod.c
  31. 1 1
      modules/tm/tm.c
  32. 2 2
      modules_k/dialog/dialog.c
  33. 6 11
      modules_k/dialog/dlg_handlers.c
  34. 1 2
      modules_k/dialog/dlg_handlers.h
  35. 10 9
      modules_k/dialog/dlg_hash.c
  36. 3 3
      modules_k/dialog/doc/dialog_admin.xml
  37. 12 3
      modules_k/dispatcher/dispatch.c
  38. 2 2
      modules_k/dispatcher/dispatcher.c
  39. 2 2
      modules_k/dispatcher/doc/dispatcher.xml
  40. 1 1
      modules_k/dispatcher/doc/dispatcher_admin.xml
  41. 2 2
      modules_k/htable/README
  42. 1 1
      modules_k/htable/doc/htable_admin.xml
  43. 38 0
      modules_k/kex/README
  44. 47 0
      modules_k/kex/doc/kex_admin.xml
  45. 23 0
      modules_k/kex/kex_mod.c
  46. 9 9
      modules_k/nathelper/nathelper.c
  47. 21 0
      modules_k/permissions/doc/permissions_admin.xml
  48. 33 23
      modules_k/permissions/hash.c
  49. 2 0
      modules_k/permissions/permissions.c
  50. 2 0
      modules_k/permissions/permissions.h
  51. 41 37
      modules_k/permissions/trusted.c
  52. 6 0
      modules_k/pv/pv.c
  53. 16 0
      modules_k/pv/pv_core.c
  54. 3 0
      modules_k/pv/pv_core.h
  55. 9 0
      modules_k/pv/pv_time.c
  56. 2 0
      modules_k/pv/pv_time.h
  57. 77 2
      modules_k/pv/pv_trans.c
  58. 1 1
      modules_k/pv/pv_trans.h
  59. 4 2
      modules_k/pv/pv_xavp.c
  60. 196 142
      modules_k/regex/README
  61. 23 9
      modules_k/regex/doc/regex_admin.xml
  62. 13 7
      modules_k/regex/regex_mod.c
  63. 41 5
      modules_k/siputils/README
  64. 27 0
      modules_k/siputils/checks.c
  65. 10 0
      modules_k/siputils/checks.h
  66. 45 5
      modules_k/siputils/doc/siputils_admin.xml
  67. 39 25
      modules_k/siputils/siputils.c
  68. 59 12
      modules_k/sqlops/README
  69. 74 5
      modules_k/sqlops/doc/sqlops_admin.xml
  70. 131 0
      modules_k/sqlops/sql_api.c
  71. 4 0
      modules_k/sqlops/sql_api.h
  72. 61 0
      modules_k/sqlops/sqlops.c
  73. 17 0
      modules_k/tmx/README
  74. 21 0
      modules_k/tmx/doc/tmx_admin.xml
  75. 21 0
      modules_k/tmx/tmx_mod.c
  76. 68 18
      modules_k/uac/README
  77. 101 3
      modules_k/uac/doc/uac_admin.xml
  78. 56 2
      modules_k/uac/uac_reg.c
  79. 80 87
      parser/hf.c
  80. 36 11
      parser/hf.h
  81. 1 1
      parser/msg_parser.c
  82. 6 0
      pkg/kamailio/deb/debian/kamailio.default
  83. 44 12
      pkg/kamailio/deb/debian/kamailio.init
  84. 2 1
      receive.c
  85. 10 143
      ser_stun.c
  86. 3 6
      ser_stun.h
  87. 2 2
      sr_module.c
  88. 4 2
      tcp_read.c
  89. 5 3
      utils/kamctl/kamdbctl.base
  90. 23 17
      xavp.c

+ 9 - 2
Makefile

@@ -772,12 +772,16 @@ utils:
 dbg: sip-router
 dbg: sip-router
 	gdb -command debug.gdb
 	gdb -command debug.gdb
 
 
+.PHONY: makefile_vars makefile-vars
+makefile_vars makefile-vars:
+	echo "FLAVOUR?=$(FLAVOUR)" > Makefile.vars
+
 .PHONY: tar
 .PHONY: tar
 .PHONY: dist
 .PHONY: dist
 
 
 dist: tar
 dist: tar
 
 
-tar: $(auto_gen_keep)
+tar: makefile_vars $(auto_gen_keep)
 	$(TAR) -C .. \
 	$(TAR) -C .. \
 		--exclude=$(notdir $(CURDIR))/test* \
 		--exclude=$(notdir $(CURDIR))/test* \
 		--exclude=$(notdir $(CURDIR))/tmp* \
 		--exclude=$(notdir $(CURDIR))/tmp* \
@@ -1143,7 +1147,7 @@ maintainer-clean: modules=$(modules_all)
 proper realclean distclean maintainer-clean: clean_cfg
 proper realclean distclean maintainer-clean: clean_cfg
 
 
 # on maintainer clean, remove also the configured module list
 # on maintainer clean, remove also the configured module list
-maintainer-clean: clean_modules_cfg
+maintainer-clean: clean_modules_cfg clean_makefile_vars
 
 
 .PHONY: proper-all realclean-all distclean-all
 .PHONY: proper-all realclean-all distclean-all
 proper-all realclean-all distclean-all: cmodules=$(all_modules_lst)
 proper-all realclean-all distclean-all: cmodules=$(all_modules_lst)
@@ -1158,6 +1162,9 @@ clean_cfg clean-cfg:
 clean_modules_cfg clean-modules-cfg:
 clean_modules_cfg clean-modules-cfg:
 	rm -f modules.lst
 	rm -f modules.lst
 
 
+.PHONY: clean_makefile_vars clean-makefile-vars
+	rm -f Makefile.vars
+
 .PHONY: dbschema
 .PHONY: dbschema
 dbschema:
 dbschema:
 	-@echo "Build database schemas"
 	-@echo "Build database schemas"

+ 4 - 1
Makefile.defs

@@ -117,6 +117,8 @@ ifeq ($(quiet),verbose)
 $(info normal Makefile.defs exec)
 $(info normal Makefile.defs exec)
 endif # verbose
 endif # verbose
 
 
+-include Makefile.vars
+
 # usage: $(call set_if_empty,VAR,value)
 # usage: $(call set_if_empty,VAR,value)
 set_if_empty=$(if $($(1)),,$(eval override $(1)=$(2)))
 set_if_empty=$(if $($(1)),,$(eval override $(1)=$(2)))
 
 
@@ -160,7 +162,7 @@ INSTALL_FLAVOUR=$(FLAVOUR)
 VERSION = 3
 VERSION = 3
 PATCHLEVEL = 2
 PATCHLEVEL = 2
 SUBLEVEL =  0
 SUBLEVEL =  0
-EXTRAVERSION = -dev2
+EXTRAVERSION = -dev3
 
 
 # memory debugger switcher
 # memory debugger switcher
 # 0 - off (release mode)
 # 0 - off (release mode)
@@ -656,6 +658,7 @@ C_DEFS= $(extra_defs) \
 	 -DUSE_DNS_FAILOVER \
 	 -DUSE_DNS_FAILOVER \
 	 -DUSE_DST_BLACKLIST \
 	 -DUSE_DST_BLACKLIST \
 	 -DUSE_NAPTR \
 	 -DUSE_NAPTR \
+	 -DWITH_XAVP \
 	 #-DUSE_DNS_CACHE_STATS \
 	 #-DUSE_DNS_CACHE_STATS \
 	 #-DUSE_DST_BLACKLIST_STATS \
 	 #-DUSE_DST_BLACKLIST_STATS \
 	 #-DDNS_WATCHDOG_SUPPORT \
 	 #-DDNS_WATCHDOG_SUPPORT \

+ 2 - 0
cfg.lex

@@ -386,6 +386,7 @@ SYN_BRANCH syn_branch
 MEMLOG		"memlog"|"mem_log"
 MEMLOG		"memlog"|"mem_log"
 MEMDBG		"memdbg"|"mem_dbg"
 MEMDBG		"memdbg"|"mem_dbg"
 MEMSUM		"mem_summary"
 MEMSUM		"mem_summary"
+CORELOG		"corelog"|"core_log"
 SIP_WARNING sip_warning
 SIP_WARNING sip_warning
 SERVER_SIGNATURE server_signature
 SERVER_SIGNATURE server_signature
 SERVER_HEADER server_header
 SERVER_HEADER server_header
@@ -747,6 +748,7 @@ SUBST       subst
 <INITIAL>{MEMLOG}	{ count(); yylval.strval=yytext; return MEMLOG; }
 <INITIAL>{MEMLOG}	{ count(); yylval.strval=yytext; return MEMLOG; }
 <INITIAL>{MEMDBG}	{ count(); yylval.strval=yytext; return MEMDBG; }
 <INITIAL>{MEMDBG}	{ count(); yylval.strval=yytext; return MEMDBG; }
 <INITIAL>{MEMSUM}	{ count(); yylval.strval=yytext; return MEMSUM; }
 <INITIAL>{MEMSUM}	{ count(); yylval.strval=yytext; return MEMSUM; }
+<INITIAL>{CORELOG}	{ count(); yylval.strval=yytext; return CORELOG; }
 <INITIAL>{SIP_WARNING}	{ count(); yylval.strval=yytext; return SIP_WARNING; }
 <INITIAL>{SIP_WARNING}	{ count(); yylval.strval=yytext; return SIP_WARNING; }
 <INITIAL>{USER}		{ count(); yylval.strval=yytext; return USER; }
 <INITIAL>{USER}		{ count(); yylval.strval=yytext; return USER; }
 <INITIAL>{GROUP}	{ count(); yylval.strval=yytext; return GROUP; }
 <INITIAL>{GROUP}	{ count(); yylval.strval=yytext; return GROUP; }

+ 3 - 0
cfg.y

@@ -434,6 +434,7 @@ extern char *finame;
 %token MEMLOG
 %token MEMLOG
 %token MEMDBG
 %token MEMDBG
 %token MEMSUM
 %token MEMSUM
+%token CORELOG
 %token SIP_WARNING
 %token SIP_WARNING
 %token SERVER_SIGNATURE
 %token SERVER_SIGNATURE
 %token SERVER_HEADER
 %token SERVER_HEADER
@@ -918,6 +919,8 @@ assign_stm:
 	| MEMDBG EQUAL error { yyerror("int value expected"); }
 	| MEMDBG EQUAL error { yyerror("int value expected"); }
 	| MEMSUM EQUAL intno { default_core_cfg.mem_summary=$3; }
 	| MEMSUM EQUAL intno { default_core_cfg.mem_summary=$3; }
 	| MEMSUM EQUAL error { yyerror("int value expected"); }
 	| MEMSUM EQUAL error { yyerror("int value expected"); }
+	| CORELOG EQUAL intno { default_core_cfg.corelog=$3; }
+	| CORELOG EQUAL error { yyerror("int value expected"); }
 	| SIP_WARNING EQUAL NUMBER { sip_warning=$3; }
 	| SIP_WARNING EQUAL NUMBER { sip_warning=$3; }
 	| SIP_WARNING EQUAL error { yyerror("boolean value expected"); }
 	| SIP_WARNING EQUAL error { yyerror("boolean value expected"); }
 	| USER EQUAL STRING     {
 	| USER EQUAL STRING     {

+ 4 - 1
cfg_core.c

@@ -119,8 +119,9 @@ struct cfg_group_core default_core_cfg = {
 	-1,  /**< udp4_raw_ttl (auto detect by default) */
 	-1,  /**< udp4_raw_ttl (auto detect by default) */
 	0,  /*!< force_rport */
 	0,  /*!< force_rport */
 	L_DBG, /*!< memlog */
 	L_DBG, /*!< memlog */
-	3 /*!< mem_summary -flags: 0 off, 1 pkg_status, 2 shm_status,
+	3, /*!< mem_summary -flags: 0 off, 1 pkg_status, 2 shm_status,
 		4 pkg_sums, 8 shm_sums */
 		4 pkg_sums, 8 shm_sums */
+	L_ERR /*!< corelog */
 };
 };
 
 
 void	*core_cfg = &default_core_cfg;
 void	*core_cfg = &default_core_cfg;
@@ -307,5 +308,7 @@ cfg_def_t core_cfg_def[] = {
 		" 2 - dump all the shm used blocks (status),"
 		" 2 - dump all the shm used blocks (status),"
 		" 4 - summary of pkg used blocks,"
 		" 4 - summary of pkg used blocks,"
 		" 8 - summary of shm used blocks" },
 		" 8 - summary of shm used blocks" },
+	{"corelog",		CFG_VAR_INT|CFG_ATOMIC,	0, 0, 0, 0,
+		"log level for non-critical core error messages"},
 	{0, 0, 0, 0, 0, 0}
 	{0, 0, 0, 0, 0, 0}
 };
 };

+ 1 - 0
cfg_core.h

@@ -108,6 +108,7 @@ struct cfg_group_core {
 	int force_rport; /*!< if set rport will always be forced*/
 	int force_rport; /*!< if set rport will always be forced*/
 	int memlog; /*!< log level for memory status/summary info */
 	int memlog; /*!< log level for memory status/summary info */
 	int mem_summary; /*!< display memory status/summary info on exit */
 	int mem_summary; /*!< display memory status/summary info on exit */
+	int corelog; /*!< log level for non-critcal core error messages */
 };
 };
 
 
 extern struct cfg_group_core default_core_cfg;
 extern struct cfg_group_core default_core_cfg;

+ 51 - 2
daemonize.c

@@ -58,6 +58,10 @@
 #include <pwd.h>
 #include <pwd.h>
 #include <grp.h>
 #include <grp.h>
 
 
+#ifdef __OS_linux
+#include <sys/prctl.h>
+#endif
+
 #ifdef HAVE_SCHED_SETSCHEDULER
 #ifdef HAVE_SCHED_SETSCHEDULER
 #include <sched.h>
 #include <sched.h>
 #endif
 #endif
@@ -202,6 +206,40 @@ void daemon_status_no_wait()
 }
 }
 
 
 
 
+/**
+ * enable dumpable flag for core dumping after setuid() & friends
+ * @return 0 when no critical error occured, -1 on such error
+ */
+int enable_dumpable(void)
+{
+#ifdef __OS_linux
+	struct rlimit lim;
+	/* re-enable core dumping on linux after setuid() & friends */
+	if(disable_core_dump==0) {
+		LM_DBG("trying enable core dumping...\n");
+		if(prctl(PR_GET_DUMPABLE, 0, 0, 0, 0)<=0) {
+			LM_DBG("core dumping is disabled now...\n");
+			if(prctl(PR_SET_DUMPABLE, 1, 0, 0, 0)<0) {
+				LM_WARN("cannot re-enable core dumping!\n");
+			} else {
+				LM_DBG("core dumping has just been enabled...\n");
+				if (getrlimit(RLIMIT_CORE, &lim)<0){
+					LOG(L_CRIT, "cannot get the maximum core size: %s\n",
+							strerror(errno));
+					return -1;
+				} else {
+					DBG("current core file limit: %lu (max: %lu)\n",
+						(unsigned long)lim.rlim_cur, (unsigned long)lim.rlim_max);
+				}
+			}
+		} else {
+			LM_DBG("core dumping is enabled now (%d)...\n",
+					prctl(PR_GET_DUMPABLE, 0, 0, 0, 0));
+		}
+	}
+#endif
+	return 0;
+}
 
 
 /** daemon init.
 /** daemon init.
  *@param name - daemon name used for logging (used when opening syslog).
  *@param name - daemon name used for logging (used when opening syslog).
@@ -289,6 +327,10 @@ int daemonize(char*  name,  int status_wait)
 			exit(0);
 			exit(0);
 		}
 		}
 	}
 	}
+
+	if(enable_dumpable()<0)
+		goto error;
+
 	/* added by noh: create a pid file for the main process */
 	/* added by noh: create a pid file for the main process */
 	if (pid_file!=0){
 	if (pid_file!=0){
 		
 		
@@ -415,6 +457,10 @@ int do_suid()
 			goto error;
 			goto error;
 		}
 		}
 	}
 	}
+
+	if(enable_dumpable()<0)
+		goto error;
+
 	return 0;
 	return 0;
 error:
 error:
 	return -1;
 	return -1;
@@ -477,7 +523,7 @@ error:
 
 
 
 
 /*! \brief enable core dumps */
 /*! \brief enable core dumps */
-int set_core_dump(int enable, int size)
+int set_core_dump(int enable, long unsigned int size)
 {
 {
 	struct rlimit lim;
 	struct rlimit lim;
 	struct rlimit newlim;
 	struct rlimit newlim;
@@ -510,8 +556,11 @@ int set_core_dump(int enable, int size)
 						(unsigned long)lim.rlim_max);
 						(unsigned long)lim.rlim_max);
 			}
 			}
 			goto error; /* it's an error we haven't got the size we wanted*/
 			goto error; /* it's an error we haven't got the size we wanted*/
+		}else{
+			newlim.rlim_cur=lim.rlim_cur;
+			newlim.rlim_max=lim.rlim_max;
+			goto done; /*nothing to do */
 		}
 		}
-		goto done; /*nothing to do */
 	}else{
 	}else{
 		/* disable */
 		/* disable */
 		newlim.rlim_cur=0;
 		newlim.rlim_cur=0;

+ 1 - 1
daemonize.h

@@ -30,7 +30,7 @@
 int daemonize(char* name, int daemon_status_fd_input);
 int daemonize(char* name, int daemon_status_fd_input);
 int do_suid();
 int do_suid();
 int increase_open_fds(int target);
 int increase_open_fds(int target);
-int set_core_dump(int enable, int size);
+int set_core_dump(int enable, long unsigned int size);
 int mem_lock_pages();
 int mem_lock_pages();
 int set_rt_prio(int prio, int policy);
 int set_rt_prio(int prio, int policy);
 
 

+ 36 - 0
dprint.c

@@ -104,3 +104,39 @@ int log_facility_fixup(void *handle, str *gname, str *name, void **val)
 	*val = (void *)(long)i;
 	*val = (void *)(long)i;
 	return 0;
 	return 0;
 }
 }
+
+
+/**
+ * per process debug log level (local)
+ */
+
+/* value for unset local log level  */
+#define UNSET_LOCAL_DEBUG_LEVEL	-255
+
+/* the local debug log level */
+static int _local_debug_level = UNSET_LOCAL_DEBUG_LEVEL;
+
+/**
+ * @brief return the log level - the local one if it set,
+ *   otherwise the global value
+ */
+int get_debug_level(void) {
+	return (_local_debug_level != UNSET_LOCAL_DEBUG_LEVEL) ?
+				_local_debug_level : cfg_get(core, core_cfg, debug);
+}
+
+/**
+ * @brief set the local debug log level
+ */
+void set_local_debug_level(int level)
+{
+	_local_debug_level = level;
+}
+
+/**
+ * @brief reset the local debug log level
+ */
+void reset_local_debug_level(void)
+{
+	_local_debug_level = UNSET_LOCAL_DEBUG_LEVEL;
+}

+ 8 - 3
dprint.h

@@ -118,7 +118,12 @@ struct log_level_info {
 	int syslog_level;
 	int syslog_level;
 };
 };
 
 
-#define is_printable(level) (cfg_get(core, core_cfg, debug)>=(level))
+/** @brief per process debug level handling */
+int get_debug_level(void);
+void set_local_debug_level(int level);
+void reset_local_debug_level(void);
+
+#define is_printable(level) (get_debug_level()>=(level))
 extern struct log_level_info log_level_info[];
 extern struct log_level_info log_level_info[];
 extern char *log_name;
 extern char *log_name;
 
 
@@ -167,7 +172,7 @@ int log_facility_fixup(void *handle, str *gname, str *name, void **val);
 #	ifdef __SUNPRO_C
 #	ifdef __SUNPRO_C
 #		define LOG_(facility, level, prefix, fmt, ...) \
 #		define LOG_(facility, level, prefix, fmt, ...) \
 			do { \
 			do { \
-				if (unlikely(cfg_get(core, core_cfg, debug) >= (level) && \
+				if (unlikely(get_debuglevel() >= (level) && \
 						DPRINT_NON_CRIT)) { \
 						DPRINT_NON_CRIT)) { \
 					DPRINT_CRIT_ENTER; \
 					DPRINT_CRIT_ENTER; \
 					if (likely(((level) >= L_ALERT) && ((level) <= L_DBG))){ \
 					if (likely(((level) >= L_ALERT) && ((level) <= L_DBG))){ \
@@ -229,7 +234,7 @@ int log_facility_fixup(void *handle, str *gname, str *name, void **val);
 #	else /* ! __SUNPRO_C */
 #	else /* ! __SUNPRO_C */
 #		define LOG_(facility, level, prefix, fmt, args...) \
 #		define LOG_(facility, level, prefix, fmt, args...) \
 			do { \
 			do { \
-				if (cfg_get(core, core_cfg, debug) >= (level) && \
+				if (get_debug_level() >= (level) && \
 						DPRINT_NON_CRIT) { \
 						DPRINT_NON_CRIT) { \
 					DPRINT_CRIT_ENTER; \
 					DPRINT_CRIT_ENTER; \
 					if (likely(((level) >= L_ALERT) && ((level) <= L_DBG))){ \
 					if (likely(((level) >= L_ALERT) && ((level) <= L_DBG))){ \

+ 20 - 1
etc/kamailio.cfg

@@ -241,6 +241,10 @@ loadmodule "pike.so"
 loadmodule "xmlrpc.so"
 loadmodule "xmlrpc.so"
 #!endif
 #!endif
 
 
+#!ifdef WITH_DEBUG
+loadmodule "debugger.so"
+#!endif
+
 # ----------------- setting module-specific parameters ---------------
 # ----------------- setting module-specific parameters ---------------
 
 
 
 
@@ -388,6 +392,11 @@ modparam("xmlrpc", "route", "XMLRPC");
 modparam("xmlrpc", "url_match", "^/RPC")
 modparam("xmlrpc", "url_match", "^/RPC")
 #!endif
 #!endif
 
 
+#!ifdef WITH_DEBUG
+# ----- debugger params -----
+modparam("debugger", "cfgtrace", 1)
+#!endif
+
 ####### Routing Logic ########
 ####### Routing Logic ########
 
 
 
 
@@ -668,10 +677,20 @@ route[AUTH] {
 			}
 			}
 			if (is_method("PUBLISH"))
 			if (is_method("PUBLISH"))
 			{
 			{
-				if ($au!=$tU) {
+				if ($au!=$fU || $au!=$tU) {
 					sl_send_reply("403","Forbidden auth ID");
 					sl_send_reply("403","Forbidden auth ID");
 					exit;
 					exit;
 				}
 				}
+				if ($au!=$rU) {
+					sl_send_reply("403","Forbidden R-URI");
+					exit;
+				}
+#!ifdef WITH_MULTIDOMAIN
+				if ($fd!=$rd) {
+					sl_send_reply("403","Forbidden R-URI domain");
+					exit;
+				}
+#!endif
 			} else {
 			} else {
 				if ($au!=$fU) {
 				if ($au!=$fU) {
 					sl_send_reply("403","Forbidden auth ID");
 					sl_send_reply("403","Forbidden auth ID");

+ 1 - 1
forward.c

@@ -783,7 +783,7 @@ int forward_reply(struct sip_msg* msg)
 		|| (msg->via2==0) || (msg->via2->error!=PARSE_OK))
 		|| (msg->via2==0) || (msg->via2->error!=PARSE_OK))
 	{
 	{
 		/* no second via => error */
 		/* no second via => error */
-		LOG(L_INFO, "broken reply to forward - no 2nd via\n");
+		LOG(L_DBG, "broken reply to forward - no 2nd via\n");
 		goto error;
 		goto error;
 	}
 	}
 
 

+ 12 - 1
lib/kcore/parse_sst.c

@@ -68,6 +68,16 @@ malloc_session_expires( void )
 	return se;
 	return se;
 }
 }
 
 
+/**
+ * wrapper to free the content of parsed session-expires header
+ */
+void hf_free_session_expires(void *parsed)
+{
+	struct session_expires *se;
+	se = (struct session_expires*)parsed;
+	free_session_expires(se);
+}
+
 
 
 void
 void
 free_session_expires( struct session_expires *se )
 free_session_expires( struct session_expires *se )
@@ -84,7 +94,7 @@ parse_session_expires_body( struct hdr_field *hf )
 	int pos = 0;
 	int pos = 0;
 	int len = hf->body.len;
 	int len = hf->body.len;
 	char *q;
 	char *q;
-	struct session_expires se = { 0, sst_refresher_unspecified };
+	struct session_expires se = { 0, 0, sst_refresher_unspecified };
 	unsigned tok;
 	unsigned tok;
 
 
 	if ( !p || len <= 0 ) {
 	if ( !p || len <= 0 ) {
@@ -165,6 +175,7 @@ parse_session_expires_body( struct hdr_field *hf )
 		LM_ERR(" out of pkg memory\n" );
 		LM_ERR(" out of pkg memory\n" );
 		return parse_sst_out_of_mem;
 		return parse_sst_out_of_mem;
 	}
 	}
+	se.hfree = hf_free_session_expires;
 	*((struct session_expires *)hf->parsed) = se;
 	*((struct session_expires *)hf->parsed) = se;
 
 
 	return parse_sst_success;
 	return parse_sst_success;

+ 1 - 0
lib/kcore/parse_sst.h

@@ -53,6 +53,7 @@ enum sst_refresher {
  * a pointer to a struct session_expires.
  * a pointer to a struct session_expires.
  */
  */
 struct session_expires {
 struct session_expires {
+	hf_parsed_free_f hfree;       /* function to free the content */
 	unsigned            interval; /* in seconds */
 	unsigned            interval; /* in seconds */
 	enum sst_refresher  refresher;
 	enum sst_refresher  refresher;
 };
 };

+ 21 - 0
lib/kcore/parse_supported.c

@@ -112,6 +112,17 @@ static inline int parse_supported_body(str *body, unsigned int *sup)
 	return 0;
 	return 0;
 }
 }
 
 
+
+/**
+ * wrapper to free the content of parsed supported header
+ */
+void hf_free_supported(void *parsed)
+{
+	struct supported_body *sb;
+	sb = (struct supported_body*)parsed;
+	free_supported(&sb);
+}
+
 /*!
 /*!
  * Parse all Supported headers
  * Parse all Supported headers
  */
  */
@@ -144,6 +155,7 @@ int parse_supported( struct sip_msg *msg)
 		}
 		}
 
 
 		parse_supported_body(&(hdr->body), &(sb->supported));
 		parse_supported_body(&(hdr->body), &(sb->supported));
+		sb->hfree = hf_free_supported;
 		sb->supported_all = 0;
 		sb->supported_all = 0;
 		hdr->parsed = (void*)sb;
 		hdr->parsed = (void*)sb;
 		supported |= sb->supported;
 		supported |= sb->supported;
@@ -153,3 +165,12 @@ int parse_supported( struct sip_msg *msg)
 		supported;
 		supported;
 	return 0;
 	return 0;
 }
 }
+
+/* free supported header structure */
+void free_supported(struct supported_body **sb)
+{
+	if (sb && *sb) {
+		pkg_free(*sb);
+		*sb = 0;
+	}
+}

+ 3 - 7
lib/kcore/parse_supported.h

@@ -36,6 +36,7 @@
 #define PARSE_SUPPORTED_H
 #define PARSE_SUPPORTED_H
 
 
 #include "../../parser/msg_parser.h"
 #include "../../parser/msg_parser.h"
+#include "../../parser/hf.h"
 #include "../../mem/mem.h"
 #include "../../mem/mem.h"
 
 
 
 
@@ -64,6 +65,7 @@
 
 
 
 
 struct supported_body {
 struct supported_body {
+	hf_parsed_free_f hfree;        /* function to free the content */
 	unsigned int supported;        /* supported mask for the current hdr */
 	unsigned int supported;        /* supported mask for the current hdr */
 	unsigned int supported_all;    /* suppoted mask for the all "supported" hdr
 	unsigned int supported_all;    /* suppoted mask for the all "supported" hdr
 	                                *  - it's set only for the first hdr in 
 	                                *  - it's set only for the first hdr in 
@@ -77,12 +79,6 @@ struct supported_body {
 int parse_supported( struct sip_msg *msg);
 int parse_supported( struct sip_msg *msg);
 
 
 
 
-static inline void free_supported(struct supported_body **sb)
-{
-	if (sb && *sb) {
-		pkg_free(*sb);
-		*sb = 0;
-	}
-}
+void free_supported(struct supported_body **sb);
 
 
 #endif /* PARSE_SUPPORTED_H */
 #endif /* PARSE_SUPPORTED_H */

+ 1 - 1
lib/srdb1/db_id.c

@@ -279,7 +279,7 @@ unsigned char cmp_db_id(const struct db_id* id1, const struct db_id* id2)
 	if (strcasecmp(id1->host, id2->host)) return 0;
 	if (strcasecmp(id1->host, id2->host)) return 0;
 	if (strcmp(id1->database, id2->database)) return 0;
 	if (strcmp(id1->database, id2->database)) return 0;
 	if(id1->pid!=id2->pid) {
 	if(id1->pid!=id2->pid) {
-		LM_WARN("identical DB URLs, but different DB connection pid [%d/%d]\n",
+		LM_DBG("identical DB URLs, but different DB connection pid [%d/%d]\n",
 				id1->pid, id2->pid);
 				id1->pid, id2->pid);
 		return 0;
 		return 0;
 	}
 	}

+ 3 - 3
lvalue.c

@@ -290,7 +290,7 @@ inline static int lval_pvar_assign(struct run_act_ctx* h, struct sip_msg* msg,
 														    break in expr*/
 														    break in expr*/
 			} else
 			} else
 				pval.ri=0;
 				pval.ri=0;
-			ret=pval.ri;
+			ret=!(!pval.ri);
 			break;
 			break;
 		case RV_BEXPR: /* logic/boolean expr. */
 		case RV_BEXPR: /* logic/boolean expr. */
 			pval.flags=PV_TYPE_INT|PV_VAL_INT;
 			pval.flags=PV_TYPE_INT|PV_VAL_INT;
@@ -301,7 +301,7 @@ inline static int lval_pvar_assign(struct run_act_ctx* h, struct sip_msg* msg,
 				WARN("error in expression\n");
 				WARN("error in expression\n");
 				pval.ri=0; /* expr. is treated as false */
 				pval.ri=0; /* expr. is treated as false */
 			}
 			}
-			ret=pval.ri;
+			ret=!(!pval.ri);
 			break;
 			break;
 		case RV_SEL:
 		case RV_SEL:
 			pval.flags=PV_VAL_STR;
 			pval.flags=PV_VAL_STR;
@@ -315,7 +315,7 @@ inline static int lval_pvar_assign(struct run_act_ctx* h, struct sip_msg* msg,
 					break;
 					break;
 				}
 				}
 			}
 			}
-			ret=(pval.rs.len)>0;
+			ret=(pval.rs.len>0);
 			break;
 			break;
 		case RV_AVP:
 		case RV_AVP:
 				r_avp = search_avp_by_index(rv->v.avps.type, rv->v.avps.name,
 				r_avp = search_avp_by_index(rv->v.avps.type, rv->v.avps.name,

+ 3 - 0
modules/dialplan/README

@@ -334,6 +334,9 @@ modparam("dialplan", "fetch_rows", 4000)
    with dialplan ID equal to id. If dest is missing, only matching and
    with dialplan ID equal to id. If dest is missing, only matching and
    storing of matching rule's attributes is done.
    storing of matching rule's attributes is done.
 
 
+   Returns 1, if translation succeeded, -1 in case of some error occurred,
+   and -2 if dialplan with ID equal to id does not exist.
+
    Meaning of the parameters is as follows:
    Meaning of the parameters is as follows:
      * id -the dialplan id of the possible matching rules. This parameter
      * id -the dialplan id of the possible matching rules. This parameter
        can have the following types:
        can have the following types:

+ 1 - 1
modules/dialplan/dialplan.c

@@ -326,7 +326,7 @@ static int dp_translate_f(struct sip_msg* msg, char* str1, char* str2)
 
 
 	if ((idp = select_dpid(dpid)) ==0 ){
 	if ((idp = select_dpid(dpid)) ==0 ){
 		LM_DBG("no information available for dpid %i\n", dpid);
 		LM_DBG("no information available for dpid %i\n", dpid);
-		return -1;
+		return -2;
 	}
 	}
 
 
 	repl_par = (str2!=NULL)? ((dp_param_p)str2):default_par2;
 	repl_par = (str2!=NULL)? ((dp_param_p)str2):default_par2;

+ 4 - 0
modules/dialplan/doc/dialplan_admin.xml

@@ -365,6 +365,10 @@ modparam("dialplan", "fetch_rows", 4000)
 	missing, only matching and storing of matching rule's
 	missing, only matching and storing of matching rule's
 	attributes is done.
 	attributes is done.
 	</para>
 	</para>
+	<para>
+	  Returns 1, if translation succeeded, -1 in case of some error
+	  occurred, and -2 if dialplan with ID equal to id does not exist.
+	</para>
 	<para>Meaning of the parameters is as follows:</para>
 	<para>Meaning of the parameters is as follows:</para>
 	<itemizedlist>
 	<itemizedlist>
 	<listitem>
 	<listitem>

+ 29 - 15
modules/dialplan/dp_repl.c

@@ -72,7 +72,7 @@ struct subst_expr* repl_exp_parse(str subst)
 	repl = p;
 	repl = p;
 	if((rw_no = parse_repl(rw, &p, end, &max_pmatch, WITHOUT_SEP))< 0)
 	if((rw_no = parse_repl(rw, &p, end, &max_pmatch, WITHOUT_SEP))< 0)
 		goto error;
 		goto error;
-	
+
 	repl_end=p;
 	repl_end=p;
 
 
     /* construct the subst_expr structure */
     /* construct the subst_expr structure */
@@ -183,8 +183,9 @@ int rule_translate(struct sip_msg *msg, str string, dpl_node_t * rule,
 	/* offset- offset in the replacement string */
 	/* offset- offset in the replacement string */
 	result->len = repl_nb = offset = 0;
 	result->len = repl_nb = offset = 0;
 	p=repl_comp->replacement.s;
 	p=repl_comp->replacement.s;
-	
+
 	while( repl_nb < repl_comp->n_escapes){
 	while( repl_nb < repl_comp->n_escapes){
+
 		token = repl_comp->replace[repl_nb];
 		token = repl_comp->replace[repl_nb];
 		
 		
 		if(offset< token.offset){
 		if(offset< token.offset){
@@ -194,12 +195,12 @@ int rule_translate(struct sip_msg *msg, str string, dpl_node_t * rule,
 				goto error;
 				goto error;
 			}
 			}
 			/*copy from the replacing string*/
 			/*copy from the replacing string*/
-			size=repl_comp->replacement.s+repl_comp->replace[repl_nb].offset-p;
-			memcpy(result->s + result->len, p, size);
+			size = token.offset - offset;
+			memcpy(result->s + result->len, p + offset, size);
+			LM_DBG("copying <%.*s> from replacing string\n",
+			       size, p + offset);
 			result->len += size;
 			result->len += size;
-			p+=size+repl_comp->replace[repl_nb].size;
-
-			offset += token.offset-offset; /*update the offset*/
+			offset = token.offset;
 		}
 		}
 
 
 		switch(token.type) {
 		switch(token.type) {
@@ -214,16 +215,21 @@ int rule_translate(struct sip_msg *msg, str string, dpl_node_t * rule,
 				}
 				}
 
 
 				memcpy(result->s + result->len, match.s, match.len);
 				memcpy(result->s + result->len, match.s, match.len);
+				LM_DBG("copying match <%.*s> token size %d\n",
+				       match.len, match.s, token.size);
 				result->len += match.len;
 				result->len += match.len;
-				offset += token.size; /*update the offset*/
+				offset += token.size;
 			break;
 			break;
 			case REPLACE_CHAR:
 			case REPLACE_CHAR:
 				if(result->len + 1>= MAX_PHONE_NB_DIGITS){
 				if(result->len + 1>= MAX_PHONE_NB_DIGITS){
 					LM_ERR("overflow\n");
 					LM_ERR("overflow\n");
 					goto error;
 					goto error;
 				}
 				}
-				*result->s=repl_comp->replace[repl_nb].u.c;
+				*(result->s + result->len) = token.u.c;
+				LM_DBG("copying char <%c> token size %d\n",
+					token.u.c, token.size);
 				result->len++;
 				result->len++;
+				offset += token.size;
 			break;
 			break;
 			case REPLACE_URI:	
 			case REPLACE_URI:	
 				if ( msg== NULL || msg->first_line.type!=SIP_REQUEST){
 				if ( msg== NULL || msg->first_line.type!=SIP_REQUEST){
@@ -238,15 +244,17 @@ int rule_translate(struct sip_msg *msg, str string, dpl_node_t * rule,
 					goto error;
 					goto error;
 				}
 				}
 				memcpy(result->s + result->len, uri->s, uri->len);
 				memcpy(result->s + result->len, uri->s, uri->len);
+				LM_DBG("copying uri <%.*s> token size %d\n",
+					uri->len, uri->s, token.size);
 				result->len+=uri->len;
 				result->len+=uri->len;
+				offset += token.size;
 			break;
 			break;
 			case REPLACE_SPEC:
 			case REPLACE_SPEC:
 				if (msg== NULL) {
 				if (msg== NULL) {
 					LM_DBG("replace spec attempted on no message\n");
 					LM_DBG("replace spec attempted on no message\n");
 					break;
 					break;
 				}
 				}
-				if(pv_get_spec_value(msg, 
-						&repl_comp->replace[repl_nb].u.spec, &sv)!=0){
+				if (pv_get_spec_value(msg, &token.u.spec, &sv) != 0) {
 					LM_CRIT("item substitution returned error\n");
 					LM_CRIT("item substitution returned error\n");
 					break; /* ignore, we can continue */
 					break; /* ignore, we can continue */
 				}
 				}
@@ -254,8 +262,12 @@ int rule_translate(struct sip_msg *msg, str string, dpl_node_t * rule,
 					LM_ERR("rule_translate: overflow\n");
 					LM_ERR("rule_translate: overflow\n");
 					goto error;
 					goto error;
 				}
 				}
-				memcpy(result->s + result->len, sv.rs.s, sv.rs.len);
+				memcpy(result->s + result->len, sv.rs.s,
+				       sv.rs.len);
+				LM_DBG("copying pvar value <%.*s> token size %d\n",
+					sv.rs.len, sv.rs.s, token.size);
 				result->len+=sv.rs.len;
 				result->len+=sv.rs.len;
+				offset += token.size;
 			break;
 			break;
 			default:
 			default:
 				LM_CRIT("unknown type %d\n", repl_comp->replace[repl_nb].type);
 				LM_CRIT("unknown type %d\n", repl_comp->replace[repl_nb].type);
@@ -264,10 +276,12 @@ int rule_translate(struct sip_msg *msg, str string, dpl_node_t * rule,
 		repl_nb++;
 		repl_nb++;
 	}
 	}
 	/* anything left? */
 	/* anything left? */
-	if( repl_nb && token.offset+token.size < repl_comp->replacement.len){
+	if( repl_nb && offset < repl_comp->replacement.len){
 		/*copy from the replacing string*/
 		/*copy from the replacing string*/
-		size = repl_comp->replacement.s+repl_comp->replacement.len-p;
-		memcpy(result->s + result->len, p, size);
+		size = repl_comp->replacement.len - offset;
+		memcpy(result->s + result->len, p + offset, size);
+		LM_DBG("copying leftover <%.*s> from replacing string\n",
+		       size, p + offset);
 		result->len += size;
 		result->len += size;
 	}
 	}
 
 

+ 4 - 4
modules/pipelimit/README

@@ -154,7 +154,7 @@ modparam("pipelimit", "db_url", "dbdriver://username:password@dbhost/dbname")
 
 
 3.2. plp_table_name (string)
 3.2. plp_table_name (string)
 
 
-   Name of DB table where data definitio for pipes is stores.
+   Name of DB table where data definition for pipes is stores.
 
 
    Default value is “pl_pipes”.
    Default value is “pl_pipes”.
 
 
@@ -223,7 +223,7 @@ modparam("ratelimit", "timer_interval", 5)
 modparam("ratelimit", "reply_code", 505)
 modparam("ratelimit", "reply_code", 505)
 ...
 ...
 
 
-   This value cant be modified at runtime using sercmd
+   This value can be modified at runtime using sercmd
 
 
    Example 1.8.  Set reply_code parameter at runtime
    Example 1.8.  Set reply_code parameter at runtime
 sercmd cfg.set_now_int ratelimit reply_code 505
 sercmd cfg.set_now_int ratelimit reply_code 505
@@ -239,7 +239,7 @@ sercmd cfg.set_now_int ratelimit reply_code 505
 modparam("ratelimit", "reply_reason", "Limiting")
 modparam("ratelimit", "reply_reason", "Limiting")
 ...
 ...
 
 
-   This value cant be modified at runtime using sercmd
+   This value can be modified at runtime using sercmd
 
 
    Example 1.10.  Set reply_reason parameter at runtime
    Example 1.10.  Set reply_reason parameter at runtime
 sercmd cfg.set_now_string ratelimit reply_reason "Limiting"
 sercmd cfg.set_now_string ratelimit reply_reason "Limiting"
@@ -387,7 +387,7 @@ sercmd cfg.set_now_string ratelimit reply_reason "Limiting"
 
 
 5.6.  pl_push_load
 5.6.  pl_push_load
 
 
-   Force the value of the load parameter. This methos is usefull for
+   Force the value of the load parameter. This command is useful for
    testing the Feedback algorithm.
    testing the Feedback algorithm.
 
 
    Name: pl_push_load
    Name: pl_push_load

+ 4 - 4
modules/pipelimit/doc/pipelimit_admin.xml

@@ -88,7 +88,7 @@ modparam("pipelimit", "db_url", "&exampledb;")
 	<section>
 	<section>
 	    <title><varname>plp_table_name</varname> (string)</title>
 	    <title><varname>plp_table_name</varname> (string)</title>
 	    <para>
 	    <para>
-			Name of DB table where data definitio for pipes is stores.
+			Name of DB table where data definition for pipes is stores.
 	    </para>
 	    </para>
 	    <para>
 	    <para>
 		<emphasis>
 		<emphasis>
@@ -210,7 +210,7 @@ modparam("ratelimit", "reply_code", 505)
 </programlisting>
 </programlisting>
 		</example>
 		</example>
 		<para>
 		<para>
-		This value cant be modified at runtime using sercmd
+		This value can be modified at runtime using sercmd
 		</para>
 		</para>
 		<example>
 		<example>
 		<title> Set <varname>reply_code</varname> parameter at runtime </title>
 		<title> Set <varname>reply_code</varname> parameter at runtime </title>
@@ -240,7 +240,7 @@ modparam("ratelimit", "reply_reason", "Limiting")
 </programlisting>
 </programlisting>
 		</example>
 		</example>
 		<para>
 		<para>
-		This value cant be modified at runtime using sercmd
+		This value can be modified at runtime using sercmd
 		</para>
 		</para>
 		<example>
 		<example>
 		<title> Set <varname>reply_reason</varname> parameter at runtime </title>
 		<title> Set <varname>reply_reason</varname> parameter at runtime </title>
@@ -471,7 +471,7 @@ sercmd cfg.set_now_string ratelimit reply_reason "Limiting"
 		<function moreinfo="none">pl_push_load</function>
 		<function moreinfo="none">pl_push_load</function>
 		</title>
 		</title>
 		<para>
 		<para>
-		Force the value of the load parameter.  This methos is usefull
+		Force the value of the load parameter.  This command is useful
 		for testing the Feedback algorithm.
 		for testing the Feedback algorithm.
 		</para>
 		</para>
 		<para>
 		<para>

+ 14 - 0
modules/sdpops/Makefile

@@ -0,0 +1,14 @@
+# $Id$
+#
+# 
+# WARNING: do not run this directly, it should be run by the master Makefile
+
+include ../../Makefile.defs
+auto_gen=
+NAME=sdpops.so
+DEFS +=
+LIBS +=
+
+DEFS+=-DOPENSER_MOD_INTERFACE
+
+include ../../Makefile.modules

+ 137 - 0
modules/sdpops/README

@@ -0,0 +1,137 @@
+SDPOPS Module
+
+Daniel-Constantin Mierla
+
+   <[email protected]>
+
+Edited by
+
+Daniel-Constantin Mierla
+
+   <[email protected]>
+
+   Copyright © 2011 asipto.com
+     __________________________________________________________________
+
+   Table of Contents
+
+   1. Admin Guide
+
+        1. Overview
+        2. Dependencies
+
+              2.1. Kamailio Modules
+              2.2. External Libraries or Applications
+
+        3. Exported Parameters
+        4. Exported Functions
+
+              4.1. sdp_remove_codecs_by_id(list)
+              4.2. sdp_with_media(type)
+              4.3. sdp_print(level)
+
+   List of Examples
+
+   1.1. sdp_remove_codecs_by_id usage
+   1.2. sdp_with_media usage
+   1.3. sdp_print usage
+
+Chapter 1. Admin Guide
+
+   Table of Contents
+
+   1. Overview
+   2. Dependencies
+
+        2.1. Kamailio Modules
+        2.2. External Libraries or Applications
+
+   3. Exported Parameters
+   4. Exported Functions
+
+        4.1. sdp_remove_codecs_by_id(list)
+        4.2. sdp_with_media(type)
+        4.3. sdp_print(level)
+
+1. Overview
+
+   This module provides function for checking and managing the SDP
+   payloads of SIP messages.
+
+   Examples of what this module offers: remove codecs from SDP, check the
+   media stream types, return attributes of SDP document. For the full
+   least of the features provided by this module and the implementation
+   state, read further to the list of exported functions.
+
+2. Dependencies
+
+   2.1. Kamailio Modules
+   2.2. External Libraries or Applications
+
+2.1. Kamailio Modules
+
+   The following modules must be loaded before this module:
+     * none.
+
+2.2. External Libraries or Applications
+
+   The following libraries or applications must be installed before
+   running Kamailio with this module loaded:
+     * None
+
+3. Exported Parameters
+
+   The module does not export any config parameter yet.
+
+4. Exported Functions
+
+   4.1. sdp_remove_codecs_by_id(list)
+   4.2. sdp_with_media(type)
+   4.3. sdp_print(level)
+
+4.1.  sdp_remove_codecs_by_id(list)
+
+   Remove the codecs provided in the parameter 'list' from all media
+   streams found in SDP payload. The parameter 'list' must be one or a
+   comma separated list of numeric codec IDs. The parameter can be a
+   static string or a variable holding the list of numeric codec IDs.
+
+   This function can be used from ANY_ROUTE.
+
+   Example 1.1. sdp_remove_codecs_by_id usage
+...
+# remove PCMU
+sdp_remove_codecs_by_id("0");
+# remove PCMU, PCMA and GSM
+sdp_remove_codecs_by_id("0,8,3");
+...
+
+4.2.  sdp_with_media(type)
+
+   Return true of the SDP has 'media=type ...' line. Useful to check the
+   content of the RTP sessions, such as 'audio' or 'video'. The parameter
+   can be static string or variable holding the media type.
+
+   This function can be used from ANY_ROUTE.
+
+   Example 1.2. sdp_with_media usage
+...
+# check for video stream
+if(sdp_with_media("video"))
+{
+    # the session has a video stream
+}
+...
+
+4.3.  sdp_print(level)
+
+   Print the SDP internal structure to log 'level'. The parameter can be
+   static integer or variable holding the integer value of the log level.
+
+   This function can be used from ANY_ROUTE.
+
+   Example 1.3. sdp_print usage
+...
+# print the SDP
+sdp_print("1");
+...

+ 4 - 0
modules/sdpops/doc/Makefile

@@ -0,0 +1,4 @@
+docs = sdpops.xml
+
+docbook_dir = ../../../docbook
+include $(docbook_dir)/Makefile.module

+ 37 - 0
modules/sdpops/doc/sdpops.xml

@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding='ISO-8859-1'?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
+"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [
+
+<!-- Include general documentation entities -->
+<!ENTITY % docentities SYSTEM "../../../docbook/entities.xml">
+%docentities;
+
+]>
+
+<book xmlns:xi="http://www.w3.org/2001/XInclude">
+    <bookinfo>
+	<title>SDPOPS Module</title>
+	<productname class="trade">sip-router.org</productname>
+	<authorgroup>
+	    <author>
+		<firstname>Daniel-Constantin</firstname>
+		<surname>Mierla</surname>
+		<email>[email protected]</email>
+	    </author>
+	    <editor>
+		<firstname>Daniel-Constantin</firstname>
+		<surname>Mierla</surname>
+		<email>[email protected]</email>
+	    </editor>
+	</authorgroup>
+	<copyright>
+	    <year>2011</year>
+	    <holder>asipto.com</holder>
+	</copyright>
+    </bookinfo>
+    <toc></toc>
+    
+    <xi:include href="sdpops_admin.xml"/>
+    
+    
+</book>

+ 145 - 0
modules/sdpops/doc/sdpops_admin.xml

@@ -0,0 +1,145 @@
+<?xml version="1.0" encoding='ISO-8859-1'?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
+"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [
+
+<!-- Include general documentation entities -->
+<!ENTITY % docentities SYSTEM "../../../docbook/entities.xml">
+%docentities;
+
+]>
+<!-- Module User's Guide -->
+
+<chapter>
+	
+	<title>&adminguide;</title>
+	
+	<section>
+	<title>Overview</title>
+	<para>
+		This module provides function for checking and managing the SDP
+		payloads of SIP messages.
+	</para>
+	<para>
+		Examples of what this module offers: remove codecs from SDP,
+		check the media stream types, return attributes of SDP document.
+		For the full least of the features provided by this module and
+		the implementation state, read further to the list of exported
+		functions.
+	</para>
+	</section>
+
+	<section>
+	<title>Dependencies</title>
+	<section>
+		<title>&kamailio; Modules</title>
+		<para>
+		The following modules must be loaded before this module:
+			<itemizedlist>
+			<listitem>
+			<para>
+				<emphasis>none</emphasis>.
+			</para>
+			</listitem>
+			</itemizedlist>
+		</para>
+	</section>
+	<section>
+		<title>External Libraries or Applications</title>
+		<para>
+		The following libraries or applications must be installed before running
+		&kamailio; with this module loaded:
+			<itemizedlist>
+			<listitem>
+			<para>
+				<emphasis>None</emphasis>
+			</para>
+			</listitem>
+			</itemizedlist>
+		</para>
+	</section>
+	</section>
+	<section>
+	<title>Exported Parameters</title>
+		<para>
+		The module does not export any config parameter yet.
+		</para>
+	</section>
+
+	<section>
+	<title>Exported Functions</title>
+	<section>
+	    <title>
+		<function moreinfo="none">sdp_remove_codecs_by_id(list)</function>
+	    </title>
+	    <para>
+			Remove the codecs provided in the parameter 'list' from all
+			media streams found in SDP payload. The parameter 'list' must
+			be one or a comma separated list of numeric codec IDs. The
+			parameter can be a static string or a variable holding the
+			list of numeric codec IDs.
+	    </para>
+		<para>
+			This function can be used from ANY_ROUTE.
+	    </para>
+		<example>
+		<title><function>sdp_remove_codecs_by_id</function> usage</title>
+		<programlisting format="linespecific">
+...
+# remove PCMU
+sdp_remove_codecs_by_id("0");
+# remove PCMU, PCMA and GSM
+sdp_remove_codecs_by_id("0,8,3");
+...
+</programlisting>
+	    </example>
+	</section>
+	<section>
+	    <title>
+		<function moreinfo="none">sdp_with_media(type)</function>
+	    </title>
+	    <para>
+		Return true of the SDP has 'media=type ...' line. Useful to check
+		the content of the RTP sessions, such as 'audio' or 'video'. The
+		parameter can be static string or variable holding the media type.
+	    </para>
+		<para>
+			This function can be used from ANY_ROUTE.
+	    </para>
+		<example>
+		<title><function>sdp_with_media</function> usage</title>
+		<programlisting format="linespecific">
+...
+# check for video stream
+if(sdp_with_media("video"))
+{
+    # the session has a video stream
+}
+...
+</programlisting>
+	    </example>
+	</section>
+	<section>
+	    <title>
+		<function moreinfo="none">sdp_print(level)</function>
+	    </title>
+	    <para>
+		Print the SDP internal structure to log 'level'. The
+		parameter can be static integer or variable holding the integer
+		value of the log level.
+	    </para>
+		<para>
+			This function can be used from ANY_ROUTE.
+	    </para>
+		<example>
+		<title><function>sdp_print</function> usage</title>
+		<programlisting format="linespecific">
+...
+# print the SDP
+sdp_print("1");
+...
+</programlisting>
+	    </example>
+	</section>
+	</section>
+</chapter>
+

+ 413 - 0
modules/sdpops/sdpops_mod.c

@@ -0,0 +1,413 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2011 Daniel-Constantin Mierla (asipto.com)
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio 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
+ *
+ * Kamailio 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
+ *
+ */
+
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "../../sr_module.h"
+#include "../../dprint.h"
+#include "../../mod_fix.h"
+#include "../../pvar.h"
+#include "../../trim.h"
+#include "../../parser/sdp/sdp.h"
+#include "../../data_lump.h"
+
+
+MODULE_VERSION
+
+static int w_sdp_remove_codecs_by_id(sip_msg_t* msg, char* codecs, char *bar);
+static int w_sdp_with_media(sip_msg_t* msg, char* media, char *bar);
+static int w_sdp_print(sip_msg_t* msg, char* level, char *bar);
+
+static int mod_init(void);
+
+static cmd_export_t cmds[] = {
+	{"sdp_remove_codecs_by_id",    (cmd_function)w_sdp_remove_codecs_by_id,
+		1, fixup_spve_null,  0, ANY_ROUTE},
+	{"sdp_with_media",             (cmd_function)w_sdp_with_media,
+		1, fixup_spve_null,  0, ANY_ROUTE},
+	{"sdp_print",                  (cmd_function)w_sdp_print,
+		1, fixup_igp_null,  0, ANY_ROUTE},
+	{0, 0, 0, 0, 0}
+};
+
+static pv_export_t mod_pvs[] = {
+#if 0
+	{{"sdp", (sizeof("sdp")-1)}, /* */
+		PVT_OTHER, pv_get_sdp, 0,
+		0, 0, 0, 0},
+#endif
+
+	{ {0, 0}, 0, 0, 0, 0, 0, 0, 0 }
+};
+
+static param_export_t params[] = {
+	{0, 0, 0}
+};
+
+/** module exports */
+struct module_exports exports= {
+	"sdpops",
+	DEFAULT_DLFLAGS, /* dlopen flags */
+	cmds,
+	params,
+	0,          /* exported statistics */
+	0  ,        /* exported MI functions */
+	mod_pvs,    /* exported pseudo-variables */
+	0,          /* extra processes */
+	mod_init,   /* module initialization function */
+	0,
+	0,
+	0           /* per-child init function */
+};
+
+/** 
+ * 
+ */
+static int mod_init(void)
+{
+	LM_DBG("sdpops module loaded\n");
+	return 0;
+}
+
+
+/**
+ *
+ */
+int str_find_token(str *text, str *result, char delim)
+{
+	int i;
+	if(text==NULL || result==NULL)
+		return -1;
+	if(text->s[0] == delim)
+	{
+		 text->s += 1;
+		 text->len -= 1;
+	}
+	trim_leading(text);
+	result->s = text->s;
+	result->len = 0;
+	for (i=0; i<text->len; i++)
+	{
+		if(result->s[i]==delim || result->s[i]=='\0'
+				|| result->s[i]=='\r' || result->s[i]=='\n')
+			return 0;
+		result->len++;
+	}
+	return 0;
+}
+
+/**
+ *
+ */
+int sdp_locate_line(sip_msg_t* msg, char *pos, str *aline)
+{
+	char *p;
+	p = pos;
+	while(*p!='\n') p--;
+	aline->s = p + 1;
+	p = pos;
+	while(*p!='\n') p++;
+	aline->len = p - aline->s + 1;
+	return 0;
+}
+
+/**
+ *
+ */
+int sdp_remove_str_codec_id_attrs(sip_msg_t* msg,
+		sdp_stream_cell_t* sdp_stream, str *rm_codec)
+{
+	str aline = {0, 0};
+	sdp_payload_attr_t *payload;
+	struct lump *anchor;
+
+	payload = sdp_stream->payload_attr;
+	while (payload) {
+		LM_DBG("a= ... for codec %.*s/%.*s\n",
+			payload->rtp_payload.len, payload->rtp_payload.s,
+			payload->rtp_enc.len, payload->rtp_enc.s);
+		if(rm_codec->len==payload->rtp_payload.len
+				&& strncmp(payload->rtp_payload.s, rm_codec->s,
+					rm_codec->len)==0) {
+			if(payload->rtp_enc.s!=NULL) {
+				if(sdp_locate_line(msg, payload->rtp_enc.s, &aline)==0)
+				{
+					anchor = del_lump(msg, aline.s - msg->buf,
+							aline.len, 0);
+					if (anchor == NULL) {
+						LM_ERR("failed to remove [%.*s] inside [%.*s]\n",
+							rm_codec->len, rm_codec->s,
+							aline.len, aline.s);
+						return -1;
+					}
+				}
+			}
+			if(payload->fmtp_string.s!=NULL) {
+				if(sdp_locate_line(msg, payload->fmtp_string.s, &aline)==0)
+				{
+					anchor = del_lump(msg, aline.s - msg->buf,
+							aline.len, 0);
+					if (anchor == NULL) {
+						LM_ERR("failed to remove [%.*s] inside [%.*s]\n",
+							rm_codec->len, rm_codec->s,
+							aline.len, aline.s);
+						return -1;
+					}
+				}
+			}
+		}
+		payload=payload->next;
+	}
+
+	return 0;
+}
+
+/**
+ *
+ */
+int sdp_remove_str_codec_id(sip_msg_t* msg, str *allcodecs, str* rmcodec)
+{
+	int i;
+	int cmp;
+	struct lump *anchor;
+
+	if(msg==NULL || allcodecs==NULL || rmcodec==NULL
+			|| allcodecs->len<=0 || rmcodec->len<=0)
+		return -1;
+
+	cmp = 1;
+	for(i=0; i<allcodecs->len; i++) {
+		if(cmp==1) {
+			if(rmcodec->len <= allcodecs->len-i) {
+				if(strncmp(&allcodecs->s[i], rmcodec->s, rmcodec->len)==0) {
+					if(&allcodecs->s[i+rmcodec->len]
+									== &allcodecs->s[allcodecs->len]
+							|| allcodecs->s[i+rmcodec->len] == ' ') {
+						/* match - remove also the space before codec id */
+						LM_DBG("found codec [%.*s] inside [%.*s]\n",
+									rmcodec->len, rmcodec->s,
+									allcodecs->len, allcodecs->s);
+						anchor = del_lump(msg, &allcodecs->s[i-1] - msg->buf,
+								rmcodec->len+1, 0);
+						if (anchor == NULL) {
+							LM_ERR("failed to remove [%.*s] inside [%.*s]\n",
+									rmcodec->len, rmcodec->s,
+									allcodecs->len, allcodecs->s);
+							return -1;
+						}
+						return 0;
+					}
+				}
+			}
+		}
+		if(allcodecs->s[i]==' ')
+			cmp = 1;
+		else
+			cmp = 0;
+	}
+
+	return 0;
+}
+
+/**
+ *
+ */
+int sdp_remove_codecs_by_id(sip_msg_t* msg, str* codecs)
+{
+	sdp_info_t *sdp = NULL;
+	int sdp_session_num;
+	int sdp_stream_num;
+	sdp_session_cell_t* sdp_session;
+	sdp_stream_cell_t* sdp_stream;
+	str sdp_codecs;
+	str tmp_codecs;
+	str rm_codec;
+
+	if(parse_sdp(msg) < 0) {
+		LM_ERR("Unable to parse sdp\n");
+		return -1;
+	}
+
+	LM_ERR("attempting to remove codecs from sdp: [%.*s]\n",
+			codecs->len, codecs->s);
+
+	sdp = (sdp_info_t*)msg->body;
+
+	sdp_session_num = 0;
+	for(;;)
+	{
+		sdp_session = get_sdp_session(msg, sdp_session_num);
+		if(!sdp_session) break;
+		sdp_stream_num = 0;
+		for(;;)
+		{
+			sdp_stream = get_sdp_stream(msg, sdp_session_num, sdp_stream_num);
+			if(!sdp_stream) break;
+
+			LM_DBG("stream %d of %d - payloads [%.*s]\n",
+				sdp_stream_num, sdp_session_num, 
+				sdp_stream->payloads.len, sdp_stream->payloads.s);
+			sdp_codecs = sdp_stream->payloads;
+			tmp_codecs = *codecs;
+			while(str_find_token(&tmp_codecs, &rm_codec, ',')==0
+					&& rm_codec.len>0)
+			{
+				tmp_codecs.len -=(int)(&rm_codec.s[rm_codec.len]-tmp_codecs.s);
+				tmp_codecs.s = rm_codec.s + rm_codec.len;
+
+				LM_DBG("codecs [%.*s] - remove [%.*s]\n",
+						sdp_codecs.len, sdp_codecs.s,
+						rm_codec.len, rm_codec.s);
+				sdp_remove_str_codec_id(msg, &sdp_codecs, &rm_codec);
+				sdp_remove_str_codec_id_attrs(msg, sdp_stream, &rm_codec);
+			}
+			sdp_stream_num++;
+		}
+		sdp_session_num++;
+	}
+
+	return 0;
+}
+
+/**
+ *
+ */
+static int w_sdp_remove_codecs_by_id(sip_msg_t* msg, char* codecs, char* bar)
+{
+	str lcodecs = {0, 0};
+
+	if(codecs==0)
+	{
+		LM_ERR("invalid parameters\n");
+		return -1;
+	}
+
+	if(fixup_get_svalue(msg, (gparam_p)codecs, &lcodecs)!=0)
+	{
+		LM_ERR("unable to get the list of codecs\n");
+		return -1;
+	}
+
+	if(sdp_remove_codecs_by_id(msg, &lcodecs)<0)
+		return -1;
+	return 1;
+}
+
+
+/** 
+ * @brief check 'media' matches the value of any 'm=value ...' lines
+ * @return -1 - error; 0 - not found; 1 - found
+ */
+static int sdp_with_media(sip_msg_t *msg, str *media)
+{
+	sdp_info_t *sdp = NULL;
+	int sdp_session_num;
+	int sdp_stream_num;
+	sdp_session_cell_t* sdp_session;
+	sdp_stream_cell_t* sdp_stream;
+
+	if(parse_sdp(msg) < 0) {
+		LM_ERR("Unable to parse sdp\n");
+		return -1;
+	}
+
+	LM_ERR("attempting to search for media type: [%.*s]\n",
+			media->len, media->s);
+
+	sdp = (sdp_info_t*)msg->body;
+
+	sdp_session_num = 0;
+	for(;;)
+	{
+		sdp_session = get_sdp_session(msg, sdp_session_num);
+		if(!sdp_session) break;
+		sdp_stream_num = 0;
+		for(;;)
+		{
+			sdp_stream = get_sdp_stream(msg, sdp_session_num, sdp_stream_num);
+			if(!sdp_stream) break;
+
+			LM_DBG("stream %d of %d - media [%.*s]\n",
+				sdp_stream_num, sdp_session_num,
+				sdp_stream->media.len, sdp_stream->media.s);
+			if(media->len==sdp_stream->media.len
+					&& strncasecmp(sdp_stream->media.s, media->s,
+							media->len)==0)
+				return 1;
+			sdp_stream_num++;
+		}
+		sdp_session_num++;
+	}
+
+	return 0;
+}
+
+/**
+ *
+ */
+static int w_sdp_with_media(sip_msg_t* msg, char* media, char *bar)
+{
+	str lmedia = {0, 0};
+
+	if(media==0)
+	{
+		LM_ERR("invalid parameters\n");
+		return -1;
+	}
+
+	if(fixup_get_svalue(msg, (gparam_p)media, &lmedia)!=0)
+	{
+		LM_ERR("unable to get the media value\n");
+		return -1;
+	}
+
+	if(sdp_with_media(msg, &lmedia)<=0)
+		return -1;
+	return 1;
+}
+
+
+static int w_sdp_print(sip_msg_t* msg, char* level, char *bar)
+{
+	sdp_info_t *sdp = NULL;
+	int llevel = L_DBG;
+
+	if(parse_sdp(msg) < 0) {
+		LM_ERR("Unable to parse sdp\n");
+		return -1;
+	}
+
+	if(fixup_get_ivalue(msg, (gparam_p)level, &llevel)!=0)
+	{
+		LM_ERR("unable to get the debug level value\n");
+		return -1;
+	}
+
+	sdp = (sdp_info_t*)msg->body;
+
+	print_sdp(sdp, llevel);
+	return 1;
+}

+ 1 - 1
modules/tm/tm.c

@@ -461,7 +461,7 @@ static cmd_export_t cmds[]={
 	{"t_save_lumps",      w_t_save_lumps,           0, 0,
 	{"t_save_lumps",      w_t_save_lumps,           0, 0,
 			REQUEST_ROUTE},
 			REQUEST_ROUTE},
 	{"t_check_trans",	  w_t_check_trans,			0, 0,
 	{"t_check_trans",	  w_t_check_trans,			0, 0,
-			REQUEST_ROUTE|TM_ONREPLY_ROUTE|BRANCH_ROUTE },
+			REQUEST_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE },
 
 
 	{"t_load_contacts", t_load_contacts,            0, 0,
 	{"t_load_contacts", t_load_contacts,            0, 0,
 			REQUEST_ROUTE | FAILURE_ROUTE},
 			REQUEST_ROUTE | FAILURE_ROUTE},

+ 2 - 2
modules_k/dialog/dialog.c

@@ -85,12 +85,12 @@ static char* rr_param = "did";
 static int dlg_flag = -1;
 static int dlg_flag = -1;
 static str timeout_spec = {NULL, 0};
 static str timeout_spec = {NULL, 0};
 static int default_timeout = 60 * 60 * 12;  /* 12 hours */
 static int default_timeout = 60 * 60 * 12;  /* 12 hours */
-static int seq_match_mode = SEQ_MATCH_STRICT_ID;
 static char* profiles_wv_s = NULL;
 static char* profiles_wv_s = NULL;
 static char* profiles_nv_s = NULL;
 static char* profiles_nv_s = NULL;
 str dlg_extra_hdrs = {NULL,0};
 str dlg_extra_hdrs = {NULL,0};
 static int db_fetch_rows = 200;
 static int db_fetch_rows = 200;
 
 
+int seq_match_mode = SEQ_MATCH_STRICT_ID;
 str dlg_bridge_controller = {"sip:[email protected]", 27};
 str dlg_bridge_controller = {"sip:[email protected]", 27};
 
 
 str ruri_pvar_param = {"$ru", 3};
 str ruri_pvar_param = {"$ru", 3};
@@ -551,7 +551,7 @@ static int mod_init(void)
 
 
 	/* init handlers */
 	/* init handlers */
 	init_dlg_handlers( rr_param, dlg_flag,
 	init_dlg_handlers( rr_param, dlg_flag,
-		timeout_spec.s?&timeout_avp:0, default_timeout, seq_match_mode);
+		timeout_spec.s?&timeout_avp:0, default_timeout);
 
 
 	/* init timer */
 	/* init timer */
 	if (init_dlg_timer(dlg_ontimeout)!=0) {
 	if (init_dlg_timer(dlg_ontimeout)!=0) {

+ 6 - 11
modules_k/dialog/dlg_handlers.c

@@ -82,8 +82,8 @@ static str       rr_param;		/*!< record-route parameter for matching */
 static int       dlg_flag;		/*!< flag for dialog tracking */
 static int       dlg_flag;		/*!< flag for dialog tracking */
 static pv_spec_t *timeout_avp;		/*!< AVP for timeout setting */
 static pv_spec_t *timeout_avp;		/*!< AVP for timeout setting */
 static int       default_timeout;	/*!< default dialog timeout */
 static int       default_timeout;	/*!< default dialog timeout */
-static int       seq_match_mode;	/*!< dlg_match mode */ 
 static int       shutdown_done = 0;	/*!< 1 when destroy_dlg_handlers was called */
 static int       shutdown_done = 0;	/*!< 1 when destroy_dlg_handlers was called */
+extern int       seq_match_mode;	/*!< dlg_match mode */ 
 extern int       detect_spirals;
 extern int       detect_spirals;
 
 
 extern struct rr_binds d_rrb;		/*!< binding to record-routing module */
 extern struct rr_binds d_rrb;		/*!< binding to record-routing module */
@@ -113,11 +113,9 @@ static unsigned int CURR_DLG_ID  = 0xffffffff;	/*!< current dialog id */
  * \param dlg_flag_p dialog flag
  * \param dlg_flag_p dialog flag
  * \param timeout_avp_p AVP for timeout setting
  * \param timeout_avp_p AVP for timeout setting
  * \param default_timeout_p default timeout
  * \param default_timeout_p default timeout
- * \param seq_match_mode_p matching mode
  */
  */
 void init_dlg_handlers(char *rr_param_p, int dlg_flag_p,
 void init_dlg_handlers(char *rr_param_p, int dlg_flag_p,
-		pv_spec_t *timeout_avp_p ,int default_timeout_p,
-		int seq_match_mode_p)
+		pv_spec_t *timeout_avp_p ,int default_timeout_p)
 {
 {
 	rr_param.s = rr_param_p;
 	rr_param.s = rr_param_p;
 	rr_param.len = strlen(rr_param.s);
 	rr_param.len = strlen(rr_param.s);
@@ -126,7 +124,6 @@ void init_dlg_handlers(char *rr_param_p, int dlg_flag_p,
 
 
 	timeout_avp = timeout_avp_p;
 	timeout_avp = timeout_avp_p;
 	default_timeout = default_timeout_p;
 	default_timeout = default_timeout_p;
-	seq_match_mode = seq_match_mode_p;
 }
 }
 
 
 
 
@@ -716,12 +713,10 @@ int dlg_new_dialog(struct sip_msg *msg, struct cell *t)
 	if (_dlg_ctx.to_bye!=0)
 	if (_dlg_ctx.to_bye!=0)
 		dlg->dflags |= DLG_FLAG_TOBYE;
 		dlg->dflags |= DLG_FLAG_TOBYE;
 
 
-	if (t) {
-		if ( d_tmb.register_tmcb( msg, t, TMCB_MAX,
-					dlg_tmcb_dummy, (void*)dlg, 0)<0 ) {
-			LM_ERR("failed cache in T the shortcut to dlg\n");
-			goto error;
-		}
+	if ( d_tmb.register_tmcb( msg, t, TMCB_MAX,
+				dlg_tmcb_dummy, (void*)dlg, 0)<0 ) {
+		LM_ERR("failed cache in T the shortcut to dlg\n");
+		goto error;
 	}
 	}
 #if 0
 #if 0
 		t->dialog_ctx = (void*) dlg;
 		t->dialog_ctx = (void*) dlg;

+ 1 - 2
modules_k/dialog/dlg_handlers.h

@@ -60,8 +60,7 @@
  * \param seq_match_mode_p matching mode
  * \param seq_match_mode_p matching mode
  */
  */
 void init_dlg_handlers(char *rr_param, int dlg_flag,
 void init_dlg_handlers(char *rr_param, int dlg_flag,
-		pv_spec_t *timeout_avp, int default_timeout,
-		int seq_match_mode);
+		pv_spec_t *timeout_avp, int default_timeout);
 
 
 
 
 /*!
 /*!

+ 10 - 9
modules_k/dialog/dlg_hash.c

@@ -543,11 +543,10 @@ void link_dlg(struct dlg_cell *dlg, int n)
  */
  */
 #define unref_dlg_unsafe(_dlg,_cnt,_d_entry)   \
 #define unref_dlg_unsafe(_dlg,_cnt,_d_entry)   \
 	do { \
 	do { \
-		(_dlg)->ref -= (_cnt); \
-		LM_DBG("unref dlg %p with %d -> %d\n",\
+		LM_DBG("unref dlg %p with %d, crt ref count: %d\n",\
 			(_dlg),(_cnt),(_dlg)->ref);\
 			(_dlg),(_cnt),(_dlg)->ref);\
-		if ((_dlg)->ref<0) {\
-			LM_CRIT("bogus ref %d with cnt %d for dlg %p [%u:%u] "\
+		if ((_dlg)->ref<=0) {\
+			LM_CRIT("bogus op: ref %d with cnt %d for dlg %p [%u:%u] "\
 				"with clid '%.*s' and tags '%.*s' '%.*s'\n",\
 				"with clid '%.*s' and tags '%.*s' '%.*s'\n",\
 				(_dlg)->ref, _cnt, _dlg,\
 				(_dlg)->ref, _cnt, _dlg,\
 				(_dlg)->h_entry, (_dlg)->h_id,\
 				(_dlg)->h_entry, (_dlg)->h_id,\
@@ -556,11 +555,13 @@ void link_dlg(struct dlg_cell *dlg, int n)
 				(_dlg)->tag[DLG_CALLER_LEG].s,\
 				(_dlg)->tag[DLG_CALLER_LEG].s,\
 				(_dlg)->tag[DLG_CALLEE_LEG].len,\
 				(_dlg)->tag[DLG_CALLEE_LEG].len,\
 				(_dlg)->tag[DLG_CALLEE_LEG].s); \
 				(_dlg)->tag[DLG_CALLEE_LEG].s); \
-		}\
-		if ((_dlg)->ref<=0) { \
-			unlink_unsafe_dlg( _d_entry, _dlg);\
-			LM_DBG("ref <=0 for dialog %p\n",_dlg);\
-			destroy_dlg(_dlg);\
+		} else { \
+			(_dlg)->ref -= (_cnt); \
+			if ((_dlg)->ref<=0) { \
+				unlink_unsafe_dlg( _d_entry, _dlg);\
+				LM_DBG("ref <=0 for dialog %p\n",_dlg);\
+				destroy_dlg(_dlg);\
+			}\
 		}\
 		}\
 	}while(0)
 	}while(0)
 
 

+ 3 - 3
modules_k/dialog/doc/dialog_admin.xml

@@ -341,9 +341,9 @@ modparam("dialog", "dlg_match_mode", 1)
 		<example>
 		<example>
 			<title>Set <varname>detect_spirals</varname> parameter</title>
 			<title>Set <varname>detect_spirals</varname> parameter</title>
 			<programlisting format="linespecific">
 			<programlisting format="linespecific">
-				...
-				modparam("dialog", "detect_spirals", 1)
-				...
+...
+modparam("dialog", "detect_spirals", 1)
+...
 			</programlisting>
 			</programlisting>
 		</example>
 		</example>
 	</section>
 	</section>

+ 12 - 3
modules_k/dispatcher/dispatch.c

@@ -1995,7 +1995,7 @@ int ds_mark_dst(struct sip_msg *msg, int mode)
 	
 	
 	if(mode==1) {
 	if(mode==1) {
 		ret = ds_set_state(group, &avp_value.s,
 		ret = ds_set_state(group, &avp_value.s,
-				DS_INACTIVE_DST|DS_PROBING_DST, 0);
+				DS_INACTIVE_DST|DS_PROBING_DST|DS_RESET_FAIL_DST, 0);
 	} else if(mode==2) {
 	} else if(mode==2) {
 		ret = ds_set_state(group, &avp_value.s, DS_PROBING_DST, 1);
 		ret = ds_set_state(group, &avp_value.s, DS_PROBING_DST, 1);
 		if (ret == 0) ret = ds_set_state(group, &avp_value.s,
 		if (ret == 0) ret = ds_set_state(group, &avp_value.s,
@@ -2039,7 +2039,6 @@ int ds_set_state(int group, str *address, int state, int type)
 				&& strncasecmp(idx->dlist[i].uri.s, address->s,
 				&& strncasecmp(idx->dlist[i].uri.s, address->s,
 					address->len)==0)
 					address->len)==0)
 		{
 		{
-			
 			/* remove the Probing/Inactive-State? Set the fail-count to 0. */
 			/* remove the Probing/Inactive-State? Set the fail-count to 0. */
 			if (state == DS_PROBING_DST) {
 			if (state == DS_PROBING_DST) {
 				if (type) {
 				if (type) {
@@ -2064,6 +2063,16 @@ int ds_set_state(int group, str *address, int state, int type)
 				idx->dlist[i].failure_count = 0;
 				idx->dlist[i].failure_count = 0;
 				state &= ~DS_RESET_FAIL_DST;
 				state &= ~DS_RESET_FAIL_DST;
 			}
 			}
+	
+			/*  Type 2 means reply from OPTIONS-Ping */
+			if (type == 2) {
+				if (idx->dlist[i].flags & DS_INACTIVE_DST) {
+					LM_INFO("Ignoring the request to set this destination"
+							" to active: It is already administratively deactivated!\n");
+					return 0;
+				}
+				type = 0;
+			}
 			
 			
 			if(type)
 			if(type)
 				idx->dlist[i].flags |= state;
 				idx->dlist[i].flags |= state;
@@ -2307,7 +2316,7 @@ static void ds_options_callback( struct cell *t, int type,
 		/* Set the according entry back to "Active":
 		/* Set the according entry back to "Active":
 		 *  remove the Probing/Inactive Flag and reset the failure counter. */
 		 *  remove the Probing/Inactive Flag and reset the failure counter. */
 		if (ds_set_state(group, &uri,
 		if (ds_set_state(group, &uri,
-					DS_INACTIVE_DST|DS_PROBING_DST|DS_RESET_FAIL_DST, 0) != 0)
+					DS_INACTIVE_DST|DS_PROBING_DST|DS_RESET_FAIL_DST, 2) != 0)
 		{
 		{
 			LM_ERR("Setting the state failed (%.*s, group %d)\n", uri.len,
 			LM_ERR("Setting the state failed (%.*s, group %d)\n", uri.len,
 					uri.s, group);
 					uri.s, group);

+ 2 - 2
modules_k/dispatcher/dispatcher.c

@@ -170,9 +170,9 @@ static cmd_export_t cmds[]={
 	{"ds_next_domain",   (cmd_function)w_ds_next_domain,   0,
 	{"ds_next_domain",   (cmd_function)w_ds_next_domain,   0,
 		ds_warn_fixup, 0, REQUEST_ROUTE|FAILURE_ROUTE},
 		ds_warn_fixup, 0, REQUEST_ROUTE|FAILURE_ROUTE},
 	{"ds_mark_dst",      (cmd_function)w_ds_mark_dst0,     0,
 	{"ds_mark_dst",      (cmd_function)w_ds_mark_dst0,     0,
-		ds_warn_fixup, 0, REQUEST_ROUTE|FAILURE_ROUTE},
+		ds_warn_fixup, 0, REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE},
 	{"ds_mark_dst",      (cmd_function)w_ds_mark_dst1,     1,
 	{"ds_mark_dst",      (cmd_function)w_ds_mark_dst1,     1,
-		ds_warn_fixup, 0, REQUEST_ROUTE|FAILURE_ROUTE},
+		ds_warn_fixup, 0, REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE},
 	{"ds_is_from_list",  (cmd_function)w_ds_is_from_list0, 0,
 	{"ds_is_from_list",  (cmd_function)w_ds_is_from_list0, 0,
 		0, 0, REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE},
 		0, 0, REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE},
 	{"ds_is_from_list",  (cmd_function)w_ds_is_from_list1, 1,
 	{"ds_is_from_list",  (cmd_function)w_ds_is_from_list1, 1,

+ 2 - 2
modules_k/dispatcher/doc/dispatcher.xml

@@ -26,9 +26,9 @@
             <editor>
             <editor>
                 <firstname>Carsten</firstname>
                 <firstname>Carsten</firstname>
                 <surname>Bock</surname>
                 <surname>Bock</surname>
-                <affiliation><orgname>BASIS AudioNet GmbH</orgname></affiliation>
+                <affiliation><orgname>ng-voice.com</orgname></affiliation>
                 <address>
                 <address>
-                <email>[email protected]</email>
+                <email>[email protected]</email>
                 </address>
                 </address>
             </editor>
             </editor>
 	</authorgroup>
 	</authorgroup>

+ 1 - 1
modules_k/dispatcher/doc/dispatcher_admin.xml

@@ -905,7 +905,7 @@ ds_select_dst("1", "$var(a)");
 		</listitem>
 		</listitem>
 		<listitem>
 		<listitem>
 			<para><emphasis>"a", "A" or "1"</emphasis> - the last destination
 			<para><emphasis>"a", "A" or "1"</emphasis> - the last destination
-				should be set to active.</para>
+				should be set to active and the error-counter should set to "0".</para>
 		</listitem>
 		</listitem>
 		<listitem>
 		<listitem>
 			<para><emphasis>"p", "P" or "2"</emphasis> - the last destination
 			<para><emphasis>"p", "P" or "2"</emphasis> - the last destination

+ 2 - 2
modules_k/htable/README

@@ -11,7 +11,7 @@ Elena-Ramona Modroiu
 
 
    <[email protected]>
    <[email protected]>
 
 
-   Copyright © 2008 http://www.asipto.com
+   Copyright © 2008-2011 http://www.asipto.com
      __________________________________________________________________
      __________________________________________________________________
 
 
    Table of Contents
    Table of Contents
@@ -179,7 +179,7 @@ if(is_present_hf("Authorization"))
                 sl_send_reply("403", "Forbidden");
                 sl_send_reply("403", "Forbidden");
             exit;
             exit;
             case -2:
             case -2:
-                if($sht(a=>$au::auth_count) == null)
+                if($sht(a=>$au::auth_count) == $null)
                     $sht(a=>$au::auth_count) = 0;
                     $sht(a=>$au::auth_count) = 0;
                 $sht(a=>$au::auth_count) = $sht(a=>$au::auth_count) + 1;
                 $sht(a=>$au::auth_count) = $sht(a=>$au::auth_count) + 1;
                 if($sht(a=>$au::auth_count) == 3)
                 if($sht(a=>$au::auth_count) == 3)

+ 1 - 1
modules_k/htable/doc/htable_admin.xml

@@ -91,7 +91,7 @@ if(is_present_hf("Authorization"))
                 sl_send_reply("403", "Forbidden");
                 sl_send_reply("403", "Forbidden");
             exit;
             exit;
             case -2:
             case -2:
-                if($sht(a=&gt;$au::auth_count) == null)
+                if($sht(a=&gt;$au::auth_count) == $null)
                     $sht(a=&gt;$au::auth_count) = 0;
                     $sht(a=&gt;$au::auth_count) = 0;
                 $sht(a=&gt;$au::auth_count) = $sht(a=&gt;$au::auth_count) + 1;
                 $sht(a=&gt;$au::auth_count) = $sht(a=&gt;$au::auth_count) + 1;
                 if($sht(a=&gt;$au::auth_count) == 3)
                 if($sht(a=&gt;$au::auth_count) == 3)

+ 38 - 0
modules_k/kex/README

@@ -38,6 +38,8 @@ Daniel-Constantin Mierla
               3.10. isdsturiset()
               3.10. isdsturiset()
               3.11. pv_printf(var, str)
               3.11. pv_printf(var, str)
               3.12. is_myself(uri)
               3.12. is_myself(uri)
+              3.13. setdebug(level)
+              3.14. resetdebug()
 
 
         4. Exported MI Functions
         4. Exported MI Functions
 
 
@@ -66,6 +68,8 @@ Daniel-Constantin Mierla
    1.10. >isdsturiset usage
    1.10. >isdsturiset usage
    1.11. >pv_printf usage
    1.11. >pv_printf usage
    1.12. >is_myself usage
    1.12. >is_myself usage
+   1.13. setdebug usage
+   1.14. >resetdebug usage
 
 
 Chapter 1. Admin Guide
 Chapter 1. Admin Guide
 
 
@@ -91,6 +95,8 @@ Chapter 1. Admin Guide
         3.10. isdsturiset()
         3.10. isdsturiset()
         3.11. pv_printf(var, str)
         3.11. pv_printf(var, str)
         3.12. is_myself(uri)
         3.12. is_myself(uri)
+        3.13. setdebug(level)
+        3.14. resetdebug()
 
 
    4. Exported MI Functions
    4. Exported MI Functions
 
 
@@ -141,6 +147,8 @@ Chapter 1. Admin Guide
    3.10. isdsturiset()
    3.10. isdsturiset()
    3.11. pv_printf(var, str)
    3.11. pv_printf(var, str)
    3.12. is_myself(uri)
    3.12. is_myself(uri)
+   3.13. setdebug(level)
+   3.14. resetdebug()
 
 
 3.1. setsflag(flag)
 3.1. setsflag(flag)
 
 
@@ -351,6 +359,36 @@ if(is_myself("$fu")) {
 }
 }
 ...
 ...
 
 
+3.13. setdebug(level)
+
+   Set the debug log level per process.
+
+   Meaning of the parameters is as follows:
+     * level - the debug log level to be set. Can be integer or
+       pseudo-variable with integer value.
+
+   This function can be used from ANY_ROUTE.
+
+   Example 1.13. setdebug usage
+...
+setdebug("1");
+...
+$var(level) = 2;
+setdebug("$var(level)");
+...
+
+3.14. resetdebug()
+
+   Reset the local debug log level back to the value of core parameter
+   'debug'.
+
+   This function can be used from ANY_ROUTE.
+
+   Example 1.14. >resetdebug usage
+...
+resetdebug();
+...
+
 4. Exported MI Functions
 4. Exported MI Functions
 
 
    4.1. arg
    4.1. arg

+ 47 - 0
modules_k/kex/doc/kex_admin.xml

@@ -404,6 +404,53 @@ if(is_myself("$fu")) {
     ...
     ...
 }
 }
 ...
 ...
+</programlisting>
+		</example>
+		</section>
+		<section>
+		<title><function moreinfo="none">setdebug(level)</function></title>
+		<para>
+			Set the debug log level per process.
+		</para>
+		<para>Meaning of the parameters is as follows:</para>
+		<itemizedlist>
+		<listitem>
+			<para>
+				<emphasis>level</emphasis> - the debug log level to
+				be set. Can be integer or pseudo-variable with integer value.
+			</para>
+		</listitem>
+		</itemizedlist>
+		<para>
+		This function can be used from ANY_ROUTE.
+		</para>
+		<example>
+		<title><function>setdebug</function> usage</title>
+		<programlisting format="linespecific">
+...
+setdebug("1");
+...
+$var(level) = 2;
+setdebug("$var(level)");
+...
+</programlisting>
+		</example>
+		</section>
+		<section>
+		<title><function moreinfo="none">resetdebug()</function></title>
+		<para>
+		Reset the local debug log level back to the value of core parameter
+		'debug'.
+		</para>
+		<para>
+		This function can be used from ANY_ROUTE.
+		</para>
+		<example>
+		<title><function>>resetdebug</function> usage</title>
+		<programlisting format="linespecific">
+...
+resetdebug();
+...
 </programlisting>
 </programlisting>
 		</example>
 		</example>
 		</section>
 		</section>

+ 23 - 0
modules_k/kex/kex_mod.c

@@ -46,6 +46,8 @@ MODULE_VERSION
 
 
 /** module functions */
 /** module functions */
 int w_is_myself(struct sip_msg *msg, char *uri, str *s2);
 int w_is_myself(struct sip_msg *msg, char *uri, str *s2);
+int w_setdebug(struct sip_msg *msg, char *level, str *s2);
+int w_resetdebug(struct sip_msg *msg, char *uri, str *s2);
 
 
 static int mod_init(void);
 static int mod_init(void);
 static int child_init(int rank);
 static int child_init(int rank);
@@ -86,6 +88,10 @@ static cmd_export_t cmds[]={
 			0, ANY_ROUTE },
 			0, ANY_ROUTE },
 	{"is_myself", (cmd_function)w_is_myself,    1, fixup_spve_null,
 	{"is_myself", (cmd_function)w_is_myself,    1, fixup_spve_null,
 			0, ANY_ROUTE },
 			0, ANY_ROUTE },
+	{"setdebug", (cmd_function)w_setdebug,      1, fixup_igp_null,
+			0, ANY_ROUTE },
+	{"resetdebug", (cmd_function)w_resetdebug,  0, 0,
+			0, ANY_ROUTE },
 
 
 	{0,0,0,0,0,0}
 	{0,0,0,0,0,0}
 };
 };
@@ -182,3 +188,20 @@ int w_is_myself(struct sip_msg *msg, char *uri, str *s2)
 	return 1;
 	return 1;
 }
 }
 
 
+int w_setdebug(struct sip_msg *msg, char *level, str *s2)
+{
+	int lval=0;
+	if(fixup_get_ivalue(msg, (gparam_p)level, &lval)!=0)
+	{
+		LM_ERR("no debug level value\n");
+		return -1;
+	}
+	set_local_debug_level(lval);
+	return 1;
+}
+
+int w_resetdebug(struct sip_msg *msg, char *uri, str *s2)
+{
+	reset_local_debug_level();
+	return 1;
+}

+ 9 - 9
modules_k/nathelper/nathelper.c

@@ -775,7 +775,7 @@ fix_nated_contact_f(struct sip_msg* msg, char* str1, char* str2)
 #define SALIAS_LEN (sizeof(SALIAS) - 1)
 #define SALIAS_LEN (sizeof(SALIAS) - 1)
 
 
 /*
 /*
- * Adds ;alias=ip:port param to cotact uri containing received ip:port
+ * Adds ;alias=ip:port param to contact uri containing received ip:port
  * if contact uri ip:port does not match received ip:port.
  * if contact uri ip:port does not match received ip:port.
  */
  */
 static int
 static int
@@ -806,14 +806,14 @@ add_contact_alias_f(struct sip_msg* msg, char* str1, char* str2)
 
 
     /* Compare source ip and port against contact uri */
     /* Compare source ip and port against contact uri */
     if ((ip = str2ip(&(uri.host))) == NULL) {
     if ((ip = str2ip(&(uri.host))) == NULL) {
-	LM_ERR("contact uri host is not an ip address\n");
-	return -1;
-    }
-    if (ip_addr_cmp(ip, &(msg->rcv.src_ip)) &&
-	((msg->rcv.src_port == uri.port_no) ||
-	 ((uri.port.len == 0) && (msg->rcv.src_port == 5060)))) {
-	LM_DBG("no need to add alias param\n");
-	return 2;
+	LM_DBG("contact uri host is not an ip address\n");
+    } else {
+	if (ip_addr_cmp(ip, &(msg->rcv.src_ip)) &&
+	    ((msg->rcv.src_port == uri.port_no) ||
+	     ((uri.port.len == 0) && (msg->rcv.src_port == 5060)))) {
+	    LM_DBG("no need to add alias param\n");
+	    return 2;
+	}
     }
     }
 	
 	
     /* Check if function has been called already */
     /* Check if function has been called already */

+ 21 - 0
modules_k/permissions/doc/permissions_admin.xml

@@ -669,6 +669,27 @@ modparam("permissions", "tag_col", "peer_tag")
 ...
 ...
 modparam("permissions", "peer_tag_avp", "$avp(i:707)")
 modparam("permissions", "peer_tag_avp", "$avp(i:707)")
 ...
 ...
+</programlisting>
+		</example>
+	</section>
+	<section>
+		<title><varname>peer_tag_mode</varname> (integer)</title>
+		<para>
+		Tag mode for allow_trusted(). 0 sets only the tag of the
+		first match. 1 adds the tags of all matches to the avp. In addition
+		the return value of allow_trusted() is the number of matches.
+		</para>
+		<para>
+		<emphasis>
+		Default value is <quote>0</quote>.
+		</emphasis>
+		</para>
+		<example>
+		<title>Set <varname>peer_tag_mode</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+modparam("permissions", "peer_tag_mode", "1")
+...
 </programlisting>
 </programlisting>
 		</example>
 		</example>
 	</section>
 	</section>

+ 33 - 23
modules_k/permissions/hash.c

@@ -40,6 +40,9 @@
 static int     tag_avp_type;
 static int     tag_avp_type;
 static int_str tag_avp;
 static int_str tag_avp;
 
 
+extern int peer_tag_mode;
+
+
 
 
 /*
 /*
  * Parse and set tag AVP specs
  * Parse and set tag AVP specs
@@ -199,6 +202,7 @@ int hash_table_insert(struct trusted_list** table, char* src_ip,
  * Check if an entry exists in hash table that has given src_ip and protocol
  * Check if an entry exists in hash table that has given src_ip and protocol
  * value and pattern that matches to From URI.  If an entry exists and tag_avp
  * value and pattern that matches to From URI.  If an entry exists and tag_avp
  * has been defined, tag of the entry is added as a value to tag_avp.
  * has been defined, tag of the entry is added as a value to tag_avp.
+ * Returns number of matches or -1 if none matched.
  */
  */
 int match_hash_table(struct trusted_list** table, struct sip_msg* msg,
 int match_hash_table(struct trusted_list** table, struct sip_msg* msg,
 		     char *src_ip_c_str, int proto)
 		     char *src_ip_c_str, int proto)
@@ -209,6 +213,7 @@ int match_hash_table(struct trusted_list** table, struct sip_msg* msg,
 	struct trusted_list *np;
 	struct trusted_list *np;
 	str src_ip;
 	str src_ip;
 	int_str val;
 	int_str val;
+	int count = 0;
 
 
 	src_ip.s = src_ip_c_str;
 	src_ip.s = src_ip_c_str;
 	src_ip.len = strlen(src_ip.s);
 	src_ip.len = strlen(src_ip.s);
@@ -223,32 +228,37 @@ int match_hash_table(struct trusted_list** table, struct sip_msg* msg,
 	uri_string[uri.len] = (char)0;
 	uri_string[uri.len] = (char)0;
 
 
 	for (np = table[perm_hash(src_ip)]; np != NULL; np = np->next) {
 	for (np = table[perm_hash(src_ip)]; np != NULL; np = np->next) {
-	    if ((np->src_ip.len == src_ip.len) && 
-		(strncmp(np->src_ip.s, src_ip.s, src_ip.len) == 0) &&
-		((np->proto == PROTO_NONE) || (np->proto == proto))) {
-		if (!(np->pattern)) goto found;
-		if (regcomp(&preg, np->pattern, REG_NOSUB)) {
-		    LM_ERR("invalid regular expression\n");
-		    return -1;
-		}
-		if (regexec(&preg, uri_string, 0, (regmatch_t *)0, 0)) {
-		    regfree(&preg);
-		} else {
-		    regfree(&preg);
-		    goto found;
+		if ((np->src_ip.len == src_ip.len) && 
+		   (strncmp(np->src_ip.s, src_ip.s, src_ip.len) == 0) &&
+		   ((np->proto == PROTO_NONE) || (np->proto == proto))) {
+			if (np->pattern) {
+				if (regcomp(&preg, np->pattern, REG_NOSUB)) {
+					LM_ERR("invalid regular expression\n");
+					continue;
+				}
+				if (regexec(&preg, uri_string, 0, (regmatch_t *)0, 0)) {
+					regfree(&preg);
+					continue;
+				}
+				regfree(&preg);
+			}
+			/* Found a match */
+			if (tag_avp.n && np->tag.s) {
+				val.s = np->tag;
+				if (add_avp(tag_avp_type|AVP_VAL_STR, tag_avp, val) != 0) {
+					LM_ERR("setting of tag_avp failed\n");
+					return -1;
+				}
+			}
+			if (!peer_tag_mode)
+				return 1;
+			count++;
 		}
 		}
-	    }
 	}
 	}
-	return -1;
-found:
-	if (tag_avp.n && np->tag.s) {
-	    val.s = np->tag;
-	    if (add_avp(tag_avp_type|AVP_VAL_STR, tag_avp, val) != 0) {
-		LM_ERR("setting of tag_avp failed\n");
+	if (!count)
 		return -1;
 		return -1;
-	    }
-	}
-	return 1;
+	else 
+		return count;
 }
 }
 
 
 
 

+ 2 - 0
modules_k/permissions/permissions.c

@@ -68,6 +68,7 @@ str proto_col = str_init("proto");         /* Name of protocol column */
 str from_col = str_init("from_pattern");   /* Name of from pattern column */
 str from_col = str_init("from_pattern");   /* Name of from pattern column */
 str tag_col = str_init("tag");             /* Name of tag column */
 str tag_col = str_init("tag");             /* Name of tag column */
 str tag_avp_param = {NULL, 0};             /* Peer tag AVP spec */
 str tag_avp_param = {NULL, 0};             /* Peer tag AVP spec */
+int peer_tag_mode = 0;                     /* Add tags form all mathcing peers to avp */
 
 
 /* for allow_address function */
 /* for allow_address function */
 str address_table = str_init("address");   /* Name of address table */
 str address_table = str_init("address");   /* Name of address table */
@@ -159,6 +160,7 @@ static param_export_t params[] = {
 	{"from_col",           STR_PARAM, &from_col.s        },
 	{"from_col",           STR_PARAM, &from_col.s        },
 	{"tag_col",            STR_PARAM, &tag_col.s         },
 	{"tag_col",            STR_PARAM, &tag_col.s         },
 	{"peer_tag_avp",       STR_PARAM, &tag_avp_param.s   },
 	{"peer_tag_avp",       STR_PARAM, &tag_avp_param.s   },
+	{"peer_tag_mode",      INT_PARAM, &peer_tag_mode     },
 	{"address_table",      STR_PARAM, &address_table.s   },
 	{"address_table",      STR_PARAM, &address_table.s   },
 	{"grp_col",            STR_PARAM, &grp_col.s         },
 	{"grp_col",            STR_PARAM, &grp_col.s         },
 	{"ip_addr_col",        STR_PARAM, &ip_addr_col.s     },
 	{"ip_addr_col",        STR_PARAM, &ip_addr_col.s     },

+ 2 - 0
modules_k/permissions/permissions.h

@@ -61,6 +61,8 @@ extern str grp_col;       /* Name of address group column */
 extern str ip_addr_col;   /* Name of ip address column */
 extern str ip_addr_col;   /* Name of ip address column */
 extern str mask_col;      /* Name of mask column */
 extern str mask_col;      /* Name of mask column */
 extern str port_col;      /* Name of port column */
 extern str port_col;      /* Name of port column */
+extern int peer_tag_mode; /* Matching mode */
+
 
 
 typedef struct int_or_pvar {
 typedef struct int_or_pvar {
     unsigned int i;
     unsigned int i;

+ 41 - 37
modules_k/permissions/trusted.c

@@ -328,18 +328,19 @@ static inline int match_proto(const char *proto_string, int proto_int)
 }
 }
 
 
 /*
 /*
- * Matches from uri against patterns returned from database.  Returns 1 when
- * first pattern matches and 0 if none of the patterns match.
+ * Matches from uri against patterns returned from database.  Returns number
+ * of matches or -1 if none of the patterns match.
  */
  */
 static int match_res(struct sip_msg* msg, int proto, db1_res_t* _r)
 static int match_res(struct sip_msg* msg, int proto, db1_res_t* _r)
 {
 {
-        int i, tag_avp_type;
+	int i, tag_avp_type;
 	str uri;
 	str uri;
 	char uri_string[MAX_URI_SIZE+1];
 	char uri_string[MAX_URI_SIZE+1];
 	db_row_t* row;
 	db_row_t* row;
 	db_val_t* val;
 	db_val_t* val;
 	regex_t preg;
 	regex_t preg;
 	int_str tag_avp, avp_val;
 	int_str tag_avp, avp_val;
+	int count = 0;
 
 
 	if (parse_from_header(msg) < 0) return -1;
 	if (parse_from_header(msg) < 0) return -1;
 	uri = get_from(msg)->uri;
 	uri = get_from(msg)->uri;
@@ -349,46 +350,49 @@ static int match_res(struct sip_msg* msg, int proto, db1_res_t* _r)
 	}
 	}
 	memcpy(uri_string, uri.s, uri.len);
 	memcpy(uri_string, uri.s, uri.len);
 	uri_string[uri.len] = (char)0;
 	uri_string[uri.len] = (char)0;
+	get_tag_avp(&tag_avp, &tag_avp_type);
 
 
 	row = RES_ROWS(_r);
 	row = RES_ROWS(_r);
-		
+
 	for(i = 0; i < RES_ROW_N(_r); i++) {
 	for(i = 0; i < RES_ROW_N(_r); i++) {
-	    val = ROW_VALUES(row + i);
-	    if ((ROW_N(row + i) == 3) &&
-		(VAL_TYPE(val) == DB1_STRING) && !VAL_NULL(val) &&
-		match_proto(VAL_STRING(val), proto) &&
-		(VAL_NULL(val + 1) ||
-		 ((VAL_TYPE(val + 1) == DB1_STRING) && !VAL_NULL(val + 1))) &&
-		(VAL_NULL(val + 2) ||
-		 ((VAL_TYPE(val + 2) == DB1_STRING) && !VAL_NULL(val + 2))))
-	    {
-		if (VAL_NULL(val + 1)) goto found;
-		if (regcomp(&preg, (char *)VAL_STRING(val + 1), REG_NOSUB)) {
-		    LM_ERR("invalid regular expression\n");
-		    continue;
-		}
-		if (regexec(&preg, uri_string, 0, (regmatch_t *)0, 0)) {
-		    regfree(&preg);
-		    continue;
-		} else {
-		    regfree(&preg);
-		    goto found;
+		val = ROW_VALUES(row + i);
+		if ((ROW_N(row + i) == 3) &&
+		    (VAL_TYPE(val) == DB1_STRING) && !VAL_NULL(val) &&
+		    match_proto(VAL_STRING(val), proto) &&
+		    (VAL_NULL(val + 1) ||
+		      ((VAL_TYPE(val + 1) == DB1_STRING) && !VAL_NULL(val + 1))) &&
+		    (VAL_NULL(val + 2) ||
+		      ((VAL_TYPE(val + 2) == DB1_STRING) && !VAL_NULL(val + 2))))
+		{
+			if (!VAL_NULL(val + 1)) {
+				if (regcomp(&preg, (char *)VAL_STRING(val + 1), REG_NOSUB)) {
+					LM_ERR("invalid regular expression\n");
+					continue;
+				}
+				if (regexec(&preg, uri_string, 0, (regmatch_t *)0, 0)) {
+					regfree(&preg);
+					continue;
+				}
+			    regfree(&preg);
+			}
+			/* Found a match */
+			if (tag_avp.n && !VAL_NULL(val + 2)) {
+				avp_val.s.s = (char *)VAL_STRING(val + 2);
+				avp_val.s.len = strlen(avp_val.s.s);
+				if (add_avp(tag_avp_type|AVP_VAL_STR, tag_avp, avp_val) != 0) {
+					LM_ERR("failed to set of tag_avp failed\n");
+					return -1;
+				}
+			}
+			if (!peer_tag_mode) 
+				return 1;
+			count++;
 		}
 		}
-	    }
 	}
 	}
-	return -1;
-
-found:
-	get_tag_avp(&tag_avp, &tag_avp_type);
-	if (tag_avp.n && !VAL_NULL(val + 2)) {
-	    avp_val.s.s = (char *)VAL_STRING(val + 2);
-	    avp_val.s.len = strlen(avp_val.s.s);
-	    if (add_avp(tag_avp_type|AVP_VAL_STR, tag_avp, avp_val) != 0) {
-		LM_ERR("failed to set of tag_avp failed\n");
+	if (!count)
 		return -1;
 		return -1;
-	    }
-	}
-	return 1;
+	else 
+		return count;
 }
 }
 
 
 
 

+ 6 - 0
modules_k/pv/pv.c

@@ -220,6 +220,9 @@ static pv_export_t mod_pvs[] = {
 	{{"ml", (sizeof("ml")-1)}, /* */
 	{{"ml", (sizeof("ml")-1)}, /* */
 		PVT_OTHER, pv_get_msg_len, 0,
 		PVT_OTHER, pv_get_msg_len, 0,
 		0, 0, 0, 0},
 		0, 0, 0, 0},
+	{{"mt", (sizeof("mt")-1)}, /* */
+		PVT_OTHER, pv_get_msgtype, 0,
+		0, 0, 0, 0},
 	{{"od", (sizeof("od")-1)}, /* */
 	{{"od", (sizeof("od")-1)}, /* */
 		PVT_OTHER, pv_get_ouri_attr, 0,
 		PVT_OTHER, pv_get_ouri_attr, 0,
 		0, 0, pv_init_iname, 2},
 		0, 0, pv_init_iname, 2},
@@ -361,6 +364,9 @@ static pv_export_t mod_pvs[] = {
 	{{"true", (sizeof("true")-1)}, /* */
 	{{"true", (sizeof("true")-1)}, /* */
 		PVT_OTHER, pv_get_true, 0,
 		PVT_OTHER, pv_get_true, 0,
 		0, 0, 0, 0},
 		0, 0, 0, 0},
+	{{"Tb", (sizeof("Tb")-1)}, /* */
+		PVT_OTHER, pv_get_timeb, 0,
+		0, 0, 0, 0},
 	{{"Tf", (sizeof("Tf")-1)}, /* */
 	{{"Tf", (sizeof("Tf")-1)}, /* */
 		PVT_CONTEXT, pv_get_timef, 0,
 		PVT_CONTEXT, pv_get_timef, 0,
 		0, 0, 0, 0},
 		0, 0, 0, 0},

+ 16 - 0
modules_k/pv/pv_core.c

@@ -152,6 +152,22 @@ int pv_get_methodid(struct sip_msg *msg, pv_param_t *param,
 			(unsigned int)(get_cseq(msg)->method_id));
 			(unsigned int)(get_cseq(msg)->method_id));
 }
 }
 
 
+int pv_get_msgtype(struct sip_msg *msg, pv_param_t *param,
+		pv_value_t *res)
+{
+	unsigned int type = 0;
+
+	if(msg==NULL)
+		return -1;
+
+	if(msg->first_line.type == SIP_REQUEST)
+		type = 1;
+	else if(msg->first_line.type == SIP_REPLY)
+		type = 2;
+
+	return pv_get_uintval(msg, param, res, type);
+}
+
 int pv_get_version(struct sip_msg *msg, pv_param_t *param,
 int pv_get_version(struct sip_msg *msg, pv_param_t *param,
 		pv_value_t *res)
 		pv_value_t *res)
 {
 {

+ 3 - 0
modules_k/pv/pv_core.h

@@ -48,6 +48,9 @@ int pv_get_method(struct sip_msg *msg, pv_param_t *param,
 int pv_get_methodid(struct sip_msg *msg, pv_param_t *param,
 int pv_get_methodid(struct sip_msg *msg, pv_param_t *param,
 		pv_value_t *res);
 		pv_value_t *res);
 
 
+int pv_get_msgtype(struct sip_msg *msg, pv_param_t *param,
+		pv_value_t *res);
+
 int pv_get_status(struct sip_msg *msg, pv_param_t *param,
 int pv_get_status(struct sip_msg *msg, pv_param_t *param,
 		pv_value_t *res);
 		pv_value_t *res);
 
 

+ 9 - 0
modules_k/pv/pv_time.c

@@ -30,6 +30,7 @@
 #include <sys/time.h>
 #include <sys/time.h>
 
 
 #include "../../dprint.h"
 #include "../../dprint.h"
+#include "../../globals.h"
 #include "../../pvar.h"
 #include "../../pvar.h"
 
 
 #include "pv_time.h"
 #include "pv_time.h"
@@ -254,6 +255,14 @@ int pv_get_timef(struct sip_msg *msg, pv_param_t *param,
 	return pv_get_strintval(msg, param, res, &s, (int)t);
 	return pv_get_strintval(msg, param, res, &s, (int)t);
 }
 }
 
 
+int pv_get_timeb(struct sip_msg *msg, pv_param_t *param,
+		pv_value_t *res)
+{
+	if(msg==NULL)
+		return -1;
+	return pv_get_uintval(msg, param, res, (unsigned int)up_since);
+}
+
 static struct timeval _timeval_ts;
 static struct timeval _timeval_ts;
 static unsigned int _timeval_msg_id = 0;
 static unsigned int _timeval_msg_id = 0;
 static char _timeval_ts_buf[32];
 static char _timeval_ts_buf[32];

+ 2 - 0
modules_k/pv/pv_time.h

@@ -40,6 +40,8 @@ int pv_get_times(struct sip_msg *msg, pv_param_t *param,
 		pv_value_t *res);
 		pv_value_t *res);
 int pv_get_timef(struct sip_msg *msg, pv_param_t *param,
 int pv_get_timef(struct sip_msg *msg, pv_param_t *param,
 		pv_value_t *res);
 		pv_value_t *res);
+int pv_get_timeb(struct sip_msg *msg, pv_param_t *param,
+		pv_value_t *res);
 
 
 int pv_parse_timeval_name(pv_spec_p sp, str *in);
 int pv_parse_timeval_name(pv_spec_p sp, str *in);
 int pv_get_timeval(struct sip_msg *msg, pv_param_t *param,
 int pv_get_timeval(struct sip_msg *msg, pv_param_t *param,

+ 77 - 2
modules_k/pv/pv_trans.c

@@ -67,7 +67,7 @@ static char _tr_buffer[TR_BUFFER_SIZE];
 int tr_eval_string(struct sip_msg *msg, tr_param_t *tp, int subtype,
 int tr_eval_string(struct sip_msg *msg, tr_param_t *tp, int subtype,
 		pv_value_t *val)
 		pv_value_t *val)
 {
 {
-	int i, j;
+	int i, j, max;
 	char *p, *s;
 	char *p, *s;
 	str st;
 	str st;
 	pv_value_t v;
 	pv_value_t v;
@@ -452,6 +452,50 @@ int tr_eval_string(struct sip_msg *msg, tr_param_t *tp, int subtype,
 			val->rs.len -= i;
 			val->rs.len -= i;
 			break;
 			break;
 
 
+		case TR_S_PREFIXES:
+		case TR_S_PREFIXES_QUOT:
+			if(!(val->flags&PV_VAL_STR))
+				val->rs.s = int2str(val->ri, &val->rs.len);
+
+			/* Set maximum prefix length */
+			max = val->rs.len;
+			if(tp!=NULL) {
+				if(tp->type==TR_PARAM_NUMBER) {
+					if (tp->v.n > 0 && tp->v.n < max)
+						max = tp->v.n;
+				} else {
+					if(pv_get_spec_value(msg, (pv_spec_p)tp->v.data, &v)!=0
+							|| (!(v.flags&PV_VAL_INT)))
+					{
+						LM_ERR("prefixes cannot get max\n");
+						return -1;
+					}
+					if (v.ri > 0 && v.ri < max)
+						max  = v.ri;
+				}
+			}
+
+			if(max * (max/2 + (subtype==TR_S_PREFIXES_QUOT ? 1 : 3)) > TR_BUFFER_SIZE-1) {
+				LM_ERR("prefixes buffer too short\n");
+				return -1;
+			}
+
+			j = 0;
+			for (i=1; i <= max; i++) {
+				if (subtype==TR_S_PREFIXES_QUOT)
+					_tr_buffer[j++] = '\'';
+				memcpy(&(_tr_buffer[j]), val->rs.s, i);
+				j += i;
+				if (subtype==TR_S_PREFIXES_QUOT)
+					_tr_buffer[j++] = '\'';
+				_tr_buffer[j++] = ',';
+			}
+			memset(val, 0, sizeof(pv_value_t));
+			val->flags = PV_VAL_STR;
+			val->rs.s = _tr_buffer;
+			val->rs.len = j-1;
+			break;
+
 		default:
 		default:
 			LM_ERR("unknown subtype %d\n",
 			LM_ERR("unknown subtype %d\n",
 					subtype);
 					subtype);
@@ -1236,6 +1280,38 @@ char* tr_parse_string(str* in, trans_t *t)
 	} else if(name.len==14 && strncasecmp(name.s, "unescape.param", 14)==0) {
 	} else if(name.len==14 && strncasecmp(name.s, "unescape.param", 14)==0) {
 		t->subtype = TR_S_UNESCAPEPARAM;
 		t->subtype = TR_S_UNESCAPEPARAM;
 		goto done;
 		goto done;
+	} else if(name.len==8 && strncasecmp(name.s, "prefixes", 8)==0) {
+		t->subtype = TR_S_PREFIXES;
+		if(*p!=TR_PARAM_MARKER)
+			goto done;
+		p++;
+		_tr_parse_nparam(p, p0, tp, spec, n, sign, in, s);
+		t->params = tp;
+		tp = 0;
+		while(*p && (*p==' ' || *p=='\t' || *p=='\n')) p++;
+		if(*p!=TR_RBRACKET)
+		{
+			LM_ERR("invalid prefixes transformation: %.*s!!\n",
+				in->len, in->s);
+			goto error;
+		}
+		goto done;
+	} else if(name.len==15 && strncasecmp(name.s, "prefixes.quoted", 15)==0) {
+		t->subtype = TR_S_PREFIXES_QUOT;
+		if(*p!=TR_PARAM_MARKER)
+			goto done;
+		p++;
+		_tr_parse_nparam(p, p0, tp, spec, n, sign, in, s);
+		t->params = tp;
+		tp = 0;
+		while(*p && (*p==' ' || *p=='\t' || *p=='\n')) p++;
+		if(*p!=TR_RBRACKET)
+		{
+			LM_ERR("invalid prefixes transformation: %.*s!!\n",
+				in->len, in->s);
+			goto error;
+		}
+		goto done;
 	} else if(name.len==6 && strncasecmp(name.s, "substr", 6)==0) {
 	} else if(name.len==6 && strncasecmp(name.s, "substr", 6)==0) {
 		t->subtype = TR_S_SUBSTR;
 		t->subtype = TR_S_SUBSTR;
 		if(*p!=TR_PARAM_MARKER)
 		if(*p!=TR_PARAM_MARKER)
@@ -1706,4 +1782,3 @@ done:
 	t->name = name;
 	t->name = name;
 	return p;
 	return p;
 }
 }
-

+ 1 - 1
modules_k/pv/pv_trans.h

@@ -39,7 +39,7 @@ enum _tr_s_subtype {
 	TR_S_SELECT, TR_S_ENCODEHEXA, TR_S_DECODEHEXA,
 	TR_S_SELECT, TR_S_ENCODEHEXA, TR_S_DECODEHEXA,
 	TR_S_ESCAPECOMMON, TR_S_UNESCAPECOMMON, TR_S_ESCAPEUSER, TR_S_UNESCAPEUSER,
 	TR_S_ESCAPECOMMON, TR_S_UNESCAPECOMMON, TR_S_ESCAPEUSER, TR_S_UNESCAPEUSER,
 	TR_S_ESCAPEPARAM, TR_S_UNESCAPEPARAM, TR_S_TOLOWER, TR_S_TOUPPER,
 	TR_S_ESCAPEPARAM, TR_S_UNESCAPEPARAM, TR_S_TOLOWER, TR_S_TOUPPER,
-	TR_S_STRIP, TR_S_STRIPTAIL
+	TR_S_STRIP, TR_S_STRIPTAIL, TR_S_PREFIXES, TR_S_PREFIXES_QUOT
 };
 };
 enum _tr_uri_subtype {
 enum _tr_uri_subtype {
 	TR_URI_NONE=0, TR_URI_USER, TR_URI_HOST, TR_URI_PASSWD, TR_URI_PORT,
 	TR_URI_NONE=0, TR_URI_USER, TR_URI_HOST, TR_URI_PASSWD, TR_URI_PORT,

+ 4 - 2
modules_k/pv/pv_xavp.c

@@ -99,7 +99,7 @@ int pv_get_xavp(struct sip_msg *msg, pv_param_t *param,
 	if(idx<0)
 	if(idx<0)
 	{
 	{
 		count = xavp_count(&xname->name, NULL);
 		count = xavp_count(&xname->name, NULL);
-		idx = count + idx + 1;
+		idx = count + idx;
 	}
 	}
 	avp = xavp_get_by_index(&xname->name, idx, NULL);
 	avp = xavp_get_by_index(&xname->name, idx, NULL);
 	if(avp==NULL)
 	if(avp==NULL)
@@ -107,6 +107,8 @@ int pv_get_xavp(struct sip_msg *msg, pv_param_t *param,
 	if(xname->next==NULL)
 	if(xname->next==NULL)
 		return pv_xavp_get_value(msg, param, res, avp);
 		return pv_xavp_get_value(msg, param, res, avp);
 
 
+	idx = 0;
+	idxf = 0;
 	if(xname->next->index.type==PVT_EXTRA)
 	if(xname->next->index.type==PVT_EXTRA)
 	{
 	{
 		/* get the index */
 		/* get the index */
@@ -120,7 +122,7 @@ int pv_get_xavp(struct sip_msg *msg, pv_param_t *param,
 	if(idx<0)
 	if(idx<0)
 	{
 	{
 		count = xavp_count(&xname->next->name, &avp->val.v.xavp);
 		count = xavp_count(&xname->next->name, &avp->val.v.xavp);
-		idx = count + idx + 1;
+		idx = count + idx;
 	}
 	}
 	avp = xavp_get_by_index(&xname->next->name, idx, &avp->val.v.xavp);
 	avp = xavp_get_by_index(&xname->next->name, idx, &avp->val.v.xavp);
 	if(avp==NULL)
 	if(avp==NULL)

+ 196 - 142
modules_k/regex/README

@@ -1,53 +1,52 @@
 Regex Module
 Regex Module
 
 
-Iñaki Baz Castillo
+Iñaki Baz Castillo
 
 
    <[email protected]>
    <[email protected]>
 
 
 Edited by
 Edited by
 
 
-Iñaki Baz Castillo
+Iñaki Baz Castillo
 
 
    <[email protected]>
    <[email protected]>
 
 
-   Copyright © 2009 Iñaki Baz Castillo
+   Copyright © 2009 Iñaki Baz Castillo
    Revision History
    Revision History
-   Revision $Revision: 5462 $ $Date: 2009-01-14 17:05:51 +0100
-                              (Mi, 14 Jan 2009) $
-     __________________________________________________________
+   Revision $Revision$ $Date$
+     __________________________________________________________________
 
 
    Table of Contents
    Table of Contents
 
 
    1. Admin Guide
    1. Admin Guide
 
 
-        1.1. Overview
-        1.2. Dependencies
+        1. Overview
+        2. Dependencies
 
 
-              1.2.1. Kamailio Modules
-              1.2.2. External Libraries or Applications
+              2.1. Kamailio Modules
+              2.2. External Libraries or Applications
 
 
-        1.3. Exported Parameters
+        3. Exported Parameters
 
 
-              1.3.1. file (string)
-              1.3.2. max_groups (int)
-              1.3.3. group_max_size (int)
-              1.3.4. pcre_caseless (int)
-              1.3.5. pcre_multiline (int)
-              1.3.6. pcre_dotall (int)
-              1.3.7. pcre_extended (int)
+              3.1. file (string)
+              3.2. max_groups (int)
+              3.3. group_max_size (int)
+              3.4. pcre_caseless (int)
+              3.5. pcre_multiline (int)
+              3.6. pcre_dotall (int)
+              3.7. pcre_extended (int)
 
 
-        1.4. Exported Functions
+        4. Exported Functions
 
 
-              1.4.1. pcre_match (string, pcre_regex)
-              1.4.2. pcre_match_group (string [, group])
+              4.1. pcre_match (string, pcre_regex)
+              4.2. pcre_match_group (string [, group])
 
 
-        1.5. Exported MI Functions
+        5. Exported MI Functions
 
 
-              1.5.1. regex_reload
+              5.1. regex_reload
 
 
-        1.6. Installation and Running
+        6. Installation and Running
 
 
-              1.6.1. File format
+              6.1. File format
 
 
    List of Examples
    List of Examples
 
 
@@ -61,165 +60,205 @@ I
    1.8. pcre_match usage (forcing case insensitive)
    1.8. pcre_match usage (forcing case insensitive)
    1.9. pcre_match usage (using "end of line" symbol)
    1.9. pcre_match usage (using "end of line" symbol)
    1.10. pcre_match_group usage
    1.10. pcre_match_group usage
-   1.11. regex file
-   1.12. Using with pua_usrloc
-   1.13. Incorrect groups file
+   1.11. pcre_match_group usage (using a pseudo-variable as group)
+   1.12. regex file
+   1.13. Using with pua_usrloc
+   1.14. Incorrect groups file
 
 
 Chapter 1. Admin Guide
 Chapter 1. Admin Guide
 
 
-1.1. Overview
+   Table of Contents
+
+   1. Overview
+   2. Dependencies
+
+        2.1. Kamailio Modules
+        2.2. External Libraries or Applications
+
+   3. Exported Parameters
+
+        3.1. file (string)
+        3.2. max_groups (int)
+        3.3. group_max_size (int)
+        3.4. pcre_caseless (int)
+        3.5. pcre_multiline (int)
+        3.6. pcre_dotall (int)
+        3.7. pcre_extended (int)
+
+   4. Exported Functions
+
+        4.1. pcre_match (string, pcre_regex)
+        4.2. pcre_match_group (string [, group])
+
+   5. Exported MI Functions
+
+        5.1. regex_reload
+
+   6. Installation and Running
 
 
-   This module offers matching operations against regular
-   expressions using the powerful PCRE library.
+        6.1. File format
 
 
-   A text file containing regular expressions categorized in
-   groups is compiled when the module is loaded, storing the
-   compiled PCRE objects in an array. A function to match a string
-   or pseudo-variable against any of these groups is provided. The
-   text file can be modified and reloaded at any time via a MI
-   command. The module also offers a function to perform a PCRE
-   matching operation against a regular expression provided as
-   function parameter.
+1. Overview
 
 
-   For a detailed list of PCRE features read the man page of the
-   library.
+   This module offers matching operations against regular expressions
+   using the powerful PCRE library.
 
 
-1.2. Dependencies
+   A text file containing regular expressions categorized in groups is
+   compiled when the module is loaded, storing the compiled PCRE objects
+   in an array. A function to match a string or pseudo-variable against
+   any of these groups is provided. The text file can be modified and
+   reloaded at any time via a MI command. The module also offers a
+   function to perform a PCRE matching operation against a regular
+   expression provided as function parameter.
 
 
-1.2.1. Kamailio Modules
+   For a detailed list of PCRE features read the man page of the library.
+
+2. Dependencies
+
+   2.1. Kamailio Modules
+   2.2. External Libraries or Applications
+
+2.1. Kamailio Modules
 
 
    The following modules must be loaded before this module:
    The following modules must be loaded before this module:
      * No dependencies on other Kamailio modules.
      * No dependencies on other Kamailio modules.
 
 
-1.2.2. External Libraries or Applications
+2.2. External Libraries or Applications
 
 
-   The following libraries or applications must be installed
-   before running Kamailio with this module loaded:
+   The following libraries or applications must be installed before
+   running Kamailio with this module loaded:
      * libpcre - the libraries of PCRE.
      * libpcre - the libraries of PCRE.
 
 
-1.3. Exported Parameters
+3. Exported Parameters
 
 
-1.3.1. file (string)
+   3.1. file (string)
+   3.2. max_groups (int)
+   3.3. group_max_size (int)
+   3.4. pcre_caseless (int)
+   3.5. pcre_multiline (int)
+   3.6. pcre_dotall (int)
+   3.7. pcre_extended (int)
 
 
-   Text file containing the regular expression groups. It must be
-   set in order to enable the group matching function.
+3.1. file (string)
 
 
-   Default value is "NULL".
+   Text file containing the regular expression groups. It must be set in
+   order to enable the group matching function.
+
+   Default value is “NULL�.
 
 
    Example 1.1. Set file parameter
    Example 1.1. Set file parameter
 ...
 ...
 modparam("regex", "file", "/etc/kamailio/regex_groups")
 modparam("regex", "file", "/etc/kamailio/regex_groups")
 ...
 ...
 
 
-1.3.2. max_groups (int)
+3.2. max_groups (int)
 
 
    Max number of regular expression groups in the text file.
    Max number of regular expression groups in the text file.
 
 
-   Default value is "20".
+   Default value is “20�.
 
 
    Example 1.2. Set max_groups parameter
    Example 1.2. Set max_groups parameter
 ...
 ...
 modparam("regex", "max_groups", 40)
 modparam("regex", "max_groups", 40)
 ...
 ...
 
 
-1.3.3. group_max_size (int)
+3.3. group_max_size (int)
 
 
    Max content size of a group in the text file.
    Max content size of a group in the text file.
 
 
-   Default value is "8192".
+   Default value is “8192�.
 
 
    Example 1.3. Set group_max_size parameter
    Example 1.3. Set group_max_size parameter
 ...
 ...
 modparam("regex", "group_max_size", 16384)
 modparam("regex", "group_max_size", 16384)
 ...
 ...
 
 
-1.3.4. pcre_caseless (int)
+3.4. pcre_caseless (int)
 
 
-   If this options is set, matching is done caseless. It is
-   equivalent to Perl's /i option, and it can be changed within a
-   pattern by a (?i) or (?-i) option setting.
+   If this options is set, matching is done caseless. It is equivalent to
+   Perl's /i option, and it can be changed within a pattern by a (?i) or
+   (?-i) option setting.
 
 
-   Default value is "0".
+   Default value is “0�.
 
 
    Example 1.4. Set pcre_caseless parameter
    Example 1.4. Set pcre_caseless parameter
 ...
 ...
 modparam("regex", "pcre_caseless", 1)
 modparam("regex", "pcre_caseless", 1)
 ...
 ...
 
 
-1.3.5. pcre_multiline (int)
+3.5. pcre_multiline (int)
 
 
-   By default, PCRE treats the subject string as consisting of a
-   single line of characters (even if it actually contains
-   newlines). The "start of line" metacharacter (^) matches only
-   at the start of the string, while the "end of line"
-   metacharacter ($) matches only at the end of the string, or
-   before a terminating newline.
+   By default, PCRE treats the subject string as consisting of a single
+   line of characters (even if it actually contains newlines). The "start
+   of line" metacharacter (^) matches only at the start of the string,
+   while the "end of line" metacharacter ($) matches only at the end of
+   the string, or before a terminating newline.
 
 
    When this option is set, the "start of line" and "end of line"
    When this option is set, the "start of line" and "end of line"
-   constructs match immediately following or immediately before
-   internal newlines in the subject string, respectively, as well
-   as at the very start and end. This is equivalent to Perl's /m
-   option, and it can be changed within a pattern by a (?m) or
-   (?-m) option setting. If there are no newlines in a subject
-   string, or no occurrences of ^ or $ in a pattern, setting this
-   option has no effect.
+   constructs match immediately following or immediately before internal
+   newlines in the subject string, respectively, as well as at the very
+   start and end. This is equivalent to Perl's /m option, and it can be
+   changed within a pattern by a (?m) or (?-m) option setting. If there
+   are no newlines in a subject string, or no occurrences of ^ or $ in a
+   pattern, setting this option has no effect.
 
 
-   Default value is "0".
+   Default value is “0�.
 
 
    Example 1.5. Set pcre_multiline parameter
    Example 1.5. Set pcre_multiline parameter
 ...
 ...
 modparam("regex", "pcre_multiline", 1)
 modparam("regex", "pcre_multiline", 1)
 ...
 ...
 
 
-1.3.6. pcre_dotall (int)
+3.6. pcre_dotall (int)
 
 
-   If this option is set, a dot metacharater in the pattern
-   matches all characters, including those that indicate newline.
-   Without it, a dot does not match when the current position is
-   at a newline. This option is equivalent to Perl's /s option,
-   and it can be changed within a pattern by a (?s) or (?-s)
-   option setting.
+   If this option is set, a dot metacharater in the pattern matches all
+   characters, including those that indicate newline. Without it, a dot
+   does not match when the current position is at a newline. This option
+   is equivalent to Perl's /s option, and it can be changed within a
+   pattern by a (?s) or (?-s) option setting.
 
 
-   Default value is "0".
+   Default value is “0�.
 
 
    Example 1.6. Set pcre_dotall parameter
    Example 1.6. Set pcre_dotall parameter
 ...
 ...
 modparam("regex", "pcre_dotall", 1)
 modparam("regex", "pcre_dotall", 1)
 ...
 ...
 
 
-1.3.7. pcre_extended (int)
+3.7. pcre_extended (int)
 
 
-   If this option is set, whitespace data characters in the
-   pattern are totally ignored except when escaped or inside a
-   character class. Whitespace does not include the VT character
-   (code 11). In addition, characters between an unescaped #
-   outside a character class and the next newline, inclusive, are
-   also ignored. This is equivalent to Perl's /x option, and it
-   can be changed within a pattern by a (?x) or (?-x) option
-   setting.
+   If this option is set, whitespace data characters in the pattern are
+   totally ignored except when escaped or inside a character class.
+   Whitespace does not include the VT character (code 11). In addition,
+   characters between an unescaped # outside a character class and the
+   next newline, inclusive, are also ignored. This is equivalent to Perl's
+   /x option, and it can be changed within a pattern by a (?x) or (?-x)
+   option setting.
 
 
-   Default value is "0".
+   Default value is “0�.
 
 
    Example 1.7. Set pcre_extended parameter
    Example 1.7. Set pcre_extended parameter
 ...
 ...
 modparam("regex", "pcre_extended", 1)
 modparam("regex", "pcre_extended", 1)
 ...
 ...
 
 
-1.4. Exported Functions
+4. Exported Functions
+
+   4.1. pcre_match (string, pcre_regex)
+   4.2. pcre_match_group (string [, group])
 
 
-1.4.1.  pcre_match (string, pcre_regex)
+4.1.  pcre_match (string, pcre_regex)
 
 
-   Matches the given string parameter against the regular
-   expression pcre_regex, which is compiled into a PCRE object.
-   Returns TRUE if it matches, FALSE otherwise.
+   Matches the given string parameter against the regular expression
+   pcre_regex, which is compiled in runtime into a PCRE object. Returns
+   TRUE if it matches, FALSE otherwise.
 
 
    Meaning of the parameters is as follows:
    Meaning of the parameters is as follows:
      * string - String or pseudo-variable to compare.
      * string - String or pseudo-variable to compare.
-     * pcre_regex - Regular expression to be compiled in a PCRE
-       object. It can be a string or pseudo-variable.
+     * pcre_regex - Regular expression to be compiled in a PCRE object. It
+       can be a string or pseudo-variable.
 
 
-   NOTE: To use the "end of line" symbol '$' in the pcre_regex
-   parameter use '$$'.
+   NOTE: To use the "end of line" symbol '$' in the pcre_regex parameter
+   use '$$'.
 
 
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
    ONREPLY_ROUTE, BRANCH_ROUTE and LOCAL_ROUTE.
    ONREPLY_ROUTE, BRANCH_ROUTE and LOCAL_ROUTE.
@@ -233,41 +272,54 @@ if (pcre_match("$ua", "(?i)^twinkle")) {
 
 
    Example 1.9.  pcre_match usage (using "end of line" symbol)
    Example 1.9.  pcre_match usage (using "end of line" symbol)
 ...
 ...
-if (pcre_match("$rU", "^user[1234]$$")) {  # Will be converted to "^user
-[1234]$"
+if (pcre_match("$rU", "^user[1234]$$")) {  # Will be converted to "^user[1234]$"
     xlog("L_INFO", "RURI username matches\n");
     xlog("L_INFO", "RURI username matches\n");
 }
 }
 ...
 ...
 
 
-1.4.2.  pcre_match_group (string [, group])
+4.2.  pcre_match_group (string [, group])
 
 
-   It uses the groups readed from the text file (see
-   Section 1.6.1, "File format") to match the given string
-   parameter against the compiled regular expression in group
-   number group. Returns TRUE if it matches, FALSE otherwise.
+   Tries to match the given string against a specific group in the text
+   file (see Section 6.1, “File format�). Returns TRUE if it matches,
+   FALSE otherwise.
 
 
    Meaning of the parameters is as follows:
    Meaning of the parameters is as follows:
      * string - String or pseudo-variable to compare.
      * string - String or pseudo-variable to compare.
-     * group - Number of group to use in the operation. If not
-       specified then 0 (the first group) is used.
+     * group - Number of group to use in the operation. If not specified
+       then 0 (the first group) is used. A pseudo-variable containing an
+       integer can also be used.
 
 
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
    ONREPLY_ROUTE, BRANCH_ROUTE and LOCAL_ROUTE.
    ONREPLY_ROUTE, BRANCH_ROUTE and LOCAL_ROUTE.
 
 
    Example 1.10.  pcre_match_group usage
    Example 1.10.  pcre_match_group usage
 ...
 ...
-if (pcre_match_group("$rU", 2)) {
+if (pcre_match_group("$rU", "2")) {
     xlog("L_INFO", "RURI username matches group 2\n");
     xlog("L_INFO", "RURI username matches group 2\n");
 }
 }
 ...
 ...
 
 
-1.5. Exported MI Functions
+   Example 1.11.  pcre_match_group usage (using a pseudo-variable as
+   group)
+                                        ...
+                                        $avp(i:10) = 5;  # Maybe got from a DB q
+uery.
+                                        if (pcre_match_group("$ua", "$avp(i:10)"
+)) {
+                                        xlog("L_INFO", "User-Agent matches group
+ 5\n");
+                                        }
+                                        ...
+
+5. Exported MI Functions
 
 
-1.5.1.  regex_reload
+   5.1. regex_reload
+
+5.1.  regex_reload
 
 
    Causes regex module to re-read the content of the text file and
    Causes regex module to re-read the content of the text file and
-   re-compile the regular expressions. The number of groups in the
-   file can be modified safely.
+   re-compile the regular expressions. The number of groups in the file
+   can be modified safely.
 
 
    Name: regex_reload
    Name: regex_reload
 
 
@@ -277,19 +329,21 @@ if (pcre_match_group("$rU", 2)) {
 :regex_reload:_reply_fifo_file_
 :regex_reload:_reply_fifo_file_
 _empty_line_
 _empty_line_
 
 
-1.6. Installation and Running
+6. Installation and Running
+
+   6.1. File format
 
 
-1.6.1. File format
+6.1. File format
 
 
-   The file contains regular expressions categorized in groups.
-   Each group starts with "[number]" line. Lines starting by
-   space, tab, CR, LF or # (comments) are ignored. Each regular
-   expression must take up just one line, this means that a
-   regular expression can't be splitted in various lines.
+   The file contains regular expressions categorized in groups. Each group
+   starts with "[number]" line. Lines starting by space, tab, CR, LF or #
+   (comments) are ignored. Each regular expression must take up just one
+   line, this means that a regular expression can't be splitted in various
+   lines.
 
 
    An example of the file format would be the following:
    An example of the file format would be the following:
 
 
-   Example 1.11. regex file
+   Example 1.12. regex file
 ### List of User-Agents publishing presence status
 ### List of User-Agents publishing presence status
 [0]
 [0]
 
 
@@ -330,12 +384,12 @@ group 0: ((^Twinkle/1)|(^X-Lite)|(^eyeBeam)|(^Bria)|(^SIP Communicator)|
 group 1: ((^190\.232\.250\.226$)|(^122\.5\.27\.125$)|(^86\.92\.112\.))
 group 1: ((^190\.232\.250\.226$)|(^122\.5\.27\.125$)|(^86\.92\.112\.))
 group 2: ((^1\d{3}$)|(^((\+|00)34)?900\d{6}$))
 group 2: ((^1\d{3}$)|(^((\+|00)34)?900\d{6}$))
 
 
-   The first group can be used to avoid auto-generated PUBLISH
-   (pua_usrloc module) for UA's already supporting presence:
+   The first group can be used to avoid auto-generated PUBLISH (pua_usrloc
+   module) for UA's already supporting presence:
 
 
-   Example 1.12. Using with pua_usrloc
+   Example 1.13. Using with pua_usrloc
 route[REGISTER] {
 route[REGISTER] {
-    if (! pcre_match_group("$ua", 0)) {
+    if (! pcre_match_group("$ua", "0")) {
         xlog("L_INFO", "Auto-generated PUBLISH for $fu ($ua)\n");
         xlog("L_INFO", "Auto-generated PUBLISH for $fu ($ua)\n");
         pua_set_publish();
         pua_set_publish();
     }
     }
@@ -343,12 +397,12 @@ route[REGISTER] {
     exit;
     exit;
 }
 }
 
 
-   NOTE: It's important to understand that the numbers in each
-   group header ([number]) must start by 0. If not, the real group
-   number will not match the number appearing in the file. For
-   example, the following text file:
+   NOTE: It's important to understand that the numbers in each group
+   header ([number]) must start by 0. If not, the real group number will
+   not match the number appearing in the file. For example, the following
+   text file:
 
 
-   Example 1.13. Incorrect groups file
+   Example 1.14. Incorrect groups file
 [1]
 [1]
 ^aaa
 ^aaa
 ^bbb
 ^bbb
@@ -361,16 +415,16 @@ route[REGISTER] {
 group 0: ((^aaa)|(^bbb))
 group 0: ((^aaa)|(^bbb))
 group 1: ((^ccc)|(^ddd))
 group 1: ((^ccc)|(^ddd))
 
 
-   Note that the real index doesn't match the group number in the
-   file. This is, compiled group 0 always points to the first
-   group in the file, regardless of its number in the file. In
-   fact, the group number appearing in the file is used for
-   nothing but for delimiting different groups.
+   Note that the real index doesn't match the group number in the file.
+   This is, compiled group 0 always points to the first group in the file,
+   regardless of its number in the file. In fact, the group number
+   appearing in the file is used for nothing but for delimiting different
+   groups.
 
 
-   NOTE: A line containing a regular expression cannot start by
-   '[' since it would be treated as a new group. The same for
-   lines starting by space, tab, or '#' (they would be ignored by
-   the parser). As a workaround, using brackets would work:
+   NOTE: A line containing a regular expression cannot start by '[' since
+   it would be treated as a new group. The same for lines starting by
+   space, tab, or '#' (they would be ignored by the parser). As a
+   workaround, using brackets would work:
 [0]
 [0]
 ([0-9]{9})
 ([0-9]{9})
 ( #abcde)
 ( #abcde)

+ 23 - 9
modules_k/regex/doc/regex_admin.xml

@@ -237,8 +237,8 @@ modparam("regex", "pcre_extended", 1)
 
 
 			<para>
 			<para>
 				Matches the given string parameter against the regular expression pcre_regex,
 				Matches the given string parameter against the regular expression pcre_regex,
-				which is compiled into a PCRE object. Returns TRUE if it matches, FALSE
-				otherwise.
+				which is compiled in runtime into a PCRE object. Returns TRUE if it matches,
+				FALSE otherwise.
 			</para>
 			</para>
 
 
 			<para>Meaning of the parameters is as follows:</para>
 			<para>Meaning of the parameters is as follows:</para>
@@ -300,10 +300,9 @@ if (pcre_match("$rU", "^user[1234]$$")) {  # Will be converted to "^user[1234]$"
 			</title>
 			</title>
 
 
 			<para>
 			<para>
-				It uses the groups readed from the text file
-				(see <xref linkend="file-format-id"/>) to match the given string
-				parameter against the compiled regular expression in group number group.
-				Returns TRUE if it matches, FALSE otherwise.
+				Tries to match the given string against a specific group in the text
+				file (see <xref linkend="file-format-id"/>). Returns TRUE if it matches,
+				FALSE otherwise.
 			</para>
 			</para>
 
 
 			<para>Meaning of the parameters is as follows:</para>
 			<para>Meaning of the parameters is as follows:</para>
@@ -317,7 +316,8 @@ if (pcre_match("$rU", "^user[1234]$$")) {  # Will be converted to "^user[1234]$"
 				<listitem>
 				<listitem>
 					<para>
 					<para>
 						<emphasis>group</emphasis> - Number of group to use in the operation.
 						<emphasis>group</emphasis> - Number of group to use in the operation.
-						If not specified then 0 (the first group) is used.
+						If not specified then 0 (the first group) is used. A pseudo-variable
+						containing an integer can also be used.
 					</para>
 					</para>
 				</listitem>
 				</listitem>
 			</itemizedlist>
 			</itemizedlist>
@@ -333,13 +333,27 @@ if (pcre_match("$rU", "^user[1234]$$")) {  # Will be converted to "^user[1234]$"
 				</title>
 				</title>
 <programlisting format="linespecific">
 <programlisting format="linespecific">
 ...
 ...
-if (pcre_match_group("$rU", 2)) {
+if (pcre_match_group("$rU", "2")) {
     xlog("L_INFO", "RURI username matches group 2\n");
     xlog("L_INFO", "RURI username matches group 2\n");
 }
 }
 ...
 ...
 </programlisting>
 </programlisting>
 			</example>
 			</example>
 
 
+			<example>
+				<title>
+					<function>pcre_match_group</function> usage (using a pseudo-variable as group)
+				</title>
+				<programlisting format="linespecific">
+...
+$avp(i:10) = 5;  # Maybe got from a DB query.
+if (pcre_match_group("$ua", "$avp(i:10)")) {
+    xlog("L_INFO", "User-Agent matches group 5\n");
+}
+...
+				</programlisting>
+			</example>
+ 
 		</section>
 		</section>
 
 
 	</section>
 	</section>
@@ -455,7 +469,7 @@ group 2: ((^1\d{3}$)|(^((\+|00)34)?900\d{6}$))
 				<title>Using with pua_usrloc</title>
 				<title>Using with pua_usrloc</title>
 <programlisting  format="linespecific">
 <programlisting  format="linespecific">
 route[REGISTER] {
 route[REGISTER] {
-    if (! pcre_match_group("$ua", 0)) {
+    if (! pcre_match_group("$ua", "0")) {
         xlog("L_INFO", "Auto-generated PUBLISH for $fu ($ua)\n");
         xlog("L_INFO", "Auto-generated PUBLISH for $fu ($ua)\n");
         pua_set_publish();
         pua_set_publish();
     }
     }

+ 13 - 7
modules_k/regex/regex_mod.c

@@ -23,7 +23,8 @@
  *
  *
  * History:
  * History:
  * --------
  * --------
- *  2009-01-14  initial version (Iñaki Baz Castillo)
+ *  2011-02-22  pcre_match_group() allows now pseudo-variable as group argument.
+ *  2009-01-14  initial version (Iñaki Baz Castillo).
  */
  */
 
 
 
 
@@ -119,7 +120,7 @@ static cmd_export_t cmds[] =
 {
 {
 	{ "pcre_match", (cmd_function)w_pcre_match, 2, fixup_spve_spve, 0,
 	{ "pcre_match", (cmd_function)w_pcre_match, 2, fixup_spve_spve, 0,
 		REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE },
 		REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE },
-	{ "pcre_match_group", (cmd_function)w_pcre_match_group, 2, fixup_spve_uint, 0,
+	{ "pcre_match_group", (cmd_function)w_pcre_match_group, 2, fixup_spve_spve, 0,
 		REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE },
 		REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE },
 	{ "pcre_match_group", (cmd_function)w_pcre_match_group, 1, fixup_spve_null, 0,
 	{ "pcre_match_group", (cmd_function)w_pcre_match_group, 1, fixup_spve_null, 0,
 		REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE },
 		REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE },
@@ -383,7 +384,7 @@ static int load_pcres(int action)
 	}
 	}
 	
 	
 	/* Log the group patterns */
 	/* Log the group patterns */
-	LM_NOTICE("num groups = %d\n\n", num_pcres_tmp);
+	LM_NOTICE("num groups = %d\n", num_pcres_tmp);
 	for (i=0; i < num_pcres_tmp; i++) {
 	for (i=0; i < num_pcres_tmp; i++) {
 		LM_NOTICE("<group[%d]>%s</group[%d]> (size = %i)\n", i, patterns[i], i, (int)strlen(patterns[i]));
 		LM_NOTICE("<group[%d]>%s</group[%d]> (size = %i)\n", i, patterns[i], i, (int)strlen(patterns[i]));
 	}
 	}
@@ -587,8 +588,8 @@ static int w_pcre_match(struct sip_msg* _msg, char* _s1, char* _s2)
 /*! \brief Return true if the string argument matches the pattern group parameter */
 /*! \brief Return true if the string argument matches the pattern group parameter */
 static int w_pcre_match_group(struct sip_msg* _msg, char* _s1, char* _s2)
 static int w_pcre_match_group(struct sip_msg* _msg, char* _s1, char* _s2)
 {
 {
-	str string;
-	int num_pcre;
+	str string, group;
+	unsigned int num_pcre;
 	int pcre_rc;
 	int pcre_rc;
 	
 	
 	/* Check if group matching feature is enabled */
 	/* Check if group matching feature is enabled */
@@ -605,7 +606,12 @@ static int w_pcre_match_group(struct sip_msg* _msg, char* _s1, char* _s2)
 	if (_s2 == NULL) {
 	if (_s2 == NULL) {
 		num_pcre = 0;
 		num_pcre = 0;
 	} else {
 	} else {
-		num_pcre = (uint)(long)_s2;
+		if (fixup_get_svalue(_msg, (gparam_p)_s2, &group))
+		{
+			LM_ERR("cannot print the format for second param\n");
+			return -5;
+		}
+		str2int(&group, &num_pcre);
 	}
 	}
 	
 	
 	if (num_pcre >= *num_pcres) {
 	if (num_pcre >= *num_pcres) {
@@ -615,7 +621,7 @@ static int w_pcre_match_group(struct sip_msg* _msg, char* _s1, char* _s2)
 	
 	
 	if (fixup_get_svalue(_msg, (gparam_p)_s1, &string))
 	if (fixup_get_svalue(_msg, (gparam_p)_s1, &string))
 	{
 	{
-		LM_ERR("cannot print the format\n");
+		LM_ERR("cannot print the format for first param\n");
 		return -5;
 		return -5;
 	}
 	}
 	
 	

+ 41 - 5
modules_k/siputils/README

@@ -24,6 +24,10 @@ Gabriel Vasile
 
 
    FhG FOKUS
    FhG FOKUS
 
 
+Juha Heinanen
+
+   TutPro Inc.
+
 Edited by
 Edited by
 
 
 Jan Janak
 Jan Janak
@@ -87,6 +91,8 @@ Gabriel Vasile
               4.18. append_rpid_hf(prefix, suffix)
               4.18. append_rpid_hf(prefix, suffix)
               4.19. is_rpid_user_e164()
               4.19. is_rpid_user_e164()
               4.20. set_uri_user(uri, user)
               4.20. set_uri_user(uri, user)
+              4.21. is_request()
+              4.22. is_reply()
 
 
    List of Examples
    List of Examples
 
 
@@ -119,6 +125,8 @@ Gabriel Vasile
    1.27. append_rpid_hf(prefix, suffix) usage
    1.27. append_rpid_hf(prefix, suffix) usage
    1.28. is_rpid_user_e164 usage
    1.28. is_rpid_user_e164 usage
    1.29. set_uri_user usage
    1.29. set_uri_user usage
+   1.30. is_request usage
+   1.31. is_reply usage
 
 
 Chapter 1. Admin Guide
 Chapter 1. Admin Guide
 
 
@@ -164,6 +172,8 @@ Chapter 1. Admin Guide
         4.18. append_rpid_hf(prefix, suffix)
         4.18. append_rpid_hf(prefix, suffix)
         4.19. is_rpid_user_e164()
         4.19. is_rpid_user_e164()
         4.20. set_uri_user(uri, user)
         4.20. set_uri_user(uri, user)
+        4.21. is_request()
+        4.22. is_reply()
 
 
 1. Overview
 1. Overview
 
 
@@ -358,6 +368,8 @@ modparam("auth", "rpid_avp", "$avp(myrpid)")
    4.18. append_rpid_hf(prefix, suffix)
    4.18. append_rpid_hf(prefix, suffix)
    4.19. is_rpid_user_e164()
    4.19. is_rpid_user_e164()
    4.20. set_uri_user(uri, user)
    4.20. set_uri_user(uri, user)
+   4.21. is_request()
+   4.22. is_reply()
 
 
 4.1.  ring_insert_callid()
 4.1.  ring_insert_callid()
 
 
@@ -424,7 +436,7 @@ if (is_user("john")) {
 
 
    Check if To header field uri contains tag parameter.
    Check if To header field uri contains tag parameter.
 
 
-   This function can be used from REQUEST_ROUTE.
+   This function can be used from ANY_ROUTE.
 
 
    Example 1.13. has_totag usage
    Example 1.13. has_totag usage
 ...
 ...
@@ -613,8 +625,7 @@ reply_route[2] {
 
 
    The function returns true if the two parameters matches as SIP URI.
    The function returns true if the two parameters matches as SIP URI.
 
 
-   This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
-   FAILURE_ROUTE and BRANCH_ROUTE.
+   This function can be used from ANY_ROUTE.
 
 
    Example 1.23. cmp_uri usage
    Example 1.23. cmp_uri usage
 ...
 ...
@@ -629,8 +640,7 @@ if(cmp_uri("$ru", "sip:[email protected]"))
    The function returns true if the two parameters matches as AoR. The
    The function returns true if the two parameters matches as AoR. The
    parameters have to be SIP URIs.
    parameters have to be SIP URIs.
 
 
-   This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
-   FAILURE_ROUTE and BRANCH_ROUTE.
+   This function can be used from ANY_ROUTE.
 
 
    Example 1.24. cmp_aor usage
    Example 1.24. cmp_aor usage
 ...
 ...
@@ -729,3 +739,29 @@ $var(uri) = "sip:user@host";
 $var(user) = "new_user";
 $var(user) = "new_user";
 set_uri_user("$var(uri)", "$var(user)");
 set_uri_user("$var(uri)", "$var(user)");
 ...
 ...
+
+4.21.  is_request()
+
+   Return true if the SIP message is a request.
+
+   This function can be used from ANY_ROUTE.
+
+   Example 1.30. is_request usage
+...
+if (is_request()) {
+        ...
+}
+...
+
+4.22.  is_reply()
+
+   Return true if the SIP message is a reply.
+
+   This function can be used from ANY_ROUTE.
+
+   Example 1.31. is_reply usage
+...
+if (is_reply()) {
+        ...
+}
+...

+ 27 - 0
modules_k/siputils/checks.c

@@ -54,6 +54,33 @@
 #include "../../lvalue.h"
 #include "../../lvalue.h"
 #include "checks.h"
 #include "checks.h"
 
 
+/**
+ * return 1 (true) if the SIP message type is request
+ */
+int w_is_request(struct sip_msg* msg, char *foo, char *bar)
+{
+	if(msg==NULL)
+		return -1;
+
+	if(msg->first_line.type == SIP_REQUEST)
+		return 1;
+
+	return -1;
+}
+
+/**
+ * return 1 (true) if the SIP message type is reply
+ */
+int w_is_reply(struct sip_msg* msg, char *foo, char *bar)
+{
+	if(msg==NULL)
+		return -1;
+
+	if(msg->first_line.type == SIP_REPLY)
+		return 1;
+
+	return -1;
+}
 
 
 /*
 /*
  * Checks if From includes a To-tag -- good to identify
  * Checks if From includes a To-tag -- good to identify

+ 10 - 0
modules_k/siputils/checks.h

@@ -95,4 +95,14 @@ int is_e164(struct sip_msg* _m, char* _sp, char* _s2);
  */
  */
 int set_uri_user(struct sip_msg* _m, char* _uri, char* _value);
 int set_uri_user(struct sip_msg* _m, char* _uri, char* _value);
 
 
+/*
+ * Return true (1) if SIP message is request, otherwise false (-1)
+ */
+int w_is_request(struct sip_msg* msg, char *foo, char *bar);
+
+/*
+ * Return true (1) if SIP message is reply, otherwise false (-1)
+ */
+int w_is_reply(struct sip_msg* msg, char *foo, char *bar);
+
 #endif /* CHECKS_H */
 #endif /* CHECKS_H */

+ 45 - 5
modules_k/siputils/doc/siputils_admin.xml

@@ -375,7 +375,7 @@ if (is_user("john")) {
 		Check if To header field uri contains tag parameter.
 		Check if To header field uri contains tag parameter.
 		</para>
 		</para>
 		<para>
 		<para>
-		This function can be used from REQUEST_ROUTE.
+		This function can be used from ANY_ROUTE.
 		</para>
 		</para>
 		<example>
 		<example>
 		<title><function>has_totag</function> usage</title>
 		<title><function>has_totag</function> usage</title>
@@ -684,8 +684,7 @@ reply_route[2] {
 		the two parameters matches as SIP URI.
 		the two parameters matches as SIP URI.
 		</para>
 		</para>
    		<para>
    		<para>
-		This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE, 
-		FAILURE_ROUTE and BRANCH_ROUTE.
+		This function can be used from ANY_ROUTE.
 		</para>
 		</para>
 		<example>
 		<example>
 		<title><function>cmp_uri</function> usage</title>
 		<title><function>cmp_uri</function> usage</title>
@@ -710,8 +709,7 @@ if(cmp_uri("$ru", "sip:[email protected]"))
 		URIs.
 		URIs.
 		</para>
 		</para>
    		<para>
    		<para>
-		This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE, 
-		FAILURE_ROUTE and BRANCH_ROUTE.
+		This function can be used from ANY_ROUTE.
 		</para>
 		</para>
 		<example>
 		<example>
 		<title><function>cmp_aor</function> usage</title>
 		<title><function>cmp_aor</function> usage</title>
@@ -859,6 +857,48 @@ $var(uri) = "sip:user@host";
 $var(user) = "new_user";
 $var(user) = "new_user";
 set_uri_user("$var(uri)", "$var(user)");
 set_uri_user("$var(uri)", "$var(user)");
 ...
 ...
+</programlisting>
+		</example>
+	</section>
+	<section>
+		<title>
+		<function moreinfo="none">is_request()</function>
+		</title>
+		<para>
+		Return true if the SIP message is a request.
+		</para>
+		<para>
+		This function can be used from ANY_ROUTE.
+		</para>
+		<example>
+		<title><function>is_request</function> usage</title>
+		<programlisting format="linespecific">
+...
+if (is_request()) {
+	...
+}
+...
+</programlisting>
+		</example>
+	</section>
+	<section>
+		<title>
+		<function moreinfo="none">is_reply()</function>
+		</title>
+		<para>
+		Return true if the SIP message is a reply.
+		</para>
+		<para>
+		This function can be used from ANY_ROUTE.
+		</para>
+		<example>
+		<title><function>is_reply</function> usage</title>
+		<programlisting format="linespecific">
+...
+if (is_reply()) {
+	...
+}
+...
 </programlisting>
 </programlisting>
 		</example>
 		</example>
 	</section>
 	</section>

+ 39 - 25
modules_k/siputils/siputils.c

@@ -113,36 +113,50 @@ static int fixup_free_set_uri(void** param, int param_no);
 char *contact_flds_separator = DEFAULT_SEPARATOR;
 char *contact_flds_separator = DEFAULT_SEPARATOR;
 
 
 static cmd_export_t cmds[]={
 static cmd_export_t cmds[]={
-	{"ring_insert_callid", (cmd_function)ring_insert_callid, 0, ring_fixup, 0, REQUEST_ROUTE|FAILURE_ROUTE},
-	{"options_reply",      (cmd_function)opt_reply, 0, 0, 0, REQUEST_ROUTE},
-	{"is_user",            (cmd_function)is_user,        1, fixup_str_null, 0, REQUEST_ROUTE|LOCAL_ROUTE},
-	{"has_totag", 	       (cmd_function)has_totag,      0, 0, 0, REQUEST_ROUTE|LOCAL_ROUTE},
-	{"uri_param",          (cmd_function)uri_param_1,    1, fixup_str_null, 0, REQUEST_ROUTE|LOCAL_ROUTE},
-	{"uri_param",          (cmd_function)uri_param_2,    2, fixup_str_str, 0, REQUEST_ROUTE|LOCAL_ROUTE},
-	{"add_uri_param",      (cmd_function)add_uri_param,  1, fixup_str_null, 0, REQUEST_ROUTE},
-	{"tel2sip",            (cmd_function)tel2sip,        0, 0,         0, REQUEST_ROUTE},
-	{"is_e164",            (cmd_function)is_e164, 1, fixup_pvar_null, fixup_free_pvar_null, REQUEST_ROUTE|FAILURE_ROUTE|LOCAL_ROUTE},
-	{"is_uri_user_e164",   (cmd_function)is_uri_user_e164, 1, fixup_pvar_null, fixup_free_pvar_null, REQUEST_ROUTE|FAILURE_ROUTE|LOCAL_ROUTE},
-	{"encode_contact",     (cmd_function)encode_contact,2,0, 0, REQUEST_ROUTE|ONREPLY_ROUTE},
-	{"decode_contact",     (cmd_function)decode_contact,0,0, 0, REQUEST_ROUTE},
-	{"decode_contact_header", (cmd_function)decode_contact_header,0,0,0,REQUEST_ROUTE|ONREPLY_ROUTE},
-	{"cmp_uri",  (cmd_function)w_cmp_uri, 2,
-		fixup_spve_spve, 0,
-		REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE},
-	{"cmp_aor",  (cmd_function)w_cmp_aor, 2,
-		fixup_spve_spve, 0,
-		REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE},
-	{"is_rpid_user_e164",   (cmd_function)is_rpid_user_e164,       0, 0,
+	{"ring_insert_callid", (cmd_function)ring_insert_callid, 0, ring_fixup,
+		0, REQUEST_ROUTE|FAILURE_ROUTE},
+	{"options_reply",      (cmd_function)opt_reply,         0, 0,
+		0, REQUEST_ROUTE},
+	{"is_user",            (cmd_function)is_user,           1, fixup_str_null,
+		0, REQUEST_ROUTE|LOCAL_ROUTE},
+	{"has_totag", 	       (cmd_function)has_totag,         0, 0,
+		0, ANY_ROUTE},
+	{"uri_param",          (cmd_function)uri_param_1,       1, fixup_str_null,
+		0, REQUEST_ROUTE|LOCAL_ROUTE},
+	{"uri_param",          (cmd_function)uri_param_2,       2, fixup_str_str,
+		0, REQUEST_ROUTE|LOCAL_ROUTE},
+	{"add_uri_param",      (cmd_function)add_uri_param,     1, fixup_str_null,
+		0, REQUEST_ROUTE},
+	{"tel2sip",            (cmd_function)tel2sip,           0, 0,
+		0, REQUEST_ROUTE},
+	{"is_e164",            (cmd_function)is_e164,           1, fixup_pvar_null,
+		fixup_free_pvar_null, REQUEST_ROUTE|FAILURE_ROUTE|LOCAL_ROUTE},
+	{"is_uri_user_e164",   (cmd_function)is_uri_user_e164,  1, fixup_pvar_null,
+		fixup_free_pvar_null, REQUEST_ROUTE|FAILURE_ROUTE|LOCAL_ROUTE},
+	{"encode_contact",     (cmd_function)encode_contact,    2, 0,
+		0, REQUEST_ROUTE|ONREPLY_ROUTE},
+	{"decode_contact",     (cmd_function)decode_contact,    0, 0,
+		0, REQUEST_ROUTE},
+	{"decode_contact_header", (cmd_function)decode_contact_header, 0, 0,
+		0,REQUEST_ROUTE|ONREPLY_ROUTE},
+	{"cmp_uri",  (cmd_function)w_cmp_uri,                   2, fixup_spve_spve,
+		0, ANY_ROUTE},
+	{"cmp_aor",  (cmd_function)w_cmp_aor,                   2, fixup_spve_spve,
+		0, ANY_ROUTE},
+	{"is_rpid_user_e164",   (cmd_function)is_rpid_user_e164, 0, 0,
 			0, REQUEST_ROUTE},
 			0, REQUEST_ROUTE},
-	{"append_rpid_hf",      (cmd_function)append_rpid_hf,          0, 0,
+	{"append_rpid_hf",      (cmd_function)append_rpid_hf,    0, 0,
 			0, REQUEST_ROUTE|BRANCH_ROUTE|FAILURE_ROUTE},
 			0, REQUEST_ROUTE|BRANCH_ROUTE|FAILURE_ROUTE},
-	{"append_rpid_hf",      (cmd_function)append_rpid_hf_p,        2, fixup_str_str,
+	{"append_rpid_hf",      (cmd_function)append_rpid_hf_p,  2, fixup_str_str,
 			0, REQUEST_ROUTE|BRANCH_ROUTE|FAILURE_ROUTE},
 			0, REQUEST_ROUTE|BRANCH_ROUTE|FAILURE_ROUTE},
-	{"set_uri_user", (cmd_function)set_uri_user, 2, fixup_set_uri,
-	 fixup_free_set_uri,	
-	 REQUEST_ROUTE|BRANCH_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE},
+	{"set_uri_user", (cmd_function)set_uri_user,             2, fixup_set_uri,
+		    fixup_free_set_uri,	ANY_ROUTE},
 	{"bind_siputils",       (cmd_function)bind_siputils,           0, 0,
 	{"bind_siputils",       (cmd_function)bind_siputils,           0, 0,
 			0, 0},
 			0, 0},
+	{"is_request",          (cmd_function)w_is_request,            0, 0,
+			0, ANY_ROUTE},
+	{"is_reply",            (cmd_function)w_is_reply,              0, 0,
+			0, ANY_ROUTE},
 	{0,0,0,0,0,0}
 	{0,0,0,0,0,0}
 };
 };
 
 

+ 59 - 12
modules_k/sqlops/README

@@ -32,7 +32,8 @@ Daniel-Constantin Mierla
         4. Exported Functions
         4. Exported Functions
 
 
               4.1. sql_query(connection, query, result)
               4.1. sql_query(connection, query, result)
-              4.2. sql_result_free(result)
+              4.2. sql_xquery(connection, query, result)
+              4.3. sql_result_free(result)
 
 
         5. Exported pseudo-variables
         5. Exported pseudo-variables
 
 
@@ -43,8 +44,9 @@ Daniel-Constantin Mierla
    1.1. Set sqlcon parameter
    1.1. Set sqlcon parameter
    1.2. Set sqlres parameter
    1.2. Set sqlres parameter
    1.3. sql_query() usage
    1.3. sql_query() usage
-   1.4. sql_result_free() usage
-   1.5. $dbr(result=>key) usage
+   1.4. sql_xquery() usage
+   1.5. sql_result_free() usage
+   1.6. $dbr(result=>key) usage
 
 
 Chapter 1. Admin Guide
 Chapter 1. Admin Guide
 
 
@@ -64,7 +66,8 @@ Chapter 1. Admin Guide
    4. Exported Functions
    4. Exported Functions
 
 
         4.1. sql_query(connection, query, result)
         4.1. sql_query(connection, query, result)
-        4.2. sql_result_free(result)
+        4.2. sql_xquery(connection, query, result)
+        4.3. sql_result_free(result)
 
 
    5. Exported pseudo-variables
    5. Exported pseudo-variables
 
 
@@ -91,6 +94,10 @@ Chapter 1. Admin Guide
        [row,column].
        [row,column].
      * persistence in process space - a result can be used many times in
      * persistence in process space - a result can be used many times in
        the same worker process. Query once, use many times.
        the same worker process. Query once, use many times.
+     * alternatively, results can be stored in xavps - columns are
+       accessed by their names, rows by xavp index. Xavp's are available
+       during the transactions lifetime and don't need to be destroyed
+       manually.
 
 
 2. Dependencies
 2. Dependencies
 
 
@@ -153,7 +160,8 @@ modparam("sqlops", "sqlres", "ra")
 4. Exported Functions
 4. Exported Functions
 
 
    4.1. sql_query(connection, query, result)
    4.1. sql_query(connection, query, result)
-   4.2. sql_result_free(result)
+   4.2. sql_xquery(connection, query, result)
+   4.3. sql_result_free(result)
 
 
 4.1.  sql_query(connection, query, result)
 4.1.  sql_query(connection, query, result)
 
 
@@ -164,8 +172,7 @@ modparam("sqlops", "sqlres", "ra")
      * result - string name to identify the result. Will be used by
      * result - string name to identify the result. Will be used by
        $dbr(...) pseudo-variable to access result attributes.
        $dbr(...) pseudo-variable to access result attributes.
 
 
-   This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
-   ONREPLY_ROUTE, BRANCH_ROUTE.
+   This function can be used from ANY_ROUTE.
 
 
    Example 1.3. sql_query() usage
    Example 1.3. sql_query() usage
 ...
 ...
@@ -176,14 +183,32 @@ xlog("number of rows in table domain: $dbr(ra=>rows)\n");
 sql_result_free("ra");
 sql_result_free("ra");
 ...
 ...
 
 
-4.2.  sql_result_free(result)
+4.2.  sql_xquery(connection, query, result)
+
+   Make a SQL query using 'connection' and store data in 'result' xavp.
+     * connection - the name of the connection to be used for query
+       (defined via the “sqlcon” parameter).
+     * query - SQL query string or pseudo-variables containing SQL query.
+     * result - string name to identify the result xavp. Each row will be
+       added to this xavp, each column can be accessed by its name.
+
+   This function can be used from ANY_ROUTE.
+
+   Example 1.4. sql_xquery() usage
+...
+modparam("sqlops","sqlcon","ca=>dbdriver://username:password@dbhost/dbname")
+...
+sql_xquery("ca", "select * from domain", "ra");
+  xlog("first domain: $xavp(ra=>domain) with id: $xavp(ra=>domain_id)\n");
+...
+
+4.3.  sql_result_free(result)
 
 
    Free data in SQL 'result'.
    Free data in SQL 'result'.
 
 
-   This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
-   ONREPLY_ROUTE, BRANCH_ROUTE.
+   This function can be used from ANY_ROUTE.
 
 
-   Example 1.4. sql_result_free() usage
+   Example 1.5. sql_result_free() usage
 ...
 ...
 modparam("sqlops","sqlcon","ca=>dbdriver://username:password@dbhost/dbname")
 modparam("sqlops","sqlcon","ca=>dbdriver://username:password@dbhost/dbname")
 ...
 ...
@@ -212,7 +237,7 @@ sql_result_free("ra");
        integer.
        integer.
      * colname[N] - return the name of the N-th column in the result set.
      * colname[N] - return the name of the N-th column in the result set.
 
 
-   Example 1.5. $dbr(result=>key) usage
+   Example 1.6. $dbr(result=>key) usage
 ...
 ...
 modparam("sqlops","sqlcon","ca=>dbdriver://username:password@dbhost/dbname")
 modparam("sqlops","sqlcon","ca=>dbdriver://username:password@dbhost/dbname")
 ...
 ...
@@ -240,3 +265,25 @@ if($dbr(ra=>rows)>0)
 }
 }
 sql_result_free("ra");
 sql_result_free("ra");
 ...
 ...
+
+
+...
+if (sql_xquery("ca", "select * from domain", "ra") == 1)
+{
+# non-destructive iteration
+    $var(i) = 0;
+    while($xavp(ra[$var(i)]) != $null)
+    {
+        xlog("[id, domain] = [$xavp(ra[$var(i)]=>id), $xavp(ra[$var(i)]=>domain)
+]\n");
+        $var(i) = $var(i) + 1;
+    }
+
+# destructive iteration
+    while($xavp(ra) != $null)
+    {
+        xlog("[id, domain] = [$xavp(ra=>id), $xavp(ra=>domain)]\n");
+        pv_unset("$xavp(ra)");
+    }
+}
+...

+ 74 - 5
modules_k/sqlops/doc/sqlops_admin.xml

@@ -60,6 +60,14 @@
 			times.
 			times.
 		</para>
 		</para>
 		</listitem>
 		</listitem>
+		<listitem>
+		<para>
+			<emphasis>alternatively, results can be stored in xavps</emphasis>
+			- columns are accessed by their names, rows by xavp index. Xavp's
+			are available during the transactions lifetime and don't need to
+			be destroyed manually.
+		</para>
+		</listitem>
 
 
 	</itemizedlist>
 	</itemizedlist>
 	</section>
 	</section>
@@ -197,8 +205,7 @@ modparam("sqlops", "sqlres", "ra")
 		</listitem>
 		</listitem>
 		</itemizedlist>
 		</itemizedlist>
 		<para>
 		<para>
-			This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
-			ONREPLY_ROUTE, BRANCH_ROUTE.
+			This function can be used from ANY_ROUTE.
 		</para>
 		</para>
 		<example>
 		<example>
 		<title><function>sql_query()</function> usage</title>
 		<title><function>sql_query()</function> usage</title>
@@ -210,6 +217,48 @@ sql_query("ca", "select * from domain", "ra");
 xlog("number of rows in table domain: $dbr(ra=&gt;rows)\n");
 xlog("number of rows in table domain: $dbr(ra=&gt;rows)\n");
 sql_result_free("ra");
 sql_result_free("ra");
 ...
 ...
+</programlisting>
+		</example>
+	</section>
+	<section>
+		<title>
+		<function moreinfo="none">sql_xquery(connection, query, result)</function>
+		</title>
+		<para>
+			Make a SQL query using 'connection' and store data in 'result' xavp.
+		</para>
+		<itemizedlist>
+		<listitem>
+			<para>
+				<emphasis>connection</emphasis> - the name of the connection
+				to be used for query (defined via the <quote>sqlcon</quote> parameter).
+			</para>
+		</listitem>
+		<listitem>
+			<para>
+				<emphasis>query</emphasis> - SQL query string or pseudo-variables containing SQL query.
+			</para>
+		</listitem>
+		<listitem>
+			<para>
+				<emphasis>result</emphasis> - string name to identify the
+				result xavp. Each row will be added to this xavp, each column can 
+				be accessed by its name.
+			</para>
+		</listitem>
+		</itemizedlist>
+		<para>
+			This function can be used from ANY_ROUTE.
+		</para>
+		<example>
+		<title><function>sql_xquery()</function> usage</title>
+		<programlisting format="linespecific">
+...
+modparam("sqlops","sqlcon","ca=&gt;&exampledb;")
+...
+sql_xquery("ca", "select * from domain", "ra");
+  xlog("first domain: $xavp(ra=>domain) with id: $xavp(ra=>domain_id)\n");
+...
 </programlisting>
 </programlisting>
 		</example>
 		</example>
 	</section>
 	</section>
@@ -221,8 +270,7 @@ sql_result_free("ra");
 			Free data in SQL 'result'.
 			Free data in SQL 'result'.
 		</para>
 		</para>
 		<para>
 		<para>
-			This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
-			ONREPLY_ROUTE, BRANCH_ROUTE.
+			This function can be used from ANY_ROUTE.
 		</para>
 		</para>
 		<example>
 		<example>
 		<title><function>sql_result_free()</function> usage</title>
 		<title><function>sql_result_free()</function> usage</title>
@@ -306,7 +354,28 @@ if($dbr(ra=>rows)>0)
 }
 }
 sql_result_free("ra");
 sql_result_free("ra");
 ...
 ...
-				 </programlisting>
+
+
+...
+if (sql_xquery("ca", "select * from domain", "ra") == 1)
+{
+# non-destructive iteration
+    $var(i) = 0;
+    while($xavp(ra[$var(i)]) != $null)
+    {
+        xlog("[id, domain] = [$xavp(ra[$var(i)]=&gt;id), $xavp(ra[$var(i)]=&gt;domain)]\n");
+        $var(i) = $var(i) + 1;
+    }
+
+# destructive iteration
+    while($xavp(ra) != $null)
+    {
+        xlog("[id, domain] = [$xavp(ra=&gt;id), $xavp(ra=&gt;domain)]\n");
+        pv_unset("$xavp(ra)");
+    }
+}
+...
+				</programlisting>
 			</example>
 			</example>
 	</section>
 	</section>
 	</section>
 	</section>

+ 131 - 0
modules_k/sqlops/sql_api.c

@@ -32,6 +32,9 @@
 #include "../../dprint.h"
 #include "../../dprint.h"
 #include "../../lib/kcore/hash_func.h"
 #include "../../lib/kcore/hash_func.h"
 #include "../../ut.h"
 #include "../../ut.h"
+#ifdef WITH_XAVP
+#include "../../xavp.h"
+#endif
 
 
 #include "sql_api.h"
 #include "sql_api.h"
 
 
@@ -341,6 +344,134 @@ error:
 	return -1;
 	return -1;
 }
 }
 
 
+#ifdef WITH_XAVP
+int sql_do_xquery(struct sip_msg *msg, sql_con_t *con, pv_elem_t *query,
+		pv_elem_t *res)
+{
+	db1_res_t* db_res = NULL;
+	sr_xavp_t *row = NULL;
+	sr_xval_t val;
+	int i, j;
+	str sv, xavp;
+
+	if(msg==NULL || query==NULL || res==NULL)
+	{
+		LM_ERR("bad parameters\n");
+		return -1;
+	}
+	if(pv_printf_s(msg, query, &sv)!=0)
+	{
+		LM_ERR("cannot print the sql query\n");
+		return -1;
+	}
+
+	if(pv_printf_s(msg, res, &xavp)!=0)
+	{
+		LM_ERR("cannot print the result parameter\n");
+		return -1;
+	}
+
+	if(con->dbf.raw_query(con->dbh, &sv, &db_res)!=0)
+	{
+		LM_ERR("cannot do the query\n");
+		return -1;
+	}
+
+	if(db_res==NULL || RES_ROW_N(db_res)<=0 || RES_COL_N(db_res)<=0)
+	{
+		LM_DBG("no result after query\n");
+		con->dbf.free_result(con->dbh, db_res);
+		return 2;
+	}
+
+	for(i=RES_ROW_N(db_res)-1; i>=0; i--)
+	{
+		row = NULL;
+		for(j=RES_COL_N(db_res)-1; j>=0; j--)
+		{
+			if(RES_ROWS(db_res)[i].values[j].nul)
+			{
+				val.type = SR_XTYPE_NULL;
+			} else
+			{
+				switch(RES_ROWS(db_res)[i].values[j].type)
+				{
+					case DB1_STRING:
+						val.type = SR_XTYPE_STR;
+						sv.s=
+							(char*)RES_ROWS(db_res)[i].values[j].val.string_val;
+						sv.len=strlen(sv.s);
+					break;
+					case DB1_STR:
+						val.type = SR_XTYPE_STR;
+						sv.len=
+							RES_ROWS(db_res)[i].values[j].val.str_val.len;
+						sv.s=
+							(char*)RES_ROWS(db_res)[i].values[j].val.str_val.s;
+					break;
+					case DB1_BLOB:
+						val.type = SR_XTYPE_STR;
+						sv.len=
+							RES_ROWS(db_res)[i].values[j].val.blob_val.len;
+						sv.s=
+							(char*)RES_ROWS(db_res)[i].values[j].val.blob_val.s;
+					break;
+					case DB1_INT:
+						val.type = SR_XTYPE_INT;
+						val.v.i
+							= (int)RES_ROWS(db_res)[i].values[j].val.int_val;
+					break;
+					case DB1_DATETIME:
+						val.type = SR_XTYPE_INT;
+						val.v.i
+							= (int)RES_ROWS(db_res)[i].values[j].val.time_val;
+					break;
+					case DB1_BITMAP:
+						val.type = SR_XTYPE_INT;
+						val.v.i
+							= (int)RES_ROWS(db_res)[i].values[j].val.bitmap_val;
+					break;
+					default:
+						val.type = SR_XTYPE_NULL;
+				}
+				if(val.type == SR_XTYPE_STR)
+				{
+					if(sv.len==0)
+					{
+						val.v.s = _sql_empty_str;
+					} else {
+						val.v.s.s = (char*)pkg_malloc(sv.len*sizeof(char));
+						if(val.v.s.s == NULL)
+						{
+							LM_ERR("no more memory\n");
+							goto error;
+						}
+						memcpy(val.v.s.s, sv.s, sv.len);
+						val.v.s.len = sv.len;
+					}
+				}
+			}
+			/* Add column to current row, under the column's name */
+			LM_DBG("Adding column: %.*s\n", RES_NAMES(db_res)[j]->len, RES_NAMES(db_res)[j]->s);
+			xavp_add_value(RES_NAMES(db_res)[j], &val, &row);
+		}
+		/* Add row to result xavp */
+		val.type = SR_XTYPE_XAVP;
+		val.v.xavp = row;
+		LM_DBG("Adding row\n");
+		xavp_add_value(&xavp, &val, NULL);
+	}
+
+	con->dbf.free_result(con->dbh, db_res);
+	return 1;
+
+error:
+	con->dbf.free_result(con->dbh, db_res);
+	return -1;
+
+}
+#endif
+
 int sql_parse_param(char *val)
 int sql_parse_param(char *val)
 {
 {
 	str name;
 	str name;

+ 4 - 0
modules_k/sqlops/sql_api.h

@@ -73,6 +73,10 @@ void sql_destroy(void);
 int sql_connect(void);
 int sql_connect(void);
 
 
 int sql_do_query(sql_con_t *con, str *query, sql_result_t *res);
 int sql_do_query(sql_con_t *con, str *query, sql_result_t *res);
+#ifdef WITH_XAVP
+int sql_do_xquery(struct sip_msg *msg, sql_con_t *con, pv_elem_t *query,
+		pv_elem_t *res);
+#endif
 sql_con_t* sql_get_connection(str *name);
 sql_con_t* sql_get_connection(str *name);
 sql_result_t* sql_get_result(str *name);
 sql_result_t* sql_get_result(str *name);
 
 

+ 61 - 0
modules_k/sqlops/sqlops.c

@@ -60,11 +60,17 @@ static int bind_sqlops(sqlops_api_t* api);
 
 
 /** module functions */
 /** module functions */
 static int sql_query(struct sip_msg*, char*, char*, char*);
 static int sql_query(struct sip_msg*, char*, char*, char*);
+#ifdef WITH_XAVP
+static int sql_xquery(struct sip_msg *msg, char *dbl, char *query, char *res);
+#endif
 static int sql_rfree(struct sip_msg*, char*, char*);
 static int sql_rfree(struct sip_msg*, char*, char*);
 static int child_init(int rank);
 static int child_init(int rank);
 static void destroy(void);
 static void destroy(void);
 
 
 static int fixup_sql_query(void** param, int param_no);
 static int fixup_sql_query(void** param, int param_no);
+#ifdef WITH_XAVP
+static int fixup_sql_xquery(void** param, int param_no);
+#endif
 static int fixup_sql_rfree(void** param, int param_no);
 static int fixup_sql_rfree(void** param, int param_no);
 
 
 static int sql_con_param(modparam_t type, void* val);
 static int sql_con_param(modparam_t type, void* val);
@@ -80,6 +86,11 @@ static cmd_export_t cmds[]={
 	{"sql_query",  (cmd_function)sql_query, 3, fixup_sql_query, 0, 
 	{"sql_query",  (cmd_function)sql_query, 3, fixup_sql_query, 0, 
 		REQUEST_ROUTE | FAILURE_ROUTE |
 		REQUEST_ROUTE | FAILURE_ROUTE |
 		ONREPLY_ROUTE | BRANCH_ROUTE | LOCAL_ROUTE},
 		ONREPLY_ROUTE | BRANCH_ROUTE | LOCAL_ROUTE},
+#ifdef WITH_XAVP
+	{"sql_xquery",  (cmd_function)sql_xquery, 3, fixup_sql_xquery, 0, 
+		REQUEST_ROUTE | FAILURE_ROUTE |
+		ONREPLY_ROUTE | BRANCH_ROUTE | LOCAL_ROUTE},
+#endif
 	{"sql_result_free",  (cmd_function)sql_rfree,  1, fixup_sql_rfree, 0, 
 	{"sql_result_free",  (cmd_function)sql_rfree,  1, fixup_sql_rfree, 0, 
 		REQUEST_ROUTE | FAILURE_ROUTE |
 		REQUEST_ROUTE | FAILURE_ROUTE |
 		ONREPLY_ROUTE | BRANCH_ROUTE | LOCAL_ROUTE},
 		ONREPLY_ROUTE | BRANCH_ROUTE | LOCAL_ROUTE},
@@ -181,6 +192,16 @@ static int sql_query(struct sip_msg *msg, char *dbl, char *query, char *res)
 	return sql_do_query((sql_con_t*)dbl, &sq, (sql_result_t*)res);
 	return sql_do_query((sql_con_t*)dbl, &sq, (sql_result_t*)res);
 }
 }
 
 
+#ifdef WITH_XAVP
+/**
+ *
+ */
+static int sql_xquery(struct sip_msg *msg, char *dbl, char *query, char *res)
+{
+	return sql_do_xquery(msg, (sql_con_t*)dbl, query, (pv_elem_t*)res);
+}
+#endif
+
 /**
 /**
  *
  *
  */
  */
@@ -230,6 +251,46 @@ static int fixup_sql_query(void** param, int param_no)
 	return 0;
 	return 0;
 }
 }
 
 
+#ifdef WITH_XAVP
+/**
+ *
+ */
+static int fixup_sql_xquery(void** param, int param_no)
+{
+	sql_con_t *con = NULL;
+	pv_elem_t *pv = NULL;
+	str s;
+
+	s.s = (char*)(*param);
+	s.len = strlen(s.s);
+
+	if (param_no==1) {
+		con = sql_get_connection(&s);
+		if(con==NULL)
+		{
+			LM_ERR("invalid connection [%s]\n", s.s);
+			return E_UNSPEC;
+		}
+		*param = (void*)con;
+	} else if (param_no==2) {
+		if(pv_parse_format(&s, &pv)<0)
+		{
+			LM_ERR("invalid query string [%s]\n", s.s);
+			return E_UNSPEC;
+		}
+		*param = (void*)pv;
+	} else if (param_no==3) {
+		if(pv_parse_format(&s, &pv)<0)
+		{
+			LM_ERR("invalid result [%s]\n", s.s);
+			return E_UNSPEC;
+		}
+		*param = (void*)pv;
+	}
+	return 0;
+}
+#endif
+
 /**
 /**
  *
  *
  */
  */

+ 17 - 0
modules_k/tmx/README

@@ -29,6 +29,7 @@ Daniel-Constantin Mierla
               3.1. t_cancel_branches(which)
               3.1. t_cancel_branches(which)
               3.2. t_cancel_callid(callid, cseq, flag)
               3.2. t_cancel_callid(callid, cseq, flag)
               3.3. t_reply_callid(callid, cseq, code, reason)
               3.3. t_reply_callid(callid, cseq, code, reason)
+              3.4. t_flush_flags()
 
 
         4. Exported pseudo-variables
         4. Exported pseudo-variables
         5. Exported MI Functions
         5. Exported MI Functions
@@ -57,6 +58,7 @@ Daniel-Constantin Mierla
    1.1. t_cancel_branches usage
    1.1. t_cancel_branches usage
    1.2. t_cancel_callid usage
    1.2. t_cancel_callid usage
    1.3. t_reply_callid usage
    1.3. t_reply_callid usage
+   1.4. t_flush_flags usage
 
 
 Chapter 1. Admin Guide
 Chapter 1. Admin Guide
 
 
@@ -73,6 +75,7 @@ Chapter 1. Admin Guide
         3.1. t_cancel_branches(which)
         3.1. t_cancel_branches(which)
         3.2. t_cancel_callid(callid, cseq, flag)
         3.2. t_cancel_callid(callid, cseq, flag)
         3.3. t_reply_callid(callid, cseq, code, reason)
         3.3. t_reply_callid(callid, cseq, code, reason)
+        3.4. t_flush_flags()
 
 
    4. Exported pseudo-variables
    4. Exported pseudo-variables
    5. Exported MI Functions
    5. Exported MI Functions
@@ -124,6 +127,7 @@ Chapter 1. Admin Guide
    3.1. t_cancel_branches(which)
    3.1. t_cancel_branches(which)
    3.2. t_cancel_callid(callid, cseq, flag)
    3.2. t_cancel_callid(callid, cseq, flag)
    3.3. t_reply_callid(callid, cseq, code, reason)
    3.3. t_reply_callid(callid, cseq, code, reason)
+   3.4. t_flush_flags()
 
 
 3.1.  t_cancel_branches(which)
 3.1.  t_cancel_branches(which)
 
 
@@ -182,6 +186,19 @@ if (t_reply_callid("123qaz", "5", "458", "Replied remotely")) {
 }
 }
 ...
 ...
 
 
+3.4.  t_flush_flags()
+
+   Flush the flags from current SIP message into the already created
+   transaction. It make sense only in routing block if the transaction was
+   created via t_newtran() and the flags have been altered since.
+
+   This function can be used from ANY_ROUTE .
+
+   Example 1.4. t_flush_flags usage
+...
+t_flush_flags();
+...
+
 4. Exported pseudo-variables
 4. Exported pseudo-variables
 
 
      * $T_branch_idx
      * $T_branch_idx

+ 21 - 0
modules_k/tmx/doc/tmx_admin.xml

@@ -168,6 +168,27 @@ if (t_reply_callid("123qaz", "5", "458", "Replied remotely")) {
 	xlog("transaction replied\n");
 	xlog("transaction replied\n");
 }
 }
 ...
 ...
+</programlisting>
+		</example>
+	</section>
+	<section>
+		<title>
+		<function moreinfo="none">t_flush_flags()</function>
+		</title>
+		<para>
+		Flush the flags from current SIP message into the already created 
+		transaction. It make sense only in routing block if the transaction was
+		created via t_newtran() and the flags have been altered since.
+		</para>
+		<para>
+		This function can be used from ANY_ROUTE .
+		</para>
+		<example>
+		<title><function>t_flush_flags</function> usage</title>
+		<programlisting format="linespecific">
+...
+t_flush_flags();
+...
 </programlisting>
 </programlisting>
 		</example>
 		</example>
 	</section>
 	</section>

+ 21 - 0
modules_k/tmx/tmx_mod.c

@@ -53,6 +53,8 @@ static int t_reply_callid(struct sip_msg* msg, char *cid, char *cseq,
 				char *rc, char *rs);
 				char *rc, char *rs);
 static int fixup_reply_callid(void** param, int param_no);
 static int fixup_reply_callid(void** param, int param_no);
 
 
+static int t_flush_flags(struct sip_msg* msg, char*, char* );
+
 /* statistic variables */
 /* statistic variables */
 stat_var *tm_rcv_rpls;
 stat_var *tm_rcv_rpls;
 stat_var *tm_rld_rpls;
 stat_var *tm_rld_rpls;
@@ -135,6 +137,8 @@ static cmd_export_t cmds[]={
 		fixup_cancel_callid, 0, ANY_ROUTE },
 		fixup_cancel_callid, 0, ANY_ROUTE },
 	{"t_reply_callid", (cmd_function)t_reply_callid,  4,
 	{"t_reply_callid", (cmd_function)t_reply_callid,  4,
 		fixup_reply_callid, 0, ANY_ROUTE },
 		fixup_reply_callid, 0, ANY_ROUTE },
+	{"t_flush_flags",   (cmd_function)t_flush_flags,    0, 0,
+			0, ANY_ROUTE  },
 	{0,0,0,0,0,0}
 	{0,0,0,0,0,0}
 };
 };
 
 
@@ -398,6 +402,23 @@ static int t_reply_callid(struct sip_msg* msg, char *cid, char *cseq,
 	return -1;
 	return -1;
 }
 }
 
 
+/**
+ *
+ */
+static int t_flush_flags(struct sip_msg* msg, char *foo, char *bar)
+{
+	struct cell *t;
+
+	t=_tmx_tmb.t_gett();
+	if ( t==0 || t==T_UNDEFINED) {
+		LM_ERR("failed to flush flags - no transaction found\n");
+		return -1;
+	}
+
+	t->uas.request->flags = msg->flags;
+	return 1;
+}
+
 #ifdef STATISTICS
 #ifdef STATISTICS
 
 
 /*** tm stats ***/
 /*** tm stats ***/

+ 68 - 18
modules_k/uac/README

@@ -14,9 +14,9 @@ Ramona-Elena Modroiu
 
 
    <[email protected]>
    <[email protected]>
 
 
-   Copyright © 2009-2010 asipto.com
+   Copyright © 2009-2010 asipto.com
 
 
-   Copyright © 2005 Voice Sistem
+   Copyright © 2005 Voice Sistem
      __________________________________________________________________
      __________________________________________________________________
 
 
    Table of Contents
    Table of Contents
@@ -51,6 +51,7 @@ Ramona-Elena Modroiu
               4.6. uac_reg_lookup(uuid, dst)
               4.6. uac_reg_lookup(uuid, dst)
 
 
         5. Exported pseudo-variables
         5. Exported pseudo-variables
+        6. Remote Registration
 
 
    List of Examples
    List of Examples
 
 
@@ -69,6 +70,7 @@ Ramona-Elena Modroiu
    1.13. uac_auth usage
    1.13. uac_auth usage
    1.14. uac_req_send usage
    1.14. uac_req_send usage
    1.15. uac_reg_lookup usage
    1.15. uac_reg_lookup usage
+   1.16. lookup remote registrations usage
 
 
 Chapter 1. Admin Guide
 Chapter 1. Admin Guide
 
 
@@ -102,13 +104,20 @@ Chapter 1. Admin Guide
         4.6. uac_reg_lookup(uuid, dst)
         4.6. uac_reg_lookup(uuid, dst)
 
 
    5. Exported pseudo-variables
    5. Exported pseudo-variables
+   6. Remote Registration
 
 
 1. Overview
 1. Overview
 
 
    UAC (User Agent Client) module provides some basic UAC functionalities
    UAC (User Agent Client) module provides some basic UAC functionalities
    like FROM header manipulation (anonymization) or client authentication.
    like FROM header manipulation (anonymization) or client authentication.
+
    From version 1.5.0 it has function to send SIP message from
    From version 1.5.0 it has function to send SIP message from
-   configuration file. Version 3.1.0 adds user registration functionality.
+   configuration file. See variable $uac_req(name) and the function
+   uac_req_send().
+
+   Version 3.1.0 adds user registration functionality. See
+   uac_reg_lookup() function and dedicated section for remote registration
+   configuration.
 
 
    Known limitations in this version:
    Known limitations in this version:
      * authentication does not support qop auth-int, just qop auth;
      * authentication does not support qop auth-int, just qop auth;
@@ -125,7 +134,7 @@ Chapter 1. Admin Guide
    The following modules must be loaded before this module:
    The following modules must be loaded before this module:
      * TM - Transaction Module
      * TM - Transaction Module
      * RR - Record-Route Module, but only if restore mode for FROM URI is
      * RR - Record-Route Module, but only if restore mode for FROM URI is
-       set to "auto".
+       set to “auto�.
 
 
 2.2. External Libraries or Applications
 2.2. External Libraries or Applications
 
 
@@ -150,7 +159,7 @@ Chapter 1. Admin Guide
    Name of Record-Route header parameter that will be used to store
    Name of Record-Route header parameter that will be used to store
    (encoded) the original FROM URI.
    (encoded) the original FROM URI.
 
 
-   This parameter is optional, it's default value being "vsf".
+   This parameter is optional, it's default value being “vsf�.
 
 
    Example 1.1. Set rr_store_param parameter
    Example 1.1. Set rr_store_param parameter
 ...
 ...
@@ -160,15 +169,15 @@ modparam("uac","rr_store_param","my_param")
 3.2. from_restore_mode (string)
 3.2. from_restore_mode (string)
 
 
    There are 3 mode of restoring the original FROM URI:
    There are 3 mode of restoring the original FROM URI:
-     * "none" - no information about original URI is stored; restoration
+     * “none� - no information about original URI is stored; restoration
        is not possible.
        is not possible.
-     * "manual" - all following replies will be restored, but not also the
+     * “manual� - all following replies will be restored, but not also the
        sequential requests - this must be manually updated based on
        sequential requests - this must be manually updated based on
        original URI.
        original URI.
-     * "auto" - all sequential requests and replies will be automatically
+     * “auto� - all sequential requests and replies will be automatically
        updated based on stored original URI.
        updated based on stored original URI.
 
 
-   This parameter is optional, it's default value being "auto".
+   This parameter is optional, it's default value being “auto�.
 
 
    Example 1.2. Set from_restore_mode parameter
    Example 1.2. Set from_restore_mode parameter
 ...
 ...
@@ -204,9 +213,9 @@ modparam("uac","credential","username:domain:password")
    The definition of an AVP that might contain the realm to be used to
    The definition of an AVP that might contain the realm to be used to
    perform authentication.
    perform authentication.
 
 
-   If you define it, you also need to define "auth_username_avp"
-   (Section 3.6, "auth_username_avp (string)") and "auth_username_avp"
-   (Section 3.7, "auth_password_avp (string)").
+   If you define it, you also need to define “auth_username_avp�
+   (Section 3.6, “auth_username_avp (string)�) and “auth_username_avp�
+   (Section 3.7, “auth_password_avp (string)�).
 
 
    Example 1.5. Set auth_realm_avp parameter
    Example 1.5. Set auth_realm_avp parameter
 ...
 ...
@@ -218,9 +227,9 @@ modparam("uac","auth_realm_avp","$avp(i:10)")
    The definition of an AVP that might contain the username to be used to
    The definition of an AVP that might contain the username to be used to
    perform authentication.
    perform authentication.
 
 
-   If you define it, you also need to define "auth_realm_avp"
-   (Section 3.5, "auth_realm_avp (string)") and "auth_username_avp"
-   (Section 3.7, "auth_password_avp (string)").
+   If you define it, you also need to define “auth_realm_avp�
+   (Section 3.5, “auth_realm_avp (string)�) and “auth_username_avp�
+   (Section 3.7, “auth_password_avp (string)�).
 
 
    Example 1.6. Set auth_username_avp parameter
    Example 1.6. Set auth_username_avp parameter
 ...
 ...
@@ -232,9 +241,9 @@ modparam("uac","auth_username_avp","$avp(i:11)")
    The definition of an AVP that might contain the password to be used to
    The definition of an AVP that might contain the password to be used to
    perform authentication.
    perform authentication.
 
 
-   If you define it, you also need to define "auth_password_avp"
-   (Section 3.7, "auth_password_avp (string)") and "auth_username_avp"
-   (Section 3.7, "auth_password_avp (string)").
+   If you define it, you also need to define “auth_password_avp�
+   (Section 3.7, “auth_password_avp (string)�) and “auth_username_avp�
+   (Section 3.7, “auth_password_avp (string)�).
 
 
    Example 1.7. Set auth_password_avp parameter
    Example 1.7. Set auth_password_avp parameter
 ...
 ...
@@ -368,3 +377,44 @@ if(uac_reg_lookup("$rU", "$ru"))
 
 
    Exported pseudo-variables are documented at
    Exported pseudo-variables are documented at
    http://www.kamailio.org/dokuwiki/.
    http://www.kamailio.org/dokuwiki/.
+
+6. Remote Registration
+
+   The module can register contact addresses to remote REGISTRAR servers.
+   You have to add records to uacreg table. The table stores following
+   attributes:
+     * l_uuid - local unique user id, e.g.,: 12345678
+
+     * l_username - local user name, e.g.,: test
+
+     * l_domain - local domain, e.g.,: mysipserver.com
+
+     * r_username - remote username, e.g.,: test123
+
+     * r_domain - remote domain, e.g.,: sipprovider.com
+
+     * realm - remote relam, e.g.,: sipprovider.com
+
+     * auth_username - authentication username, e.g.,: test123
+
+     * auth_password - authentication password, e.g.,: xxxxxx
+
+     * auth_proxy - SIP address of authentication proxy, e.g.,:
+       sip:sipprovider.com
+
+     * expires - expiration time for registration, in seconds, e.g.,: 360
+
+   The module takes care of sending REGISTER and refresh registrations
+   before they expire.
+
+   When calls come in, you have to run uac_reg_lookup() that will detect
+   if the call is coming from a remote SIP provider and can change the
+   R-URI to local username@domain. Afterwards you can run location lookup.
+
+   Example 1.16. lookup remote registrations usage
+...
+    if(uac_reg_lookup("$rU", "$ru")) {
+        xlog("request from a remote SIP provider [$ou => $ru]\n");
+    }
+    lookup("location");
+...

+ 101 - 3
modules_k/uac/doc/uac_admin.xml

@@ -19,9 +19,17 @@
 		<para>
 		<para>
 		UAC (User Agent Client) module provides some basic UAC
 		UAC (User Agent Client) module provides some basic UAC
 		functionalities like FROM header manipulation (anonymization)
 		functionalities like FROM header manipulation (anonymization)
-		or client authentication. From version 1.5.0 it has function to
-		send SIP message from configuration file. Version 3.1.0 adds user
-		registration functionality.
+		or client authentication.
+		</para>
+		<para>
+		From version 1.5.0 it has function to send SIP message from
+		configuration file. See variable $uac_req(name) and the function
+		uac_req_send().
+		</para>
+		<para>
+		Version 3.1.0 adds user registration functionality. See
+		uac_reg_lookup() function and dedicated section for remote
+		registration configuration.
 		</para>
 		</para>
 		<para>
 		<para>
 		Known limitations in this version:
 		Known limitations in this version:
@@ -441,5 +449,95 @@ if(uac_reg_lookup("$rU", "$ru"))
 		Exported pseudo-variables are documented at &kamwikilink;.
 		Exported pseudo-variables are documented at &kamwikilink;.
 		</para>
 		</para>
 	</section>
 	</section>
+	<section>
+		<title>Remote Registration</title>
+		<para>
+		The module can register contact addresses to remote REGISTRAR servers.
+		You have to add records to uacreg table. The table stores following
+		attributes:
+		</para>
+
+		<itemizedlist>
+			<listitem><para>
+			<emphasis>l_uuid</emphasis> - local unique user id, e.g.,:
+			12345678
+			</para></listitem>
+		</itemizedlist>
+		<itemizedlist>
+			<listitem><para>
+			<emphasis>l_username</emphasis> - local user name, e.g.,: test
+			</para></listitem>
+		</itemizedlist>
+		<itemizedlist>
+			<listitem><para>
+			<emphasis>l_domain</emphasis> - local domain, e.g.,:
+			mysipserver.com
+			</para></listitem>
+		</itemizedlist>
+		<itemizedlist>
+			<listitem><para>
+			<emphasis>r_username</emphasis> - remote username, e.g.,:
+			test123
+			</para></listitem>
+		</itemizedlist>
+		<itemizedlist>
+			<listitem><para>
+			<emphasis>r_domain</emphasis> - remote domain, e.g.,:
+			sipprovider.com
+			</para></listitem>
+		</itemizedlist>
+		<itemizedlist>
+			<listitem><para>
+			<emphasis>realm</emphasis> - remote relam, e.g.,:
+			sipprovider.com
+			</para></listitem>
+		</itemizedlist>
+		<itemizedlist>
+			<listitem><para>
+			<emphasis>auth_username</emphasis> - authentication username,
+			e.g.,: test123
+			</para></listitem>
+		</itemizedlist>
+		<itemizedlist>
+			<listitem><para>
+			<emphasis>auth_password</emphasis> - authentication password,
+			e.g.,: xxxxxx
+			</para></listitem>
+		</itemizedlist>
+		<itemizedlist>
+			<listitem><para>
+			<emphasis>auth_proxy</emphasis> - SIP address of authentication
+			proxy, e.g.,: sip:sipprovider.com
+			</para></listitem>
+		</itemizedlist>
+		<itemizedlist>
+			<listitem><para>
+			<emphasis>expires</emphasis> - expiration time for registration,
+			in seconds, e.g.,: 360
+			</para></listitem>
+		</itemizedlist>
+
+		<para>
+		The module takes care of sending REGISTER and refresh registrations
+		before they expire.
+		</para>
+		<para>
+		When calls come in, you have to run uac_reg_lookup() that will detect
+		if the call is coming from a remote SIP provider and can change the
+		R-URI to local username@domain. Afterwards you can run location lookup.
+		</para>
+
+		<example>
+		<title><function>lookup remote registrations</function> usage</title>
+			<programlisting format="linespecific">
+...
+    if(uac_reg_lookup("$rU", "$ru")) {
+        xlog("request from a remote SIP provider [$ou => $ru]\n");
+    }
+    lookup("location");
+...
+			</programlisting>
+		</example>
+	</section>
 </chapter>
 </chapter>
 
 

+ 56 - 2
modules_k/uac/uac_reg.c

@@ -28,8 +28,11 @@
 #include "../../mem/shm_mem.h"
 #include "../../mem/shm_mem.h"
 #include "../../lib/srdb1/db.h"
 #include "../../lib/srdb1/db.h"
 #include "../../ut.h"
 #include "../../ut.h"
+#include "../../trim.h"
 #include "../../hashes.h"
 #include "../../hashes.h"
 #include "../../parser/parse_uri.h"
 #include "../../parser/parse_uri.h"
+#include "../../parser/parse_from.h"
+#include "../../parser/parse_to.h"
 #include "../../parser/contact/parse_contact.h"
 #include "../../parser/contact/parse_contact.h"
 #include "../../rpc.h"
 #include "../../rpc.h"
 #include "../../rpc_lookup.h"
 #include "../../rpc_lookup.h"
@@ -385,6 +388,41 @@ reg_uac_t *reg_ht_get_byuser(str *user, str *domain)
 	return NULL;
 	return NULL;
 }
 }
 
 
+int uac_reg_tmdlg(dlg_t *tmdlg, sip_msg_t *rpl)
+{
+	if(tmdlg==NULL || rpl==NULL)
+		return -1;
+
+	if (parse_headers(rpl, HDR_EOH_F, 0) < 0) {
+		LM_ERR("error while parsing all headers in the reply\n");
+		return -1;
+	}
+	if(parse_to_header(rpl)<0 || parse_from_header(rpl)<0) {
+		LM_ERR("error while parsing From/To headers in the reply\n");
+		return -1;
+	}
+	memset(tmdlg, 0, sizeof(dlg_t));
+
+	str2int(&(get_cseq(rpl)->number), &tmdlg->loc_seq.value);
+	tmdlg->loc_seq.is_set = 1;
+
+	tmdlg->id.call_id = rpl->callid->body;
+	trim(&tmdlg->id.call_id);
+
+	if (get_from(rpl)->tag_value.len) {
+		tmdlg->id.loc_tag = get_from(rpl)->tag_value;
+	}
+#if 0
+	if (get_to(rpl)->tag_value.len) {
+		tmdlg->id.rem_tag = get_to(rpl)->tag_value;
+	}
+#endif
+	tmdlg->loc_uri = get_from(rpl)->uri;
+	tmdlg->rem_uri = get_to(rpl)->uri;
+	tmdlg->state= DLG_CONFIRMED;
+	return 0;
+}
+
 void uac_reg_tm_callback( struct cell *t, int type, struct tmcb_params *ps)
 void uac_reg_tm_callback( struct cell *t, int type, struct tmcb_params *ps)
 {
 {
 	char *uuid;
 	char *uuid;
@@ -400,13 +438,16 @@ void uac_reg_tm_callback( struct cell *t, int type, struct tmcb_params *ps)
 	struct uac_credential cred;
 	struct uac_credential cred;
 	char  b_ruri[MAX_URI_SIZE];
 	char  b_ruri[MAX_URI_SIZE];
 	str   s_ruri;
 	str   s_ruri;
+#ifdef UAC_OLD_AUTH
 	char  b_turi[MAX_URI_SIZE];
 	char  b_turi[MAX_URI_SIZE];
 	str   s_turi;
 	str   s_turi;
+#endif
 	char  b_hdrs[MAX_UACH_SIZE];
 	char  b_hdrs[MAX_UACH_SIZE];
 	str   s_hdrs;
 	str   s_hdrs;
 	uac_req_t uac_r;
 	uac_req_t uac_r;
 	str method = {"REGISTER", 8};
 	str method = {"REGISTER", 8};
 	int ret;
 	int ret;
+	dlg_t tmdlg;
 
 
 	if(ps->param==NULL || *ps->param==0)
 	if(ps->param==NULL || *ps->param==0)
 	{
 	{
@@ -531,11 +572,12 @@ void uac_reg_tm_callback( struct cell *t, int type, struct tmcb_params *ps)
 			goto done;
 			goto done;
 		}
 		}
 		
 		
+#ifdef UAC_OLD_AUTH
 		snprintf(b_turi, MAX_URI_SIZE, "sip:%.*s@%.*s",
 		snprintf(b_turi, MAX_URI_SIZE, "sip:%.*s@%.*s",
 				ri->r_username.len, ri->r_username.s,
 				ri->r_username.len, ri->r_username.s,
 				ri->r_domain.len, ri->r_domain.s);
 				ri->r_domain.len, ri->r_domain.s);
 		s_turi.s = b_turi; s_turi.len = strlen(s_turi.s);
 		s_turi.s = b_turi; s_turi.len = strlen(s_turi.s);
-
+#endif
 		snprintf(b_hdrs, MAX_UACH_SIZE,
 		snprintf(b_hdrs, MAX_UACH_SIZE,
 				"Contact: <sip:%.*s@%.*s>\r\n"
 				"Contact: <sip:%.*s@%.*s>\r\n"
 				"Expires: %d\r\n"
 				"Expires: %d\r\n"
@@ -547,20 +589,32 @@ void uac_reg_tm_callback( struct cell *t, int type, struct tmcb_params *ps)
 		s_hdrs.s = b_hdrs; s_hdrs.len = strlen(s_hdrs.s);
 		s_hdrs.s = b_hdrs; s_hdrs.len = strlen(s_hdrs.s);
 		pkg_free(new_auth_hdr->s);
 		pkg_free(new_auth_hdr->s);
 
 
-		memset(&uac_r, '\0', sizeof(uac_r));
+		memset(&uac_r, 0, sizeof(uac_r));
+		if(uac_reg_tmdlg(&tmdlg, ps->rpl)<0)
+		{
+			LM_ERR("failed to build tm dialog\n");
+			goto done;
+		}
+		tmdlg.rem_target = s_ruri;
+		if(ri->auth_proxy.len)
+			tmdlg.dst_uri = ri->auth_proxy;
 		uac_r.method = &method;
 		uac_r.method = &method;
 		uac_r.headers = &s_hdrs;
 		uac_r.headers = &s_hdrs;
+		uac_r.dialog = &tmdlg;
 		uac_r.cb_flags = TMCB_LOCAL_COMPLETED;
 		uac_r.cb_flags = TMCB_LOCAL_COMPLETED;
 		/* Callback function */
 		/* Callback function */
 		uac_r.cb  = uac_reg_tm_callback;
 		uac_r.cb  = uac_reg_tm_callback;
 		/* Callback parameter */
 		/* Callback parameter */
 		uac_r.cbp = (void*)uuid;
 		uac_r.cbp = (void*)uuid;
+#ifdef UAC_OLD_AUTH
 		ret = uac_tmb.t_request(&uac_r,  /* UAC Req */
 		ret = uac_tmb.t_request(&uac_r,  /* UAC Req */
 				&s_ruri, /* Request-URI */
 				&s_ruri, /* Request-URI */
 				&s_turi, /* To */
 				&s_turi, /* To */
 				&s_turi, /* From */
 				&s_turi, /* From */
 				(ri->auth_proxy.len)?&ri->auth_proxy:NULL /* outbound uri */
 				(ri->auth_proxy.len)?&ri->auth_proxy:NULL /* outbound uri */
 			);
 			);
+#endif
+		ret = uac_tmb.t_request_within(&uac_r);
 		ri->flags |= UAC_REG_AUTHSENT;
 		ri->flags |= UAC_REG_AUTHSENT;
 
 
 		if(ret<0)
 		if(ret<0)

+ 80 - 87
parser/hf.c

@@ -68,145 +68,129 @@ void clean_hdr_field(struct hdr_field* hf)
 	void** h_parsed;
 	void** h_parsed;
 
 
 	if (hf->parsed){
 	if (hf->parsed){
-		h_parsed=&hf->parsed; /*strict aliasing warnings workarround */
+		h_parsed=&hf->parsed; /* strict aliasing warnings workarround */
 		switch(hf->type){
 		switch(hf->type){
-		case HDR_VIA_T:
-			free_via_list(hf->parsed);
-			break;
-
-		case HDR_TO_T:
-			free_to(hf->parsed);
-			break;
-
-		case HDR_FROM_T:
-			free_to(hf->parsed);
-			break;
-
-		case HDR_CSEQ_T:
-			free_cseq(hf->parsed);
+		/* headers with pkg alloc for parsed structure (alphabetic order) */
+		case HDR_ACCEPT_T:
+			pkg_free(hf->parsed);
 			break;
 			break;
 
 
-		case HDR_CALLID_T:
+		case HDR_ALLOW_T:
+			free_allow_header(hf);
 			break;
 			break;
 
 
-		case HDR_SIPIFMATCH_T:
-			free_sipifmatch((str **)h_parsed);
+		case HDR_AUTHORIZATION_T:
+			free_credentials((auth_body_t**)h_parsed);
 			break;
 			break;
 
 
 		case HDR_CONTACT_T:
 		case HDR_CONTACT_T:
 			free_contact((contact_body_t**)h_parsed);
 			free_contact((contact_body_t**)h_parsed);
 			break;
 			break;
 
 
-		case HDR_MAXFORWARDS_T:
-			break;
-
-		case HDR_ROUTE_T:
-			free_rr((rr_t**)h_parsed);
-			break;
-
-		case HDR_RECORDROUTE_T:
-			free_rr((rr_t**)h_parsed);
+		case HDR_CONTENTDISPOSITION_T:
+			free_disposition( ((struct disposition**)h_parsed));
 			break;
 			break;
 
 
-		case HDR_CONTENTTYPE_T:
+		case HDR_CSEQ_T:
+			free_cseq(hf->parsed);
 			break;
 			break;
 
 
-		case HDR_CONTENTLENGTH_T:
+		case HDR_DATE_T:
+			free_date(hf->parsed);
 			break;
 			break;
 
 
-		case HDR_RETRY_AFTER_T:
+		case HDR_DIVERSION_T:
+			free_to(hf->parsed);
 			break;
 			break;
 
 
-		case HDR_AUTHORIZATION_T:
-			free_credentials((auth_body_t**)h_parsed);
+		case HDR_EVENT_T:
+			free_event((event_t**)h_parsed);
 			break;
 			break;
 
 
 		case HDR_EXPIRES_T:
 		case HDR_EXPIRES_T:
 			free_expires((exp_body_t**)h_parsed);
 			free_expires((exp_body_t**)h_parsed);
 			break;
 			break;
 
 
-		case HDR_PROXYAUTH_T:
-			free_credentials((auth_body_t**)h_parsed);
-			break;
-
-		case HDR_SUPPORTED_T:
-			break;
-
-		case HDR_REQUIRE_T:
-			break;
-
-		case HDR_PROXYREQUIRE_T:
-			break;
-
-		case HDR_UNSUPPORTED_T:
-			break;
-
-		case HDR_ALLOW_T:
-			free_allow_header(hf);
-			break;
-
-		case HDR_EVENT_T:
-			free_event((event_t**)h_parsed);
-			break;
-
-		case HDR_ACCEPT_T:
-			pkg_free(hf->parsed);
+		case HDR_FROM_T:
+			free_to(hf->parsed);
 			break;
 			break;
 
 
-		case HDR_ACCEPTLANGUAGE_T:
+		case HDR_IDENTITY_INFO_T:
+			free_identityinfo(hf->parsed);
 			break;
 			break;
 
 
-		case HDR_ORGANIZATION_T:
+		case HDR_IDENTITY_T:
+			free_identity(hf->parsed);
 			break;
 			break;
 
 
-		case HDR_PRIORITY_T:
+		case HDR_PAI_T:
+			free_to(hf->parsed);
 			break;
 			break;
 
 
-		case HDR_SUBJECT_T:
+		case HDR_PPI_T:
+			free_to(hf->parsed);
 			break;
 			break;
 
 
-		case HDR_USERAGENT_T:
+		case HDR_PROXYAUTH_T:
+			free_credentials((auth_body_t**)h_parsed);
 			break;
 			break;
 
 
-		case HDR_SERVER_T:
+		case HDR_RECORDROUTE_T:
+			free_rr((rr_t**)h_parsed);
 			break;
 			break;
 
 
-		case HDR_ACCEPTDISPOSITION_T:
+		case HDR_REFER_TO_T:
+			free_to(hf->parsed);
 			break;
 			break;
 
 
-		case HDR_CONTENTDISPOSITION_T:
-			free_disposition( ((struct disposition**)h_parsed));
+		case HDR_ROUTE_T:
+			free_rr((rr_t**)h_parsed);
 			break;
 			break;
 
 
-		case HDR_DIVERSION_T:
+		case HDR_RPID_T:
 			free_to(hf->parsed);
 			free_to(hf->parsed);
 			break;
 			break;
 
 
-		case HDR_RPID_T:
-			free_to(hf->parsed);
+		case HDR_SESSIONEXPIRES_T:
+			hdr_free_parsed(h_parsed);
 			break;
 			break;
 
 
-		case HDR_REFER_TO_T:
-			free_to(hf->parsed);
+		case HDR_SIPIFMATCH_T:
+			free_sipifmatch((str **)h_parsed);
 			break;
 			break;
 
 
 		case HDR_SUBSCRIPTION_STATE_T:
 		case HDR_SUBSCRIPTION_STATE_T:
 			free_subscription_state((subscription_state_t**)h_parsed);
 			free_subscription_state((subscription_state_t**)h_parsed);
 			break;
 			break;
 
 
-		case HDR_DATE_T:
-			free_date(hf->parsed);
+		case HDR_SUPPORTED_T:
+			hdr_free_parsed(h_parsed);
 			break;
 			break;
 
 
-		case HDR_IDENTITY_INFO_T:
-			free_identityinfo(hf->parsed);
+		case HDR_TO_T:
+			free_to(hf->parsed);
 			break;
 			break;
 
 
-		case HDR_IDENTITY_T:
-			free_identity(hf->parsed);
+		case HDR_VIA_T:
+			free_via_list(hf->parsed);
 			break;
 			break;
 
 
-		case HDR_SESSIONEXPIRES_T:
+		/* headers with no alloc for parsed structure */
+		case HDR_CALLID_T:
+		case HDR_MAXFORWARDS_T:
+		case HDR_CONTENTTYPE_T:
+		case HDR_CONTENTLENGTH_T:
+		case HDR_RETRY_AFTER_T:
+		case HDR_REQUIRE_T:
+		case HDR_PROXYREQUIRE_T:
+		case HDR_UNSUPPORTED_T:
+		case HDR_ACCEPTLANGUAGE_T:
+		case HDR_ORGANIZATION_T:
+		case HDR_PRIORITY_T:
+		case HDR_SUBJECT_T:
+		case HDR_USERAGENT_T:
+		case HDR_SERVER_T:
+		case HDR_ACCEPTDISPOSITION_T:
 		case HDR_MIN_SE_T:
 		case HDR_MIN_SE_T:
 		case HDR_ACCEPTCONTACT_T:
 		case HDR_ACCEPTCONTACT_T:
 		case HDR_ALLOWEVENTS_T:
 		case HDR_ALLOWEVENTS_T:
@@ -221,14 +205,6 @@ void clean_hdr_field(struct hdr_field* hf)
 		case HDR_REASON_T:
 		case HDR_REASON_T:
 			break;
 			break;
 
 
-		case HDR_PPI_T:
-			free_to(hf->parsed);
-			break;
-
-		case HDR_PAI_T:
-			free_to(hf->parsed);
-			break;
-
 		default:
 		default:
 			LOG(L_CRIT, "BUG: clean_hdr_field: unknown header type %d\n",
 			LOG(L_CRIT, "BUG: clean_hdr_field: unknown header type %d\n",
 			    hf->type);
 			    hf->type);
@@ -252,6 +228,7 @@ void free_hdr_field_lst(struct hdr_field* hf)
 	}
 	}
 }
 }
 
 
+/* print the content of hdr_field */
 void dump_hdr_field( struct hdr_field* hf )
 void dump_hdr_field( struct hdr_field* hf )
 {
 {
 	LOG(L_ERR, "DEBUG: dump_hdr_field: type=%d, name=%.*s, "
 	LOG(L_ERR, "DEBUG: dump_hdr_field: type=%d, name=%.*s, "
@@ -260,3 +237,19 @@ void dump_hdr_field( struct hdr_field* hf )
 		hf->body.len, ZSW(hf->body.s),
 		hf->body.len, ZSW(hf->body.s),
 		hf->parsed, hf->next );
 		hf->parsed, hf->next );
 }
 }
+
+/**
+ * free hdr parsed structure using inner free function
+ * - hdr parsed struct must have as first file a free function,
+ *   so it can be caseted to hf_parsed_t
+ */
+void hdr_free_parsed(void **h_parsed)
+{
+	if(h_parsed==NULL || *h_parsed==NULL)
+		return;
+
+	if(((hf_parsed_t*)(*h_parsed))->hfree) {
+		((hf_parsed_t*)(*h_parsed))->hfree(*h_parsed);
+	}
+	*h_parsed = 0;
+}

+ 36 - 11
parser/hf.h

@@ -213,27 +213,44 @@ typedef struct hdr_field {
 } hdr_field_t;
 } hdr_field_t;
 
 
 
 
+/* type of the function to free the structure of parsed header field */
+typedef void (*hf_parsed_free_f)(void *parsed);
+
+/* structure to hold the function to free the parsed header field */
+typedef struct hdr_parsed {
+	hf_parsed_free_f hfree;
+} hf_parsed_t;
 
 
 /** returns true if the header links allocated memory on parse field. */
 /** returns true if the header links allocated memory on parse field. */
 static inline int hdr_allocs_parse(struct hdr_field* hdr)
 static inline int hdr_allocs_parse(struct hdr_field* hdr)
 {
 {
 	switch(hdr->type){
 	switch(hdr->type){
-		case HDR_VIA_T:
-		case HDR_TO_T:
-		case HDR_FROM_T:
-		case HDR_CONTACT_T:
-		case HDR_ROUTE_T:
-		case HDR_RECORDROUTE_T:
-		case HDR_AUTHORIZATION_T:
-		case HDR_EXPIRES_T:
-		case HDR_PROXYAUTH_T:
-		case HDR_EVENT_T:
 		case HDR_ACCEPT_T:
 		case HDR_ACCEPT_T:
+		case HDR_ALLOW_T:
+		case HDR_AUTHORIZATION_T:
+		case HDR_CONTACT_T:
 		case HDR_CONTENTDISPOSITION_T:
 		case HDR_CONTENTDISPOSITION_T:
+		case HDR_CSEQ_T:
+		case HDR_DATE_T:
 		case HDR_DIVERSION_T:
 		case HDR_DIVERSION_T:
-		case HDR_RPID_T:
+		case HDR_EVENT_T:
+		case HDR_EXPIRES_T:
+		case HDR_FROM_T:
+		case HDR_IDENTITY_INFO_T:
+		case HDR_IDENTITY_T:
+		case HDR_PAI_T:
+		case HDR_PPI_T:
+		case HDR_PROXYAUTH_T:
+		case HDR_RECORDROUTE_T:
 		case HDR_REFER_TO_T:
 		case HDR_REFER_TO_T:
+		case HDR_ROUTE_T:
+		case HDR_RPID_T:
+		case HDR_SESSIONEXPIRES_T:
+		case HDR_SIPIFMATCH_T:
 		case HDR_SUBSCRIPTION_STATE_T:
 		case HDR_SUBSCRIPTION_STATE_T:
+		case HDR_SUPPORTED_T:
+		case HDR_TO_T:
+		case HDR_VIA_T:
 			return 1;
 			return 1;
 		default:
 		default:
 			return 0;
 			return 0;
@@ -251,6 +268,14 @@ void clean_hdr_field(struct hdr_field* hf);
  */
  */
 void free_hdr_field_lst(struct hdr_field* hf);
 void free_hdr_field_lst(struct hdr_field* hf);
 
 
+/* print content of hdr_field */
 void dump_hdr_field( struct hdr_field* hf );
 void dump_hdr_field( struct hdr_field* hf );
 
 
+/**
+ * free hdr parsed structure using inner free function
+ * - hdr parsed struct must have as first file a free function,
+ *   so it can be caseted to hf_parsed_t
+ */
+void hdr_free_parsed(void **h_parsed);
+
 #endif /* HF_H */
 #endif /* HF_H */

+ 1 - 1
parser/msg_parser.c

@@ -710,7 +710,7 @@ int parse_msg(char* buf, unsigned int len, struct sip_msg* msg)
 
 
 error:
 error:
 	/* more debugging, msg->orig is/should be null terminated*/
 	/* more debugging, msg->orig is/should be null terminated*/
-	LOG(L_ERR, "ERROR: parse_msg: message=<%.*s>\n",
+	LOG(cfg_get(core, core_cfg, corelog), "ERROR: parse_msg: message=<%.*s>\n",
 			(int)msg->len, ZSW(msg->buf));
 			(int)msg->len, ZSW(msg->buf));
 	return -1;
 	return -1;
 }
 }

+ 6 - 0
pkg/kamailio/deb/debian/kamailio.default

@@ -14,6 +14,12 @@ GROUP=kamailio
 # Amount of memory to allocate for the running Kamailio server (in Mb)
 # Amount of memory to allocate for the running Kamailio server (in Mb)
 MEMORY=64
 MEMORY=64
 
 
+# Switch to USER and GROUP by start-stop-daemon or by kamailio itself
+# - with recent kernels, changing user ID inside applicaton prevents
+#   dumping core files. If the value is 'yes', the suid is done by
+#   start-stop-daemon, otherwise it is done by kamailio itself
+SSD_SUID=no
+
 # Enable the server to leave a core file when it crashes.
 # Enable the server to leave a core file when it crashes.
 # Set this to 'yes' to enable Kamailio to leave a core file when it crashes
 # Set this to 'yes' to enable Kamailio to leave a core file when it crashes
 # or 'no' to disable this feature. This option is case sensitive and only
 # or 'no' to disable this feature. This option is case sensitive and only

+ 44 - 12
pkg/kamailio/deb/debian/kamailio.init

@@ -22,13 +22,14 @@ DESC=kamailio
 HOMEDIR=/var/run/kamailio
 HOMEDIR=/var/run/kamailio
 PIDFILE=$HOMEDIR/$NAME.pid
 PIDFILE=$HOMEDIR/$NAME.pid
 DEFAULTS=/etc/default/kamailio
 DEFAULTS=/etc/default/kamailio
+CFGFILE=/etc/kamailio/kamailio.cfg
 RUN_KAMAILIO=no
 RUN_KAMAILIO=no
 
 
 # Do not start kamailio if fork=no is set in the config file
 # Do not start kamailio if fork=no is set in the config file
 # otherwise the boot process will just stop
 # otherwise the boot process will just stop
 check_fork ()
 check_fork ()
 {
 {
-    if grep -q "^[[:space:]]*fork[[:space:]]*=[[:space:]]*no.*" /etc/kamailio/kamailio.cfg; then
+    if grep -q "^[[:space:]]*fork[[:space:]]*=[[:space:]]*no.*" $CFGFILE; then
 	echo "Not starting $DESC: fork=no specified in config file; run /etc/init.d/kamailio debug instead"
 	echo "Not starting $DESC: fork=no specified in config file; run /etc/init.d/kamailio debug instead"
 	exit 1
 	exit 1
     fi
     fi
@@ -80,7 +81,10 @@ create_radius_seqfile ()
     chmod 660 $RADIUS_SEQ_FILE
     chmod 660 $RADIUS_SEQ_FILE
 }
 }
 
 
-test -f $DAEMON || exit 0
+if [ ! -f $DAEMON ]; then
+	echo "No Kamailio daemon at: $DAEMON"
+	exit 0
+fi
 
 
 # Load startup options if available
 # Load startup options if available
 if [ -f $DEFAULTS ]; then
 if [ -f $DEFAULTS ]; then
@@ -89,7 +93,16 @@ fi
 
 
 if [ "$RUN_KAMAILIO" != "yes" ]; then
 if [ "$RUN_KAMAILIO" != "yes" ]; then
     echo "Kamailio not yet configured. Edit /etc/default/kamailio first."
     echo "Kamailio not yet configured. Edit /etc/default/kamailio first."
-    exit 0
+    case "$1" in
+    status)
+        # 4 program or service status is unknown
+        exit 4
+       ;;
+    *)
+        # 6 program is not configured
+        exit 6
+       ;;
+    esac
 fi
 fi
 
 
 set -e
 set -e
@@ -104,13 +117,34 @@ if test "$DUMP_CORE" = "yes" ; then
     ulimit -c unlimited
     ulimit -c unlimited
     
     
     # directory for the core dump files
     # directory for the core dump files
-    # COREDIR=/home/corefiles
+    # COREDIR=/tmp/corefiles
     # [ -d $COREDIR ] || mkdir $COREDIR
     # [ -d $COREDIR ] || mkdir $COREDIR
     # chmod 777 $COREDIR
     # chmod 777 $COREDIR
     # echo "$COREDIR/core.%e.sig%s.%p" > /proc/sys/kernel/core_pattern
     # echo "$COREDIR/core.%e.sig%s.%p" > /proc/sys/kernel/core_pattern
 fi
 fi
 
 
-OPTIONS="-P $PIDFILE -m $MEMORY -u $USER -g $GROUP"
+if [ "$SSD_SUID" != "yes" ]; then
+	OPTIONS="-f $CFGFILE -P $PIDFILE -m $MEMORY -u $USER -g $GROUP"
+	SSDOPTS=""
+else
+	OPTIONS="-f $CFGFILE -P $PIDFILE -m $MEMORY"
+	SSDOPTS="--chuid $USER:$GROUP"
+fi
+
+start_kamailio_daemon ()
+{
+	start-stop-daemon --start --quiet --pidfile $PIDFILE $SSDOPTS \
+		--exec $DAEMON -- $OPTIONS || if [ ! -r "$PIDFILE" ]; then
+			echo " error, failed to start."
+			exit 1
+		elif read pid < "$PIDFILE" && ps -p "$pid" > /dev/null 2>&1; then
+			echo -n " already running"
+			echo "."
+		else
+			echo " error, failed to start ($PIDFILE exists)."
+			exit 1
+		fi
+}
 
 
 case "$1" in
 case "$1" in
   start|debug)
   start|debug)
@@ -122,13 +156,12 @@ case "$1" in
 	    check_fork
 	    check_fork
 	fi
 	fi
 
 
-	echo -n "Starting $DESC: $NAME"
-	start-stop-daemon --start --quiet --pidfile $PIDFILE \
-		--exec $DAEMON -- $OPTIONS || echo -n " already running"
+	echo -n "Starting $DESC: $NAME "
+	start_kamailio_daemon
 	echo "."
 	echo "."
 	;;
 	;;
   stop)
   stop)
-	echo -n "Stopping $DESC: $NAME"
+	echo -n "Stopping $DESC: $NAME "
 	start-stop-daemon --oknodo --stop --quiet --pidfile $PIDFILE \
 	start-stop-daemon --oknodo --stop --quiet --pidfile $PIDFILE \
 		--exec $DAEMON
 		--exec $DAEMON
 	echo "."
 	echo "."
@@ -138,12 +171,11 @@ case "$1" in
 	check_homedir
 	check_homedir
 	create_radius_seqfile
 	create_radius_seqfile
 
 
-	echo -n "Restarting $DESC: $NAME"
+	echo -n "Restarting $DESC: $NAME "
 	start-stop-daemon --oknodo --stop --quiet --pidfile \
 	start-stop-daemon --oknodo --stop --quiet --pidfile \
 		$PIDFILE --exec $DAEMON
 		$PIDFILE --exec $DAEMON
 	sleep 1
 	sleep 1
-	start-stop-daemon --start --quiet --pidfile \
-		$PIDFILE --exec $DAEMON  -- $OPTIONS
+	start_kamailio_daemon
 	echo "."
 	echo "."
 	;;
 	;;
   status)
   status)

+ 2 - 1
receive.c

@@ -139,7 +139,8 @@ int receive_msg(char* buf, unsigned int len, struct receive_info* rcv_info)
 	msg->set_global_port=default_global_port;
 	msg->set_global_port=default_global_port;
 	
 	
 	if (parse_msg(buf,len, msg)!=0){
 	if (parse_msg(buf,len, msg)!=0){
-		LOG(L_ERR, "ERROR: receive_msg: parse_msg failed\n");
+		LOG(cfg_get(core, core_cfg, corelog),
+				"ERROR: receive_msg: parse_msg failed\n");
 		goto error02;
 		goto error02;
 	}
 	}
 	DBG("After parse_msg...\n");
 	DBG("After parse_msg...\n");

+ 10 - 143
ser_stun.c

@@ -64,9 +64,7 @@ int stun_add_address_attr(struct stun_msg* res,
 						int do_xor);
 						int do_xor);
 int add_unknown_attr(struct stun_msg* res, struct stun_unknown_att* unknown);
 int add_unknown_attr(struct stun_msg* res, struct stun_unknown_att* unknown);
 int add_error_code(struct stun_msg* res, USHORT_T error_code);
 int add_error_code(struct stun_msg* res, USHORT_T error_code);
-int add_fingerprint(struct stun_buffer* msg);
 int copy_str_to_buffer(struct stun_msg* res, const char* data, UINT_T pad);
 int copy_str_to_buffer(struct stun_msg* res, const char* data, UINT_T pad);
-int validate_fingerprint(struct stun_msg* req, USHORT_T* error_code);
 int reallock_buffer(struct stun_buffer* buffer, UINT_T len);
 int reallock_buffer(struct stun_buffer* buffer, UINT_T len);
 int buf_copy(struct stun_buffer* msg, void* source, UINT_T len);
 int buf_copy(struct stun_buffer* msg, void* source, UINT_T len);
 void clean_memory(struct stun_msg* req,
 void clean_memory(struct stun_msg* req,
@@ -231,11 +229,9 @@ int stun_parse_body(
 	struct stun_unknown_att*	tmp_unknown;
 	struct stun_unknown_att*	tmp_unknown;
 	struct stun_unknown_att*	body;
 	struct stun_unknown_att*	body;
 	char*	buf;
 	char*	buf;
-	int		fp_present;
 	
 	
 	attr_size = sizeof(struct stun_attr);
 	attr_size = sizeof(struct stun_attr);
 	buf = &req->msg.buf.s[sizeof(struct stun_hdr)];
 	buf = &req->msg.buf.s[sizeof(struct stun_hdr)];
-	fp_present = 0;
 	
 	
 	/* 
 	/* 
 	 * Mark the body lenght as unparsed.
 	 * Mark the body lenght as unparsed.
@@ -286,7 +282,6 @@ int stun_parse_body(
 			case MAPPED_ADDRESS_ATTR:
 			case MAPPED_ADDRESS_ATTR:
 			case XOR_MAPPED_ADDRESS_ATTR:
 			case XOR_MAPPED_ADDRESS_ATTR:
 			case ALTERNATE_SERVER_ATTR:
 			case ALTERNATE_SERVER_ATTR:
-			case REFRESH_INTERVAL_ATTR:
 			case RESPONSE_ADDRESS_ATTR:
 			case RESPONSE_ADDRESS_ATTR:
 			case SOURCE_ADDRESS_ATTR:
 			case SOURCE_ADDRESS_ATTR:
 			case REFLECTED_FROM_ATTR:		
 			case REFLECTED_FROM_ATTR:		
@@ -300,10 +295,9 @@ int stun_parse_body(
 			
 			
 			/* following attributes must be padded to 4 bytes */
 			/* following attributes must be padded to 4 bytes */
 			case USERNAME_ATTR:
 			case USERNAME_ATTR:
-			case PASSWORD_ATTR:
 			case ERROR_CODE_ATTR:
 			case ERROR_CODE_ATTR:
 			case UNKNOWN_ATTRIBUTES_ATTR:
 			case UNKNOWN_ATTRIBUTES_ATTR:
-			case SERVER_ATTR:
+			case SOFTWARE_ATTR:
 				padded_len = PADDED_TO_FOUR(ntohs(attr.len));
 				padded_len = PADDED_TO_FOUR(ntohs(attr.len));
 #ifdef EXTRA_DEBUG
 #ifdef EXTRA_DEBUG
 				LOG(L_DBG, "DEBUG: stun_parse_body: padded to four\n");
 				LOG(L_DBG, "DEBUG: stun_parse_body: padded to four\n");
@@ -322,25 +316,8 @@ int stun_parse_body(
 #ifdef EXTRA_DEBUG
 #ifdef EXTRA_DEBUG
 				LOG(L_DBG, "DEBUG: stun_parse_body: fingerprint attribute found\n");
 				LOG(L_DBG, "DEBUG: stun_parse_body: fingerprint attribute found\n");
 #endif
 #endif
-				fp_present = 1;
-				if (ntohs(attr.len) != SHA_DIGEST_LENGTH) {
-					LOG(L_WARN, 
-						"WARNING: STUN: Incorrect fingerprint of request.\n");
-					*error_code = BAD_REQUEST_ERR;
-					continue;
-				}
-
-				memcpy(req->fp, buf, SHA_DIGEST_LENGTH);
-				if(stun_allow_fp) {
-					if (validate_fingerprint(req, error_code) != 0) {
-						LOG(L_WARN, 
-							"WARNING: STUN: Incorrect fingerprint of request.\n");
-						*error_code = BAD_REQUEST_ERR;
-						continue;
-					}
-				} 
-
 				padded_len = SHA_DIGEST_LENGTH;
 				padded_len = SHA_DIGEST_LENGTH;
+
 				if (not_parsed > SHA_DIGEST_LENGTH) {
 				if (not_parsed > SHA_DIGEST_LENGTH) {
 #ifdef EXTRA_DEBUG
 #ifdef EXTRA_DEBUG
 					LOG(L_DBG, "DEBUG: stun_parse_body: fingerprint is not the last attribute\n");
 					LOG(L_DBG, "DEBUG: stun_parse_body: fingerprint is not the last attribute\n");
@@ -396,14 +373,6 @@ int stun_parse_body(
 		*error_code = UNKNOWN_ATTRIBUTE_ERR;
 		*error_code = UNKNOWN_ATTRIBUTE_ERR;
 	} 
 	} 
 	
 	
-	if (fp_present == 0 && req->old == 0) {
-#ifdef EXTRA_DEBUG
-		LOG(L_DBG, "DEBUG: stun_parse_body: fingerprint is missing is this new request\n");
-#endif
-		/* missing mandatory attribute fingerprint */
-		*error_code = BAD_REQUEST_ERR;
-	}
-	
 	return 0;
 	return 0;
 }
 }
 
 
@@ -431,7 +400,6 @@ int stun_create_response(
 						struct stun_unknown_att* unknown, 
 						struct stun_unknown_att* unknown, 
 						UINT_T error_code)
 						UINT_T error_code)
 {
 {
-	UINT_T msg_len;
 	/*
 	/*
 	 * Alloc some space for response.
 	 * Alloc some space for response.
 	 * Optimalization? - maybe it would be better to use biggish static array.
 	 * Optimalization? - maybe it would be better to use biggish static array.
@@ -477,14 +445,6 @@ int stun_create_response(
 						  XOR) != 0) {
 						  XOR) != 0) {
 #ifdef EXTRA_DEBUG
 #ifdef EXTRA_DEBUG
 				LOG(L_DBG, "DEBUG: stun_create_response: failed to add address\n");
 				LOG(L_DBG, "DEBUG: stun_create_response: failed to add address\n");
-#endif
-				return FATAL_ERROR;
-			}
-			
-			if (stun_add_common_integer_attr(res, REFRESH_INTERVAL_ATTR, 
-						stun_refresh_interval) != 0) {
-#ifdef EXTRA_DEBUG
-				LOG(L_DBG, "DEBUG: stun_create_response: failed to common attributes\n");
 #endif
 #endif
 				return FATAL_ERROR;
 				return FATAL_ERROR;
 			}
 			}
@@ -532,10 +492,10 @@ int stun_create_response(
 	
 	
 	if (req->old == 0) {
 	if (req->old == 0) {
 		/* 
 		/* 
-		 * add optional information about server; attribute SERVER is not a part of 
-		 * rfc3489.txt 
+		 * add optional information about server; attribute SOFTWARE is part of 
+		 * rfc5389.txt
 		 * */
 		 * */
-		if (stun_add_common_text_attr(res, SERVER_ATTR, SERVER_HDR, PAD4)!=0) {
+		if (stun_add_common_text_attr(res, SOFTWARE_ATTR, SERVER_HDR, PAD4)!=0) {
 #ifdef EXTRA_DEBUG
 #ifdef EXTRA_DEBUG
 			LOG(L_DBG, "DEBUG: stun_create_response: failed to add common text attribute\n");
 			LOG(L_DBG, "DEBUG: stun_create_response: failed to add common text attribute\n");
 #endif
 #endif
@@ -543,28 +503,9 @@ int stun_create_response(
 		}
 		}
 	}	
 	}	
 	
 	
-	if (req->old == 0 && stun_allow_fp) {
-		/* count length of body except header and fingerprint
-	 	 * and copy message length at the beginning of buffer
-	   */
-	  msg_len = res->msg.buf.len - sizeof(struct stun_hdr);
-	  msg_len += SHA_DIGEST_LENGTH + sizeof(struct stun_attr);
-		res->hdr.len = htons(msg_len);
-		memcpy(&res->msg.buf.s[sizeof(USHORT_T)], (void *) &res->hdr.len,
-	  	sizeof(USHORT_T));
-	  		
-		if (add_fingerprint(&res->msg) != 0) {
-#ifdef EXTRA_DEBUG
-			LOG(L_DBG, "DEBUG: stun_create_response: failed to add fingerprint\n");
-#endif
-			return FATAL_ERROR;
-		}
-	}
-	else {
-		res->hdr.len = htons(res->msg.buf.len - sizeof(struct stun_hdr));
-		memcpy(&res->msg.buf.s[sizeof(USHORT_T)], (void *) &res->hdr.len,
-	  	sizeof(USHORT_T));
-	}
+	res->hdr.len = htons(res->msg.buf.len - sizeof(struct stun_hdr));
+	memcpy(&res->msg.buf.s[sizeof(USHORT_T)], (void *) &res->hdr.len,
+	       sizeof(USHORT_T));
 	
 	
 	return 0;
 	return 0;
 }
 }
@@ -824,14 +765,14 @@ int stun_add_address_attr(struct stun_msg* res,
 	
 	
 	ip_struct_len = 0;
 	ip_struct_len = 0;
 	attr.type = htons(type);
 	attr.type = htons(type);
-	res->ip_addr.port = (do_xor) ? htons(port) ^ MAGIC_COOKIE_2B : htons(port);
+	res->ip_addr.port = htons((do_xor) ? (port ^ MAGIC_COOKIE_2B) : port);
 	switch(af) {
 	switch(af) {
 		case AF_INET:
 		case AF_INET:
 			ip_struct_len = sizeof(struct stun_ip_addr) - 3*sizeof(UINT_T);
 			ip_struct_len = sizeof(struct stun_ip_addr) - 3*sizeof(UINT_T);
 			res->ip_addr.family = htons(IPV4_FAMILY);
 			res->ip_addr.family = htons(IPV4_FAMILY);
 			memcpy(res->ip_addr.ip, ip_addr, IPV4_LEN);
 			memcpy(res->ip_addr.ip, ip_addr, IPV4_LEN);
 			res->ip_addr.ip[0] = (do_xor) ? 
 			res->ip_addr.ip[0] = (do_xor) ? 
-					res->ip_addr.ip[0] ^ MAGIC_COOKIE : res->ip_addr.ip[0];		
+				res->ip_addr.ip[0] ^ htonl(MAGIC_COOKIE) : res->ip_addr.ip[0];
 			break;
 			break;
 #ifdef USE_IPV6
 #ifdef USE_IPV6
 		case AF_INET6:
 		case AF_INET6:
@@ -864,48 +805,6 @@ int stun_add_address_attr(struct stun_msg* res,
 	return 0;
 	return 0;
 }
 }
 
 
-/*
- * add_fingerprint()
- * 			- msg: response buffer
- * 
- * The function add_fingerprint ensures adding fingerprint attribute into
- * response buffer.
- * 
- * Return value:	0	if there is no environment error
- * 					-1	if there is some enviroment error such as insufficiency
- * 						of memory
- */
-int add_fingerprint(struct stun_buffer* msg)
-{
-	struct stun_attr attr;
-	USHORT_T attr_type_size;
-	
-	attr_type_size = sizeof(struct stun_attr);
-	attr.type = htons(FINGERPRINT_ATTR);
-	attr.len = htons(SHA_DIGEST_LENGTH);
-	
-	if (msg->empty < (SHA_DIGEST_LENGTH + attr_type_size)) {
-		if (reallock_buffer(msg, SHA_DIGEST_LENGTH + attr_type_size) != 0) {
-			return FATAL_ERROR;
-		}
-	}
-	
-	memcpy(&msg->buf.s[msg->buf.len], (void *) &attr, attr_type_size);	
-	msg->buf.len += attr_type_size;
-	msg->empty -= attr_type_size;
-	
-	if (SHA1((UCHAR_T *)msg->buf.s, msg->buf.len-attr_type_size, 
-			 (UCHAR_T *) &msg->buf.s[msg->buf.len]) == 0) {
-		LOG(L_ERR, "ERROR: STUN: SHA-1 algorithm failed.\n");
-		return FATAL_ERROR;
-	}
-	
-	msg->buf.len += SHA_DIGEST_LENGTH;
-	msg->empty -= SHA_DIGEST_LENGTH;
-	
-	return 0;
-}
-
 /*
 /*
  * stun_alloc_unknown_attr()
  * stun_alloc_unknown_attr()
  * 			- type: type of unknown attribute
  * 			- type: type of unknown attribute
@@ -957,38 +856,6 @@ void stun_delete_unknown_attrs(struct stun_unknown_att* unknown)
 	pkg_free(unknown);
 	pkg_free(unknown);
 }
 }
 
 
-/*
- * validate_fingerprint()
- * 			- req: structure representing request message
- * 			- error_code: indication of any protocol error
- * 
- * The function validate_fingerprint ensures validation of FINGERPRINT
- * attribute.
- * 
- * Return value:	0	if there is no environment error
- * 					-1	if there is some enviroment error such as insufficiency
- * 						of memory
- */
-int validate_fingerprint(struct stun_msg* req, USHORT_T* error_code)
-{
-	UCHAR_T	msg_digest[SHA_DIGEST_LENGTH];
-	UINT_T	buf_len; 
-	
-	buf_len = req->hdr.len + sizeof(struct stun_hdr);
-	buf_len -= SHA_DIGEST_LENGTH + sizeof(struct stun_attr);
-	
-	if (SHA1((UCHAR_T *) req->msg.buf.s, buf_len, msg_digest) == 0) {
-		LOG(L_ERR, "ERROR: STUN: SHA-1 algorithm failed.\n");
-		return FATAL_ERROR;
-	} 
-	
-	if (memcmp((void *)req->fp, (void *)&msg_digest, SHA_DIGEST_LENGTH) != 0) {
-		*error_code = BAD_REQUEST_ERR;
-	}
-	
-	return 0;	
-}
-
 /*
 /*
  * buf_copy()
  * buf_copy()
  * 			- msg: buffer where the data will be copy to
  * 			- msg: buffer where the data will be copy to

+ 3 - 6
ser_stun.h

@@ -56,19 +56,17 @@ typedef unsigned long	ULONG_T;
 /* common STUN attributes */
 /* common STUN attributes */
 #define MAPPED_ADDRESS_ATTR		0x0001
 #define MAPPED_ADDRESS_ATTR		0x0001
 #define USERNAME_ATTR			0x0006
 #define USERNAME_ATTR			0x0006
-#define PASSWORD_ATTR			0x0007
 #define MESSAGE_INTEGRITY_ATTR	0x0008
 #define MESSAGE_INTEGRITY_ATTR	0x0008
 #define ERROR_CODE_ATTR			0x0009
 #define ERROR_CODE_ATTR			0x0009
 #define UNKNOWN_ATTRIBUTES_ATTR	0x000A
 #define UNKNOWN_ATTRIBUTES_ATTR	0x000A
 
 
-/* STUN attributes defined by rfc3489bis */
+/* STUN attributes defined by rfc5389 */
 #define REALM_ATTR				0x0014
 #define REALM_ATTR				0x0014
 #define NONCE_ATTR				0x0015
 #define NONCE_ATTR				0x0015
 #define XOR_MAPPED_ADDRESS_ATTR	0x0020 
 #define XOR_MAPPED_ADDRESS_ATTR	0x0020 
-#define FINGERPRINT_ATTR		0x0023
-#define SERVER_ATTR				0x8022
+#define FINGERPRINT_ATTR		0x8028
+#define SOFTWARE_ATTR				0x8022
 #define ALTERNATE_SERVER_ATTR	0x8023
 #define ALTERNATE_SERVER_ATTR	0x8023
-#define REFRESH_INTERVAL_ATTR	0x8024
 
 
 /* STUN attributes defined by rfc3489 */
 /* STUN attributes defined by rfc3489 */
 #define RESPONSE_ADDRESS_ATTR	0x0002
 #define RESPONSE_ADDRESS_ATTR	0x0002
@@ -167,7 +165,6 @@ struct stun_msg {
 	struct stun_hdr			hdr;
 	struct stun_hdr			hdr;
 	struct stun_ip_addr		ip_addr;		/* XOR values for rfc3489bis, 
 	struct stun_ip_addr		ip_addr;		/* XOR values for rfc3489bis, 
 											normal values for rfc3489 */
 											normal values for rfc3489 */
-	char					fp[SHA_DIGEST_LENGTH];		/* fingerprint value */
 	struct stun_buffer		msg;
 	struct stun_buffer		msg;
 	UCHAR_T					old;		/* true: the format of message is in 
 	UCHAR_T					old;		/* true: the format of message is in 
 										accordance with rfc3489 */ 
 										accordance with rfc3489 */ 

+ 2 - 2
sr_module.c

@@ -1038,7 +1038,7 @@ int fix_param(int type, void** param)
 {
 {
 	fparam_t* p;
 	fparam_t* p;
 	str name, s;
 	str name, s;
-	unsigned int num;
+	int num;
 	int err;
 	int err;
 
 
 	p = (fparam_t*)pkg_malloc(sizeof(fparam_t));
 	p = (fparam_t*)pkg_malloc(sizeof(fparam_t));
@@ -1064,7 +1064,7 @@ int fix_param(int type, void** param)
 		case FPARAM_INT:
 		case FPARAM_INT:
 			s.s = (char*)*param;
 			s.s = (char*)*param;
 			s.len = strlen(s.s);
 			s.len = strlen(s.s);
-			err = str2int(&s, &num);
+			err = str2sint(&s, &num);
 			if (err == 0) {
 			if (err == 0) {
 				p->v.i = (int)num;
 				p->v.i = (int)num;
 			} else {
 			} else {

+ 4 - 2
tcp_read.c

@@ -266,7 +266,8 @@ again:
 								break;
 								break;
 						}
 						}
 				}
 				}
-				LOG(L_ERR, "error reading: %s (%d)\n", strerror(errno), errno);
+				LOG(cfg_get(core, core_cfg, corelog),
+						"error reading: %s (%d)\n", strerror(errno), errno);
 				return -1;
 				return -1;
 			}
 			}
 		}else if (unlikely((bytes_read==0) || 
 		}else if (unlikely((bytes_read==0) || 
@@ -879,7 +880,8 @@ again:
 					req->start);
 					req->start);
 #endif
 #endif
 			if (unlikely(bytes==-1)){
 			if (unlikely(bytes==-1)){
-				LOG(L_ERR, "ERROR: tcp_read_req: error reading \n");
+				LOG(cfg_get(core, core_cfg, corelog),
+						"ERROR: tcp_read_req: error reading \n");
 				resp=CONN_ERROR;
 				resp=CONN_ERROR;
 				goto end_req;
 				goto end_req;
 			}
 			}

+ 5 - 3
utils/kamctl/kamdbctl.base

@@ -36,8 +36,9 @@ STANDARD_TABLES=${STANDARD_TABLES:-version acc dbaliases domain grp
 		uri speed_dial lcr_gw lcr_rule lcr_rule_target pdt subscriber
 		uri speed_dial lcr_gw lcr_rule lcr_rule_target pdt subscriber
 		location re_grp trusted address missed_calls usr_preferences
 		location re_grp trusted address missed_calls usr_preferences
 		aliases silo dialog dispatcher dialplan}
 		aliases silo dialog dispatcher dialplan}
-EXTRA_TABLES=${EXTRA_TABLES:-imc_members imc_rooms cpl sip_trace domainpolicy carrierroute
-		carrier_name domain_name carrierfailureroute userblacklist globalblacklist htable purplemap}
+EXTRA_TABLES=${EXTRA_TABLES:-imc_members imc_rooms cpl sip_trace domainpolicy
+		carrierroute carrier_name domain_name carrierfailureroute userblacklist
+		globalblacklist htable purplemap uacreg}
 PRESENCE_TABLES=${PRESENCE_TABLES:-presentity active_watchers watchers xcap 
 PRESENCE_TABLES=${PRESENCE_TABLES:-presentity active_watchers watchers xcap 
 		pua rls_presentity rls_watchers}
 		pua rls_presentity rls_watchers}
 
 
@@ -65,7 +66,8 @@ STANDARD_MODULES=${STANDARD_MODULES:-standard acc lcr domain group permissions
 				     registrar usrloc msilo alias_db uri_db
 				     registrar usrloc msilo alias_db uri_db
 				     speeddial avpops auth_db pdt dialog dispatcher
 				     speeddial avpops auth_db pdt dialog dispatcher
 				     dialplan}
 				     dialplan}
-EXTRA_MODULES=${EXTRA_MODULES:-imc cpl siptrace domainpolicy carrierroute userblacklist htable purple}
+EXTRA_MODULES=${EXTRA_MODULES:-imc cpl siptrace domainpolicy carrierroute
+    userblacklist htable purple uac}
 
 
 ############################################################
 ############################################################
 
 

+ 23 - 17
xavp.c

@@ -459,50 +459,56 @@ sr_xavp_t **xavp_get_crt_list(void)
 	return _xavp_list_crt;
 	return _xavp_list_crt;
 }
 }
 
 
-void xavp_print_list(sr_xavp_t **head)
+void xavp_print_list_content(sr_xavp_t **head, int level)
 {
 {
 	sr_xavp_t *avp=0;
 	sr_xavp_t *avp=0;
+	sr_xavp_t *start=0;
 
 
 	if(head!=NULL)
 	if(head!=NULL)
-		avp = *head;
+		start = *head;
 	else
 	else
-		avp=*_xavp_list_crt;
-	LM_DBG("+++++ XAVP list: %p\n", avp);
+		start=*_xavp_list_crt;
+	LM_INFO("+++++ start XAVP list: %p (level=%d)\n", start, level);
+	avp = start;
 	while(avp)
 	while(avp)
 	{
 	{
-		LM_DBG("     *** XAVP name: %s\n", avp->name.s);
-		LM_DBG("     XAVP id: %u\n", avp->id);
-		LM_DBG("     XAVP value type: %d\n", avp->val.type);
+		LM_INFO("     *** XAVP name: %s\n", avp->name.s);
+		LM_INFO("     XAVP id: %u\n", avp->id);
+		LM_INFO("     XAVP value type: %d\n", avp->val.type);
 		switch(avp->val.type) {
 		switch(avp->val.type) {
 			case SR_XTYPE_NULL:
 			case SR_XTYPE_NULL:
-				LM_DBG("     XAVP value: <null>\n");
+				LM_INFO("     XAVP value: <null>\n");
 			break;
 			break;
 			case SR_XTYPE_INT:
 			case SR_XTYPE_INT:
-				LM_DBG("     XAVP value: %d\n", avp->val.v.i);
+				LM_INFO("     XAVP value: %d\n", avp->val.v.i);
 			break;
 			break;
 			case SR_XTYPE_STR:
 			case SR_XTYPE_STR:
-				LM_DBG("     XAVP value: %s\n", avp->val.v.s.s);
+				LM_INFO("     XAVP value: %s\n", avp->val.v.s.s);
 			break;
 			break;
 			case SR_XTYPE_TIME:
 			case SR_XTYPE_TIME:
-				LM_DBG("     XAVP value: %lu\n", avp->val.v.t);
+				LM_INFO("     XAVP value: %lu\n", avp->val.v.t);
 			break;
 			break;
 			case SR_XTYPE_LONG:
 			case SR_XTYPE_LONG:
-				LM_DBG("     XAVP value: %ld\n", avp->val.v.l);
+				LM_INFO("     XAVP value: %ld\n", avp->val.v.l);
 			break;
 			break;
 			case SR_XTYPE_LLONG:
 			case SR_XTYPE_LLONG:
-				LM_DBG("     XAVP value: %lld\n", avp->val.v.ll);
+				LM_INFO("     XAVP value: %lld\n", avp->val.v.ll);
 			break;
 			break;
 			case SR_XTYPE_XAVP:
 			case SR_XTYPE_XAVP:
-				LM_DBG("     XAVP value: <xavp:%p>\n", avp->val.v.xavp);
-				xavp_print_list(&avp->val.v.xavp);
+				LM_INFO("     XAVP value: <xavp:%p>\n", avp->val.v.xavp);
+				xavp_print_list_content(&avp->val.v.xavp, level+1);
 			break;
 			break;
 			case SR_XTYPE_DATA:
 			case SR_XTYPE_DATA:
-				LM_DBG("     XAVP value: <data:%p>\n", avp->val.v.data);
+				LM_INFO("     XAVP value: <data:%p>\n", avp->val.v.data);
 			break;
 			break;
 		}
 		}
 		avp = avp->next;
 		avp = avp->next;
 	}
 	}
-	LM_DBG("----- XAVP list\n");
+	LM_INFO("----- end XAVP list: %p (level=%d)\n", start, level);
 }
 }
 
 
+void xavp_print_list(sr_xavp_t **head)
+{
+	xavp_print_list_content(head, 0);
+}
 #endif
 #endif