Преглед на файлове

Merge branch 'master' of ssh://[email protected]/sip-router

* 'master' of ssh://[email protected]/sip-router:
  makefile: even more quiet
  modules warning fixes
  * callcontrol
  makefile: quiet output support
  pike_top: moved from tools/ to utils/
  kamctl: moved from tools/ to utils/
  core ev: minor cleanups
  topoh: new module for hiding topology details
  core: new sr events system
  core: execute callbacks for NET_DATA_IN and NET_DATA_OUT
oej преди 16 години
родител
ревизия
dcf0add128
променени са 100 файла, в които са добавени 2392 реда и са изтрити 52 реда
  1. 31 25
      Makefile
  2. 11 3
      Makefile.defs
  3. 2 0
      Makefile.libs
  4. 34 5
      Makefile.rules
  5. 98 0
      events.c
  6. 40 0
      events.h
  7. 14 4
      forward.h
  8. 1 1
      lib/binrpc/binrpc_api.c
  9. 1 1
      lib/srdb1/schema/Makefile
  10. 15 0
      modules/topoh/Makefile
  11. 186 0
      modules/topoh/README
  12. 4 0
      modules/topoh/doc/Makefile
  13. 37 0
      modules/topoh/doc/topoh.xml
  14. 198 0
      modules/topoh/doc/topoh_admin.xml
  15. 175 0
      modules/topoh/th_mask.c
  16. 30 0
      modules/topoh/th_mask.h
  17. 913 0
      modules/topoh/th_msg.c
  18. 45 0
      modules/topoh/th_msg.h
  19. 332 0
      modules/topoh/topoh_mod.c
  20. 210 9
      modules_k/call_control/call_control.c
  21. 1 1
      modules_k/siputils/contact_ops.c
  22. 1 1
      modules_k/tmx/tmx_mod.c
  23. 2 0
      modules_s/ctl/binrpc_run.c
  24. 1 0
      modules_s/eval/eval.c
  25. 1 0
      modules_s/msilo/msilo.c
  26. 1 0
      modules_s/permissions/ip_set.c
  27. 6 0
      receive.c
  28. 2 2
      test/unit/include/common
  29. 0 0
      utils/kamctl/Makefile
  30. 0 0
      utils/kamctl/db_berkeley/kamailio/acc
  31. 0 0
      utils/kamctl/db_berkeley/kamailio/active_watchers
  32. 0 0
      utils/kamctl/db_berkeley/kamailio/address
  33. 0 0
      utils/kamctl/db_berkeley/kamailio/aliases
  34. 0 0
      utils/kamctl/db_berkeley/kamailio/carrier_name
  35. 0 0
      utils/kamctl/db_berkeley/kamailio/carrierfailureroute
  36. 0 0
      utils/kamctl/db_berkeley/kamailio/carrierroute
  37. 0 0
      utils/kamctl/db_berkeley/kamailio/cpl
  38. 0 0
      utils/kamctl/db_berkeley/kamailio/dbaliases
  39. 0 0
      utils/kamctl/db_berkeley/kamailio/dialog
  40. 0 0
      utils/kamctl/db_berkeley/kamailio/dialplan
  41. 0 0
      utils/kamctl/db_berkeley/kamailio/dispatcher
  42. 0 0
      utils/kamctl/db_berkeley/kamailio/domain
  43. 0 0
      utils/kamctl/db_berkeley/kamailio/domain_name
  44. 0 0
      utils/kamctl/db_berkeley/kamailio/domainpolicy
  45. 0 0
      utils/kamctl/db_berkeley/kamailio/globalblacklist
  46. 0 0
      utils/kamctl/db_berkeley/kamailio/grp
  47. 0 0
      utils/kamctl/db_berkeley/kamailio/gw
  48. 0 0
      utils/kamctl/db_berkeley/kamailio/htable
  49. 0 0
      utils/kamctl/db_berkeley/kamailio/imc_members
  50. 0 0
      utils/kamctl/db_berkeley/kamailio/imc_rooms
  51. 0 0
      utils/kamctl/db_berkeley/kamailio/lcr
  52. 0 0
      utils/kamctl/db_berkeley/kamailio/location
  53. 0 0
      utils/kamctl/db_berkeley/kamailio/missed_calls
  54. 0 0
      utils/kamctl/db_berkeley/kamailio/pdt
  55. 0 0
      utils/kamctl/db_berkeley/kamailio/presentity
  56. 0 0
      utils/kamctl/db_berkeley/kamailio/pua
  57. 0 0
      utils/kamctl/db_berkeley/kamailio/purplemap
  58. 0 0
      utils/kamctl/db_berkeley/kamailio/re_grp
  59. 0 0
      utils/kamctl/db_berkeley/kamailio/rls_presentity
  60. 0 0
      utils/kamctl/db_berkeley/kamailio/rls_watchers
  61. 0 0
      utils/kamctl/db_berkeley/kamailio/silo
  62. 0 0
      utils/kamctl/db_berkeley/kamailio/sip_trace
  63. 0 0
      utils/kamctl/db_berkeley/kamailio/speed_dial
  64. 0 0
      utils/kamctl/db_berkeley/kamailio/subscriber
  65. 0 0
      utils/kamctl/db_berkeley/kamailio/trusted
  66. 0 0
      utils/kamctl/db_berkeley/kamailio/uri
  67. 0 0
      utils/kamctl/db_berkeley/kamailio/userblacklist
  68. 0 0
      utils/kamctl/db_berkeley/kamailio/usr_preferences
  69. 0 0
      utils/kamctl/db_berkeley/kamailio/version
  70. 0 0
      utils/kamctl/db_berkeley/kamailio/watchers
  71. 0 0
      utils/kamctl/db_berkeley/kamailio/xcap
  72. 0 0
      utils/kamctl/dbtext/kamailio/acc
  73. 0 0
      utils/kamctl/dbtext/kamailio/active_watchers
  74. 0 0
      utils/kamctl/dbtext/kamailio/address
  75. 0 0
      utils/kamctl/dbtext/kamailio/aliases
  76. 0 0
      utils/kamctl/dbtext/kamailio/carrier_name
  77. 0 0
      utils/kamctl/dbtext/kamailio/carrierfailureroute
  78. 0 0
      utils/kamctl/dbtext/kamailio/carrierroute
  79. 0 0
      utils/kamctl/dbtext/kamailio/cpl
  80. 0 0
      utils/kamctl/dbtext/kamailio/dbaliases
  81. 0 0
      utils/kamctl/dbtext/kamailio/dialog
  82. 0 0
      utils/kamctl/dbtext/kamailio/dialplan
  83. 0 0
      utils/kamctl/dbtext/kamailio/dispatcher
  84. 0 0
      utils/kamctl/dbtext/kamailio/domain
  85. 0 0
      utils/kamctl/dbtext/kamailio/domain_name
  86. 0 0
      utils/kamctl/dbtext/kamailio/domainpolicy
  87. 0 0
      utils/kamctl/dbtext/kamailio/globalblacklist
  88. 0 0
      utils/kamctl/dbtext/kamailio/grp
  89. 0 0
      utils/kamctl/dbtext/kamailio/gw
  90. 0 0
      utils/kamctl/dbtext/kamailio/htable
  91. 0 0
      utils/kamctl/dbtext/kamailio/imc_members
  92. 0 0
      utils/kamctl/dbtext/kamailio/imc_rooms
  93. 0 0
      utils/kamctl/dbtext/kamailio/lcr
  94. 0 0
      utils/kamctl/dbtext/kamailio/location
  95. 0 0
      utils/kamctl/dbtext/kamailio/missed_calls
  96. 0 0
      utils/kamctl/dbtext/kamailio/pdt
  97. 0 0
      utils/kamctl/dbtext/kamailio/presentity
  98. 0 0
      utils/kamctl/dbtext/kamailio/pua
  99. 0 0
      utils/kamctl/dbtext/kamailio/purplemap
  100. 0 0
      utils/kamctl/dbtext/kamailio/re_grp

+ 31 - 25
Makefile

@@ -247,7 +247,9 @@ ifeq (,$(strip \
 	$(filter config.mak config cfg cfg-defs $(clean_targets),$(MAKECMDGOALS))))
 include config.mak
 ifeq ($(makefile_defs),1)
+ifeq ($(quiet),verbose)
 $(info config.mak loaded)
+endif # verbose
 # config_make valid & used
 config_mak=1
 ifeq ($(MAIN_NAME),)
@@ -265,6 +267,10 @@ $(shell rm -rf config.mak)
 config_mak=0
 makefile_defs=0
 exported_vars=0
+else
+# config.mak not strictly needed, but try to load it if exists for $(Q)
+config_mak=skip
+-include config.mak
 endif
 endif
 
@@ -401,7 +407,7 @@ ifeq ($(config_mak),1)
 
 include Makefile.cfg
 
-else
+else ifneq ($(config_mak),skip)
 
 config.mak: Makefile.defs
 	@echo making config...
@@ -494,8 +500,8 @@ $(1)_target=$(prefix)/$(modules_dir)$(1)
 $(1): modules.lst
 	@for r in $($(1)) "" ; do \
 		if [ -n "$$$$r" -a -r "$$$$r/Makefile" ]; then \
-			echo  "" ; \
-			echo  "" ; \
+			$(call oecho, "" ;) \
+			$(call oecho, "" ;) \
 			if  $(MAKE) -C $$$$r $$(mk_params) || [ ${err_fail} != 1 ] ; then \
 				:; \
 			else \
@@ -508,8 +514,8 @@ $(1): modules.lst
 $(1)-doc: modules.lst
 	@for r in $($(1)) "" ; do \
 		if [ -n "$$$$r" ]; then \
-			echo  "" ; \
-			echo  "" ; \
+			$(call oecho, "" ;) \
+			$(call oecho, "" ;) \\
 			$(MAKE) -C $$$$r/doc $(doc_format) $$(mk_params); \
 		fi ; \
 	done
@@ -519,8 +525,8 @@ $(1)-doc: modules.lst
 $(1)-readme: modules.lst
 	-@for r in $($(1)) "" ; do \
 		if [ -n "$$$$r" ]; then \
-			echo  "" ; \
-			echo  "" ; \
+			$(call oecho, "" ;) \
+			$(call oecho, "" ;) \
 			if  $(MAKE) -C $$$$r $$(mk_params) README || [ ${err_fail} != 1 ];\
 			then \
 				:; \
@@ -534,8 +540,8 @@ $(1)-readme: modules.lst
 $(1)-man: modules.lst
 	-@for r in $($(1)) "" ; do \
 		if [ -n "$$$$r" ]; then \
-			echo  "" ; \
-			echo  "" ; \
+			$(call oecho, "" ;) \
+			$(call oecho, "" ;) \
 			if  $(MAKE) -C $$$$r $$(mk_params) man || [ ${err_fail} != 1 ] ;\
 			then \
 				:; \
@@ -550,8 +556,8 @@ $(1)-man: modules.lst
 install-$(1): modules.lst $$($(1)_dst)
 	@for r in $($(1)) "" ; do \
 		if [ -n "$$$$r" -a -r "$$$$r/Makefile" ]; then \
-			echo  "" ; \
-			echo  "" ; \
+			$(call oecho, "" ;) \
+			$(call oecho, "" ;) \
 			if  $(MAKE) -C $$$$r install mods_dst=$$($(1)_dst) $$(mk_params) \
 				|| [ ${err_fail} != 1 ] ; then \
 				:; \
@@ -617,8 +623,8 @@ $(extra_objs):
 	@echo "Extra objs: $(extra_objs)" 
 	@for r in $(static_modules_path) "" ; do \
 		if [ -n "$$r" -a -r "$$r/Makefile"  ]; then \
-			echo  "" ; \
-			echo  "Making static module $r" ; \
+			$(call oecho, "" ;) \
+			$(call oecho, "Making static module $r" ;) \
 			if $(MAKE) -C $$r static $(mk_params) ; then  \
 				:; \
 			else \
@@ -631,8 +637,8 @@ $(extra_objs):
 utils:
 	@for r in $(utils_compile) "" ; do \
 		if [ -n "$$r" ]; then \
-			echo  "" ; \
-			echo  "" ; \
+			$(call oecho, "" ;) \
+			$(call oecho, "" ;) \
 			if  $(MAKE) -C $$r $(mk_params) || [ ${err_fail} != 1 ] ; \
 			then \
 				:; \
@@ -774,22 +780,22 @@ $(man_prefix)/$(man_dir)/man5:
 
 # note: sed with POSIX.1 regex doesn't support |, + or ? (darwin, solaris ...) 
 install-cfg: $(cfg_prefix)/$(cfg_dir)
-		sed $(foreach m,$(modules_dirs),\
+		@sed $(foreach m,$(modules_dirs),\
 				-e "s#/usr/[^:]*lib/$(CFG_NAME)/$(m)\([:/\"]\)#$($(m)_target)\1#g") \
 			< etc/$(CFG_NAME)-basic.cfg > \
 			$(cfg_prefix)/$(cfg_dir)$(MAIN_NAME).cfg.sample
-		chmod 644 $(cfg_prefix)/$(cfg_dir)$(MAIN_NAME).cfg.sample
-		if [ -z "${skip_cfg_install}" -a \
+		@chmod 644 $(cfg_prefix)/$(cfg_dir)$(MAIN_NAME).cfg.sample
+		@if [ -z "${skip_cfg_install}" -a \
 				! -f $(cfg_prefix)/$(cfg_dir)$(MAIN_NAME).cfg ]; then \
 			mv -f $(cfg_prefix)/$(cfg_dir)$(MAIN_NAME).cfg.sample \
 				$(cfg_prefix)/$(cfg_dir)$(MAIN_NAME).cfg; \
 		fi
-		sed $(foreach m,$(modules_dirs),\
+		@sed $(foreach m,$(modules_dirs),\
 			-e "s#/usr/[^:]*lib/$(CFG_NAME)/$(m)\([:/\"]\)#$($(m)_target)\1#g") \
 			< etc/$(CFG_NAME)-oob.cfg \
 			> $(cfg_prefix)/$(cfg_dir)$(MAIN_NAME)-advanced.cfg.sample
-		chmod 644 $(cfg_prefix)/$(cfg_dir)$(MAIN_NAME)-advanced.cfg.sample
-		if [ -z "${skip_cfg_install}" -a \
+		@chmod 644 $(cfg_prefix)/$(cfg_dir)$(MAIN_NAME)-advanced.cfg.sample
+		@if [ -z "${skip_cfg_install}" -a \
 				! -f $(cfg_prefix)/$(cfg_dir)$(MAIN_NAME)-advanced.cfg ]; \
 		then \
 			mv -f $(cfg_prefix)/$(cfg_dir)$(MAIN_NAME)-advanced.cfg.sample \
@@ -878,22 +884,22 @@ install-doc: $(doc_prefix)/$(doc_dir) install-every-module-doc
 
 
 install-sr-man: $(man_prefix)/$(man_dir)/man8 $(man_prefix)/$(man_dir)/man5
-		sed -e "s#/etc/$(CFG_NAME)/$(CFG_NAME)\.cfg#$(cfg_target)$(MAIN_NAME).cfg#g" \
+		@sed -e "s#/etc/$(CFG_NAME)/$(CFG_NAME)\.cfg#$(cfg_target)$(MAIN_NAME).cfg#g" \
 			-e "s#/usr/sbin/#$(bin_target)#g" \
 			$(foreach m,$(modules_dirs),\
 				-e "s#/usr/lib/$(CFG_NAME)/$(m)\([^_]\)#$($(m)_target)\1#g") \
 			-e "s#/usr/share/doc/$(CFG_NAME)/#$(doc_target)#g" \
 			< $(CFG_NAME).8 >  \
 							$(man_prefix)/$(man_dir)/man8/$(MAIN_NAME).8
-		chmod 644  $(man_prefix)/$(man_dir)/man8/$(MAIN_NAME).8
-		sed -e "s#/etc/$(CFG_NAME)/$(CFG_NAME)\.cfg#$(cfg_target)$(MAIN_NAME).cfg#g" \
+		@chmod 644  $(man_prefix)/$(man_dir)/man8/$(MAIN_NAME).8
+		@sed -e "s#/etc/$(CFG_NAME)/$(CFG_NAME)\.cfg#$(cfg_target)$(MAIN_NAME).cfg#g" \
 			-e "s#/usr/sbin/#$(bin_target)#g" \
 			$(foreach m,$(modules_dirs),\
 				-e "s#/usr/lib/$(CFG_NAME)/$(m)\([^_]\)#$($(m)_target)\1#g") \
 			-e "s#/usr/share/doc/$(CFG_NAME)/#$(doc_target)#g" \
 			< $(CFG_NAME).cfg.5 >  \
 			$(man_prefix)/$(man_dir)/man5/$(MAIN_NAME).cfg.5
-		chmod 644  $(man_prefix)/$(man_dir)/man5/$(MAIN_NAME).cfg.5
+		@chmod 644  $(man_prefix)/$(man_dir)/man5/$(MAIN_NAME).cfg.5
 
 install-man:  install-sr-man install-every-module-man
 

+ 11 - 3
Makefile.defs

@@ -75,15 +75,18 @@
 #  2009-10-01  use -fsigned-char for gcc on ppc, ppc64, arm and arm6
 #              (on those archs char is unsigned by default) (andrei)
 
+quiet?=$(if $(filter 1 yes on,$(Q)),silent,verbose)
 
 # check if already included/exported
 
-
 # used for sanity checks for Makefile.defs inclusion (!= makefile_defs which
 # specifies if we have a set of valid defs)
 override makefile_defs_included:=1
 ifeq ($(makefile_defs),1)
+ifeq ($(quiet),verbose)
 $(info Makefile.defs defs skipped)
+endif # verbose
+
 else
 
 ifeq (,$(main_makefile))
@@ -94,7 +97,9 @@ ifeq (,$(main_makefile))
 # don't export the vars)
 COREPATH?= ../..
 include $(COREPATH)/config.mak
+ifeq ($(quiet),verbose)
 $(info config.mak included)
+endif # verbose
 # config.mak should set makefile_defs if complete
 export makefile_defs
 
@@ -103,7 +108,9 @@ override makefile_defs=1
 export makefile_defs
 
 
+ifeq ($(quiet),verbose)
 $(info normal Makefile.defs exec)
+endif # verbose
 # main binary name
 MAIN_NAME=ser
 #prefix for various configs and scripts
@@ -417,11 +424,11 @@ endif # predefined macros tests (x86_macros, ...)
 endif # gcc
 
 ifdef CC_ARCH
-$(info target architecture <$(CC_ARCH)>, host architecture <$(HOST_ARCH)>)
 ARCH:=$(CC_ARCH)
 else
 ARCH:=$(HOST_ARCH)
 endif
+$(info target architecture <$(ARCH)>, host architecture <$(HOST_ARCH)>)
 
 # compile-time options
 #
@@ -1901,7 +1908,8 @@ saved_fixed_vars:=	MAIN_NAME  CFG_NAME SCR_NAME \
 		PREFIX LOCALBASE \
 		TAR \
 		INSTALL INSTALL_CFG INSTALL_BIN INSTALL_MODULES INSTALL_DOC \
-		INSTALL_MAN INSTALL_LIB INSTALL_TOUCH INSTALL_SHARE
+		INSTALL_MAN INSTALL_LIB INSTALL_TOUCH INSTALL_SHARE \
+		Q
 
 # variable changeable at compile time
 # extra: prefix DESTDIR BASEDIR basedirt

+ 2 - 0
Makefile.libs

@@ -20,7 +20,9 @@ endif
 
 ifneq	(,$(filter install% %install install, $(MAKECMDGOALS)))
 compile_for_install:=yes
+ifeq ($(quiet),verbose)
 $(info install mode)
+endif # verbose
 endif
 
 ifeq ($(NAME),)

+ 34 - 5
Makefile.rules

@@ -52,9 +52,38 @@ endif
 
 ALLDEP+=makecfg.lst
 
+# returns current type: "" core/unknown, "M" module, "L" libray, "U" util
+crt_type=$(if $(MOD_NAME),M,$(if $(LIB_NAME),L,$(if $(UTIL_NAME),U)))
+
+cmd_CC=$(CC) $(CFLAGS) $(C_INCLUDES) $(INCLUDES) $(C_DEFS) $(DEFS) -c $< -o $@
+cmd_LD=$(LD) $(LDFLAGS) $(objs) $(extra_objs) $(ALL_LIBS) $(SER_RPATH) \
+	-o $(NAME)
+
+# what will be displayed if quiet==silent
+silent_cmd_CC=CC ($(CC)) [$(strip $(crt_type) $(NAME))]		$@
+silent_cmd_LD=LD ($(LD)) [$(strip $(crt_type) $(NAME))]		$@
+
+ifneq (,$(filter 1 yes on, $(Q) $(QUIET)))
+quiet=silent
+Q=1
+MAKE+= --no-print-directory
+#shell optional print
+oecho=
+else
+override Q:=
+quiet=verbose
+#shell optional print
+oecho=echo $(1)
+endif
+
+quote:= "
+escall= $(subst $$,$$$$,$(subst $(quote),\$(quote),$1))
+exec_cmd= $(if $($(quiet)_cmd_$(1)),\
+			@echo "$(call escall,$($(quiet)_cmd_$(1)))" ;) $(cmd_$(1))
+
 #implicit rules
 %.o:%.c  $(ALLDEP)
-	$(CC) $(CFLAGS) $(C_INCLUDES) $(INCLUDES) $(C_DEFS) $(DEFS) -c $< -o $@
+	$(call exec_cmd,CC)
 
 %.d: %.c $(ALLDEP)
 	@set -e; $(MKDEP) $(CFLAGS) $(C_INCLUDES) $(INCLUDES) $(C_DEFS) $(DEFS) $<\
@@ -132,14 +161,14 @@ $(SER_IPATH_LST): FORCE
 		$(@) 1>/dev/null 2>/dev/null ; \
 	then :; \
 	else \
-		echo "re-building $(@D)" ; \
+		$(call oecho,"re-building $(@D)" ;) \
 		$(MAKE) -wC $(@D) compile_for_install=$(lib_compile_for_install) ; \
 	fi
 
 .PHONY: FORCE-BUILD-LIBS
 FORCE-BUILD-LIBS:
 	@for r in $(SER_LIBS_DIRS) ; do \
-		echo building lib $$r; \
+		$(call oecho,building lib $$r ;) \
 		$(MAKE) -wC $$r compile_for_install=$(lib_compile_for_install) ; \
 	done
 
@@ -149,7 +178,7 @@ endif
 
 # normal rules
 $(NAME): $(objs) $(ALLDEP)
-	$(LD) $(LDFLAGS) $(objs) $(extra_objs) $(ALL_LIBS) $(SER_RPATH) -o $(NAME)
+	$(call exec_cmd,LD)
 
 
 librpath.lst: $(ALLDEP)
@@ -183,7 +212,7 @@ clean: local-clean
 clean-modules:
 	-@for r in $(cmodules) $(static_modules_path) "" ; do \
 		if [ -d "$$r" ]; then \
-			echo "module $$r" ; \
+			$(call oecho,"module $$r" ;) \
 			$(MAKE) -C "$$r" clean ; \
 			[ -d "$$r"/doc/Makefile ] && $(MAKE) -C "$$r"/doc clean ; \
 		fi ; \

+ 98 - 0
events.c

@@ -0,0 +1,98 @@
+/**
+ * $Id$
+ *
+ * Copyright (C) 2009 SIP-Router.org
+ *
+ * This file is part of Extensible SIP Router, a free SIP server.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "dprint.h"
+#include "mem/mem.h"
+#include "events.h"
+
+static sr_event_cb_t _sr_events_list;
+static int _sr_events_inited = 0;
+
+void sr_event_cb_init(void)
+{
+	if(_sr_events_inited == 0)
+	{
+		memset(&_sr_events_list, 0, sizeof(sr_event_cb_t));
+		_sr_events_inited = 1;
+	}
+}
+
+int sr_event_register_cb(int type, sr_event_cb_f f)
+{
+	sr_event_cb_init();
+	switch(type) {
+		case SREV_NET_DATA_IN:
+				if(_sr_events_list.net_data_in==0)
+					_sr_events_list.net_data_in = f;
+				else return -1;
+			break;
+		case SREV_NET_DATA_OUT:
+				if(_sr_events_list.net_data_out==0)
+					_sr_events_list.net_data_out = f;
+				else return -1;
+			break;
+		default:
+			return -1;
+	}
+	return 0;
+}
+
+int sr_event_exec(int type, void *data)
+{
+	int ret;
+	str *p;
+	switch(type) {
+		case SREV_NET_DATA_IN:
+				if(unlikely(_sr_events_list.net_data_in!=0))
+				{
+					p = (str*)data;
+#ifdef EXTRA_DEBUG
+					LM_DBG("PRE-IN ++++++++++++++++++++++++++++++++\n"
+							"%.*s\n+++++\n", p->len, p->s);
+#endif /* EXTRA_DEBUG */
+					ret = _sr_events_list.net_data_in(data);
+#ifdef EXTRA_DEBUG
+					LM_DBG("POST-IN ++++++++++++++++++++++++++++++++\n"
+							"%.*s\n+++++\n", p->len, p->s);
+#endif /* EXTRA_DEBUG */
+					return ret;
+				} else return 1;
+			break;
+		case SREV_NET_DATA_OUT:
+				if(unlikely(_sr_events_list.net_data_out!=0))
+				{
+					p = (str*)data;
+#ifdef EXTRA_DEBUG
+					LM_DBG("PRE-OUT ++++++++++++++++++++\n"
+							"%.*s\n+++++++++++++++++++\n", p->len, p->s);
+#endif /* EXTRA_DEBUG */
+					ret = _sr_events_list.net_data_out(data);
+#ifdef EXTRA_DEBUG
+					LM_DBG("POST-OUT ++++++++++++++++++++\n"
+							"%.*s\n+++++++++++++++++++\n", p->len, p->s);
+#endif /* EXTRA_DEBUG */
+					return ret;
+				} else return 1;
+			break;
+		default:
+			return -1;
+	}
+}
+

+ 40 - 0
events.h

@@ -0,0 +1,40 @@
+/**
+ * $Id$
+ *
+ * Copyright (C) 2009 SIP-Router.org
+ *
+ * This file is part of Extensible SIP Router, a free SIP server.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _SR_EVENTS_H_
+#define _SR_EVENTS_H_
+
+#include "parser/msg_parser.h"
+
+#define SREV_NET_DATA_IN	1
+#define SREV_NET_DATA_OUT	2
+
+typedef int (*sr_event_cb_f)(void *data);
+
+typedef struct sr_event_cb {
+	sr_event_cb_f net_data_in;
+	sr_event_cb_f net_data_out;
+} sr_event_cb_t;
+
+void sr_event_cb_init(void);
+int sr_event_register_cb(int type, sr_event_cb_f f);
+int sr_event_exec(int type, void *data);
+
+#endif

+ 14 - 4
forward.h

@@ -60,6 +60,7 @@
 #endif
 
 #include "compiler_opt.h"
+#include "events.h"
 
 
 enum ss_mismatch {
@@ -117,9 +118,14 @@ int forward_reply( struct sip_msg* msg);
  *         that generated them; use 0 if you don't want this)
  * buf, len = buffer
  * returns: 0 if ok, -1 on error*/
+
 static inline int msg_send(struct dest_info* dst, char* buf, int len)
 {
 	struct dest_info new_dst;
+	str outb;
+	outb.s = buf;
+	outb.len = len;
+	sr_event_exec(SREV_NET_DATA_OUT, (void*)&outb);
 	
 	if (likely(dst->proto==PROTO_UDP)){
 		if (unlikely((dst->send_sock==0) || 
@@ -132,7 +138,7 @@ static inline int msg_send(struct dest_info* dst, char* buf, int len)
 			}
 			dst=&new_dst;
 		}
-		if (unlikely(udp_send(dst, buf, len)==-1)){
+		if (unlikely(udp_send(dst, outb.s, outb.len)==-1)){
 			STATS_TX_DROPS;
 			LOG(L_ERR, "msg_send: ERROR: udp_send failed\n");
 			goto error;
@@ -146,7 +152,7 @@ static inline int msg_send(struct dest_info* dst, char* buf, int len)
 					" support is disabled\n");
 			goto error;
 		}else{
-			if (unlikely(tcp_send(dst, 0, buf, len)<0)){
+			if (unlikely(tcp_send(dst, 0, outb.s, outb.len)<0)){
 				STATS_TX_DROPS;
 				LOG(L_ERR, "msg_send: ERROR: tcp_send failed\n");
 				goto error;
@@ -161,7 +167,7 @@ static inline int msg_send(struct dest_info* dst, char* buf, int len)
 					" support is disabled\n");
 			goto error;
 		}else{
-			if (unlikely(tcp_send(dst, 0, buf, len)<0)){
+			if (unlikely(tcp_send(dst, 0, outb.s, outb.len)<0)){
 				STATS_TX_DROPS;
 				LOG(L_ERR, "msg_send: ERROR: tcp_send failed\n");
 				goto error;
@@ -187,7 +193,7 @@ static inline int msg_send(struct dest_info* dst, char* buf, int len)
 				}
 				dst=&new_dst;
 			}
-			if (unlikely(sctp_msg_send(dst, buf, len)<0)){
+			if (unlikely(sctp_msg_send(dst, outb.s, outb.len)<0)){
 				STATS_TX_DROPS;
 				LOG(L_ERR, "msg_send: ERROR: sctp_msg_send failed\n");
 				goto error;
@@ -199,8 +205,12 @@ static inline int msg_send(struct dest_info* dst, char* buf, int len)
 			LOG(L_CRIT, "BUG: msg_send: unknown proto %d\n", dst->proto);
 			goto error;
 	}
+	if(outb.s != buf)
+		pkg_free(outb.s);
 	return 0;
 error:
+	if(outb.s != buf)
+		pkg_free(outb.s);
 	return -1;
 }
 

+ 1 - 1
lib/binrpc/binrpc_api.c

@@ -457,7 +457,7 @@ static int get_reply(struct binrpc_handle *handle,
 			if (n == 0)
 				snprintf(binrpc_last_errs, sizeof(binrpc_last_errs)-1,
 					"get_reply: read unexpected EOF: received %d bytes"
-					" of reply", crt - handle->buf);
+					" of reply", (int)(long)(crt - handle->buf));
 			else
 				snprintf(binrpc_last_errs, sizeof(binrpc_last_errs)-1,
 					"get_reply: read reply failed: %s (%d)",

+ 1 - 1
lib/srdb1/schema/Makefile

@@ -7,7 +7,7 @@ TABLES := $(patsubst kamailio-%.xml,%,$(wildcard kamailio-*.xml))
 
 ROOT=../../../
 STYLESHEETS=$(ROOT)/doc/stylesheets/dbschema_k/xsl
-SCHEME=$(ROOT)/tools/kamctl/
+SCHEME=$(ROOT)/utils/kamctl/
 
 # Stylesheet used to generate MySQL database schema
 MYSQL_XSL = $(STYLESHEETS)/mysql.xsl

+ 15 - 0
modules/topoh/Makefile

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

+ 186 - 0
modules/topoh/README

@@ -0,0 +1,186 @@
+topoh Module
+
+Daniel-Constantin Mierla
+
+   <[email protected]>
+
+Edited by
+
+Daniel-Constantin Mierla
+
+   <[email protected]>
+
+   Copyright © 2009 FhG FOKUS
+     __________________________________________________________________
+
+   Table of Contents
+
+   1. Admin Guide
+
+        1. Overview
+        2. Dependencies
+
+              2.1. Kamailio Modules
+              2.2. External Libraries or Applications
+
+        3. Exported Parameters
+
+              3.1. mask_key (str)
+              3.2. mask_callid (integer)
+              3.3. uparam_name (str)
+              3.4. uparam_prefix (str)
+              3.5. vparam_name (str)
+              3.6. vparam_prefix (str)
+
+        4. Exported Functions
+
+              4.1.
+
+   List of Examples
+
+   1.1. Set mask_key parameter
+   1.2. Set mask_callid parameter
+   1.3. Set uparam_name parameter
+   1.4. Set uparam_prefix parameter
+   1.5. Set vparam_name parameter
+   1.6. Set vparam_prefix parameter
+
+Chapter 1. Admin Guide
+
+   Table of Contents
+
+   1. Overview
+   2. Dependencies
+
+        2.1. Kamailio Modules
+        2.2. External Libraries or Applications
+
+   3. Exported Parameters
+
+        3.1. mask_key (str)
+        3.2. mask_callid (integer)
+        3.3. uparam_name (str)
+        3.4. uparam_prefix (str)
+        3.5. vparam_name (str)
+        3.6. vparam_prefix (str)
+
+   4. Exported Functions
+
+        4.1.
+
+1. Overview
+
+   This module hides the routing headers that show topology details. It it
+   is not affected by the server being transaction statless or stateful.
+   The script interpretor gets the SIP messages decoded, so all
+   functionality existing so far is preserved.
+
+   The module is transparent for config writer. It only needs to be loaded
+   (tune the parameters if wanted). The SIP server can be restarted
+   whitout affecting ongoing calls - once it is up, can encode/decode
+   topology details, thus no call is lost.
+
+   By using same mask_key, many SIP servers can decode the message, for
+   examlple, applicable for servers behind load balancers.
+
+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:
+     * rr module - server must perform record routing to ensure in-dialog
+       requests are encoded/decoded.
+
+2.2. External Libraries or Applications
+
+   The following libraries or applications must be installed before
+   running Kamailio with this module loaded:
+     * None. In the future the module can be enhnaced to use a stronger
+       encryption algorithm.
+
+3. Exported Parameters
+
+   3.1. mask_key (str)
+   3.2. mask_callid (integer)
+   3.3. uparam_name (str)
+   3.4. uparam_prefix (str)
+   3.5. vparam_name (str)
+   3.6. vparam_prefix (str)
+
+3.1. mask_key (str)
+
+   Keyword to mask the headers.
+
+   Default value is "_static_value_".
+
+   Example 1.1. Set mask_key parameter
+...
+modparam("topoh", "mask_key", "some secret here")
+...
+
+3.2. mask_callid (integer)
+
+   Whether to encode or not the call-id. Some SIP extensions include the
+   call-id in SIP message payload or header, so it is safe to not encode
+   call-id in such cases. Well-known extensions such as call transfer or
+   conference join will be added to work with encoded call-id.
+
+   Default value is 0 (do not mask).
+
+   Example 1.2. Set mask_callid parameter
+...
+modparam("topoh", "mask_callid", 1)
+...
+
+3.3. uparam_name (str)
+
+   Name of URI param where to store encoded value.
+
+   Default value is "line".
+
+   Example 1.3. Set uparam_name parameter
+...
+modparam("topoh", "uparam_name", "myparam")
+...
+
+3.4. uparam_prefix (str)
+
+   Prefix to be added in encoded URI params.
+
+   Default value is "sr-".
+
+   Example 1.4. Set uparam_prefix parameter
+...
+modparam("topoh", "uparam_prefix", "xyz")
+...
+
+3.5. vparam_name (str)
+
+   Name of Via param where to store encoded value.
+
+   Default value is "branch".
+
+   Example 1.5. Set vparam_name parameter
+...
+modparam("topoh", "vparam_name", "myv")
+...
+
+3.6. vparam_prefix (str)
+
+   Prefix to be added in encoded Via params.
+
+   Default value is "z9hG4bKsr-".
+
+   Example 1.6. Set vparam_prefix parameter
+...
+modparam("topoh", "vparam_prefix", "xyz")
+...
+
+4. Exported Functions
+
+   4.1.
+
+   None.

+ 4 - 0
modules/topoh/doc/Makefile

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

+ 37 - 0
modules/topoh/doc/topoh.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>topoh 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>2009</year>
+	    <holder>&fhg;</holder>
+	</copyright>
+    </bookinfo>
+    <toc></toc>
+    
+    <xi:include href="topoh_admin.xml"/>
+    
+    
+</book>

+ 198 - 0
modules/topoh/doc/topoh_admin.xml

@@ -0,0 +1,198 @@
+<?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 hides the routing headers that show topology details.
+		It it is not affected by the server being transaction statless or
+		stateful. The script interpretor gets the SIP messages decoded,
+		so all functionality existing so far is preserved.
+	</para>
+	<para>
+		The module is transparent for config writer. It only needs to be
+		loaded (tune the parameters if wanted). The SIP server can be restarted
+		whitout affecting ongoing calls - once it is up, can encode/decode
+		topology details, thus no call is lost.
+	</para>
+	<para>
+		By using same mask_key, many SIP servers can decode the message,
+		for examlple, applicable for servers behind load balancers.
+	</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>rr module</emphasis> - server must perform record
+				routing to ensure in-dialog requests are encoded/decoded.
+			</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>. In the future the module can be
+				enhnaced to use a stronger encryption algorithm.
+			</para>
+			</listitem>
+			</itemizedlist>
+		</para>
+	</section>
+	</section>
+	<section>
+	<title>Exported Parameters</title>
+	<section>
+		<title><varname>mask_key</varname> (str)</title>
+		<para>
+		Keyword to mask the headers.
+		</para>
+		<para>
+		<emphasis>
+			Default value is "_static_value_".
+		</emphasis>
+		</para>
+		<example>
+		<title>Set <varname>mask_key</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+modparam("topoh", "mask_key", "some secret here")
+...
+</programlisting>
+		</example>
+	</section>
+	<section>
+		<title><varname>mask_callid</varname> (integer)</title>
+		<para>
+			Whether to encode or not the call-id. Some SIP extensions include
+			the call-id in SIP message payload or header, so it is safe to
+			not encode call-id in such cases. Well-known extensions such as
+			call transfer or conference join will be added to work with encoded
+			call-id.
+		</para>
+		<para>
+		<emphasis>
+			Default value is 0 (do not mask).
+		</emphasis>
+		</para>
+		<example>
+		<title>Set <varname>mask_callid</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+modparam("topoh", "mask_callid", 1)
+...
+</programlisting>
+		</example>
+	</section>
+	<section>
+		<title><varname>uparam_name</varname> (str)</title>
+		<para>
+		Name of URI param where to store encoded value.
+		</para>
+		<para>
+		<emphasis>
+			Default value is "line".
+		</emphasis>
+		</para>
+		<example>
+		<title>Set <varname>uparam_name</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+modparam("topoh", "uparam_name", "myparam")
+...
+</programlisting>
+		</example>
+	</section>
+	<section>
+		<title><varname>uparam_prefix</varname> (str)</title>
+		<para>
+		Prefix to be added in encoded URI params.
+		</para>
+		<para>
+		<emphasis>
+			Default value is "sr-".
+		</emphasis>
+		</para>
+		<example>
+		<title>Set <varname>uparam_prefix</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+modparam("topoh", "uparam_prefix", "xyz")
+...
+</programlisting>
+		</example>
+	</section>
+		<section>
+		<title><varname>vparam_name</varname> (str)</title>
+		<para>
+		Name of Via param where to store encoded value.
+		</para>
+		<para>
+		<emphasis>
+			Default value is "branch".
+		</emphasis>
+		</para>
+		<example>
+		<title>Set <varname>vparam_name</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+modparam("topoh", "vparam_name", "myv")
+...
+</programlisting>
+		</example>
+	</section>
+	<section>
+		<title><varname>vparam_prefix</varname> (str)</title>
+		<para>
+		Prefix to be added in encoded Via params.
+		</para>
+		<para>
+		<emphasis>
+			Default value is "z9hG4bKsr-".
+		</emphasis>
+		</para>
+		<example>
+		<title>Set <varname>vparam_prefix</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+modparam("topoh", "vparam_prefix", "xyz")
+...
+</programlisting>
+		</example>
+	</section>
+
+	</section>
+	<section>
+	<title>Exported Functions</title>
+	<section>
+		<para>
+			None.
+		</para>
+	</section>
+	</section>
+</chapter>
+

+ 175 - 0
modules/topoh/th_mask.c

@@ -0,0 +1,175 @@
+/**
+ * $Id$
+ *
+ * Copyright (C) 2009 SIP-Router.org
+ *
+ * This file is part of Extensible SIP Router, a free SIP server.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <string.h>
+
+#include "../../dprint.h"
+#include "../../md5.h"
+#include "../../crc.h"
+#include "../../mem/mem.h"
+#include "th_mask.h"
+
+#define TH_EB64I \
+		"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.-"
+
+char _th_EB64[65];
+int _th_DB64[256];
+char *_th_PD64 = "*";
+
+extern str _th_key;
+
+void th_shuffle(char *in, int size)
+{
+	char tmp;
+	int last;
+	unsigned int r;
+	unsigned char md5[16];
+	unsigned int *md5i;
+	unsigned int crc;
+	MD5_CTX ctx;
+
+	MD5Init(&ctx);
+	MD5Update(&ctx, _th_key.s, _th_key.len);
+	MD5Update(&ctx, _th_key.s, _th_key.len);
+	MD5Final(md5, &ctx);
+
+	md5i = (unsigned int*)md5;
+
+	crc = (unsigned int)crcitt_string(_th_key.s, _th_key.len);
+	for (last = size; last > 1; last--)
+	{
+		r = (md5i[(crc+last+_th_key.len)%4]
+				+ _th_key.s[(crc+last+_th_key.len)%_th_key.len]) % last;
+		tmp = in[r];
+		in[r] = in[last - 1];
+		in[last - 1] = tmp;
+	}
+}
+
+void th_mask_init(void)
+{
+	int i;
+
+	_th_key.len = strlen(_th_key.s);
+	memcpy(_th_EB64, TH_EB64I, sizeof(TH_EB64I));
+	th_shuffle(_th_EB64, 64);
+	LM_ERR("+++ %s\n", TH_EB64I);
+	LM_ERR("+++ %s\n", _th_EB64);
+	for(i=0; i<256; i++)
+		_th_DB64[i] = -1;
+	for(i=0; i<64; i++)
+		_th_DB64[(int)_th_EB64[i]] = i;
+
+	return;
+}
+
+char* th_mask_encode(char *in, int ilen, str *prefix, int *olen)
+{
+	char *out;
+	int  left;
+	int  idx;
+	int  i;
+	int  r;
+	char *p;
+	int  block;
+
+	*olen = (((ilen+2)/3)<<2) + ((prefix!=NULL&&prefix->len>0)?prefix->len:0);
+	out = (char*)pkg_malloc((*olen+1)*sizeof(char));
+	if(out==NULL)
+	{
+		LM_ERR("no more pkg\n");
+		*olen = 0;
+		return NULL;
+	}
+	memset(out, 0, (*olen+1)*sizeof(char));
+	if(prefix!=NULL&&prefix->len>0)
+		memcpy(out, prefix->s, prefix->len);
+
+	p = out + (int)((prefix!=NULL&&prefix->len>0)?prefix->len:0);
+	for(idx=0; idx<ilen; idx+=3)
+	{
+		left = ilen - idx - 1 ;
+		left = (left>1)?2:left;
+
+		block = 0;
+		for(i=0, r=16; i<=left; i++, r-=8)
+			block += ((unsigned char)in[idx+i]) << r;
+
+		*(p++) = _th_EB64[(block >> 18) & 0x3f];
+		*(p++) = _th_EB64[(block >> 12) & 0x3f];
+		*(p++) = (left>0)?_th_EB64[(block >> 6) & 0x3f]:_th_PD64[0];
+		*(p++) = (left>1)?_th_EB64[block & 0x3f]:_th_PD64[0];
+	}
+
+	return out;
+}
+
+char* th_mask_decode(char *in, int ilen, str *prefix, int extra, int *olen)
+{
+	char *out;
+	int n;
+	int block;
+	int idx;
+	int i;
+	int j;
+	int end;
+	char c;
+
+	for(n=0,i=ilen-1; in[i]==_th_PD64[0]; i--)
+		n++;
+
+	*olen = (((ilen-((prefix!=NULL&&prefix->len>0)?prefix->len:0)) * 6) >> 3)
+				- n;
+	out = (char*)pkg_malloc((*olen+1+extra)*sizeof(char));
+
+	if(out==NULL)
+	{
+		LM_ERR("no more pkg\n");
+		*olen = 0;
+		return NULL;
+	}
+	memset(out, 0, (*olen+1+extra)*sizeof(char));
+
+	end = ilen - n;
+	i = (prefix!=NULL&&prefix->len>0)?prefix->len:0;
+	for(idx=0; i<end; idx+=3)
+	{
+		block = 0;
+		for(j=0; j<4 && i<end ; j++)
+		{
+			c = _th_DB64[(int)in[i++]];
+			if(c<0)
+			{
+				LM_ERR("invalid input string\"%.*s\"\n", ilen, in);
+				pkg_free(out);
+				*olen = 0;
+				return NULL;
+			}
+			block += c << (18 - 6*j);
+		}
+
+		for(j=0, n=16; j<3 && idx+j< *olen; j++, n-=8)
+			out[idx+j] = (char)((block >> n) & 0xff);
+	}
+
+	return out;
+}
+
+

+ 30 - 0
modules/topoh/th_mask.h

@@ -0,0 +1,30 @@
+/**
+ * $Id$
+ *
+ * Copyright (C) 2009 SIP-Router.org
+ *
+ * This file is part of Extensible SIP Router, a free SIP server.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _TH_MASK_H_
+#define _TH_MASK_H_
+
+#include "../../str.h"
+
+void th_mask_init(void);
+char* th_mask_encode(char *in, int ilen, str *prefix, int *olen);
+char* th_mask_decode(char *in, int ilen, str *prefix, int extra, int *olen);
+
+#endif

+ 913 - 0
modules/topoh/th_msg.c

@@ -0,0 +1,913 @@
+/**
+ * $Id$
+ *
+ * Copyright (C) 2009 SIP-Router.org
+ *
+ * This file is part of Extensible SIP Router, a free SIP server.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <string.h>
+
+#include "../../dprint.h"
+#include "../../mem/mem.h"
+#include "../../data_lump.h"
+#include "../../forward.h"
+#include "../../msg_translator.h"
+#include "../../parser/parse_rr.h"
+#include "../../parser/parse_uri.h"
+#include "../../parser/parse_param.h"
+#include "../../parser/parse_from.h"
+#include "../../parser/parse_to.h"
+#include "../../parser/parse_via.h"
+#include "../../parser/contact/parse_contact.h"
+#include "th_mask.h"
+#include "th_msg.h"
+
+extern str th_cookie_name;
+extern str th_cookie_value;
+extern str th_via_prefix;
+extern str th_uri_prefix;
+
+extern str th_ip;
+extern str th_uparam_name;
+extern str th_uparam_prefix;
+extern str th_vparam_name;
+extern str th_vparam_prefix;
+
+extern int th_param_mask_callid;
+
+int th_skip_rw(char *s, int len)
+{
+	while(len>0)
+	{
+		if(s[len-1]==' ' || s[len-1]=='\t' || s[len-1]=='\n' || s[len-1]=='\r'
+				|| s[len-1]==',')
+			len--;
+		else return len;
+	}
+	return 0;
+}
+
+struct via_param *th_get_via_param(struct via_body *via, str *name)
+{
+	struct via_param *p;
+	for(p=via->param_lst; p; p=p->next)
+	{
+		if(p->name.len==name->len
+				&& strncasecmp(p->name.s, name->s, name->len)==0)
+			return p;
+	}
+	return NULL;
+}
+
+int th_get_param_value(str *in, str *name, str *value)
+{
+	param_t* params = NULL;
+	param_t* p = NULL;
+	param_hooks_t phooks;
+	if (parse_params(in, CLASS_ANY, &phooks, &params)<0)
+		return -1;
+	for (p = params; p; p=p->next)
+	{
+		if (p->name.len==name->len
+				&& strncasecmp(p->name.s, name->s, name->len)==0)
+		{
+			*value = p->body;
+			free_params(params);
+			return 0;
+		}
+	}
+	
+	if(params) free_params(params);
+	return 1;
+
+}
+
+int th_get_uri_param_value(str *uri, str *name, str *value)
+{
+	struct sip_uri puri;
+
+	memset(value, 0, sizeof(str));
+	if(parse_uri(uri->s, uri->len, &puri)<0)
+		return -1;
+	return th_get_param_value(&puri.params, name, value);
+}
+
+int th_get_uri_type(str *uri, int *mode, str *value)
+{
+	struct sip_uri puri;
+	int ret;
+	str r2 = {"r2", 2};
+
+	memset(value, 0, sizeof(str));
+	*mode = 0;
+	if(parse_uri(uri->s, uri->len, &puri)<0)
+		return -1;
+
+	LM_DBG("+++++++++++ PARAMS [%.*s]\n", puri.params.len, puri.params.s);
+	if(puri.host.len==th_ip.len
+			&& strncasecmp(puri.host.s, th_ip.s, th_ip.len)==0)
+	{
+		/* host matches TH ip */
+		ret = th_get_param_value(&puri.params, &th_uparam_name, value);
+		if(ret<0)
+			return -1;
+		return 2; /* decode */
+	} else {
+		if(check_self(&puri.host, (puri.port_no)?puri.port_no:SIP_PORT, 0)==1)
+		{
+			/* myself -- matched on all protos */
+			ret = th_get_param_value(&puri.params, &r2, value);
+			if(ret<0)
+				return -1;
+			if(ret==1) /* not found */
+				return 0; /* skip */
+			LM_DBG("+++++++++++++++++++************ [%.*s]\n",
+					value->len, value->s);
+			if(value->len==2 && strncasecmp(value->s, "on", 2)==0)
+				*mode = 1;
+			memset(value, 0, sizeof(str));
+			return 0; /* skip */
+		} else {
+			return 1; /* encode */
+		}
+	}
+}
+
+int th_mask_via(sip_msg_t *msg)
+{
+	hdr_field_t *hdr;
+	struct via_body *via;
+	struct lump* l;
+	int i;
+	str out;
+	int vlen;
+
+	i=0;
+	for(hdr=msg->h_via1; hdr; hdr=next_sibling_hdr(hdr))
+	{
+		for(via=(struct via_body*)hdr->parsed; via; via=via->next)
+		{
+			i++;
+			LM_DBG("=======via[%d]\n", i);
+			LM_DBG("hdr: [%.*s]\n", via->hdr.len, via->hdr.s);
+			vlen = th_skip_rw(via->name.s, via->bsize);
+			LM_DBG("body: %d: [%.*s]\n", vlen, vlen, via->name.s);
+			if(i!=1)
+			{
+				out.s = th_mask_encode(via->name.s, vlen, &th_via_prefix,
+						&out.len);
+				if(out.s==NULL)
+				{
+					LM_ERR("cannot encode via %d\n", i);
+					return -1;
+				}
+					
+				LM_DBG("+body: %d: [%.*s]\n", out.len, out.len, out.s);
+				l=del_lump(msg, via->name.s-msg->buf, vlen, 0);
+				if (l==0)
+				{
+					LM_ERR("failed deleting via [%d]\n", i);
+					pkg_free(out.s);
+					return -1;
+				}
+				if (insert_new_lump_after(l, out.s, out.len, 0)==0){
+					LM_ERR("could not insert new lump\n");
+					pkg_free(out.s);
+					return -1;
+				}
+			}
+		}
+	}
+	return 0;
+}
+
+int th_mask_callid(sip_msg_t *msg)
+{
+	struct lump* l;
+	str out;
+
+	if(th_param_mask_callid==0)
+		return 0;
+
+	if(msg->callid==NULL)
+	{
+		LM_ERR("cannot get Call-Id header\n");
+		return -1;
+	}
+				
+	out.s = th_mask_encode(msg->callid->body.s, msg->callid->body.len, 0,
+						&out.len);
+	if(out.s==NULL)
+	{
+		LM_ERR("cannot encode callid\n");
+		return -1;
+	}
+				
+	l=del_lump(msg, msg->callid->body.s-msg->buf, msg->callid->body.len, 0);
+	if (l==0)
+	{
+		LM_ERR("failed deleting callid\n");
+		pkg_free(out.s);
+		return -1;
+	}
+	if (insert_new_lump_after(l, out.s, out.len, 0)==0) {
+		LM_ERR("could not insert new lump\n");
+		pkg_free(out.s);
+		return -1;
+	}
+
+	return 0;
+}
+
+int th_mask_contact(sip_msg_t *msg)
+{
+	struct lump* l;
+	str out;
+	str in;
+	contact_t *c;
+
+	if(msg->contact==NULL) 
+	{
+		LM_DBG("no contact header\n");
+		return 0;
+	}
+
+	if(parse_contact(msg->contact) < 0)
+	{
+		LM_ERR("failed parsing contact header\n");
+		return -1;
+	}
+	
+	c = ((contact_body_t*)msg->contact->parsed)->contacts;
+	in = c->uri;
+
+	out.s = th_mask_encode(in.s, in.len, &th_uri_prefix, &out.len);
+	if(out.s==NULL)
+	{
+		LM_ERR("cannot encode contact uri\n");
+		return -1;
+	}
+				
+	l=del_lump(msg, in.s-msg->buf, in.len, 0);
+	if (l==0)
+	{
+		LM_ERR("failed deleting contact uri\n");
+		pkg_free(out.s);
+		return -1;
+	}
+	if (insert_new_lump_after(l, out.s, out.len, 0)==0) {
+		LM_ERR("could not insert new lump\n");
+		pkg_free(out.s);
+		return -1;
+	}
+
+	return 0;
+}
+
+int th_mask_record_route(sip_msg_t *msg)
+{
+	hdr_field_t *hdr;
+	struct lump* l;
+	int i;
+	rr_t *rr;
+	str out;
+
+	if(msg->record_route==NULL)
+	{
+		LM_DBG("no record route header\n");
+		return 0;
+	}
+	hdr = msg->record_route;
+	i = 0;
+	while(hdr!=NULL) 
+	{
+		if (parse_rr(hdr) < 0) 
+		{
+			LM_ERR("failed to parse RR\n");
+			return -1;
+		}
+
+		rr =(rr_t*)hdr->parsed;
+		while(rr)
+		{
+			i++;
+			if(i!=1)
+			{
+				out.s = th_mask_encode(rr->nameaddr.uri.s, rr->nameaddr.uri.len,
+						&th_uri_prefix, &out.len);
+				if(out.s==NULL)
+				{
+					LM_ERR("cannot encode r-r %d\n", i);
+					return -1;
+				}
+				l=del_lump(msg, rr->nameaddr.uri.s-msg->buf,
+						rr->nameaddr.uri.len, 0);
+				if (l==0)
+				{
+					LM_ERR("failed deleting r-r [%d]\n", i);
+					pkg_free(out.s);
+					return -1;
+				}
+				if (insert_new_lump_after(l, out.s, out.len, 0)==0){
+					LM_ERR("could not insert new lump\n");
+					pkg_free(out.s);
+					return -1;
+				}
+			}
+			rr = rr->next;
+		}
+		hdr = next_sibling_hdr(hdr);
+	}
+
+	return 0;
+}
+
+int th_unmask_via(sip_msg_t *msg, str *cookie)
+{
+	hdr_field_t *hdr;
+	struct via_body *via;
+	struct via_body *via2;
+	struct via_param *vp;
+	struct lump* l;
+	int i;
+	str out;
+	int vlen;
+
+	i=0;
+	for(hdr=msg->h_via1; hdr; hdr=next_sibling_hdr(hdr))
+	{
+		for(via=(struct via_body*)hdr->parsed; via; via=via->next)
+		{
+			i++;
+			LM_DBG("=======via[%d]\n", i);
+			LM_DBG("hdr: [%.*s]\n", via->hdr.len, via->hdr.s);
+			vlen = th_skip_rw(via->name.s, via->bsize);
+			LM_DBG("body: %d: [%.*s]\n", vlen, vlen, via->name.s);
+			if(i!=1)
+			{
+				vp = th_get_via_param(via, &th_vparam_name);
+				if(vp==NULL)
+				{
+					LM_ERR("cannot find param in via %d\n", i);
+					return -1;
+				}
+				if(i==2)
+					out.s = th_mask_decode(vp->value.s, vp->value.len,
+							&th_vparam_prefix, CRLF_LEN+1, &out.len);
+				else
+					out.s = th_mask_decode(vp->value.s, vp->value.len,
+							&th_vparam_prefix, 0, &out.len);
+				if(out.s==NULL)
+				{
+					LM_ERR("cannot encode via %d\n", i);
+					return -1;
+				}
+					
+				LM_DBG("+body: %d: [%.*s]\n", out.len, out.len, out.s);
+				if(i==2)
+				{
+					via2=pkg_malloc(sizeof(struct via_body));
+					if (via2==0)
+					{
+						LM_ERR("out of memory\n");
+						pkg_free(out.s);
+						return -1;
+
+					}
+					
+					memset(via2, 0, sizeof(struct via_body));
+					memcpy(out.s+out.len, CRLF, CRLF_LEN);
+					out.s[out.len+CRLF_LEN]='X';
+					if(parse_via(out.s, out.s+out.len+CRLF_LEN+1, via2)==NULL)
+					{
+						LM_ERR("error parsing decoded via2\n");
+						free_via_list(via2);
+						pkg_free(out.s);
+						return -1;
+					}
+					out.s[out.len] = '\0';
+					vp = th_get_via_param(via2, &th_cookie_name);
+					if(vp==NULL)
+					{
+						LM_ERR("cannot find cookie in via2\n");
+						free_via_list(via2);
+						pkg_free(out.s);
+						return -1;
+					}
+					*cookie = vp->value;
+					free_via_list(via2);
+				}
+				l=del_lump(msg, via->name.s-msg->buf, vlen, 0);
+				if (l==0)
+				{
+					LM_ERR("failed deleting via [%d]\n", i);
+					pkg_free(out.s);
+					return -1;
+				}
+				if (insert_new_lump_after(l, out.s, out.len, 0)==0)
+				{
+					LM_ERR("could not insert new lump\n");
+					pkg_free(out.s);
+					return -1;
+				}
+			}
+		}
+	}
+
+	return 0;
+}
+
+int th_unmask_callid(sip_msg_t *msg)
+{
+	struct lump* l;
+	str out;
+	
+	if(th_param_mask_callid==0)
+		return 0;
+	
+	if(msg->callid==NULL)
+	{
+		LM_ERR("cannot get Call-Id header\n");
+		return -1;
+	}
+				
+	out.s = th_mask_decode(msg->callid->body.s, msg->callid->body.len, 0, 0,
+						&out.len);
+	if(out.s==NULL)
+	{
+		LM_ERR("cannot decode callid\n");
+		return -1;
+	}
+				
+	l=del_lump(msg, msg->callid->body.s-msg->buf, msg->callid->body.len, 0);
+	if (l==0)
+	{
+		LM_ERR("failed deleting callid\n");
+		pkg_free(out.s);
+		return -1;
+	}
+	if (insert_new_lump_after(l, out.s, out.len, 0)==0) {
+		LM_ERR("could not insert new lump\n");
+		pkg_free(out.s);
+		return -1;
+	}
+
+	return 0;
+}
+
+int th_flip_record_route(sip_msg_t *msg, int mode)
+{
+	hdr_field_t *hdr;
+	struct lump* l;
+	int i;
+	rr_t *rr;
+	str out;
+	int utype;
+	str pval;
+	int r2;
+	int act;
+
+	if(msg->record_route==NULL)
+	{
+		LM_DBG("no record route header\n");
+		return 0;
+	}
+	hdr = msg->record_route;
+	i = 0;
+	act = 0;
+	if(mode==1)
+		act = 2;
+	while(hdr!=NULL) 
+	{
+		if (parse_rr(hdr) < 0) 
+		{
+			LM_ERR("failed to parse RR\n");
+			return -1;
+		}
+
+		rr =(rr_t*)hdr->parsed;
+		while(rr)
+		{
+			i++;
+			r2 = 0;
+			utype = th_get_uri_type(&rr->nameaddr.uri, &r2, &pval);
+			if(utype==0 && mode==1)
+			{
+				if(r2==1)
+				{
+					act--;
+					if(act==0)
+						return 0;
+					utype = 1;
+				} else {
+					return 0;
+				}
+			}
+			out.s = NULL;
+			switch(utype) {
+				case 1: /* encode */
+					if(act!=0 && mode==1)
+					{
+						out.s = th_mask_encode(rr->nameaddr.uri.s,
+							rr->nameaddr.uri.len, &th_uri_prefix, &out.len);
+						if(out.s==NULL)
+						{
+							LM_ERR("cannot encode r-r %d\n", i);
+							return -1;
+						}
+					}
+				break;
+				case 2: /* decode */
+					if(mode==0)
+					{
+						out.s = th_mask_decode(pval.s,
+							pval.len, &th_uparam_prefix, 0, &out.len);
+						if(out.s==NULL)
+						{
+							LM_ERR("cannot decode r-r %d\n", i);
+							return -1;
+						}
+					}
+				break;
+			}
+			if(out.s!=NULL)
+			{
+				l=del_lump(msg, rr->nameaddr.uri.s-msg->buf,
+						rr->nameaddr.uri.len, 0);
+				if (l==0)
+				{
+					LM_ERR("failed deleting r-r [%d]\n", i);
+					pkg_free(out.s);
+					return -1;
+				}
+				if (insert_new_lump_after(l, out.s, out.len, 0)==0){
+					LM_ERR("could not insert new lump\n");
+					pkg_free(out.s);
+					return -1;
+				}
+			}
+			rr = rr->next;
+		}
+		hdr = next_sibling_hdr(hdr);
+	}
+
+	return 0;
+}
+
+int th_unmask_route(sip_msg_t *msg)
+{
+	hdr_field_t *hdr;
+	struct lump* l;
+	int i;
+	rr_t *rr;
+	str out;
+	str eval;
+
+	if(msg->route==NULL)
+	{
+		LM_DBG("no record route header\n");
+		return 0;
+	}
+	hdr = msg->route;
+	i = 0;
+	while(hdr!=NULL) 
+	{
+		if (parse_rr(hdr) < 0) 
+		{
+			LM_ERR("failed to parse RR\n");
+			return -1;
+		}
+
+		rr =(rr_t*)hdr->parsed;
+		while(rr)
+		{
+			i++;
+			if(i!=1)
+			{
+				if(th_get_uri_param_value(&rr->nameaddr.uri, &th_uparam_name,
+							&eval)<0 || eval.len<=0)
+					return -1;
+	
+				out.s = th_mask_decode(eval.s, eval.len,
+							&th_uparam_prefix, 0, &out.len);
+
+				if(out.s==NULL)
+				{
+					LM_ERR("cannot decode R %d\n", i);
+					return -1;
+				}
+				l=del_lump(msg, rr->nameaddr.uri.s-msg->buf,
+						rr->nameaddr.uri.len, 0);
+				if (l==0)
+				{
+					LM_ERR("failed deleting R [%d]\n", i);
+					pkg_free(out.s);
+					return -1;
+				}
+				if (insert_new_lump_after(l, out.s, out.len, 0)==0){
+					LM_ERR("could not insert new lump\n");
+					pkg_free(out.s);
+					return -1;
+				}
+			}
+			rr = rr->next;
+		}
+		hdr = next_sibling_hdr(hdr);
+	}
+
+	return 0;
+}
+
+int th_unmask_ruri(sip_msg_t *msg)
+{
+	str eval;
+	struct lump* l;
+	str out;
+
+	if(th_get_uri_param_value(&REQ_LINE(msg).uri, &th_uparam_name, &eval)<0
+			|| eval.len<=0)
+		return -1;
+	
+	out.s = th_mask_decode(eval.s, eval.len,
+				&th_uparam_prefix, 0, &out.len);
+	if(out.s==NULL)
+	{
+		LM_ERR("cannot decode r-uri\n");
+		return -1;
+	}
+					
+	LM_DBG("+decoded: %d: [%.*s]\n", out.len, out.len, out.s);
+	l=del_lump(msg, REQ_LINE(msg).uri.s-msg->buf, REQ_LINE(msg).uri.len, 0);
+	if (l==0)
+	{
+		LM_ERR("failed deleting r-uri\n");
+		pkg_free(out.s);
+		return -1;
+	}
+	if (insert_new_lump_after(l, out.s, out.len, 0)==0)
+	{
+		LM_ERR("could not insert new lump\n");
+		pkg_free(out.s);
+		return -1;
+	}
+
+	return 0;
+}
+
+char* th_msg_update(sip_msg_t *msg, unsigned int *olen)
+{
+	struct dest_info dst;
+
+	init_dest_info(&dst);
+	dst.proto = PROTO_UDP;
+	return build_req_buf_from_sip_req(msg,
+			olen, &dst, BUILD_NO_LOCAL_VIA|BUILD_NO_VIA1_UPDATE);
+}
+
+int th_add_via_cookie(sip_msg_t *msg, struct via_body *via)
+{
+	struct lump* l;
+	int viap;
+	str out;
+
+	if (via->params.s) {
+		viap = via->params.s - via->hdr.s - 1;
+	} else {
+		viap = via->host.s - via->hdr.s + via->host.len;
+		if (via->port!=0)
+			viap += via->port_str.len + 1; /* +1 for ':'*/
+	}
+	l = anchor_lump(msg, via->hdr.s - msg->buf + viap, 0, 0);
+	if (l==0)
+	{
+		LM_ERR("failed adding cookie to via [%p]\n", via);
+		return -1;
+	}
+	
+	out.len = 1+th_cookie_name.len+1+th_cookie_value.len+1;
+	out.s = (char*)pkg_malloc(out.len+1);
+	if(out.s==0)
+	{
+		LM_ERR("no pkg memory\n");
+		return -1;
+	}
+	out.s[0] = ';';
+	memcpy(out.s+1, th_cookie_name.s, th_cookie_name.len);
+	out.s[th_cookie_name.len+1]='=';
+	memcpy(out.s+th_cookie_name.len+2, th_cookie_value.s, th_cookie_value.len);
+	out.s[out.len-1] = 'v';
+	out.s[out.len] = '\0';
+	if (insert_new_lump_after(l, out.s, out.len, 0)==0){
+		LM_ERR("could not insert new lump!\n");
+		pkg_free(out.s);
+		return -1;
+	}
+	return 0;
+}
+
+int th_add_hdr_cookie(sip_msg_t *msg)
+{
+	struct lump* anchor;
+	str h;
+
+	h.len = th_cookie_name.len + 2 + th_cookie_value.len + 1 + CRLF_LEN;
+	h.s = (char*)pkg_malloc(h.len+1);
+	if(h.s == 0)
+	{
+		LM_ERR("no more pkg\n");
+		return -1;
+	}
+	anchor = anchor_lump(msg, msg->unparsed - msg->buf, 0, 0);
+	if(anchor == 0)
+	{
+		LM_ERR("can't get anchor\n");
+		pkg_free(h.s);
+		return -1;
+	}
+	memcpy(h.s, th_cookie_name.s, th_cookie_name.len);
+	memcpy(h.s+th_cookie_name.len, ": ", 2);
+	memcpy(h.s+th_cookie_name.len+2, th_cookie_value.s, th_cookie_value.len);
+	memcpy(h.s+th_cookie_name.len+2+th_cookie_value.len+1, CRLF, CRLF_LEN);
+	h.s[h.len-1-CRLF_LEN] = 'h';
+	h.s[h.len] = '\0';
+	if (insert_new_lump_before(anchor, h.s, h.len, 0) == 0)
+	{
+		LM_ERR("can't insert lump\n");
+		pkg_free(h.s);
+		return -1;
+	}
+	LM_DBG("+++++++++++++ added cookie header [%s]\n", h.s);
+	return 0;
+}
+
+struct via_param *th_get_via_cookie(sip_msg_t *msg, struct via_body *via)
+{
+	struct via_param *p;
+	for(p=via->param_lst; p; p=p->next)
+	{
+		if(p->name.len==th_cookie_name.len
+				&& strncasecmp(p->name.s, th_cookie_name.s,
+					th_cookie_name.len)==0)
+			return p;
+	}
+	return NULL;
+}
+
+hdr_field_t *th_get_hdr_cookie(sip_msg_t *msg)
+{
+	hdr_field_t *hf;
+	for (hf=msg->headers; hf; hf=hf->next)
+	{
+		if (hf->name.len==th_cookie_name.len
+				&& strncasecmp(hf->name.s, th_cookie_name.s,
+					th_cookie_name.len)==0)
+			return hf;
+	}
+	return NULL;
+}
+
+int th_add_cookie(sip_msg_t *msg)
+{
+	if(th_cookie_value.len<=0)
+		return 0;
+	th_add_hdr_cookie(msg);
+	th_add_via_cookie(msg, msg->via1);
+	return 0;
+}
+
+int th_del_hdr_cookie(sip_msg_t *msg)
+{
+	hdr_field_t *hf;
+	struct lump* l;
+	for (hf=msg->headers; hf; hf=hf->next)
+	{
+		if (hf->name.len==th_cookie_name.len
+				&& strncasecmp(hf->name.s, th_cookie_name.s,
+					th_cookie_name.len)==0)
+		{
+			l=del_lump(msg, hf->name.s-msg->buf, hf->len, 0);
+			if (l==0) {
+				LM_ERR("unable to delete cookie header\n");
+				return -1;
+			}
+			return 0;
+		}
+	}
+	return 0;
+}
+
+int th_del_via_cookie(sip_msg_t *msg, struct via_body *via)
+{
+	struct via_param *p;
+	struct lump* l;
+	for(p=via->param_lst; p; p=p->next)
+	{
+		if(p->name.len==th_cookie_name.len
+				&& strncasecmp(p->name.s, th_cookie_name.s,
+					th_cookie_name.len)==0)
+		{
+			l=del_lump(msg, p->start-msg->buf-1, p->size+1, 0);
+			if (l==0) {
+				LM_ERR("unable to delete cookie header\n");
+				return -1;
+			}
+			return 0;
+		}
+	}
+	return 0;
+}
+
+int th_del_cookie(sip_msg_t *msg)
+{
+	th_del_hdr_cookie(msg);
+	if(msg->first_line.type==SIP_REPLY)
+		th_del_via_cookie(msg, msg->via1);
+	return 0;
+}
+
+
+char* th_get_cookie(sip_msg_t *msg, int *clen)
+{
+	hdr_field_t *hf;
+	struct via_param *p;
+
+	hf = th_get_hdr_cookie(msg);
+	if(hf!=NULL)
+	{
+		*clen = hf->body.len;
+		return hf->body.s;
+	}
+	p = th_get_via_cookie(msg, msg->via1);
+	if(p!=NULL)
+	{
+		*clen = p->value.len;
+		return p->value.s;
+	}
+
+	*clen = 3;
+	return "xxx";
+}
+
+int th_route_direction(sip_msg_t *msg)
+{
+	rr_t *rr;
+	struct sip_uri puri;
+	str ftn = {"ftag", 4};
+	str ftv = {0, 0};
+
+	if(get_from(msg)->tag_value.len<=0)
+	{
+		LM_ERR("failed to get from header tag\n");
+		return -1;
+	}
+	if(msg->route==NULL)
+	{
+		LM_DBG("no route header - downstream\n");
+		return 0;
+	}
+	if (parse_rr(msg->route) < 0) 
+	{
+		LM_ERR("failed to parse route header\n");
+		return -1;
+	}
+
+	rr =(rr_t*)msg->route->parsed;
+
+	if (parse_uri(rr->nameaddr.uri.s, rr->nameaddr.uri.len, &puri) < 0) {
+		LM_ERR("failed to parse the first route URI\n");
+		return -1;
+	}
+	if(th_get_param_value(&puri.params, &ftn, &ftv)!=0)
+		return 0;
+
+	if(get_from(msg)->tag_value.len!=ftv.len
+			|| strncmp(get_from(msg)->tag_value.s, ftv.s, ftv.len)!=0)
+	{
+		LM_DBG("ftag mismatch\n");
+		return 1;
+	}
+	LM_DBG("ftag match\n");
+	return 0;
+}
+
+int th_skip_msg(sip_msg_t *msg)
+{
+	if((get_cseq(msg)->method_id)&(METHOD_REGISTER|METHOD_PUBLISH))
+		return 1;
+
+	return 0;
+}
+

+ 45 - 0
modules/topoh/th_msg.h

@@ -0,0 +1,45 @@
+/**
+ * $Id$
+ *
+ * Copyright (C) 2009 SIP-Router.org
+ *
+ * This file is part of Extensible SIP Router, a free SIP server.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _TH_MSG_H_
+#define _TH_MSG_H_
+
+#include "../../parser/msg_parser.h"
+
+int th_mask_via(sip_msg_t *msg);
+int th_mask_callid(sip_msg_t *msg);
+int th_mask_contact(sip_msg_t *msg);
+int th_mask_record_route(sip_msg_t *msg);
+int th_unmask_via(sip_msg_t *msg, str *cookie);
+int th_unmask_callid(sip_msg_t *msg);
+int th_flip_record_route(sip_msg_t *msg, int mode);
+int th_unmask_ruri(sip_msg_t *msg);
+int th_unmask_route(sip_msg_t *msg);
+char* th_msg_update(sip_msg_t *msg, unsigned int *olen);
+int th_add_via_cookie(sip_msg_t *msg, struct via_body *via);
+int th_add_hdr_cookie(sip_msg_t *msg);
+hdr_field_t *th_get_hdr_cookie(sip_msg_t *msg);
+int th_add_cookie(sip_msg_t *msg);
+int th_route_direction(sip_msg_t *msg);
+char* th_get_cookie(sip_msg_t *msg, int *clen);
+int th_del_cookie(sip_msg_t *msg);
+int th_skip_msg(sip_msg_t *msg);
+
+#endif

+ 332 - 0
modules/topoh/topoh_mod.c

@@ -0,0 +1,332 @@
+/**
+ * $Id$
+ *
+ * Copyright (C) 2009 SIP-Router.org
+ *
+ * This file is part of Extensible SIP Router, a free SIP server.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "../../sr_module.h"
+#include "../../events.h"
+#include "../../dprint.h"
+#include "../../ut.h"
+#include "../../parser/msg_parser.h"
+#include "../../parser/parse_to.h"
+#include "../../parser/parse_from.h"
+
+#include "th_mask.h"
+#include "th_msg.h"
+
+MODULE_VERSION
+
+
+/** module parameters */
+str _th_key = { "aL9.n8~Hm]Z", 0 };
+str th_cookie_name = {"TH", 0};
+str th_cookie_value = {0, 0};
+str th_ip = {"10.1.1.2", 0};
+str th_uparam_name = {"line", 0};
+str th_uparam_prefix = {"sr-", 0};
+str th_vparam_name = {"branch", 0};
+str th_vparam_prefix = {"z9hG4bKsr-", 0};
+
+str th_via_prefix = {0, 0};
+str th_uri_prefix = {0, 0};
+
+int th_param_mask_callid = 0;
+
+int th_msg_received(void *data);
+int th_msg_sent(void *data);
+
+/** module functions */
+static int mod_init(void);
+
+static param_export_t params[]={
+	{"mask_key",		STR_PARAM, &_th_key.s},
+	{"mask_callid",		INT_PARAM, &th_param_mask_callid},
+	{"uparam_name",		STR_PARAM, &th_uparam_name.s},
+	{"uparam_prefix",	STR_PARAM, &th_uparam_prefix.s},
+	{"vparam_name",		STR_PARAM, &th_vparam_name.s},
+	{"vparam_prefix",	STR_PARAM, &th_vparam_prefix.s},
+	{0,0,0}
+};
+
+
+/** module exports */
+struct module_exports exports= {
+	"topoh",
+	DEFAULT_DLFLAGS, /* dlopen flags */
+	0,
+	params,
+	0,          /* exported statistics */
+	0,          /* exported MI functions */
+	0,          /* exported pseudo-variables */
+	0,          /* extra processes */
+	mod_init,   /* module initialization function */
+	0,
+	0,
+	0           /* per-child init function */
+};
+
+/**
+ * init module function
+ */
+static int mod_init(void)
+{
+	th_cookie_name.len = strlen(th_cookie_name.s);
+	th_ip.len = strlen(th_ip.s);
+	th_uparam_name.len = strlen(th_uparam_name.s);
+	th_uparam_prefix.len = strlen(th_uparam_prefix.s);
+	th_vparam_name.len = strlen(th_vparam_name.s);
+	th_vparam_prefix.len = strlen(th_vparam_prefix.s);
+
+	/* 'SIP/2.0/UDP ' + ip + ';' + param + '=' + prefix (+ '\0') */
+	th_via_prefix.len = 12 + th_ip.len + 1 + th_vparam_name.len + 1
+		+ th_vparam_prefix.len;
+	th_via_prefix.s = (char*)pkg_malloc(th_via_prefix.len+1);
+	if(th_via_prefix.s==NULL)
+		goto error;
+	/* 'sip:' + ip + ';' + param + '=' + prefix (+ '\0') */
+	th_uri_prefix.len = 4 + th_ip.len + 1 + th_uparam_name.len + 1
+		+ th_uparam_prefix.len;
+	th_uri_prefix.s = (char*)pkg_malloc(th_uri_prefix.len+1);
+	if(th_uri_prefix.s==NULL)
+		goto error;
+	/* build via prefix */
+	memcpy(th_via_prefix.s, "SIP/2.0/UDP ", 12);
+	memcpy(th_via_prefix.s+12, th_ip.s, th_ip.len);
+	th_via_prefix.s[12+th_ip.len] = ';';
+	memcpy(th_via_prefix.s+12+th_ip.len+1, th_vparam_name.s, th_vparam_name.len);
+	th_via_prefix.s[12+th_ip.len+1+th_vparam_name.len] = '=';
+	memcpy(th_via_prefix.s+12+th_ip.len+1+th_vparam_name.len+1,
+			th_vparam_prefix.s, th_vparam_prefix.len);
+	th_via_prefix.s[th_via_prefix.len] = '\0';
+	LM_DBG("VIA prefix: [%s]\n", th_via_prefix.s);
+	/* build uri prefix */
+	memcpy(th_uri_prefix.s, "sip:", 4);
+	memcpy(th_uri_prefix.s+4, th_ip.s, th_ip.len);
+	th_uri_prefix.s[4+th_ip.len] = ';';
+	memcpy(th_uri_prefix.s+4+th_ip.len+1, th_uparam_name.s, th_uparam_name.len);
+	th_uri_prefix.s[4+th_ip.len+1+th_uparam_name.len] = '=';
+	memcpy(th_uri_prefix.s+4+th_ip.len+1+th_uparam_name.len+1,
+			th_uparam_prefix.s, th_uparam_prefix.len);
+	th_uri_prefix.s[th_uri_prefix.len] = '\0';
+	LM_DBG("URI prefix: [%s]\n", th_uri_prefix.s);
+
+	th_mask_init();
+	sr_event_register_cb(SREV_NET_DATA_IN, th_msg_received);
+	sr_event_register_cb(SREV_NET_DATA_OUT, th_msg_sent);
+	return 0;
+error:
+	return -1;
+}
+
+int th_prepare_msg(sip_msg_t *msg)
+{
+	if (parse_msg(msg->buf, msg->len, msg)!=0)
+	{
+		LM_DBG("outbuf buffer parsing failed!");
+		return 1;
+	}
+
+	if (parse_headers(msg, HDR_EOH_F, 0)==-1)
+	{
+		LM_DBG("parsing headers failed");
+		return 2;
+	}
+
+	if(parse_from_header(msg)<0)
+	{
+		LM_ERR("cannot parse FROM header\n");
+		return 3;
+	}
+	
+	return 0;
+}
+
+int th_msg_received(void *data)
+{
+	sip_msg_t msg;
+	str *obuf;
+	char *nbuf;
+	int direction;
+	int dialog;
+
+	obuf = (str*)data;
+	memset(&msg, 0, sizeof(sip_msg_t));
+	msg.buf = obuf->s;
+	msg.len = obuf->len;
+
+	th_prepare_msg(&msg);
+
+	if(th_skip_msg(&msg))
+	{
+		goto done;
+	}
+
+	direction = 0;
+	th_cookie_value.s = "xx";
+	th_cookie_value.len = 2;
+	if(msg.first_line.type==SIP_REQUEST)
+	{
+		dialog = (get_to(&msg)->tag_value.len>0)?1:0;
+		if(dialog)
+		{
+			direction = th_route_direction(&msg);
+			if(direction<0)
+			{
+				LM_ERR("not able to detect direction\n");
+				goto done;
+			}
+			th_cookie_value.s = (direction==0)?"dc":"uc";
+		} else {
+			th_cookie_value.s = "di";
+		}
+		if(dialog)
+		{
+			/* dialog request */
+			th_unmask_ruri(&msg);
+			th_unmask_route(&msg);
+			if(direction==1)
+			{
+				th_unmask_callid(&msg);
+			}
+		}
+	} else {
+		/* reply */
+		th_unmask_via(&msg, &th_cookie_value);
+		th_flip_record_route(&msg, 0);
+		if(th_cookie_value.s[0]=='u')
+		{
+			th_cookie_value.s = "dc";
+		} else {
+			th_cookie_value.s = "uc";
+			th_unmask_callid(&msg);
+		}
+		th_cookie_value.len = 2;
+	}
+
+	th_add_cookie(&msg);
+	nbuf = th_msg_update(&msg, (unsigned int*)&obuf->len);
+
+	if(obuf->len>=BUF_SIZE)
+	{
+		LM_ERR("new buffer overflow (%d)\n", obuf->len);
+		pkg_free(nbuf);
+		return -1;
+	}
+	memcpy(obuf->s, nbuf, obuf->len);
+	obuf->s[obuf->len] = '\0';
+
+done:
+	free_sip_msg(&msg);
+	return 0;
+}
+
+int th_msg_sent(void *data)
+{
+	sip_msg_t msg;
+	str *obuf;
+	int direction;
+	int dialog;
+	int local;
+
+	obuf = (str*)data;
+	memset(&msg, 0, sizeof(sip_msg_t));
+	msg.buf = obuf->s;
+	msg.len = obuf->len;
+
+	th_prepare_msg(&msg);
+
+	if(th_skip_msg(&msg))
+	{
+		goto done;
+	}
+
+	th_cookie_value.s = th_get_cookie(&msg, &th_cookie_value.len);
+	LM_DBG("the COOKIE is [%.*s]\n", th_cookie_value.len, th_cookie_value.s);
+	if(th_cookie_value.s[0]!='x')
+		th_del_cookie(&msg);
+	if(msg.first_line.type==SIP_REQUEST)
+	{
+		direction = (th_cookie_value.s[0]=='u')?1:0; /* upstream/downstram */
+		dialog = (get_to(&msg)->tag_value.len>0)?1:0;
+		local = (th_cookie_value.s[0]!='d'&&th_cookie_value.s[0]!='u')?1:0;
+		/* local generated requests */
+		if(local)
+		{
+			/* ACK and CANCEL go downstream */
+			if(get_cseq(&msg)->method_id==METHOD_ACK
+					|| get_cseq(&msg)->method_id==METHOD_CANCEL)
+			{
+				th_mask_callid(&msg);
+				goto ready;
+			} else {
+				/* should be for upstream */
+				goto done;
+			}
+		}
+		th_mask_via(&msg);
+		th_mask_contact(&msg);
+		th_mask_record_route(&msg);
+		if(dialog)
+		{
+			/* dialog request */
+			if(direction==0)
+			{
+				/* downstream */
+				th_mask_callid(&msg);
+			}
+		} else {
+			/* initial request */
+			th_mask_callid(&msg);
+		}
+	} else {
+		/* reply */
+		if(th_cookie_value.s[th_cookie_value.len-1]=='x')
+		{
+			/* ?!?! - we should have a cookie in any reply case */
+			goto done;
+		}
+		if(th_cookie_value.s[th_cookie_value.len-1]=='v')
+		{
+			/* reply generated locally - direction was set by request */
+			if(th_cookie_value.s[0]=='u')
+			{
+				th_mask_callid(&msg);
+			}
+		} else {
+			th_flip_record_route(&msg, 1);
+			th_mask_contact(&msg);
+			if(th_cookie_value.s[0]=='d')
+			{
+				th_mask_callid(&msg);
+			}
+		}
+	}
+
+ready:
+	obuf->s = th_msg_update(&msg, (unsigned int*)&obuf->len);
+
+done:
+	free_sip_msg(&msg);
+	return 0;
+}
+

+ 210 - 9
modules_k/call_control/call_control.c

@@ -86,6 +86,12 @@ typedef struct AVP_Param {
     unsigned short type;
 } AVP_Param;
 
+typedef struct AVP_List {
+    pv_spec_p pv;
+    str name;
+    struct AVP_List *next;
+} AVP_List;
+
 #define RETRY_INTERVAL 10
 #define BUFFER_SIZE    8192
 
@@ -103,8 +109,12 @@ static int CallControl(struct sip_msg *msg, char *str1, char *str2);
 
 static int mod_init(void);
 static int child_init(int rank);
-static int postprocess_request(struct sip_msg *msg, unsigned int flags, void *_param);
+static void destroy(void);
+static int postprocess_request(struct sip_msg *msg, void *_param);
 
+int parse_param_init(unsigned int type, void *val);
+int parse_param_start(unsigned int type, void *val);
+int parse_param_stop(unsigned int type, void *val);
 
 /* Local global variables */
 static CallControlSocket callcontrol_socket = {
@@ -128,6 +138,9 @@ static AVP_Param signaling_ip_avp = {str_init(SIGNALING_IP_AVP_SPEC), {0}, 0};
 struct dlg_binds dlg_api;
 static int dialog_flag = -1;
 
+AVP_List *cc_init_avps = NULL, *cc_start_avps = NULL, *cc_stop_avps = NULL;
+
+pv_elem_t *model;
 
 static cmd_export_t commands[] = {
     {"call_control",  (cmd_function)CallControl, 0, 0, 0, REQUEST_ROUTE },
@@ -135,6 +148,9 @@ static cmd_export_t commands[] = {
 };
 
 static param_export_t parameters[] = {
+    {"init",                STR_PARAM | USE_FUNC_PARAM, parse_param_init},
+    {"start",               STR_PARAM | USE_FUNC_PARAM, parse_param_start},
+    {"stop",                STR_PARAM | USE_FUNC_PARAM, parse_param_stop},
     {"disable",             INT_PARAM, &disable},
     {"socket_name",         STR_PARAM, &(callcontrol_socket.name)},
     {"socket_timeout",      INT_PARAM, &(callcontrol_socket.timeout)},
@@ -155,7 +171,7 @@ struct module_exports exports = {
     NULL,            // extra processes
     mod_init,        // module init function (before fork. kids will inherit)
     NULL,            // reply processing function
-    NULL,            // destroy function
+    destroy,         // destroy function
     child_init       // child init function
 };
 
@@ -191,6 +207,117 @@ typedef struct CallInfo {
 } CallInfo;
 
 
+
+#define CHECK_COND(cond) \
+    if ((cond) == 0) { \
+        LM_ERR("malformed modparam\n"); \
+        return -1;                            \
+    }
+
+#define CHECK_ALLOC(p) \
+    if (!(p)) {    \
+        LM_ERR("no memory left\n"); \
+        return -1;    \
+    }
+
+
+void
+destroy_list(AVP_List *list) {
+	AVP_List *cur, *next;
+
+	cur = list;
+	while (cur) {
+		next = cur->next;
+		pkg_free(cur);
+		cur = next;
+	}
+}
+
+
+int
+parse_param(void *val, AVP_List** avps) {
+
+    char *p;
+    str *s, content;
+    AVP_List *mp = NULL;
+
+    //LM_DBG("%.*s\n", content.len, content.s);
+
+    content.s = (char*) val;
+    content.len = strlen(content.s);
+
+
+    p = (char*) pkg_malloc (content.len + 1);
+    CHECK_ALLOC(p);
+
+    p[content.len] = '\0';
+    memcpy(p, content.s, content.len);
+
+    s = (str*) pkg_malloc(sizeof(str));
+    CHECK_ALLOC(s);
+
+    for (;*p != '\0';) {
+
+        mp = (AVP_List*) pkg_malloc (sizeof(AVP_List));
+        CHECK_ALLOC(mp);
+        mp->next = *avps;
+        mp->pv = (pv_spec_p) pkg_malloc (sizeof(pv_spec_t));
+        CHECK_ALLOC(mp->pv);
+
+        for (; isspace(*p); p++);
+        CHECK_COND(*p != '\0');
+
+        mp->name.s = p;
+
+        for(; isgraph(*p) && *p != '='; p++)
+            CHECK_COND(*p != '\0');
+
+        mp->name.len = p - mp->name.s;
+
+        for (; isspace(*p); p++);
+        CHECK_COND(*p != '\0' && *p == '=');
+        p++;
+
+        //LM_DBG("%.*s\n", mp->name.len, mp->name.s);
+
+        for (; isspace(*p); p++);
+        CHECK_COND(*p != '\0' && *p == '$');
+
+        s->s = p;
+        s->len = strlen(p);
+
+        p = pv_parse_spec(s, mp->pv);
+
+        for (; isspace(*p); p++);
+        *avps = mp;
+    }
+
+    return 0;
+}
+
+
+int
+parse_param_init(unsigned int type, void *val) {
+    if (parse_param(val, &cc_init_avps) == -1)
+        return E_CFG;
+    return 0;
+}
+
+int
+parse_param_start(unsigned int type, void *val) {
+    if (parse_param(val, &cc_start_avps) == -1)
+        return E_CFG;
+    return 0;
+}
+
+int
+parse_param_stop(unsigned int type, void *val) {
+    if (parse_param(val, &cc_stop_avps) == -1)
+        return E_CFG;
+    return 0;
+}
+
+
 // Functions dealing with strings
 //
 
@@ -414,9 +541,55 @@ get_call_info(struct sip_msg *msg, CallControlAction action)
     return &call_info;
 }
 
+static char*
+make_custom_request(struct sip_msg *msg, CallInfo *call)
+{
+    static char request[8192];
+    int len = 0;
+    AVP_List *al;
+    pv_value_t pt;
+
+    switch (call->action) {
+    case CAInitialize:
+        al = cc_init_avps;
+        break;
+    case CAStart:
+        al = cc_start_avps;
+        break;
+    case CAStop:
+        al = cc_stop_avps;
+        break;
+    default:
+        // should never get here, but keep gcc from complaining
+        assert(False);
+        return NULL;
+    }
+
+    for (; al; al = al->next) {
+        pv_get_spec_value(msg, al->pv, &pt);
+        if (pt.flags & PV_VAL_INT) {
+            len += snprintf(request + len, sizeof(request),
+                      "%.*s = %d ", al->name.len, al->name.s,
+                   pt.ri);
+        } else    if (pt.flags & PV_VAL_STR) {
+            len += snprintf(request + len, sizeof(request),
+                      "%.*s = %.*s ", al->name.len, al->name.s,
+                   pt.rs.len, pt.rs.s);
+        }
+
+          if (len >= sizeof(request)) {
+               LM_ERR("callcontrol request is longer than %ld bytes\n", (unsigned long)sizeof(request));
+            return NULL;
+             }
+    }
+
+
+    return request;
+}
+
 
 static char*
-make_request(CallInfo *call)
+make_default_request(CallInfo *call)
 {
     static char request[8192];
     int len;
@@ -645,18 +818,25 @@ static int
 call_control_initialize(struct sip_msg *msg)
 {
     CallInfo *call;
-    char *message, *result;
+    char *message, *result = NULL;
+
 
     call = get_call_info(msg, CAInitialize);
     if (!call) {
         LOG(L_ERR, "can't retrieve call info\n");
         return -5;
     }
-    message = make_request(call);
+
+
+    if (!cc_init_avps)
+        message = make_default_request(call);
+    else
+        message = make_custom_request(msg, call);
+
     if (!message)
         return -5;
 
-    result = send_command(message);
+   result = send_command(message);
 
     if (result==NULL) {
         return -5;
@@ -695,7 +875,11 @@ call_control_start(struct sip_msg *msg, struct dlg_cell *dlg)
     call->dialog_id.h_entry = dlg->h_entry;
     call->dialog_id.h_id = dlg->h_id;
 
-    message = make_request(call);
+    if (!cc_start_avps)
+        message = make_default_request(call);
+    else
+        message = make_custom_request(msg, call);
+
     if (!message)
         return -5;
 
@@ -728,7 +912,11 @@ call_control_stop(struct sip_msg *msg, str callid)
     call.action = CAStop;
     call.callid = callid;
 
-    message = make_request(&call);
+    if (!cc_stop_avps)
+        message = make_default_request(&call);
+    else
+        message = make_custom_request(msg, &call);
+
     if (!message)
         return -5;
 
@@ -933,6 +1121,19 @@ child_init(int rank)
 }
 
 
+static void
+destroy(void) {
+	if (cc_init_avps)
+		destroy_list(cc_init_avps);
+
+	if (cc_start_avps)
+		destroy_list(cc_start_avps);
+
+	if (cc_stop_avps)
+		destroy_list(cc_stop_avps);
+}
+
+
 // Postprocess a request after the main script route is done.
 //
 // After all script processing is done, check if the dialog was actually
@@ -943,7 +1144,7 @@ child_init(int rank)
 // would remain dangling until it expires.
 //
 static int
-postprocess_request(struct sip_msg *msg, unsigned int flags, void *_param)
+postprocess_request(struct sip_msg *msg, void *_param)
 {
     CallInfo *call;
 

+ 1 - 1
modules_k/siputils/contact_ops.c

@@ -488,7 +488,7 @@ decode2format (str uri, char separator, struct uri_format *format)
 		}
 
 #ifdef DEBUG
-		fprintf (stdout, "Decoding %.*s\n",end-start,start);
+		fprintf (stdout, "Decoding %.*s\n", (int)(long)(end-start), start);
 #endif
 	
 	state = EX_PREFIX;

+ 1 - 1
modules_k/tmx/tmx_mod.c

@@ -228,7 +228,7 @@ static int t_cancel_branches(struct sip_msg* msg, char *k, char *s2)
 	tcx = _tmx_tmb.tm_ctx_get();
 	if(tcx != NULL)
 		idx = tcx->branch_index;
-	n = (int)k;
+	n = (int)(long)k;
 	switch(n) {
 		case 1:
 			/* prepare cancel for every branch except idx */

+ 2 - 0
modules_s/ctl/binrpc_run.c

@@ -302,6 +302,7 @@ error:
 
 
 
+#if 0
 /* expects an initialized new_b */
 static int build_structs(struct binrpc_pkt *new_b, struct binrpc_pkt* body, 
 							struct rpc_struct_head* sl_head)
@@ -323,6 +324,7 @@ static int build_structs(struct binrpc_pkt *new_b, struct binrpc_pkt* body,
 error:
 	return ret;
 }
+#endif
 
 
 

+ 1 - 0
modules_s/eval/eval.c

@@ -182,6 +182,7 @@ static void get_uri_and_skip_until_params(str *param_area, str *uri) {
 	int i, quoted, uri_pos, uri_done;
 
 	uri->len = 0;
+	uri->s = 0;
 	uri_done = 0;
 	for (i=0; i<param_area->len && param_area->s[i]!=';'; ) {	/* [ *(token LSW)/quoted-string ] "<" addr-spec ">" | addr-spec */
 		/* skip name */

+ 1 - 0
modules_s/msilo/msilo.c

@@ -561,6 +561,7 @@ static int m_dump(struct sip_msg* msg, char* str1, char* str2)
 	str next_hop = STR_NULL;
 	uac_req_t	uac_r;
 	
+	i=0; /* fix warning in DBG() */
 	if (str1) {
 		next_hop.s = str1;
 		next_hop.len = strlen(str1);

+ 1 - 0
modules_s/permissions/ip_set.c

@@ -101,6 +101,7 @@ int ip_set_add_list(struct ip_set *ip_set, str ip_set_s){
 		ip_set_s.s += ip_s.len;
 		ip_set_s.len -= ip_s.len;
 		mask_s.len = 0;
+		mask_s.s=0;
 		if (ip_set_s.len && ip_set_s.s[0] == '/') {
 			ip_set_s.s++;
 			ip_set_s.len--;

+ 6 - 0
receive.c

@@ -98,6 +98,12 @@ int receive_msg(char* buf, unsigned int len, struct receive_info* rcv_info)
 	struct timezone tz;
 	unsigned int diff;
 #endif
+	str inb;
+
+	inb.s = buf;
+	inb.len = len;
+	sr_event_exec(SREV_NET_DATA_IN, (void*)&inb);
+	len = inb.len;
 
 	msg=pkg_malloc(sizeof(struct sip_msg));
 	if (msg==0) {

+ 2 - 2
test/unit/include/common

@@ -2,11 +2,11 @@
 DB_ALL_MOD="acc|alias_db|auth_db|avpops|dialog|dialplan|dispatcher|domain|domainpolicy|group|imc|lcr|msilo|siptrace|speeddial|uri_db|usrloc|permissions|pdt|userblacklist"
 # root directory relative to tests
 SR_DIR="../.."
-CTL_DIR="$SR_DIR/tools/kamctl"
+CTL_DIR="$SR_DIR/utils/kamctl"
 CTLRC="$CTL_DIR/kamctlrc"
 CTL="$CTL_DIR/kamctl"
 DBCTL="$CTL_DIR/kamdbctl"
 BIN="$SR_DIR/ser"
 KILL="killall -15 $BIN"
 # test directory relative to root
-TEST_DIR="test/unit"
+TEST_DIR="test/unit"

+ 0 - 0
tools/kamctl/Makefile → utils/kamctl/Makefile


+ 0 - 0
tools/kamctl/db_berkeley/kamailio/acc → utils/kamctl/db_berkeley/kamailio/acc


+ 0 - 0
tools/kamctl/db_berkeley/kamailio/active_watchers → utils/kamctl/db_berkeley/kamailio/active_watchers


+ 0 - 0
tools/kamctl/db_berkeley/kamailio/address → utils/kamctl/db_berkeley/kamailio/address


+ 0 - 0
tools/kamctl/db_berkeley/kamailio/aliases → utils/kamctl/db_berkeley/kamailio/aliases


+ 0 - 0
tools/kamctl/db_berkeley/kamailio/carrier_name → utils/kamctl/db_berkeley/kamailio/carrier_name


+ 0 - 0
tools/kamctl/db_berkeley/kamailio/carrierfailureroute → utils/kamctl/db_berkeley/kamailio/carrierfailureroute


+ 0 - 0
tools/kamctl/db_berkeley/kamailio/carrierroute → utils/kamctl/db_berkeley/kamailio/carrierroute


+ 0 - 0
tools/kamctl/db_berkeley/kamailio/cpl → utils/kamctl/db_berkeley/kamailio/cpl


+ 0 - 0
tools/kamctl/db_berkeley/kamailio/dbaliases → utils/kamctl/db_berkeley/kamailio/dbaliases


+ 0 - 0
tools/kamctl/db_berkeley/kamailio/dialog → utils/kamctl/db_berkeley/kamailio/dialog


+ 0 - 0
tools/kamctl/db_berkeley/kamailio/dialplan → utils/kamctl/db_berkeley/kamailio/dialplan


+ 0 - 0
tools/kamctl/db_berkeley/kamailio/dispatcher → utils/kamctl/db_berkeley/kamailio/dispatcher


+ 0 - 0
tools/kamctl/db_berkeley/kamailio/domain → utils/kamctl/db_berkeley/kamailio/domain


+ 0 - 0
tools/kamctl/db_berkeley/kamailio/domain_name → utils/kamctl/db_berkeley/kamailio/domain_name


+ 0 - 0
tools/kamctl/db_berkeley/kamailio/domainpolicy → utils/kamctl/db_berkeley/kamailio/domainpolicy


+ 0 - 0
tools/kamctl/db_berkeley/kamailio/globalblacklist → utils/kamctl/db_berkeley/kamailio/globalblacklist


+ 0 - 0
tools/kamctl/db_berkeley/kamailio/grp → utils/kamctl/db_berkeley/kamailio/grp


+ 0 - 0
tools/kamctl/db_berkeley/kamailio/gw → utils/kamctl/db_berkeley/kamailio/gw


+ 0 - 0
tools/kamctl/db_berkeley/kamailio/htable → utils/kamctl/db_berkeley/kamailio/htable


+ 0 - 0
tools/kamctl/db_berkeley/kamailio/imc_members → utils/kamctl/db_berkeley/kamailio/imc_members


+ 0 - 0
tools/kamctl/db_berkeley/kamailio/imc_rooms → utils/kamctl/db_berkeley/kamailio/imc_rooms


+ 0 - 0
tools/kamctl/db_berkeley/kamailio/lcr → utils/kamctl/db_berkeley/kamailio/lcr


+ 0 - 0
tools/kamctl/db_berkeley/kamailio/location → utils/kamctl/db_berkeley/kamailio/location


+ 0 - 0
tools/kamctl/db_berkeley/kamailio/missed_calls → utils/kamctl/db_berkeley/kamailio/missed_calls


+ 0 - 0
tools/kamctl/db_berkeley/kamailio/pdt → utils/kamctl/db_berkeley/kamailio/pdt


+ 0 - 0
tools/kamctl/db_berkeley/kamailio/presentity → utils/kamctl/db_berkeley/kamailio/presentity


+ 0 - 0
tools/kamctl/db_berkeley/kamailio/pua → utils/kamctl/db_berkeley/kamailio/pua


+ 0 - 0
tools/kamctl/db_berkeley/kamailio/purplemap → utils/kamctl/db_berkeley/kamailio/purplemap


+ 0 - 0
tools/kamctl/db_berkeley/kamailio/re_grp → utils/kamctl/db_berkeley/kamailio/re_grp


+ 0 - 0
tools/kamctl/db_berkeley/kamailio/rls_presentity → utils/kamctl/db_berkeley/kamailio/rls_presentity


+ 0 - 0
tools/kamctl/db_berkeley/kamailio/rls_watchers → utils/kamctl/db_berkeley/kamailio/rls_watchers


+ 0 - 0
tools/kamctl/db_berkeley/kamailio/silo → utils/kamctl/db_berkeley/kamailio/silo


+ 0 - 0
tools/kamctl/db_berkeley/kamailio/sip_trace → utils/kamctl/db_berkeley/kamailio/sip_trace


+ 0 - 0
tools/kamctl/db_berkeley/kamailio/speed_dial → utils/kamctl/db_berkeley/kamailio/speed_dial


+ 0 - 0
tools/kamctl/db_berkeley/kamailio/subscriber → utils/kamctl/db_berkeley/kamailio/subscriber


+ 0 - 0
tools/kamctl/db_berkeley/kamailio/trusted → utils/kamctl/db_berkeley/kamailio/trusted


+ 0 - 0
tools/kamctl/db_berkeley/kamailio/uri → utils/kamctl/db_berkeley/kamailio/uri


+ 0 - 0
tools/kamctl/db_berkeley/kamailio/userblacklist → utils/kamctl/db_berkeley/kamailio/userblacklist


+ 0 - 0
tools/kamctl/db_berkeley/kamailio/usr_preferences → utils/kamctl/db_berkeley/kamailio/usr_preferences


+ 0 - 0
tools/kamctl/db_berkeley/kamailio/version → utils/kamctl/db_berkeley/kamailio/version


+ 0 - 0
tools/kamctl/db_berkeley/kamailio/watchers → utils/kamctl/db_berkeley/kamailio/watchers


+ 0 - 0
tools/kamctl/db_berkeley/kamailio/xcap → utils/kamctl/db_berkeley/kamailio/xcap


+ 0 - 0
tools/kamctl/dbtext/kamailio/acc → utils/kamctl/dbtext/kamailio/acc


+ 0 - 0
tools/kamctl/dbtext/kamailio/active_watchers → utils/kamctl/dbtext/kamailio/active_watchers


+ 0 - 0
tools/kamctl/dbtext/kamailio/address → utils/kamctl/dbtext/kamailio/address


+ 0 - 0
tools/kamctl/dbtext/kamailio/aliases → utils/kamctl/dbtext/kamailio/aliases


+ 0 - 0
tools/kamctl/dbtext/kamailio/carrier_name → utils/kamctl/dbtext/kamailio/carrier_name


+ 0 - 0
tools/kamctl/dbtext/kamailio/carrierfailureroute → utils/kamctl/dbtext/kamailio/carrierfailureroute


+ 0 - 0
tools/kamctl/dbtext/kamailio/carrierroute → utils/kamctl/dbtext/kamailio/carrierroute


+ 0 - 0
tools/kamctl/dbtext/kamailio/cpl → utils/kamctl/dbtext/kamailio/cpl


+ 0 - 0
tools/kamctl/dbtext/kamailio/dbaliases → utils/kamctl/dbtext/kamailio/dbaliases


+ 0 - 0
tools/kamctl/dbtext/kamailio/dialog → utils/kamctl/dbtext/kamailio/dialog


+ 0 - 0
tools/kamctl/dbtext/kamailio/dialplan → utils/kamctl/dbtext/kamailio/dialplan


+ 0 - 0
tools/kamctl/dbtext/kamailio/dispatcher → utils/kamctl/dbtext/kamailio/dispatcher


+ 0 - 0
tools/kamctl/dbtext/kamailio/domain → utils/kamctl/dbtext/kamailio/domain


+ 0 - 0
tools/kamctl/dbtext/kamailio/domain_name → utils/kamctl/dbtext/kamailio/domain_name


+ 0 - 0
tools/kamctl/dbtext/kamailio/domainpolicy → utils/kamctl/dbtext/kamailio/domainpolicy


+ 0 - 0
tools/kamctl/dbtext/kamailio/globalblacklist → utils/kamctl/dbtext/kamailio/globalblacklist


+ 0 - 0
tools/kamctl/dbtext/kamailio/grp → utils/kamctl/dbtext/kamailio/grp


+ 0 - 0
tools/kamctl/dbtext/kamailio/gw → utils/kamctl/dbtext/kamailio/gw


+ 0 - 0
tools/kamctl/dbtext/kamailio/htable → utils/kamctl/dbtext/kamailio/htable


+ 0 - 0
tools/kamctl/dbtext/kamailio/imc_members → utils/kamctl/dbtext/kamailio/imc_members


+ 0 - 0
tools/kamctl/dbtext/kamailio/imc_rooms → utils/kamctl/dbtext/kamailio/imc_rooms


+ 0 - 0
tools/kamctl/dbtext/kamailio/lcr → utils/kamctl/dbtext/kamailio/lcr


+ 0 - 0
tools/kamctl/dbtext/kamailio/location → utils/kamctl/dbtext/kamailio/location


+ 0 - 0
tools/kamctl/dbtext/kamailio/missed_calls → utils/kamctl/dbtext/kamailio/missed_calls


+ 0 - 0
tools/kamctl/dbtext/kamailio/pdt → utils/kamctl/dbtext/kamailio/pdt


+ 0 - 0
tools/kamctl/dbtext/kamailio/presentity → utils/kamctl/dbtext/kamailio/presentity


+ 0 - 0
tools/kamctl/dbtext/kamailio/pua → utils/kamctl/dbtext/kamailio/pua


+ 0 - 0
tools/kamctl/dbtext/kamailio/purplemap → utils/kamctl/dbtext/kamailio/purplemap


+ 0 - 0
tools/kamctl/dbtext/kamailio/re_grp → utils/kamctl/dbtext/kamailio/re_grp


Някои файлове не бяха показани, защото твърде много файлове са промени