浏览代码

Merge branch 'sr' into kcore

* sr: (39 commits)
  New function to return the To tag for local reply
  Allow parser syn'ced with kamailio version
  New functions that can be used to search for a header with given type
  tcp: minor optimization
  sercmd: minor makefile fix
  tcp internal: send timeout is now kept only in ticks
  core: typo fix
  tcp: typo & minor optimization
  Support for auto_inv_100_reason tm parameter.
  Rename Contact parameter select 'method' to 'methods'
  Rename Contact parameter 'method' to 'methods'
  make install: avoid re-linking lib dependent modules
  Kamailio compatiblity: export last_retcode via a global variable
  build system: avoid libraries re-compiling
  Add support for SET_HOSTALL_T action.
  Replace missing logging macros with va_arg support using static buffer.
  Adding send_sock to the dlg_t structure.
  Update to the refurbished event parser.
  Refurbished event header field parser.
  Extend the parser parameter with support for dialog event parameters.
  ...
Jan Janak 16 年之前
父节点
当前提交
534aa29209
共有 89 个文件被更改,包括 1309 次插入445 次删除
  1. 6 3
      Makefile
  2. 78 75
      Makefile.defs
  3. 2 3
      Makefile.libs
  4. 5 1
      Makefile.modules
  5. 1 1
      Makefile.radius
  6. 19 13
      Makefile.rules
  7. 14 0
      NEWS
  8. 130 16
      action.c
  9. 10 0
      cfg.lex
  10. 31 5
      cfg.y
  11. 2 2
      cfg/cfg.h
  12. 14 8
      cfg/cfg_ctx.c
  13. 6 2
      cfg/cfg_struct.c
  14. 3 3
      cfg/cfg_struct.h
  15. 3 4
      core_cmd.c
  16. 5 5
      dns_cache.c
  17. 4 4
      dns_cache.h
  18. 2 2
      doc/cfg.txt
  19. 1 1
      dprint.c
  20. 1 1
      dprint.h
  21. 140 0
      dset.c
  22. 30 0
      dset.h
  23. 2 2
      dst_blacklist.c
  24. 2 2
      dst_blacklist.h
  25. 37 0
      flags.c
  26. 20 0
      flags.h
  27. 1 0
      ip_addr.h
  28. 13 2
      modules/carrierroute/cr_config.c
  29. 3 0
      modules/tm/config.c
  30. 1 0
      modules/tm/config.h
  31. 2 0
      modules/tm/dlg.h
  32. 23 2
      modules/tm/doc/params.xml
  33. 18 0
      modules/tm/sip_msg.c
  34. 1 1
      modules/tm/t_cancel.c
  35. 1 1
      modules/tm/t_cancel.h
  36. 1 1
      modules/tm/t_funcs.c
  37. 1 1
      modules/tm/t_fwd.c
  38. 1 1
      modules/tm/t_fwd.h
  39. 13 0
      modules/tm/t_reply.c
  40. 3 0
      modules/tm/t_reply.h
  41. 1 1
      modules/tm/timer.c
  42. 1 1
      modules/tm/timer.h
  43. 3 1
      modules/tm/tm.c
  44. 2 0
      modules/tm/tm_load.c
  45. 1 0
      modules/tm/tm_load.h
  46. 42 12
      msg_translator.c
  47. 1 1
      msg_translator.h
  48. 41 0
      parser/case_path.h
  49. 2 2
      parser/contact/contact.c
  50. 1 1
      parser/contact/contact.h
  51. 3 0
      parser/hf.c
  52. 2 0
      parser/hf.h
  53. 1 0
      parser/keys.h
  54. 27 0
      parser/msg_parser.c
  55. 4 0
      parser/msg_parser.h
  56. 65 18
      parser/parse_allow.c
  57. 24 4
      parser/parse_allow.h
  58. 7 0
      parser/parse_cseq.c
  59. 1 0
      parser/parse_cseq.h
  60. 62 39
      parser/parse_event.c
  61. 26 16
      parser/parse_event.h
  62. 2 0
      parser/parse_hname2.c
  63. 1 1
      parser/parse_methods.c
  64. 2 0
      parser/parse_methods.h
  65. 72 6
      parser/parse_param.c
  66. 21 6
      parser/parse_param.h
  67. 7 1
      parser/parse_to.c
  68. 1 0
      parser/parse_to.h
  69. 4 4
      parser/parse_uri.c
  70. 1 0
      parser/parse_uri.h
  71. 1 3
      pkg/debian/rules
  72. 2 2
      pt.c
  73. 2 2
      pt.h
  74. 1 1
      receive.c
  75. 4 4
      resolve.c
  76. 4 4
      resolve.h
  77. 2 1
      route_struct.h
  78. 1 1
      scripts/mysql/ser_mysql.sh
  79. 3 3
      select_core.c
  80. 2 2
      select_core.h
  81. 39 0
      socket_info.c
  82. 2 0
      sr_module.h
  83. 18 8
      tcp_conn.h
  84. 4 0
      tcp_init.h
  85. 45 36
      tcp_main.c
  86. 65 70
      tcp_options.c
  87. 5 5
      tcp_options.h
  88. 29 26
      tcp_read.c
  89. 2 1
      utils/sercmd/Makefile

+ 6 - 3
Makefile

@@ -54,6 +54,8 @@
 #               the modules list can be changed without rebuilding the whole
 #               ser (andrei)
 #              added cfg-defs, new target that only rebuilds config.mak
+#  2009-03-10  replaced DEFS with C_DEFS (DEFS are now used only for
+#              "temporary" defines inside modules or libs) (andrei)
 #
 
 auto_gen=lex.yy.c cfg.tab.c #lexx, yacc etc
@@ -203,7 +205,7 @@ ALLDEP=config.mak Makefile Makefile.sources Makefile.rules
 # hack to force makefile.defs re-inclusion (needed when make calls itself with
 # other options -- e.g. make bin)
 #makefile_defs=0
-#DEFS:=
+#C_DEFS:=
 
 
 # try saved cfg, unless we are in the process of building it
@@ -331,7 +333,7 @@ config.mak: Makefile.defs
 	@$(call mapf2,cfg_save_var,saved_fixed_vars,$(@))
 	@$(call mapf2,cfg_save_var2,saved_chg_vars,$(@))
 	@echo "override makefile_defs:=1" >>$@
-	@echo "DEFS:=\$$(filter-out \$$(DEFS_RM) \$$(extra_defs),\$$(DEFS))" \
+	@echo "C_DEFS:=\$$(filter-out \$$(DEFS_RM) \$$(extra_defs),\$$(C_DEFS))" \
 					"\$$(extra_defs)"  >>$@
 	@echo "CFLAGS:=\$$(filter-out \$$(CFLAGS_RM) \$$(CC_EXTRA_OPTS)," \
 						"\$$(CFLAGS)) \$$(CC_EXTRA_OPTS)" >>$@
@@ -538,7 +540,8 @@ man: modules.lst
 	done; true
 
 .PHONY: install
-install:all install-bin install-modules install-cfg \
+install: export compile_for_install=yes
+install: install-bin install-modules install-cfg \
 	install-doc install-man install-utils install-share
 
 .PHONY: dbinstall

+ 78 - 75
Makefile.defs

@@ -66,6 +66,9 @@
 #  2008-06-26  support for make cfg / config.mak and hack to load 
 #               automatically config.mak when included from a module, lib 
 #               a.s.o (not from the main Makefile)  (andrei)
+#  2009-03-10  replaced DEFS with C_DEFS and INCLUDES with C_INCLUDES (DEFS
+#              and INCLUDES are now used only for "temporary" defines/includes
+#              inside modules or libs) (andrei)
 
 
 # check if already included/exported
@@ -460,7 +463,7 @@ endif
 #		adds support for Application Server interface
 # Sometimes is needes correct non-quoted $OS. HACK: gcc translates known OS to number ('linux'), so there is added underscore
 
-DEFS= $(extra_defs) \
+C_DEFS= $(extra_defs) \
 	 -DNAME='"$(MAIN_NAME)"' -DVERSION='"$(RELEASE)"' -DARCH='"$(ARCH)"' \
 	 -DOS='$(OS)_' -DOS_QUOTED='"$(OS)"' -DCOMPILER='"$(CC_VER)"' -D__CPU_$(ARCH) -D__OS_$(OS) \
 	 -DSER_VER=$(SER_VER) \
@@ -507,14 +510,14 @@ DEFS= $(extra_defs) \
 # debugging symbols in all cases (-g). --andrei
 
 ifeq ($(CORE_TLS), 1)
-	DEFS+= -DUSE_TLS -DCORE_TLS
+	C_DEFS+= -DUSE_TLS -DCORE_TLS
 endif
 ifeq ($(TLS_HOOKS), 1)
-	DEFS+= -DUSE_TLS -DTLS_HOOKS
+	C_DEFS+= -DUSE_TLS -DTLS_HOOKS
 endif
 
 ifneq ($(STUN),)
-	DEFS+= -DUSE_STUN
+	C_DEFS+= -DUSE_STUN
 endif
 
 ifeq ($(mode),)
@@ -522,7 +525,7 @@ ifeq ($(mode),)
 endif
 
 ifeq ($(mode),debug)
-	DEFS+= -DEXTRA_DEBUG
+	C_DEFS+= -DEXTRA_DEBUG
 endif
 
 # platform dependent settings
@@ -598,7 +601,7 @@ endif
 
 ifeq ($(ARCH), arm)
 	use_fast_lock=yes
-	DEFS+=-DNOSMP # very unlikely to have an smp arm
+	C_DEFS+=-DNOSMP # very unlikely to have an smp arm
 endif
 
 ifeq ($(ARCH), arm6)
@@ -616,8 +619,8 @@ endif
 ifeq ($(ARCH), mips)
 # mips1 arch. (e.g. R3000) - no hardware locking support
 	use_fast_lock=no
-	DEFS+=-DMIPS_HAS_LLSC # likely
-	DEFS+=-DNOSMP # very likely
+	C_DEFS+=-DMIPS_HAS_LLSC # likely
+	C_DEFS+=-DNOSMP # very likely
 endif
 
 ifeq ($(ARCH), mips2)
@@ -632,24 +635,24 @@ endif
 
 ifeq ($(ARCH), alpha)
 	use_fast_lock=yes
-	DEFS+=-DNOSMP # very likely
+	C_DEFS+=-DNOSMP # very likely
 endif
 
 ifeq ($(use_fast_lock), yes)
-	DEFS+= -DFAST_LOCK -DADAPTIVE_WAIT -DADAPTIVE_WAIT_LOOPS=1024 
+	C_DEFS+= -DFAST_LOCK -DADAPTIVE_WAIT -DADAPTIVE_WAIT_LOOPS=1024 
 	found_lock_method=yes
 endif
 
 CFLAGS=
 LDFLAGS=
-INCLUDES=
+C_INCLUDES=
 # setting CFLAGS
 ifeq ($(mode), release)
 	#if i386
 ifeq	($(ARCH), i386)
 		# if gcc 
 ifeq		($(CC_NAME), gcc)
-				DEFS+=-DCC_GCC_LIKE_ASM
+				C_DEFS+=-DCC_GCC_LIKE_ASM
 				#common stuff
 				CFLAGS=-g -O9 -funroll-loops  -Wcast-align $(PROFILE)
 			#if gcc 4.0+
@@ -692,7 +695,7 @@ endif			# CC_SHORTVER, 4.x
 
 else		# CC_NAME, gcc
 ifeq		($(CC_NAME), icc)
-			DEFS+=-DCC_GCC_LIKE_ASM
+			C_DEFS+=-DCC_GCC_LIKE_ASM
 			CFLAGS=-g -O3  -ipo -ipo_obj -unroll  $(PROFILE) \
 					 -tpp6 -xK  #-openmp  #optimize for PIII 
 				# -prefetch doesn't seem to work
@@ -710,7 +713,7 @@ endif	#ARCH, i386
 ifeq	($(ARCH), x86_64)
 		# if gcc 
 ifeq		($(CC_NAME), gcc)
-				DEFS+=-DCC_GCC_LIKE_ASM
+				C_DEFS+=-DCC_GCC_LIKE_ASM
 				#common stuff
 				CFLAGS=-m64 -g -O9 -funroll-loops  -Wcast-align $(PROFILE)
 				LDFLAGS+=-m64
@@ -754,7 +757,7 @@ endif			# CC_SHORTVER, 4.x
 
 else		# CC_NAME, gcc
 ifeq		($(CC_NAME), icc)
-			DEFS+=-DCC_GCC_LIKE_ASM
+			C_DEFS+=-DCC_GCC_LIKE_ASM
 			CFLAGS=-g -O3  -ipo -ipo_obj -unroll  $(PROFILE) \
 					 -tpp6 -xK  #-openmp  #optimize for PIII 
 				# -prefetch doesn't seem to work
@@ -772,7 +775,7 @@ endif	#ARCH, x86_64
 ifeq	($(ARCH), sparc64)
 			#if gcc
 ifeq		($(CC_NAME), gcc)
-				DEFS+=-DCC_GCC_LIKE_ASM -DSPARC64_MODE
+				C_DEFS+=-DCC_GCC_LIKE_ASM -DSPARC64_MODE
 				#common stuff
 				CFLAGS=-m64 -g -O9 -funroll-loops  $(PROFILE) \
 					#-Wcast-align \
@@ -834,7 +837,7 @@ endif			#CC_SHORTVER, 4.x
 	
 else		#CC_NAME, gcc
 ifeq		($(CC_NAME), suncc)
-			DEFS+=-DSPARC64_MODE
+			C_DEFS+=-DSPARC64_MODE
 			CFLAGS+= -m64 -g -xO5 -fast -native -xarch=v9 -xCC \
 					-xc99 # C99 support
 			# -Dinline="" # add this if cc < 5.3 (define inline as null)
@@ -849,7 +852,7 @@ endif	#ARCH, sparc64
 ifeq	($(ARCH), sparc)
 			#if gcc
 ifeq		($(CC_NAME), gcc)
-				DEFS+=-DCC_GCC_LIKE_ASM
+				C_DEFS+=-DCC_GCC_LIKE_ASM
 				#common stuff
 				CFLAGS=-g -O9 -funroll-loops  $(PROFILE) \
 					#-Wcast-align \
@@ -906,7 +909,7 @@ endif	#ARCH, sparc
 ifeq	($(ARCH), arm)
 		# if gcc 
 ifeq		($(CC_NAME), gcc)
-				DEFS+=-DCC_GCC_LIKE_ASM
+				C_DEFS+=-DCC_GCC_LIKE_ASM
 				#common stuff
 				CFLAGS=-O9 -funroll-loops $(PROFILE)
 			#if gcc 4.x+
@@ -948,7 +951,7 @@ endif	#ARCH, arm
 ifeq	($(ARCH), arm6)
 		# if gcc 
 ifeq		($(CC_NAME), gcc)
-				DEFS+=-DCC_GCC_LIKE_ASM
+				C_DEFS+=-DCC_GCC_LIKE_ASM
 				#common stuff
 				CFLAGS=-march=armv6 -O9 -funroll-loops \
 						$(PROFILE)
@@ -990,7 +993,7 @@ endif	#ARCH, arm6
 ifeq	($(ARCH), mips)
 		# if gcc 
 ifeq		($(CC_NAME), gcc)
-				DEFS+=-DCC_GCC_LIKE_ASM
+				C_DEFS+=-DCC_GCC_LIKE_ASM
 				#common stuff
 				CFLAGS=-O9 -funroll-loops  $(PROFILE)
 			#if gcc 4.0+
@@ -1031,7 +1034,7 @@ endif	#ARCH, mips
 ifeq	($(ARCH), mips2)
 		# if gcc 
 ifeq		($(CC_NAME), gcc)
-				DEFS+=-DCC_GCC_LIKE_ASM
+				C_DEFS+=-DCC_GCC_LIKE_ASM
 				#common stuff
 				CFLAGS= -mips2 -O9 -funroll-loops $(PROFILE)
 			#if gcc 4.0+
@@ -1070,7 +1073,7 @@ endif	#ARCH, mips2
 ifeq	($(ARCH), mips64)
 		# if gcc 
 ifeq		($(CC_NAME), gcc)
-				DEFS+=-DCC_GCC_LIKE_ASM
+				C_DEFS+=-DCC_GCC_LIKE_ASM
 				#common stuff
 				CFLAGS= -mips64 -O9 -funroll-loops $(PROFILE)
 			#if gcc 4.0+
@@ -1109,7 +1112,7 @@ endif	#ARCH, mips64
 ifeq	($(ARCH), alpha)
 		# if gcc 
 ifeq		($(CC_NAME), gcc)
-				DEFS+=-DCC_GCC_LIKE_ASM
+				C_DEFS+=-DCC_GCC_LIKE_ASM
 				#common stuff
 				CFLAGS= -O9 -funroll-loops $(PROFILE)
 			#if gcc 4.0+
@@ -1149,7 +1152,7 @@ endif	#ARCH, alpha
 ifeq	($(ARCH), ppc)
 		# if gcc 
 ifeq		($(CC_NAME), gcc)
-				DEFS+=-DCC_GCC_LIKE_ASM
+				C_DEFS+=-DCC_GCC_LIKE_ASM
 				#common stuff
 				CFLAGS= -O9 -funroll-loops $(PROFILE)
 			#if gcc 4.0+
@@ -1190,7 +1193,7 @@ endif	#ARCH, ppc
 ifeq	($(ARCH), ppc64)
 		# if gcc 
 ifeq		($(CC_NAME), gcc)
-				DEFS+=-DCC_GCC_LIKE_ASM
+				C_DEFS+=-DCC_GCC_LIKE_ASM
 				#common stuff
 				CFLAGS= -O9 -funroll-loops $(PROFILE)
 ifeq			($(CC_SHORTVER), 4.x)
@@ -1269,9 +1272,9 @@ endif
 else	#mode,release
 ifeq	($(CC_NAME), gcc)
 		CFLAGS=-g -Wcast-align $(PROFILE)
-		DEFS+=-DCC_GCC_LIKE_ASM
+		C_DEFS+=-DCC_GCC_LIKE_ASM
 ifeq		($(ARCH), sparc64)
-			DEFS+=SPARC64_MODE
+			C_DEFS+=SPARC64_MODE
 			CFLAGS+= -mcpu=ultrasparc -m64
 			LDFLAGS+=-m64
 endif
@@ -1292,7 +1295,7 @@ else
 endif
 endif
 ifeq	($(CC_NAME), icc)
-		DEFS+=-DCC_GCC_LIKE_ASM
+		C_DEFS+=-DCC_GCC_LIKE_ASM
 		CFLAGS=-g  $(PROFILE)
 		LDFLAGS+=-g -Wl,-E $(PROFILE)
 		MOD_LDFLAGS:=-shared $(LDFLAGS)
@@ -1357,27 +1360,27 @@ LIB_SUFFIX:=.so
 ifeq ($(OS), linux)
 # by default use futexes if available
 	use_futex= yes
-	DEFS+=-DHAVE_GETHOSTBYNAME2 -DHAVE_UNION_SEMUN -DHAVE_SCHED_YIELD \
+	C_DEFS+=-DHAVE_GETHOSTBYNAME2 -DHAVE_UNION_SEMUN -DHAVE_SCHED_YIELD \
 			-DHAVE_MSG_NOSIGNAL -DHAVE_MSGHDR_MSG_CONTROL -DHAVE_ALLOCA_H \
 			-DHAVE_TIMEGM -DHAVE_SCHED_SETSCHEDULER
 	ifneq ($(found_lock_method), yes)
-		#DEFS+= -DUSE_POSIX_SEM
-		DEFS+=-DUSE_PTHREAD_MUTEX
+		#C_DEFS+= -DUSE_POSIX_SEM
+		C_DEFS+=-DUSE_PTHREAD_MUTEX
 		LIBS+= -lpthread
-		#DEFS+= -DUSE_SYSV_SEM  # try posix sems
+		#C_DEFS+= -DUSE_SYSV_SEM  # try posix sems
 		found_lock_method=yes
 	else
-		ifneq (,$(findstring -DUSE_POSIX_SEM, $(DEFS)))
+		ifneq (,$(findstring -DUSE_POSIX_SEM, $(C_DEFS)))
 			LIBS+=-lpthread
 		endif
-		ifneq (,$(findstring -DUSE_PTHREAD_MUTEX, $(DEFS)))
+		ifneq (,$(findstring -DUSE_PTHREAD_MUTEX, $(C_DEFS)))
 			LIBS+=-lpthread
 		endif
 	endif
 	# check for >= 2.5.44
 	ifeq ($(shell [ $(OSREL_N) -ge 2005044 ] && echo has_epoll), has_epoll)
 		ifeq ($(NO_EPOLL),)
-			DEFS+=-DHAVE_EPOLL
+			C_DEFS+=-DHAVE_EPOLL
 			# linux + gcc >= 3.0 + -malign-double + epoll => problems
 			CFLAGS_RM+=-malign-double
 			#CFLAGS:=$(filter-out -malign-double, $(CFLAGS))
@@ -1386,17 +1389,17 @@ ifeq ($(OS), linux)
 	# check for >= 2.2.0
 	ifeq ($(shell [ $(OSREL_N) -ge 2002000 ] && echo has_sigio), has_sigio)
 		ifeq ($(NO_SIGIO),)
-			DEFS+=-DHAVE_SIGIO_RT -DSIGINFO64_WORKARROUND
+			C_DEFS+=-DHAVE_SIGIO_RT -DSIGINFO64_WORKARROUND
 		endif
 	endif
 	# check for >= 2.5.70
 	ifeq ($(shell [ $(OSREL_N) -ge 2005070 ] && echo has_futex), has_futex)
 		ifeq ($(use_futex), yes)
-			DEFS+=-DUSE_FUTEX
+			C_DEFS+=-DUSE_FUTEX
 		endif
 	endif
 	ifeq ($(NO_SELECT),)
-		DEFS+=-DHAVE_SELECT
+		C_DEFS+=-DHAVE_SELECT
 	endif
 	# sctp support
 	ifeq ($(SCTP),1)
@@ -1418,27 +1421,27 @@ $(info "sctp libraries not installed -- sctp disabled")
 		
 		ifeq ($(SCTP),1)
 			# use lksctp
-			DEFS+=-DUSE_SCTP
+			C_DEFS+=-DUSE_SCTP
 			LIBS+=-lsctp
 		endif
 	endif # SCTP
 endif
 
 ifeq  ($(OS), solaris)
-	DEFS+= -DHAVE_GETIPNODEBYNAME -DHAVE_SYS_SOCKIO_H -DHAVE_SCHED_YIELD \
+	C_DEFS+= -DHAVE_GETIPNODEBYNAME -DHAVE_SYS_SOCKIO_H -DHAVE_SCHED_YIELD \
 			-DHAVE_ALLOCA_H -DUSE_SIGACTION
 	ifneq ($(found_lock_method), yes)
-		DEFS+= -DUSE_PTHREAD_MUTEX  # try pthread sems
+		C_DEFS+= -DUSE_PTHREAD_MUTEX  # try pthread sems
 		found_lock_method=yes
 	endif
 	# check for ver >= 5.7
 	ifeq ($(shell [ $(OSREL_N) -gt 5007 ] && echo has_devpoll), has_devpoll)
 		ifeq ($(NO_DEVPOLL),)
-			DEFS+=-DHAVE_DEVPOLL
+			C_DEFS+=-DHAVE_DEVPOLL
 		endif
 	endif
 	ifeq ($(NO_SELECT),)
-		DEFS+=-DHAVE_SELECT
+		C_DEFS+=-DHAVE_SELECT
 	endif
 	# check for filio.h
 	filio_h_locations= /usr/include/sys/filio.h \
@@ -1448,7 +1451,7 @@ ifeq  ($(OS), solaris)
 						done;\
 				)
 	ifeq ($(has_filio_h), yes)
-		DEFS+=-DHAVE_FILIO_H
+		C_DEFS+=-DHAVE_FILIO_H
 	endif
 	ifeq ($(mode), release)
 		#use these only if you're using gcc with Solaris ld
@@ -1475,12 +1478,12 @@ endif
 endif
 
 ifeq ($(OS), freebsd)
-	DEFS+=-DHAVE_SOCKADDR_SA_LEN -DHAVE_GETHOSTBYNAME2 -DHAVE_UNION_SEMUN \
+	C_DEFS+=-DHAVE_SOCKADDR_SA_LEN -DHAVE_GETHOSTBYNAME2 -DHAVE_UNION_SEMUN \
 		-DHAVE_SCHED_YIELD -DHAVE_MSGHDR_MSG_CONTROL \
 		-DHAVE_CONNECT_ECONNRESET_BUG -DHAVE_TIMEGM \
 		-DHAVE_NETINET_IN_SYSTM
 	ifneq ($(found_lock_method), yes)
-		DEFS+= -DUSE_PTHREAD_MUTEX  # try pthread sems
+		C_DEFS+= -DUSE_PTHREAD_MUTEX  # try pthread sems
 		found_lock_method=yes
 		LIBS+= -pthread   #dlopen is in libc
 	else
@@ -1489,11 +1492,11 @@ ifeq ($(OS), freebsd)
 	# check for ver >= 4.1
 	ifeq ($(shell [ $(OSREL_N) -gt 4001 ] && echo has_kqueue), has_kqueue)
 		ifeq ($(NO_KQUEUE),)
-			DEFS+=-DHAVE_KQUEUE
+			C_DEFS+=-DHAVE_KQUEUE
 		endif
 	endif
 	ifeq ($(NO_SELECT),)
-		DEFS+=-DHAVE_SELECT
+		C_DEFS+=-DHAVE_SELECT
 	endif
 	YACC=yacc
 	# sctp support
@@ -1512,29 +1515,29 @@ $(info "old freebsd version (>= 7.0 needed) -- sctp disabled")
 		endif
 		
 		ifeq ($(SCTP),1)
-			DEFS+=-DUSE_SCTP
+			C_DEFS+=-DUSE_SCTP
 			LIBS+=  # no extra libs needed on freebsd
 		endif
 	endif # SCTP
 endif
 
 ifeq ($(OS), openbsd)
-	DEFS+=-DHAVE_SOCKADDR_SA_LEN  -DHAVE_GETHOSTBYNAME2 \
+	C_DEFS+=-DHAVE_SOCKADDR_SA_LEN  -DHAVE_GETHOSTBYNAME2 \
 		-DHAVE_UNION_SEMUN -DHAVE_MSGHDR_MSG_CONTROL \
 		-DHAVE_CONNECT_ECONNRESET_BUG -DHAVE_TIMEGM \
 		-DHAVE_NETINET_IN_SYSTM -DUSE_SIGWAIT
 	ifneq ($(found_lock_method), yes)
-		DEFS+= -DUSE_PTHREAD_MUTEX  # try pthread sems
+		C_DEFS+= -DUSE_PTHREAD_MUTEX  # try pthread sems
 		found_lock_method=yes
 	endif
 	# check for ver >=2 9
 	ifeq ($(shell [ $(OSREL_N) -ge 2009 ] && echo has_kqueue), has_kqueue)
 		ifeq ($(NO_KQUEUE),)
-			DEFS+=-DHAVE_KQUEUE
+			C_DEFS+=-DHAVE_KQUEUE
 		endif
 	endif
 	ifeq ($(NO_SELECT),)
-		DEFS+=-DHAVE_SELECT
+		C_DEFS+=-DHAVE_SELECT
 	endif
 	# (symbols on openbsd are prefixed by "_")
 	YACC=yacc
@@ -1554,29 +1557,29 @@ endif
 endif
 	
 ifeq ($(OPENBSD_IS_AOUT), yes)
-		DEFS+=-DDLSYM_PREFIX='"_"'
+		C_DEFS+=-DDLSYM_PREFIX='"_"'
 		LDFLAGS=        # openbsd ld doesn't like -O2 or -E
 endif
 endif   # if opensd
 	
 ifeq ($(OS), netbsd)
-	DEFS+=-DHAVE_SOCKADDR_SA_LEN -DHAVE_GETHOSTBYNAME2 \
+	C_DEFS+=-DHAVE_SOCKADDR_SA_LEN -DHAVE_GETHOSTBYNAME2 \
 		-DHAVE_MSGHDR_MSG_CONTROL -DHAVE_CONNECT_ECONNRESET_BUG -DHAVE_TIMEGM
 	ifneq ($(found_lock_method), yes)
-		DEFS+= -DUSE_SYSV_SEM  # try pthread sems
+		C_DEFS+= -DUSE_SYSV_SEM  # try pthread sems
 		found_lock_method=yes
 	endif
 	# check for ver >= 2.0.0
 	ifeq ($(shell [ $(OSREL_N) -ge 2000000 ] && echo has_kqueue), has_kqueue)
 		ifeq ($(NO_KQUEUE),)
-			DEFS+=-DHAVE_KQUEUE
+			C_DEFS+=-DHAVE_KQUEUE
 			# netbsd + kqueue and -malign-double don't work
 			CFLAGS_RM+=-malign-double
 			#CFLAGS:=$(filter-out -malign-double, $(CFLAGS))
 		endif
 	endif
 	ifeq ($(NO_SELECT),)
-		DEFS+=-DHAVE_SELECT
+		C_DEFS+=-DHAVE_SELECT
 	endif
 	YACC=yacc
 	LIBS=  
@@ -1584,7 +1587,7 @@ endif
 
 # OS X support, same as freebsd
 ifeq ($(OS), darwin)
-	DEFS+=-DHAVE_SOCKADDR_SA_LEN -DHAVE_GETHOSTBYNAME2 -DHAVE_UNION_SEMUN \
+	C_DEFS+=-DHAVE_SOCKADDR_SA_LEN -DHAVE_GETHOSTBYNAME2 -DHAVE_UNION_SEMUN \
 		-DHAVE_SCHED_YIELD -DHAVE_MSGHDR_MSG_CONTROL \
 		-DUSE_ANON_MMAP \
 		-DNDEBUG -DHAVE_CONNECT_ECONNRESET_BUG -DHAVE_TIMEGM \
@@ -1592,18 +1595,18 @@ ifeq ($(OS), darwin)
 	# -DNDEBUG used to turn off assert (assert wants to call
 	# eprintf which doesn't seem to be defined in any shared lib
 	ifneq ($(found_lock_method), yes)
-		DEFS+= -DUSE_PTHREAD_MUTEX  # try pthread sems
+		C_DEFS+= -DUSE_PTHREAD_MUTEX  # try pthread sems
 		found_lock_method=yes
-		DEFS+= -DUSE_SYSV_SEM  # try sys v sems (pthread don't work for
+		C_DEFS+= -DUSE_SYSV_SEM  # try sys v sems (pthread don't work for
 		                       # processes and unnamed posix sems are not
 		                       # supported)
 	endif
 	LIBS= -lresolv  #dlopen is in libc
 	ifeq ($(NO_KQUEUE),)
-		DEFS+=-DHAVE_KQUEUE
+		C_DEFS+=-DHAVE_KQUEUE
 	endif
 	ifeq ($(NO_SELECT),)
-		DEFS+=-DHAVE_SELECT
+		C_DEFS+=-DHAVE_SELECT
 	endif
 	LDFLAGS=        # darwin doesn't like -O2 or -E
 	# the modules uses symbols from ser => either 
@@ -1621,34 +1624,34 @@ endif
 
 ifneq (,$(findstring cygwin, $(OS)))
 	# cygwin doesn't support IPV6 and doesn't support fd passing so no TCP
-	#DEFS:=$(filter-out -DUSE_IPV6 -DUSE_TCP, $(DEFS))
+	#C_DEFS:=$(filter-out -DUSE_IPV6 -DUSE_TCP, $(C_DEFS))
 	DEFS_RM+=-DUSE_IPV6 -DUSE_TCP
-	DEFS+=-DHAVE_UNION_SEMUN -DHAVE_SCHED_YIELD \
+	C_DEFS+=-DHAVE_UNION_SEMUN -DHAVE_SCHED_YIELD \
 			-DHAVE_MSG_NOSIGNAL -DHAVE_MSGHDR_MSG_CONTROL -DHAVE_ALLOCA_H \
 			-DHAVE_TIMEGM -DHAVE_SCHED_SETSCHEDULER
 	ifneq ($(found_lock_method), yes)
-		DEFS+= -DUSE_POSIX_SEM
-		#DEFS+= -DUSE_SYSV_SEM  # try posix sems
+		C_DEFS+= -DUSE_POSIX_SEM
+		#C_DEFS+= -DUSE_SYSV_SEM  # try posix sems
 		# PTHREAD_MUTEX do not work for processes (try test/pthread_test.c)
 		#LIBS+= -lpthread
 		found_lock_method=yes
 	else
-		ifneq (,$(findstring -DUSE_POSIX_SEM, $(DEFS)))
+		ifneq (,$(findstring -DUSE_POSIX_SEM, $(C_DEFS)))
 			#LIBS+=-lpthread
 		endif
-		ifneq (,$(findstring -DUSE_PTHREAD_MUTEX, $(DEFS)))
+		ifneq (,$(findstring -DUSE_PTHREAD_MUTEX, $(C_DEFS)))
 $(error PTHREAD_MUTEX do not work for processes on Windows/CYGWIN)
 		endif
 	endif
 	# check for >= 2.5.70
 	ifeq ($(NO_SELECT),)
-		DEFS+=-DHAVE_SELECT
+		C_DEFS+=-DHAVE_SELECT
 	endif
 endif
 
 #add libssl if needed
 ifeq ($(CORE_TLS), 1)
-DEFS+= -I$(LOCALBASE)/ssl/include
+C_DEFS+= -I$(LOCALBASE)/ssl/include
 LIBS+= -L$(LOCALBASE)/lib -L$(LOCALBASE)/ssl/lib -lssl -lcrypto \
 		$(TLS_EXTRA_LIBS)
 # NOTE: depending on the way in which libssl was compiled you might
@@ -1657,13 +1660,13 @@ LIBS+= -L$(LOCALBASE)/lib -L$(LOCALBASE)/ssl/lib -lssl -lcrypto \
 endif
 
 ifneq ($(STUN),)
-DEFS+= -I$(LOCALBASE)/ssl/include
+C_DEFS+= -I$(LOCALBASE)/ssl/include
 LIBS+= -L$(LOCALBASE)/lib -L$(LOCALBASE)/ssl/lib -lcrypto
 endif
 
 ifneq ($(found_lock_method), yes)
 $(warning	No locking method found so far, trying SYS V sems)
-		DEFS+= -DUSE_SYSV_SEM  # try sys v sems
+		C_DEFS+= -DUSE_SYSV_SEM  # try sys v sems
 		found_lock_method=yes
 endif
 
@@ -1685,7 +1688,7 @@ export exported_vars
 #  is run)
 saved_fixed_vars:=	MAIN_NAME \
 		RELEASE OS ARCH \
-		DEFS DEFS_RM PROFILE CC LD MKDEP MKTAGS LDFLAGS INCLUDES \
+		C_DEFS DEFS_RM PROFILE CC LD MKDEP MKTAGS LDFLAGS C_INCLUDES \
 		MOD_LDFLAGS LIB_LDFLAGS LIB_SONAME LD_RPATH \
 		LIB_SUFFIX LIB_PREFIX \
 		LIBS \

+ 2 - 3
Makefile.libs

@@ -20,7 +20,7 @@ endif
 
 ifneq	(,$(filter install% %install install, $(MAKECMDGOALS)))
 compile_for_install:=yes
-$(info install mode => compile_for_install=$(compile_for_install))
+$(info install mode)
 endif
 
 ifeq ($(NAME),)
@@ -157,8 +157,7 @@ endif
 .PHONY:install-if-newer
 install-if-newer: $(lib_prefix)/$(lib_dir)/$(LIB_RUNTIME_NAME) 
 
-$(lib_prefix)/$(lib_dir)/$(LIB_RUNTIME_NAME): $(LIB_NAME) $(LIBINAME_F)
-	@$(MAKE) install
+$(lib_prefix)/$(lib_dir)/$(LIB_RUNTIME_NAME): $(LIB_NAME) $(LIBINAME_F) install
 
 
 ifneq ($(strip $(LIBINAME_F)),)

+ 5 - 1
Makefile.modules

@@ -11,6 +11,9 @@
 #               installed if needed (andrei)
 #  2008-06-23  added the README & man targets (andrei)
 #  2008-06-27  make cfg / config.mak support (andrei)
+#  2009-03-10  replaced DEFS with C_DEFS and INCLUDES with C_INCLUDES (DEFS
+#              and INCLUDES are now used only for "temporary" defines/includes
+#              inside modules or libs) (andrei)
 #
 
 MOD_NAME=$(NAME:.so=)
@@ -26,9 +29,10 @@ override modules=
 override static_modules=
 override static_modules_path=
 
-# should be set in Makefile of apart module
+# should be set in the Makefile of each module
 # INCLUDES += -I$(COREPATH)
 
+# temporary def (visible only in the module, not exported)
 DEFS += -DMOD_NAME='"$(MOD_NAME)"'
 
 ifneq ($(makefile_defs_included),1)

+ 1 - 1
Makefile.radius

@@ -19,7 +19,7 @@
 # Radiusclient-ng is often installed from tarballs so we
 # need to look int /usr/local/lib as well
 #
-DEFS+=-I$(LOCALBASE)/include
+INCLUDES+=-I$(LOCALBASE)/include
 
 ifneq ($(radiusclient_ng), 4)
 

+ 19 - 13
Makefile.rules

@@ -6,7 +6,8 @@
 #
 
 #
-# Uses: NAME, ALLDEP, CC, CFLAGS, DEFS, INCLUDES, LIBS, MKDEP, auto_gen, 
+# Uses: NAME, ALLDEP, CC, CFLAGS, C_DEFS, DEFS, C_INCLUDES, INCLUDES, LIBS, 
+#       MKDEP, auto_gen, 
 # auto_gen_others, depends, objs, extra_objs, static_modules, 
 # static_modules_path, LD_RPATH
 # (all this must  be defined previously!,  see Makefile.defs & Makefile)
@@ -20,7 +21,10 @@
 #              automatically build listed SER_LIBS if needed (andrei)
 #  2008-06-23  automatically rebuild if make time defines or includes
 #              changed (via makecfg.lst)
-#
+#  2009-03-10  support for C_DEFS and C_INCLUDES (DEFS and INCLUDES are now
+#              used only for "temporary" defines/includes inside modules or
+#              libs, C_DEFS and C_INCLUDES are used for the common stuff)
+#              (andrei)
 
 
 # check if the saved cfg corresponds with the current one
@@ -30,17 +34,18 @@ ifeq (,$(filter $(nodep_targets),$(MAKECMDGOALS)))
 # if trying  to build a lib automatically and the lib is already compiled,
 # don't rebuild it if the only differences in DEFS or INCLUDES are covered
 # by LIB_NOREBUILD_DEFS/LIB_NOREBUILD_INCLUDES
-LIB_NOREBUILD_DEFS+= -DMOD_NAME% -D%_MOD_INTERFACE -DMOD_INTERFACE_% -DSR_%
+LIB_NOREBUILD_DEFS=
 
 # don't rebuild if the differences are covered by NOREBUILD_DEFS or 
 # NOREBUILD_INCLUDES
-ifneq ($(filter-out $(NOREBUILD_DEFS),$(strip $(DEFS))), $(strip $(CFG_DEFS)))
+ifneq ($(strip $(filter-out $(NOREBUILD_DEFS),\
+		$(C_DEFS) $(DEFS))),$(strip $(CFG_DEFS)))
 #$(warning different defs: <$(strip $(DEFS))> != )
 #$(warning               : <$(strip $(CFG_DEFS))>)
 $(shell rm -f makecfg.lst)
 endif
-ifneq ($(filter-out $(NOREBUILD_INCLUDES), $(strip $(INCLUDES))),\
-		$(strip $(CFG_INCLUDES)))
+ifneq ($(strip $(filter-out $(NOREBUILD_INCLUDES),\
+			$(C_INCLUDES) $(INCLUDES))),$(strip $(CFG_INCLUDES)))
 $(shell rm -f makecfg.lst)
 endif
 endif
@@ -49,10 +54,10 @@ ALLDEP+=makecfg.lst
 
 #implicit rules
 %.o:%.c  $(ALLDEP)
-	$(CC) $(CFLAGS) $(INCLUDES) $(DEFS) -c $< -o $@
+	$(CC) $(CFLAGS) $(C_INCLUDES) $(INCLUDES) $(C_DEFS) $(DEFS) -c $< -o $@
 
 %.d: %.c $(ALLDEP)
-	@set -e; $(MKDEP) $(CFLAGS) $(INCLUDES) $(DEFS) $< \
+	@set -e; $(MKDEP) $(CFLAGS) $(C_INCLUDES) $(INCLUDES) $(C_DEFS) $(DEFS) $<\
 	    |  sed 's#\(\($(*D)/\)\{0,1\}$(*F)\)\.o[ :]*#$*.o $@ : #g' > $@; \
 	    test -s $@ || ( rm -f $@; false )
 
@@ -66,7 +71,7 @@ ifneq	(,$(filter install install% %install, $(MAKECMDGOALS)))
 lib_compile_for_install=yes
 expected_lib_ipath=$(lib_target)
 else
-lib_compile_for_install=no
+lib_compile_for_install=$(compile_for_install)
 # function: expected_lib_ipath ser_lib_dir
 expected_lib_ipath=$(1)
 endif
@@ -144,10 +149,11 @@ librpath.lst: $(ALLDEP)
 	@echo LIB_RPATH_LST:=$(SER_RPATH_LST) >librpath.lst
 
 makecfg.lst:
-	@echo CFG_DEFS:=$(subst ',\', $(subst ",\", \
-		$(filter-out $(NOREBUILD_DEFS), $(strip $(DEFS))))) >>$@
-	@echo CFG_INCLUDES:=$(subst ',\', $(subst ",\", \
-		$(filter-out $(NOREBUILD_INCLUDES), $(strip $(INCLUDES))))) >>$@
+	@echo CFG_DEFS:=$(subst ',\', $(subst ",\",$(strip \
+			$(filter-out $(NOREBUILD_DEFS), $(C_DEFS) $(DEFS))))) >>$@
+	@echo CFG_INCLUDES:=$(subst ',\', $(subst ",\",$(strip \
+			$(filter-out $(NOREBUILD_INCLUDES),\
+				$(C_INCLUDES) $(INCLUDES))))) >>$@
 .PHONY: all
 all: $(NAME) modules
 

+ 14 - 0
NEWS

@@ -256,6 +256,20 @@ core:
                between the short name and long name in cache as CNAME record
 
 new config variables:
+  tcp_rd_buf_size = buffer size used for tcp reads.
+                    A high buffer size increases performance on server with few
+                    connections and lot of traffic on them, but also increases
+                     memory consumption (so for lots of connection is better 
+                    to use a low value). Note also that this value limits the
+                    maximum datagram size that can be received over tcp.
+                    Default: 4096, can be changed at runtime.
+  tcp_wq_blk_size = block size used for tcp async writes. It should be big
+                    enough to hold a few datagrams. If it's smaller then a
+                    datagram (in fact a tcp write()) size, it will be rounded
+                    up. It has no influenced on the number of datagrams 
+                    queued (for that see tcp_conn_wq_max or tcp_wq_max).
+                    It has mostly debugging and testing value (can be ignored).
+                    Default: 2100 (~ 2 INVITEs), can be changed at runtime.
   tcp_no_connect = yes/no - disable connects, ser will only accept new 
                      connections, it will never try to open new ones.
                      Default: no, can be changed at runtime.

+ 130 - 16
action.c

@@ -93,7 +93,7 @@
 #include <dmalloc.h>
 #endif
 
-
+int _last_returned_code  = 0;
 struct onsend_info* p_onsend=0; /* onsend route send info */
 
 /* ret= 0! if action -> end of list(e.g DROP),
@@ -122,7 +122,7 @@ int do_action(struct run_act_ctx* h, struct action* a, struct sip_msg* msg)
 	struct rvalue* rv1;
 	struct rval_cache c1;
 	str s;
-
+	int orig_p2t;
 
 	/* reset the value of error to E_UNSPEC so avoid unknowledgable
 	   functions to return with error (status<0) and not setting it
@@ -461,6 +461,7 @@ int do_action(struct run_act_ctx* h, struct action* a, struct sip_msg* msg)
 			/*ret=((ret=run_actions(rlist[a->val[0].u.number], msg))<0)?ret:1;*/
 			ret=run_actions(h, main_rt.rlist[a->val[0].u.number], msg);
 			h->last_retcode=ret;
+			_last_returned_code = h->last_retcode;
 			h->run_flags&=~(RETURN_R_F|BREAK_R_F); /* absorb return & break */
 			break;
 		case EXEC_T:
@@ -490,6 +491,7 @@ int do_action(struct run_act_ctx* h, struct action* a, struct sip_msg* msg)
 		case SET_HOST_T:
 		case SET_HOSTPORT_T:
 		case SET_HOSTPORTTRANS_T:
+		case SET_HOSTALL_T:
 		case SET_USER_T:
 		case SET_USERPASS_T:
 		case SET_PORT_T:
@@ -497,18 +499,22 @@ int do_action(struct run_act_ctx* h, struct action* a, struct sip_msg* msg)
 		case PREFIX_T:
 		case STRIP_T:
 		case STRIP_TAIL_T:
+		case SET_USERPHONE_T:
 				user=0;
 				if (a->type==STRIP_T || a->type==STRIP_TAIL_T) {
 					if (a->val[0].type!=NUMBER_ST) {
 						LOG(L_CRIT, "BUG: do_action: bad set*() type %d\n",
 							a->val[0].type);
+						ret=E_BUG;
 						break;
 					}
-				} else if (a->val[0].type!=STRING_ST){
-					LOG(L_CRIT, "BUG: do_action: bad set*() type %d\n",
+				} else if (a->type!=SET_USERPHONE_T) {
+					if (a->val[0].type!=STRING_ST) {
+						LOG(L_CRIT, "BUG: do_action: bad set*() type %d\n",
 							a->val[0].type);
-					ret=E_BUG;
-					break;
+						ret=E_BUG;
+						break;
+					}
 				}
 				if (a->type==SET_URI_T){
 					if (msg->new_uri.s) {
@@ -531,7 +537,7 @@ int do_action(struct run_act_ctx* h, struct action* a, struct sip_msg* msg)
 					ret=1;
 					break;
 				}
-				if (msg->parsed_uri_ok==0) {
+				if ((msg->parsed_uri_ok==0) || ((uri.flags & URI_SIP_USER_PHONE)!=0)) {
 					if (msg->new_uri.s) {
 						tmp=msg->new_uri.s;
 						len=msg->new_uri.len;
@@ -539,16 +545,41 @@ int do_action(struct run_act_ctx* h, struct action* a, struct sip_msg* msg)
 						tmp=msg->first_line.u.request.uri.s;
 						len=msg->first_line.u.request.uri.len;
 					}
+					/* don't convert sip:user=phone to tel, otherwise we loose parameters */
+					orig_p2t=phone2tel;
+					phone2tel=0;
+					msg->parsed_uri_ok=0;
 					if (parse_uri(tmp, len, &uri)<0){
+						phone2tel=orig_p2t;
 						LOG(L_ERR, "ERROR: do_action: bad uri <%s>, dropping"
 									" packet\n", tmp);
 						ret=E_UNSPEC;
 						break;
 					}
+					phone2tel=orig_p2t;
 				} else {
 					uri=msg->parsed_uri;
 				}
 
+				/* skip SET_USERPHONE_T action if the URI is already
+				 * a tel: or tels: URI, or contains the user=phone param */
+				if ((a->type==SET_USERPHONE_T) 
+					&& ((uri.type==TEL_URI_T) || (uri.type==TELS_URI_T)
+						|| ((uri.user_param_val.len==5) && (memcmp(uri.user_param_val.s, "phone", 5)==0)))
+				) {
+					ret=1;
+					break;
+				}
+				/* SET_PORT_T does not work with tel: URIs */
+				if ((a->type==SET_PORT_T)
+					&& ((uri.type==TEL_URI_T) || (uri.type==TELS_URI_T))
+					&& ((uri.flags & URI_SIP_USER_PHONE)==0)
+				) {
+					LOG(L_ERR, "ERROR: do_action: port number of a tel: URI cannot be set\n");
+					ret=E_UNSPEC;
+					break;
+				}
+
 				new_uri=pkg_malloc(MAX_URI_SIZE);
 				if (new_uri==0){
 					LOG(L_ERR, "ERROR: do_action: memory allocation "
@@ -559,8 +590,57 @@ int do_action(struct run_act_ctx* h, struct action* a, struct sip_msg* msg)
 				end=new_uri+MAX_URI_SIZE;
 				crt=new_uri;
 				/* begin copying */
-				len=strlen("sip:"); if(crt+len>end) goto error_uri;
-				memcpy(crt,"sip:",len);crt+=len;
+				/* Preserve the URI scheme unless the host part needs
+				 * to be rewritten, and the shceme is tel: or tels: */
+				switch (uri.type) {
+				case SIP_URI_T:
+					len=s_sip.len;
+					tmp=s_sip.s;
+					break;
+
+				case SIPS_URI_T:
+					len=s_sips.len;
+					tmp=s_sips.s;
+					break;
+
+				case TEL_URI_T:
+					if ((uri.flags & URI_SIP_USER_PHONE)
+						|| (a->type==SET_HOST_T)
+						|| (a->type==SET_HOSTPORT_T)
+						|| (a->type==SET_HOSTPORTTRANS_T)
+					) {
+						len=s_sip.len;
+						tmp=s_sip.s;
+						break;
+					}
+					len=s_tel.len;
+					tmp=s_tel.s;
+					break;
+
+				case TELS_URI_T:
+					if ((uri.flags & URI_SIP_USER_PHONE)
+						|| (a->type==SET_HOST_T)
+						|| (a->type==SET_HOSTPORT_T)
+						|| (a->type==SET_HOSTPORTTRANS_T)
+					) {
+						len=s_sips.len;
+						tmp=s_sips.s;
+						break;
+					}
+					len=s_tels.len;
+					tmp=s_tels.s;
+					break;
+
+				default:
+					LOG(L_ERR, "ERROR: Unsupported URI scheme (%d), "
+						"reverted to sip:\n",
+						uri.type);
+					len=s_sip.len;
+					tmp=s_sip.s;
+				}
+				if(crt+len+1 /* colon */ >end) goto error_uri;
+				memcpy(crt,tmp,len);crt+=len;
+				*crt=':'; crt++;
 
 				/* user */
 
@@ -621,24 +701,33 @@ int do_action(struct run_act_ctx* h, struct action* a, struct sip_msg* msg)
 					memcpy(crt,tmp,len);crt+=len;
 				}
 				/* host */
-				if (user || tmp){ /* add @ */
-					if(crt+1>end) goto error_uri;
-					*crt='@'; crt++;
-				}
 				if ((a->type==SET_HOST_T)
 						|| (a->type==SET_HOSTPORT_T)
-						|| (a->type==SET_HOSTPORTTRANS_T)) {
+						|| (a->type==SET_HOSTALL_T)
+						|| (a->type==SET_HOSTPORTTRANS_T)
+				) {
 					tmp=a->val[0].u.string;
 					if (tmp) len = strlen(tmp);
 					else len=0;
-				} else {
+				} else if ((uri.type==SIP_URI_T)
+					|| (uri.type==SIPS_URI_T)
+					|| (uri.flags & URI_SIP_USER_PHONE)
+				) {
 					tmp=uri.host.s;
-					len = uri.host.len;
+					len=uri.host.len;
+				} else {
+					tmp=0;
 				}
 				if (tmp){
+					if (user) { /* add @ */
+						if(crt+1>end) goto error_uri;
+						*crt='@'; crt++;
+					}
 					if(crt+len>end) goto error_uri;
 					memcpy(crt,tmp,len);crt+=len;
 				}
+				if(a->type==SET_HOSTALL_T)
+					goto done_seturi;
 				/* port */
 				if ((a->type==SET_HOSTPORT_T)
 						|| (a->type==SET_HOSTPORTTRANS_T))
@@ -683,6 +772,22 @@ int do_action(struct run_act_ctx* h, struct action* a, struct sip_msg* msg)
 						memcpy(crt,tmp,len);crt+=len;
 					}
 				}
+				/* Add the user=phone param if a tel: or tels:
+				 * URI was converted to sip: or sips:.
+				 * (host part of a tel/tels URI was set.)
+				 * Or in case of sip: URI and SET_USERPHONE_T action */
+				if (((((uri.type==TEL_URI_T) || (uri.type==TELS_URI_T))
+					&& ((uri.flags & URI_SIP_USER_PHONE)==0))
+					&& ((a->type==SET_HOST_T)
+						|| (a->type==SET_HOSTPORT_T)
+						|| (a->type==SET_HOSTPORTTRANS_T)))
+					|| (a->type==SET_USERPHONE_T)
+				) {
+					tmp=";user=phone";
+					len=strlen(tmp);
+					if(crt+len>end) goto error_uri;
+					memcpy(crt,tmp,len);crt+=len;
+				}
 				/* headers */
 				tmp=uri.headers.s;
 				if (tmp){
@@ -690,6 +795,7 @@ int do_action(struct run_act_ctx* h, struct action* a, struct sip_msg* msg)
 					*crt='?'; crt++;
 					memcpy(crt,tmp,len);crt+=len;
 				}
+	done_seturi:
 				*crt=0; /* null terminate the thing */
 				/* copy it to the msg */
 				if (msg->new_uri.s) pkg_free(msg->new_uri.s);
@@ -740,6 +846,7 @@ int do_action(struct run_act_ctx* h, struct action* a, struct sip_msg* msg)
 									);
 				if (ret==0) h->run_flags|=EXIT_R_F;
 				h->last_retcode=ret;
+				_last_returned_code = h->last_retcode;
 			} else {
 				LOG(L_CRIT,"BUG: do_action: bad module call\n");
 			}
@@ -757,6 +864,7 @@ int do_action(struct run_act_ctx* h, struct action* a, struct sip_msg* msg)
 									);
 				if (ret==0) h->run_flags|=EXIT_R_F;
 				h->last_retcode=ret;
+				_last_returned_code = h->last_retcode;
 			} else {
 				LOG(L_CRIT,"BUG: do_action: bad module call\n");
 			}
@@ -772,6 +880,7 @@ int do_action(struct run_act_ctx* h, struct action* a, struct sip_msg* msg)
 									);
 				if (ret==0) h->run_flags|=EXIT_R_F;
 				h->last_retcode=ret;
+				_last_returned_code = h->last_retcode;
 			} else {
 				LOG(L_CRIT,"BUG: do_action: bad module call\n");
 			}
@@ -788,6 +897,7 @@ int do_action(struct run_act_ctx* h, struct action* a, struct sip_msg* msg)
 									);
 				if (ret==0) h->run_flags|=EXIT_R_F;
 				h->last_retcode=ret;
+				_last_returned_code = h->last_retcode;
 			} else {
 				LOG(L_CRIT,"BUG: do_action: bad module call\n");
 			}
@@ -805,6 +915,7 @@ int do_action(struct run_act_ctx* h, struct action* a, struct sip_msg* msg)
 									);
 				if (ret==0) h->run_flags|=EXIT_R_F;
 				h->last_retcode=ret;
+				_last_returned_code = h->last_retcode;
 			} else {
 				LOG(L_CRIT,"BUG: do_action: bad module call\n");
 			}
@@ -818,6 +929,7 @@ int do_action(struct run_act_ctx* h, struct action* a, struct sip_msg* msg)
 										);
 				if (ret==0) h->run_flags|=EXIT_R_F;
 				h->last_retcode=ret;
+				_last_returned_code = h->last_retcode;
 			} else {
 				LOG(L_CRIT,"BUG: do_action: bad module call\n");
 			}
@@ -1114,6 +1226,7 @@ int run_actions(struct run_act_ctx* h, struct action* a, struct sip_msg* msg)
 	if (h->rec_lev==1){
 		h->run_flags=0;
 		h->last_retcode=0;
+		_last_returned_code = h->last_retcode;
 #ifdef USE_LONGJMP
 		if (setjmp(h->jmp_env)){
 			h->rec_lev=0;
@@ -1137,6 +1250,7 @@ int run_actions(struct run_act_ctx* h, struct action* a, struct sip_msg* msg)
 			if (h->run_flags & EXIT_R_F){
 #ifdef USE_LONGJMP
 				h->last_retcode=ret;
+				_last_returned_code = h->last_retcode;
 				longjmp(h->jmp_env, ret);
 #endif
 			}

+ 10 - 0
cfg.lex

@@ -77,6 +77,7 @@
  *  2008-01-24  added CFG_DESCRIPTION used by cfg_var (Miklos)
  *  2008-11-28  added support for kamailio pvars and avp/pvar guessing (andrei)
  *  2008-12-11  added support for "string1" "string2" (andrei)
+ *  2009-03-10  added SET_USERPHONE action (Miklos)
 */
 
 
@@ -183,6 +184,7 @@ REVERT_URI		"revert_uri"
 PREFIX			"prefix"
 STRIP			"strip"
 STRIP_TAIL		"strip_tail"
+SET_USERPHONE		"userphone"
 APPEND_BRANCH	"append_branch"
 IF				"if"
 ELSE			"else"
@@ -332,6 +334,8 @@ TCP_OPT_FD_CACHE	"tcp_fd_cache"
 TCP_OPT_BUF_WRITE	"tcp_buf_write"|"tcp_async"
 TCP_OPT_CONN_WQ_MAX	"tcp_conn_wq_max"
 TCP_OPT_WQ_MAX		"tcp_wq_max"
+TCP_OPT_RD_BUF		"tcp_rd_buf_size"
+TCP_OPT_WQ_BLK		"tcp_wq_blk_size"
 TCP_OPT_DEFER_ACCEPT "tcp_defer_accept"
 TCP_OPT_DELAYED_ACK	"tcp_delayed_ack"
 TCP_OPT_SYNCNT		"tcp_syncnt"
@@ -491,6 +495,8 @@ EAT_ABLE	[\ \t\b\r]
 <INITIAL>{STRIP_TAIL}	{ count(); yylval.strval=yytext; return STRIP_TAIL; }
 <INITIAL>{APPEND_BRANCH}	{ count(); yylval.strval=yytext;
 								return APPEND_BRANCH; }
+<INITIAL>{SET_USERPHONE}	{ count(); yylval.strval=yytext;
+								return SET_USERPHONE; }
 <INITIAL>{FORCE_RPORT}	{ count(); yylval.strval=yytext; return FORCE_RPORT; }
 <INITIAL>{FORCE_TCP_ALIAS}	{ count(); yylval.strval=yytext;
 								return FORCE_TCP_ALIAS; }
@@ -637,6 +643,10 @@ EAT_ABLE	[\ \t\b\r]
 									return TCP_OPT_CONN_WQ_MAX; }
 <INITIAL>{TCP_OPT_WQ_MAX}	{ count(); yylval.strval=yytext;
 									return TCP_OPT_WQ_MAX; }
+<INITIAL>{TCP_OPT_RD_BUF}	{ count(); yylval.strval=yytext;
+									return TCP_OPT_RD_BUF; }
+<INITIAL>{TCP_OPT_WQ_BLK}	{ count(); yylval.strval=yytext;
+									return TCP_OPT_WQ_BLK; }
 <INITIAL>{TCP_OPT_BUF_WRITE}	{ count(); yylval.strval=yytext;
 									return TCP_OPT_BUF_WRITE; }
 <INITIAL>{TCP_OPT_DEFER_ACCEPT}	{ count(); yylval.strval=yytext;

+ 31 - 5
cfg.y

@@ -94,6 +94,7 @@
  * 2007-12-06  expression are now evaluated in terms of rvalues;
  *             NUMBER is now always positive; cleanup (andrei)
  * 2009-01-26  case/switch() support (andrei)
+ * 2009-03-10  added SET_USERPHONE action (Miklos)
 */
 
 %{
@@ -137,6 +138,7 @@
 #ifdef CORE_TLS
 #include "tls/tls_config.h"
 #endif
+#include "timer_ticks.h"
 
 #ifdef DEBUG_DMALLOC
 #include <dmalloc.h>
@@ -271,6 +273,7 @@ static int case_check_default(struct case_stms* stms);
 %token PREFIX
 %token STRIP
 %token STRIP_TAIL
+%token SET_USERPHONE
 %token APPEND_BRANCH
 %token SET_USER
 %token SET_USERPASS
@@ -396,6 +399,8 @@ static int case_check_default(struct case_stms* stms);
 %token TCP_OPT_BUF_WRITE
 %token TCP_OPT_CONN_WQ_MAX
 %token TCP_OPT_WQ_MAX
+%token TCP_OPT_RD_BUF
+%token TCP_OPT_WQ_BLK
 %token TCP_OPT_DEFER_ACCEPT
 %token TCP_OPT_DELAYED_ACK
 %token TCP_OPT_SYNCNT
@@ -839,7 +844,7 @@ assign_stm:
 	| TCP_CONNECT_TIMEOUT EQUAL error { yyerror("number expected"); }
 	| TCP_SEND_TIMEOUT EQUAL intno {
 		#ifdef USE_TCP
-			tcp_default_cfg.send_timeout_s=$3;
+			tcp_default_cfg.send_timeout=S_TO_TICKS($3);
 		#else
 			warn("tcp support not compiled in");
 		#endif
@@ -847,7 +852,10 @@ assign_stm:
 	| TCP_SEND_TIMEOUT EQUAL error { yyerror("number expected"); }
 	| TCP_CON_LIFETIME EQUAL intno {
 		#ifdef USE_TCP
-			tcp_default_cfg.con_lifetime_s=$3;
+			if ($3<0)
+				tcp_default_cfg.con_lifetime=-1;
+			else
+				tcp_default_cfg.con_lifetime=S_TO_TICKS($3);
 		#else
 			warn("tcp support not compiled in");
 		#endif
@@ -953,7 +961,23 @@ assign_stm:
 			warn("tcp support not compiled in");
 		#endif
 	}
-	| TCP_OPT_WQ_MAX error { yyerror("boolean value expected"); }
+	| TCP_OPT_WQ_MAX error { yyerror("number expected"); }
+	| TCP_OPT_RD_BUF EQUAL NUMBER {
+		#ifdef USE_TCP
+			tcp_default_cfg.rd_buf_size=$3;
+		#else
+			warn("tcp support not compiled in");
+		#endif
+	}
+	| TCP_OPT_RD_BUF error { yyerror("number expected"); }
+	| TCP_OPT_WQ_BLK EQUAL NUMBER {
+		#ifdef USE_TCP
+			tcp_default_cfg.wq_blk_size=$3;
+		#else
+			warn("tcp support not compiled in");
+		#endif
+	}
+	| TCP_OPT_WQ_BLK error { yyerror("number expected"); }
 	| TCP_OPT_DEFER_ACCEPT EQUAL NUMBER {
 		#ifdef USE_TCP
 			tcp_default_cfg.defer_accept=$3;
@@ -1315,10 +1339,10 @@ assign_stm:
 	| UDP_MTU EQUAL NUMBER { default_core_cfg.udp_mtu=$3; }
 	| UDP_MTU EQUAL error { yyerror("number expected"); }
 	| FORCE_RPORT EQUAL NUMBER 
-		{ default_core_cfg.force_rport=$3; fix_global_req_flags(0); }
+		{ default_core_cfg.force_rport=$3; fix_global_req_flags(0, 0); }
 	| FORCE_RPORT EQUAL error { yyerror("boolean value expected"); }
 	| UDP_MTU_TRY_PROTO EQUAL proto
-		{ default_core_cfg.udp_mtu_try_proto=$3; fix_global_req_flags(0); }
+		{ default_core_cfg.udp_mtu_try_proto=$3; fix_global_req_flags(0, 0); }
 	| UDP_MTU_TRY_PROTO EQUAL error
 		{ yyerror("TCP, TLS, SCTP or UDP expected"); }
 	| cfg_var
@@ -2546,6 +2570,8 @@ cmd:
 	| STRIP LPAREN NUMBER RPAREN { $$=mk_action(STRIP_T, 1, NUMBER_ST, (void*) $3); }
 	| STRIP error { $$=0; yyerror("missing '(' or ')' ?"); }
 	| STRIP LPAREN error RPAREN { $$=0; yyerror("bad argument, number expected"); }
+	| SET_USERPHONE LPAREN RPAREN { $$=mk_action(SET_USERPHONE_T, 0); }
+	| SET_USERPHONE error { $$=0; yyerror("missing '(' or ')' ?"); }
 	| APPEND_BRANCH LPAREN STRING COMMA STRING RPAREN {
 		qvalue_t q;
 		if (str2q(&q, $5, strlen($5)) < 0) {

+ 2 - 2
cfg/cfg.h

@@ -56,8 +56,8 @@
 /* variable is read-only */
 #define CFG_READONLY		(1U<<(2*CFG_INPUT_SHIFT+1))
 
-typedef int (*cfg_on_change)(void *, str *, void **);
-typedef void (*cfg_on_set_child)(str *);
+typedef int (*cfg_on_change)(void *, str *, str *, void **);
+typedef void (*cfg_on_set_child)(str *, str *);
 
 /* strutrure to be used by the module interface */
 typedef struct _cfg_def {

+ 14 - 8
cfg/cfg_ctx.c

@@ -258,7 +258,7 @@ int cfg_set_now(cfg_ctx_t *ctx, str *group_name, str *var_name,
 	cfg_mapping_t	*var;
 	void		*p, *v;
 	cfg_block_t	*block = NULL;
-	str		s;
+	str		s, s2;
 	char		*old_string = NULL;
 	char		**replaced = NULL;
 	cfg_child_cb_t	*child_cb = NULL;
@@ -300,6 +300,7 @@ int cfg_set_now(cfg_ctx_t *ctx, str *group_name, str *var_name,
 		There is no need to set a temporary cfg handle,
 		becaue a single variable is changed */
 		if (var->def->on_change_cb(*(group->handle),
+						group_name,
 						var_name,
 						&v) < 0) {
 			LOG(L_ERR, "ERROR: cfg_set_now(): fixup failed\n");
@@ -311,9 +312,11 @@ int cfg_set_now(cfg_ctx_t *ctx, str *group_name, str *var_name,
 	if (var->def->on_set_child_cb) {
 		/* get the name of the variable from the internal struct,
 		because var_name may be freed before the callback needs it */
-		s.s = var->def->name;
-		s.len = var->name_len;
-		child_cb = cfg_child_cb_new(&s,
+		s.s = group->name;
+		s.len = group->name_len;
+		s2.s = var->def->name;
+		s2.len = var->name_len;
+		child_cb = cfg_child_cb_new(&s, &s2,
 					var->def->on_set_child_cb);
 		if (!child_cb) {
 			LOG(L_ERR, "ERROR: cfg_set_now(): not enough shm memory\n");
@@ -579,6 +582,7 @@ int cfg_set_delayed(cfg_ctx_t *ctx, str *group_name, str *var_name,
 		}
 			
 		if (var->def->on_change_cb(temp_handle,
+						group_name,
 						var_name,
 						&v) < 0) {
 			LOG(L_ERR, "ERROR: cfg_set_delayed(): fixup failed\n");
@@ -711,7 +715,7 @@ int cfg_commit(cfg_ctx_t *ctx)
 	cfg_child_cb_t	*child_cb_last = NULL;
 	int	size;
 	void	*p;
-	str	s;
+	str	s, s2;
 
 	if (!ctx) {
 		LOG(L_ERR, "ERROR: cfg_commit(): context is undefined\n");
@@ -740,9 +744,11 @@ int cfg_commit(cfg_ctx_t *ctx)
 
 
 		if (changed->var->def->on_set_child_cb) {
-			s.s = changed->var->def->name;
-			s.len = changed->var->name_len;
-			child_cb = cfg_child_cb_new(&s,
+			s.s = changed->group->name;
+			s.len = changed->group->name_len;
+			s2.s = changed->var->def->name;
+			s2.len = changed->var->name_len;
+			child_cb = cfg_child_cb_new(&s, &s2,
 					changed->var->def->on_set_child_cb);
 			if (!child_cb) goto error0;
 

+ 6 - 2
cfg/cfg_struct.c

@@ -317,7 +317,7 @@ int cfg_init(void)
 	This stucture will be the entry point for the child processes, and
 	will be freed later, when none of the processes refers to it */
 	*cfg_child_cb_first = *cfg_child_cb_last =
-		cfg_child_cb_new(NULL, NULL);
+		cfg_child_cb_new(NULL, NULL, NULL);
 
 	if (!*cfg_child_cb_first) goto error;
 
@@ -552,7 +552,7 @@ void cfg_install_global(cfg_block_t *block, char **replaced,
 }
 
 /* creates a structure for a per-child process callback */
-cfg_child_cb_t *cfg_child_cb_new(str *name, cfg_on_set_child cb)
+cfg_child_cb_t *cfg_child_cb_new(str *gname, str *name, cfg_on_set_child cb)
 {
 	cfg_child_cb_t	*cb_struct;
 
@@ -562,6 +562,10 @@ cfg_child_cb_t *cfg_child_cb_new(str *name, cfg_on_set_child cb)
 		return NULL;
 	}
 	memset(cb_struct, 0, sizeof(cfg_child_cb_t));
+	if (gname) {
+		cb_struct->gname.s = gname->s;
+		cb_struct->gname.len = gname->len;
+	}
 	if (name) {
 		cb_struct->name.s = name->s;
 		cb_struct->name.len = name->len;

+ 3 - 3
cfg/cfg_struct.h

@@ -98,7 +98,7 @@ typedef struct _cfg_block {
 typedef struct _cfg_child_cb {
 	atomic_t		refcnt; /* number of child processes
 					referring to the element */
-	str			name;	/* name of the variable that has changed */
+	str			gname, name;	/* name of the variable that has changed */
 	cfg_on_set_child	cb;	/* callback function that has to be called */
 
 	struct _cfg_child_cb	*next;
@@ -232,7 +232,7 @@ static inline void cfg_update_local(void)
 			}
 		}
 		/* execute the callback */
-		cfg_child_cb->cb(&cfg_child_cb->name);
+		cfg_child_cb->cb(&cfg_child_cb->gname, &cfg_child_cb->name);
 	}
 }
 
@@ -280,7 +280,7 @@ void cfg_install_global(cfg_block_t *block, char **replaced,
 			cfg_child_cb_t *cb_first, cfg_child_cb_t *cb_last);
 
 /* creates a structure for a per-child process callback */
-cfg_child_cb_t *cfg_child_cb_new(str *name, cfg_on_set_child cb);
+cfg_child_cb_t *cfg_child_cb_new(str *gname, str *name, cfg_on_set_child cb);
 
 /* free the memory allocated for a child cb list */
 void cfg_child_cb_free(cfg_child_cb_t *child_cb_first);

+ 3 - 4
core_cmd.c

@@ -567,10 +567,10 @@ static void core_tcp_options(rpc_t* rpc, void* c)
 	if (!tcp_disable){
 		tcp_options_get(&t);
 		rpc->add(c, "{", &handle);
-		rpc->struct_add(handle, "ddddddddddddddddddddddd",
+		rpc->struct_add(handle, "dddddddddddddddddddddd",
 			"connect_timeout", t.connect_timeout_s,
-			"send_timeout",  t.send_timeout_s,
-			"connection_lifetime",  t.con_lifetime_s,
+			"send_timeout",  TICKS_TO_S(t.send_timeout),
+			"connection_lifetime",  TICKS_TO_S(t.con_lifetime),
 			"max_connections(soft)", t.max_connections,
 			"no_connect",	t.no_connect,
 			"fd_cache",		t.fd_cache,
@@ -578,7 +578,6 @@ static void core_tcp_options(rpc_t* rpc, void* c)
 			"connect_wait",	t.tcp_connect_wait,
 			"conn_wq_max",	t.tcpconn_wq_max,
 			"wq_max",		t.tcp_wq_max,
-			"wq_timeout",	TICKS_TO_S(t.tcp_wq_timeout),
 			"defer_accept",	t.defer_accept,
 			"delayed_ack",	t.delayed_ack,
 			"syncnt",		t.syncnt,

+ 5 - 5
dns_cache.c

@@ -265,7 +265,7 @@ void destroy_dns_cache()
 }
 
 /* set the value of dns_flags */
-void fix_dns_flags(str *name)
+void fix_dns_flags(str *gname, str *name)
 {
 	/* restore the original value of dns_cache_flags first
 	 * (DNS_IPV4_ONLY may have been set only because dns_try_ipv6
@@ -300,7 +300,7 @@ void fix_dns_flags(str *name)
 /* fixup function for use_dns_failover
  * verifies that use_dns_cache is set to 1
  */
-int use_dns_failover_fixup(void *handle, str *name, void **val)
+int use_dns_failover_fixup(void *handle, str *gname, str *name, void **val)
 {
 	if ((int)(long)(*val) && !cfg_get(core, handle, use_dns_cache)) {
 		LOG(L_ERR, "ERROR: use_dns_failover_fixup(): "
@@ -314,7 +314,7 @@ int use_dns_failover_fixup(void *handle, str *name, void **val)
 /* fixup function for use_dns_cache
  * verifies that dns_cache_init is set to 1
  */
-int use_dns_cache_fixup(void *handle, str *name, void **val)
+int use_dns_cache_fixup(void *handle, str *gname, str *name, void **val)
 {
 	if ((int)(long)(*val) && !dns_cache_init) {
 		LOG(L_ERR, "ERROR: use_dns_cache_fixup(): "
@@ -332,7 +332,7 @@ int use_dns_cache_fixup(void *handle, str *name, void **val)
 }
 
 /* KByte to Byte conversion */
-int dns_cache_max_mem_fixup(void *handle, str *name, void **val)
+int dns_cache_max_mem_fixup(void *handle, str *gname, str *name, void **val)
 {
 	unsigned int    u;
 
@@ -407,7 +407,7 @@ int init_dns_cache()
 	if (default_core_cfg.use_dns_cache==0)
 		default_core_cfg.use_dns_failover=0; /* cannot work w/o dns_cache support */
 	/* fix flags */
-	fix_dns_flags(NULL);
+	fix_dns_flags(NULL, NULL);
 
 	dns_timer_h=timer_alloc();
 	if (dns_timer_h==0){

+ 4 - 4
dns_cache.h

@@ -178,10 +178,10 @@ struct dns_srv_handle{
 
 const char* dns_strerror(int err);
 
-void fix_dns_flags(str *name);
-int use_dns_failover_fixup(void *handle, str *name, void **val);
-int use_dns_cache_fixup(void *handle, str *name, void **val);
-int dns_cache_max_mem_fixup(void *handle, str *name, void **val);
+void fix_dns_flags(str *gname, str *name);
+int use_dns_failover_fixup(void *handle, str *gname, str *name, void **val);
+int use_dns_cache_fixup(void *handle, str *gname, str *name, void **val);
+int dns_cache_max_mem_fixup(void *handle, str *gname, str *name, void **val);
 int init_dns_cache();
 #ifdef USE_DNS_CACHE_STATS
 int init_dns_cache_stats(int iproc_num);

+ 2 - 2
doc/cfg.txt

@@ -129,7 +129,7 @@ Each row consists of the following items:
   handle within the fixup function. String and str values are cloned to
   shm memory by the framework. The callback type is:
 
-  typedef int (*cfg_on_change)(void *temp_handle, str *var_name, void **value);
+  typedef int (*cfg_on_change)(void *temp_handle, str *group_name, str *var_name, void **value);
 
 - per-child process callback function (optional) that is called by each child
   process separately, after the new values have been committed, and the
@@ -137,7 +137,7 @@ Each row consists of the following items:
   longer be used by the process. (Useful for fix-ups that cannot be done
   in shm memory, for example regexp compilation.)
 
-  typedef void (*cfg_on_set_child)(str *var_name);
+  typedef void (*cfg_on_set_child)(str *group_name, str *var_name);
 
 - description of the variable
 

+ 1 - 1
dprint.c

@@ -84,7 +84,7 @@ int str2facility(char *s)
 }
 
 /* fixup function for log_facility cfg parameter */
-int log_facility_fixup(void *handle, str *name, void **val)
+int log_facility_fixup(void *handle, str *gname, str *name, void **val)
 {
 	int	i;
 

+ 1 - 1
dprint.h

@@ -115,7 +115,7 @@ extern volatile int dprint_crit;
 #endif
 
 int str2facility(char *s);
-int log_facility_fixup(void *handle, str *name, void **val);
+int log_facility_fixup(void *handle, str *gname, str *name, void **val);
 
 
 /*

+ 140 - 0
dset.c

@@ -126,6 +126,25 @@ int resetbflag(unsigned int branch, flag_t flag)
 }
 
 
+int getbflags(flag_t* res, unsigned int branch)
+{
+	flag_t* flags;
+	if (res == NULL) return -1;
+	if ((flags = get_bflags_ptr(branch)) == NULL) return -1;
+	*res = *flags;
+	return 1;
+}
+
+
+int setbflagsval(unsigned int branch, flag_t val)
+{
+	flag_t* flags;
+	if ((flags = get_bflags_ptr(branch)) == NULL) return -1;
+	*flags = val;
+	return 1;
+}
+
+
 /*
  * Initialize the branch iterator, the next
  * call to next_branch will return the first
@@ -174,6 +193,46 @@ char* next_branch(int* len, qvalue_t* q, char** dst_uri, int* dst_len, struct so
 }
 
 
+/** \brief Get a branch from the destination set
+ * \return Return the 'i' branch from the dset
+ * array, 0 is returned if there are no
+ * more branches
+ */
+char* get_branch(unsigned int i, int* len, qvalue_t* q, str* dst_uri,
+				 str* path, unsigned int *flags, struct socket_info** force_socket)
+{
+	if (i < nr_branches) {
+		*len = branches[i].len;
+		*q = branches[i].q;
+		if (dst_uri) {
+			dst_uri->len = branches[i].dst_uri_len;
+			dst_uri->s = (dst_uri->len)?branches[i].dst_uri:0;
+		}
+		if (path) {
+			path->len = branches[i].path_len;
+			path->s = (path->len)?branches[i].path:0;
+		}
+		if (force_socket)
+			*force_socket = branches[i].force_send_socket;
+		if (flags)
+			*flags = branches[i].flags;
+		return branches[i].uri;
+	} else {
+		*len = 0;
+		*q = Q_UNSPECIFIED;
+		if (dst_uri) {
+			dst_uri->s = 0;
+			dst_uri->len = 0;
+		}
+		if (force_socket)
+			*force_socket = 0;
+		if (flags)
+			*flags = 0;
+		return 0;
+	}
+}
+
+
 /*
  * Empty the dset array
  */
@@ -244,6 +303,87 @@ int append_branch(struct sip_msg* msg, char* uri, int uri_len, char* dst_uri, in
 }
 
 
+/* ! \brief
+ * Add a new branch to current transaction using str parameters
+ * Kamailio compatibility version
+ */
+int km_append_branch(struct sip_msg* msg, str* uri, str* dst_uri, str* path,
+		qvalue_t q, unsigned int flags, struct socket_info* force_socket)
+{
+	str luri;
+
+#ifdef USE_LOCAL_ROUTE
+	if (dset_state==0)
+		return -1;
+#endif
+
+	/* if we have already set up the maximum number
+	 * of branches, don't try new ones 
+	 */
+	if (nr_branches == MAX_BRANCHES - 1) {
+		LOG(L_ERR, "max nr of branches exceeded\n");
+		ser_error = E_TOO_MANY_BRANCHES;
+		return -1;
+	}
+
+	/* if not parameterized, take current uri */
+	if (uri==0 || uri->len==0 || uri->s==0) {
+		if (msg->new_uri.s)
+			luri = msg->new_uri;
+		else
+			luri = msg->first_line.u.request.uri;
+	} else {
+		luri = *uri;
+	}
+
+	if (luri.len > MAX_URI_SIZE - 1) {
+		LOG(L_ERR, "too long uri: %.*s\n", luri.len, luri.s);
+		return -1;
+	}
+
+	/* copy the dst_uri */
+	if (dst_uri && dst_uri->len && dst_uri->s) {
+		if (dst_uri->len > MAX_URI_SIZE - 1) {
+			LOG(L_ERR, "too long dst_uri: %.*s\n",
+				dst_uri->len, dst_uri->s);
+			return -1;
+		}
+		memcpy(branches[nr_branches].dst_uri, dst_uri->s, dst_uri->len);
+		branches[nr_branches].dst_uri[dst_uri->len] = 0;
+		branches[nr_branches].dst_uri_len = dst_uri->len;
+	} else {
+		branches[nr_branches].dst_uri[0] = '\0';
+		branches[nr_branches].dst_uri_len = 0;
+	}
+
+	/* copy the path string */
+	if (path && path->len && path->s) {
+		if (path->len > MAX_PATH_SIZE - 1) {
+			LOG(L_ERR, "too long path: %.*s\n", path->len, path->s);
+			return -1;
+		}
+		memcpy(branches[nr_branches].path, path->s, path->len);
+		branches[nr_branches].path[path->len] = 0;
+		branches[nr_branches].path_len = path->len;
+	} else {
+		branches[nr_branches].path[0] = '\0';
+		branches[nr_branches].path_len = 0;
+	}
+
+	/* copy the ruri */
+	memcpy(branches[nr_branches].uri, luri.s, luri.len);
+	branches[nr_branches].uri[luri.len] = 0;
+	branches[nr_branches].len = luri.len;
+	branches[nr_branches].q = q;
+
+	branches[nr_branches].force_send_socket = force_socket;
+	branches[nr_branches].flags = flags;
+
+	nr_branches++;
+	return 1;
+}
+
+
 /*
  * Create a Contact header field from the dset
  * array

+ 30 - 0
dset.h

@@ -44,6 +44,10 @@ int append_branch(struct sip_msg* msg, char* uri, int uri_len, char* dst_uri, in
 		  qvalue_t q, struct socket_info* force_socket);
 
 
+int km_append_branch(struct sip_msg* msg, str* uri, str* dst_uri, str* path,
+					 qvalue_t q, unsigned int flags, struct socket_info* force_socket);
+
+
 /* 
  * Iterate through the list of transaction branches 
  */
@@ -56,6 +60,10 @@ void init_branch_iterator(void);
 char* next_branch(int* len, qvalue_t* q, char** dst_uri, int* dst_len, struct socket_info** force_socket);
 
 
+char* get_branch( unsigned int i, int* len, qvalue_t* q, str* dst_uri,
+				  str* path, unsigned int *flags, struct socket_info** force_socket);
+
+
 /*
  * Empty the array of branches
  */
@@ -113,4 +121,26 @@ int resetbflag(unsigned int branch, flag_t flag);
  */
 int isbflagset(unsigned int branch, flag_t flag);
 
+/**
+ * Get the value of all branch flags for a branch
+ *
+ * This function returns the value of all branch flags
+ * combined in a single variable.
+ * @param res A pointer to a variable to store the result
+ * @param branch Number of the branch (0 for the main Request-URI branch)
+ * @return 1 on success, -1 on failure
+ */
+int getbflags(flag_t* res, unsigned int branch);
+
+/**
+ * Set the value of all branch flags at once for a given branch.
+ *
+ * This function sets the value of all branch flags for a given
+ * branch at once.
+ * @param branch Number of the branch (0 for the main Request-URI branch)
+ * @param val All branch flags combined into a single variable
+ * @return 1 on success, -1 on failure
+ */
+int setbflagsval(unsigned int branch, flag_t val);
+
 #endif /* _DSET_H */

+ 2 - 2
dst_blacklist.c

@@ -1176,7 +1176,7 @@ void dst_blst_add(rpc_t* rpc, void* ctx)
 /* fixup function for use_dst_blacklist
  * verifies that dst_blacklist_init is set to 1
  */
-int use_dst_blacklist_fixup(void *handle, str *name, void **val)
+int use_dst_blacklist_fixup(void *handle, str *gname, str *name, void **val)
 {
 	if ((int)(long)(*val) && !dst_blacklist_init) {
 		LOG(L_ERR, "ERROR: use_dst_blacklist_fixup(): "
@@ -1188,7 +1188,7 @@ int use_dst_blacklist_fixup(void *handle, str *name, void **val)
 }
 
 /* KByte to Byte conversion */
-int blst_max_mem_fixup(void *handle, str *name, void **val)
+int blst_max_mem_fixup(void *handle, str *gname, str *name, void **val)
 {
 	unsigned int	u;
 

+ 2 - 2
dst_blacklist.h

@@ -116,8 +116,8 @@ int dst_blacklist_del(struct dest_info* si, struct sip_msg* msg);
  */
 void dst_blst_flush(void);
 
-int use_dst_blacklist_fixup(void *handle, str *name, void **val);
+int use_dst_blacklist_fixup(void *handle, str *gname, str *name, void **val);
 /* KByte to Byte conversion */
-int blst_max_mem_fixup(void *handle, str *name, void **val);
+int blst_max_mem_fixup(void *handle, str *gname, str *name, void **val);
 
 #endif

+ 37 - 0
flags.c

@@ -43,6 +43,10 @@
 #include "clist.h"
 #include "mem/mem.h"
 
+/* Script flags */
+static flag_t sflags = 0;
+
+
 int setflag( struct sip_msg* msg, flag_t flag ) {
 	msg->flags |= 1 << flag;
 	return 1;
@@ -72,6 +76,39 @@ int flag_in_range( flag_t flag ) {
 }
 
 
+int setsflagsval(flag_t val)
+{
+	sflags = val;
+	return 1;
+}
+
+
+int setsflag(flag_t flag)
+{
+	sflags |= 1 << flag;
+	return 1;
+}
+
+
+int resetsflag(flag_t flag)
+{
+	sflags &= ~ (1 << flag);
+	return 1;
+}
+
+
+int issflagset(flag_t flag)
+{
+	return (sflags & (1<<flag)) ? 1 : -1;
+}
+
+
+flag_t getsflags(void)
+{
+	return sflags;
+}
+
+
 /* use 2^k */
 #define FLAGS_NAME_HASH_ENTRIES		32
 

+ 20 - 0
flags.h

@@ -43,6 +43,26 @@ int setflag( struct sip_msg* msg, flag_t flag );
 int resetflag( struct sip_msg* msg, flag_t flag );
 int isflagset( struct sip_msg* msg, flag_t flag );
 
+
+/* Script flag functions. Script flags are global flags that keep their
+ * value regardless of the SIP message being processed.
+ */
+
+/* Set the value of all the global flags */
+int setsflagsval(flag_t val);
+
+/* Set the given flag to 1. Parameter flag contains the index of the flag */
+int setsflag(flag_t flag);
+
+/* Reset the given flag to 0. Parameter flag contains the index of the flag */
+int resetsflag(flag_t flag);
+
+/* Returns 1 if the given flag is set and -1 otherwise */
+int issflagset(flag_t flag);
+
+/* Get the value of all the script flags combined */
+flag_t getsflags(void);
+
 int flag_in_range( flag_t flag );
 
 int register_flag(char* name, int pos);

+ 1 - 0
ip_addr.h

@@ -113,6 +113,7 @@ struct socket_info{
 	struct socket_info* prev;
 	unsigned short port_no;  /* port number */
 	char proto; /* tcp or udp*/
+	str sock_str; /* Socket proto, ip, and port as string */
 	struct addr_info* addr_info_lst; /* extra addresses (e.g. SCTP mh) */
 };
 

+ 13 - 2
modules/carrierroute/cr_config.c

@@ -32,6 +32,8 @@
 #include <sys/stat.h>
 #include <unistd.h>
 #include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
 #include "../../mem/shm_mem.h"
 #include "../../mem/mem.h"
 #include "../../ut.h"
@@ -50,8 +52,17 @@
  * @param ap format arguments
  */
 static void conf_error(cfg_t *cfg, const char * fmt, va_list ap) {
-	// FIXME this don't seems to work reliable, produces strange error messages
-	LM_GEN1(L_ERR, (char *) fmt, ap);
+	int ret;
+	static char buf[1024];
+
+	ret = vsnprintf(buf, sizeof(buf), fmt, ap);
+	if (ret < 0 || ret >= sizeof(buf)) {
+		LM_ERR("could not print error message\n");
+	} else {
+		// FIXME this don't seems to work reliable in all cases, charset 
+		// problems
+		LM_GEN1(L_ERR, "%s", buf);
+	}
 }
 
 

+ 3 - 0
modules/tm/config.c

@@ -66,6 +66,7 @@ struct cfg_group_tm	default_tm_cfg = {
 	MAX_NONINV_LIFETIME,	/* tm_max_noninv_lifetime */
 	1,	/* noisy_ctimer */
 	1,	/* tm_auto_inv_100 */
+	"trying -- your call is important to us",	/* tm_auto_inv_100_r */
 	500,	/* tm_unix_tx_timeout -- 500 ms by default */
 	1,	/* restart_fr_on_each_reply */
 	0,	/* pass_provisional_replies */
@@ -126,6 +127,8 @@ cfg_def_t	tm_cfg_def[] = {
 		"will be always replied"},
 	{"auto_inv_100",	CFG_VAR_INT,	0, 1, 0, 0,
 		"automatically send 100 to an INVITE"},
+	{"auto_inv_100_reason",	CFG_VAR_STRING,	0, 0, 0, 0,
+		"reason text of the automatically send 100 to an INVITE"},   
 	{"unix_tx_timeout",	CFG_VAR_INT,	0, 0, 0, 0,
 		"Unix socket transmission timeout, in milliseconds"},
 	{"restart_fr_on_each_reply",	CFG_VAR_INT,	0, 1, 0, 0,

+ 1 - 0
modules/tm/config.h

@@ -111,6 +111,7 @@ struct cfg_group_tm {
 	unsigned int	tm_max_noninv_lifetime;
 	int	noisy_ctimer;
 	int	tm_auto_inv_100;
+	char	*tm_auto_inv_100_r;	
 	int	tm_unix_tx_timeout;
 	int	restart_fr_on_each_reply;
 	int	pass_provisional_replies;

+ 2 - 0
modules/tm/dlg.h

@@ -35,6 +35,7 @@
 
 #include <stdio.h>
 #include "../../str.h"
+#include "../../ip_addr.h"
 #include "../../parser/parse_rr.h"
 #include "../../parser/msg_parser.h"
 
@@ -118,6 +119,7 @@ typedef struct dlg {
 				 * can be reused when building a message (to
 				 * prevent repeated analyzing of the dialog data
 				 */
+	struct socket_info* send_sock;
 #ifdef DIALOG_CALLBACKS
 	struct tmcb_head_list dlg_callbacks;
 #endif

+ 23 - 2
modules/tm/doc/params.xml

@@ -332,8 +332,8 @@ modparam("tm", "restart_fr_on_each_reply", 0)
 		Default value is 1 (on).
 	</para>
 	<para>
-		See also:
-				<function>t_set_auto_inv_100()</function>.
+		See also: <function>t_set_auto_inv_100()</function>
+				  <varname>auto_inv_100_reason</varname>. 
 	</para>
 	<example>
 		<title>Set <varname>auto_inv_100</varname> parameter</title>
@@ -345,6 +345,27 @@ modparam("tm", "auto_inv_100", 0)
 	</example>
 	</section>
 
+	<section id="auto_inv_100_reason">
+	<title><varname>auto_inv_100_reason</varname> (string)</title>
+	<para>
+		Set reason text of the automatically send 100 to an INVITE.
+	</para>
+	<para>
+		Default value is "trying -- your call is important to us".
+	</para>
+	<para>
+		See also: <varname>auto_inv_100</varname>.
+	</para>
+	<example>
+		<title>Set <varname>auto_inv_100_reason</varname> parameter</title>
+		<programlisting>
+...
+modparam("tm", "auto_inv_100_reason", "Trying")
+...
+	    </programlisting>
+	</example>
+	</section>
+
 	<section id="unix_tx_timeout">
 	<title><varname>unix_tx_timeout</varname> (integer)</title>
 	<para>

+ 18 - 0
modules/tm/sip_msg.c

@@ -487,6 +487,9 @@ struct sip_msg*  sip_msg_cloner( struct sip_msg *org_msg, int *sip_msg_len )
 		case HDR_DATE_T:
 		case HDR_IDENTITY_T:
 		case HDR_IDENTITY_INFO_T:
+		case HDR_PPI_T:
+		case HDR_PAI_T:
+		case HDR_PATH_T:
 			/* we ignore them for now even if they have something parsed*/
 			break;
 		}/*switch*/
@@ -874,6 +877,21 @@ struct sip_msg*  sip_msg_cloner( struct sip_msg *org_msg, int *sip_msg_len )
 				new_msg->sipifmatch = new_hdr;
 			}
 			break;
+		case HDR_PPI_T:
+			if (!HOOK_SET(ppi)) {
+				new_msg->ppi = new_hdr;
+			}
+			break;
+		case HDR_PAI_T:
+			if (!HOOK_SET(pai)) {
+				new_msg->pai = new_hdr;
+			}
+			break;
+		case HDR_PATH_T:
+			if (!HOOK_SET(path)) {
+				new_msg->path = new_hdr;
+			}
+			break;
 		}/*switch*/
 
 		if ( last_hdr )

+ 1 - 1
modules/tm/t_cancel.c

@@ -392,7 +392,7 @@ int cancel_b_flags_get(unsigned int* f, int m)
 
 /* fixup function for the default cancel branch method/flags
  * (called by the configuration framework) */
-int cancel_b_flags_fixup(void* handle, str* name, void** val)
+int cancel_b_flags_fixup(void* handle, str* gname, str* name, void** val)
 {
 	unsigned int m,f;
 	int ret;

+ 1 - 1
modules/tm/t_cancel.h

@@ -115,7 +115,7 @@ inline short static should_cancel_branch( struct cell *t, int b, int noreply )
 
 const char* rpc_cancel_doc[2];
 void rpc_cancel(rpc_t* rpc, void* c);
-int cancel_b_flags_fixup(void* handle, str* name, void** val);
+int cancel_b_flags_fixup(void* handle, str* gname, str* name, void** val);
 int cancel_b_flags_get(unsigned int* f, int m);
 
 #endif

+ 1 - 1
modules/tm/t_funcs.c

@@ -324,7 +324,7 @@ int t_relay_to( struct sip_msg  *p_msg , struct proxy_l *proxy, int proto,
 	{
 		DBG( "SER: new INVITE\n");
 		if (!t_reply( t, p_msg , 100 ,
-			"trying -- your call is important to us"))
+			cfg_get(tm, tm_cfg, tm_auto_inv_100_r)))
 				DBG("SER: ERROR: t_reply (100)\n");
 	} 
 

+ 1 - 1
modules/tm/t_fwd.c

@@ -1299,7 +1299,7 @@ int t_replicate(struct sip_msg *p_msg,  struct proxy_l *proxy, int proto )
 }
 
 /* fixup function for reparse_on_dns_failover modparam */
-int reparse_on_dns_failover_fixup(void *handle, str *name, void **val)
+int reparse_on_dns_failover_fixup(void *handle, str *gname, str *name, void **val)
 {
 #ifdef USE_DNS_FAILOVER
 	if ((int)(long)(*val) && mhomed) {

+ 1 - 1
modules/tm/t_fwd.h

@@ -76,7 +76,7 @@ int t_send_branch( struct cell *t, int branch, struct sip_msg* p_msg ,
 					struct proxy_l * proxy, int lock_replies);
 int t_relay_cancel(struct sip_msg* p_msg);
 
-int reparse_on_dns_failover_fixup(void *handle, str *name, void **val);
+int reparse_on_dns_failover_fixup(void *handle, str *gname, str *name, void **val);
 
 #endif
 

+ 13 - 0
modules/tm/t_reply.c

@@ -170,6 +170,19 @@ static unsigned short resp_class_prio[]={
 };
 
 
+int t_get_reply_totag(struct sip_msg *msg, str *totag)
+{
+	if(msg==NULL || totag==NULL) {
+		return -1;
+	}
+
+    calc_crc_suffix(msg, tm_tag_suffix);
+	*totag = tm_tag;
+	
+	return 1;
+}
+
+
 
 /* we store the reply_route # in private memory which is
    then processed during t_relay; we cannot set this value

+ 3 - 0
modules/tm/t_reply.h

@@ -73,6 +73,9 @@ typedef int (*treply_wb_f)( struct cell* trans,
 /* wrapper function needed after changes in w_t_reply */
 int w_t_reply_wrp(struct sip_msg *m, unsigned int code, char *txt);
 
+typedef int (*tget_reply_totag_f)(struct sip_msg *, str *);
+int t_get_reply_totag(struct sip_msg *msg, str *totag);
+
 #define LOCK_REPLIES(_t) lock(&(_t)->reply_mutex )
 #define UNLOCK_REPLIES(_t) unlock(&(_t)->reply_mutex )
 

+ 1 - 1
modules/tm/timer.c

@@ -233,7 +233,7 @@ error:
 /* fixup function for the timer values
  * (called by the configuration framework)
  */
-int timer_fixup(void *handle, str *name, void **val)
+int timer_fixup(void *handle, str *gname, str *name, void **val)
 {
 	ticks_t	t;
 

+ 1 - 1
modules/tm/timer.h

@@ -79,7 +79,7 @@ extern struct msgid_var user_noninv_max_lifetime;
 
 
 extern int tm_init_timers();
-int timer_fixup(void *handle, str *name, void **val);
+int timer_fixup(void *handle, str *gname, str *name, void **val);
 
 ticks_t wait_handler(ticks_t t, struct timer_ln *tl, void* data);
 ticks_t retr_buf_handler(ticks_t t, struct timer_ln *tl, void* data);

+ 3 - 1
modules/tm/tm.c

@@ -90,7 +90,8 @@
  *               t_relay_to_{udp,tcp,tls}(<no param>) (force protocol, but 
  *               forward to uri)  (andrei)
  *  2008-08-11  sctp support: t_relay_to_sctp, t_replicate_sctp,
- *               t_forward_nonack_sctp (andrei
+ *               t_forward_nonack_sctp (andrei)
+ *  2009-03-18  added a new param: auto_inv_100_reason (aheise) 
  */
 
 
@@ -425,6 +426,7 @@ static param_export_t params[]={
 	{"max_noninv_lifetime", PARAM_INT, &default_tm_cfg.tm_max_noninv_lifetime},
 	{"noisy_ctimer",        PARAM_INT, &default_tm_cfg.noisy_ctimer          },
 	{"auto_inv_100",        PARAM_INT, &default_tm_cfg.tm_auto_inv_100       },
+	{"auto_inv_100_reason", PARAM_STRING, &default_tm_cfg.tm_auto_inv_100_r  },    
 	{"unix_tx_timeout",     PARAM_INT, &default_tm_cfg.tm_unix_tx_timeout    },
 	{"restart_fr_on_each_reply", PARAM_INT,
 									&default_tm_cfg.restart_fr_on_each_reply},

+ 2 - 0
modules/tm/tm_load.c

@@ -225,5 +225,7 @@ int load_tm( struct tm_binds *tmb)
 		LOG( L_ERR, LOAD_ERROR "'t_continue' not found\n");
 		return -1;
 	}
+
+	tmb->t_get_reply_totag = t_get_reply_totag;
 	return 1;
 }

+ 1 - 0
modules/tm/tm_load.h

@@ -132,6 +132,7 @@ struct tm_binds {
 #endif
 	t_suspend_f	t_suspend;
 	t_continue_f	t_continue;
+	tget_reply_totag_f t_get_reply_totag;
 };
 
 extern int tm_init;

+ 42 - 12
msg_translator.c

@@ -163,7 +163,7 @@ static unsigned int global_req_flags=0;
 /** per process fixup function for global_req_flags.
   * It should be called from the configuration framework.
   */
-void fix_global_req_flags( str* name)
+void fix_global_req_flags(str* gname, str* name)
 {
 	global_req_flags=0;
 	switch(cfg_get(core, core_cfg, udp_mtu_try_proto)){
@@ -1359,6 +1359,10 @@ static inline int adjust_clen(struct sip_msg* msg, int body_delta, int proto)
 	struct lump* anchor;
 	char* clen_buf;
 	int clen_len, body_only;
+#ifdef USE_TCP
+	char* body;
+	int comp_clen;
+#endif /* USE_TCP */
 
 	/* Calculate message length difference caused by lumps modifying message
 	 * body, from this point on the message body must not be modified. Zero
@@ -1380,7 +1384,7 @@ static inline int adjust_clen(struct sip_msg* msg, int body_delta, int proto)
 			LOG(L_ERR, "adjust_clen: error parsing content-length\n");
 			goto error;
 		}
-		if (msg->content_length==0){
+		if (unlikely(msg->content_length==0)){
 			/* not present, we need to add it */
 			/* msg->unparsed should point just before the final crlf
 			 * - whole message was parsed by the above parse_headers
@@ -1392,12 +1396,37 @@ static inline int adjust_clen(struct sip_msg* msg, int body_delta, int proto)
 				goto error;
 			}
 			body_only=0;
+		}else{
+			/* compute current content length and compare it with the
+			   one in the message */
+			body=get_body(msg);
+			if (unlikely(body==0)){
+				ser_error=E_BAD_REQ;
+				LOG(L_ERR, "adjust_clen: no message body found"
+						" (missing crlf?)");
+				goto error;
+			}
+			comp_clen=msg->len-(int)(body-msg->buf)+body_delta;
+			if (comp_clen!=(int)(long)msg->content_length->parsed){
+				/* note: we don't distinguish here between received with
+				   wrong content-length and content-length changed, we just
+				   fix it automatically in both cases (the reason being
+				   that an error message telling we have received a msg-
+				   with wrong content-length is of very little use) */
+				anchor = del_lump(msg, msg->content_length->body.s-msg->buf,
+									msg->content_length->body.len,
+									HDR_CONTENTLENGTH_T);
+				if (anchor==0) {
+					LOG(L_ERR, "adjust_clen: Can't remove original"
+								" Content-Length\n");
+					goto error;
+				}
+				body_only=1;
+			}
 		}
-	}
-#endif
-
-
-	if ((anchor==0) && body_delta){
+	}else
+#endif /* USE_TCP */
+	if (body_delta){
 		if (parse_headers(msg, HDR_CONTENTLENGTH_F, 0) == -1) {
 			LOG(L_ERR, "adjust_clen: Error parsing Content-Length\n");
 			goto error;
@@ -1421,13 +1450,14 @@ static inline int adjust_clen(struct sip_msg* msg, int body_delta, int proto)
 					goto error;
 				}
 				body_only=0;
-			}else{
-				DBG("adjust_clen: UDP packet with no clen => not adding one \n");
-			}
+			} /* else
+				DBG("adjust_clen: UDP packet with no clen => "
+						"not adding one \n"); */
 		}else{
 			/* Content-Length has been found, remove it */
 			anchor = del_lump(	msg, msg->content_length->body.s - msg->buf,
-								msg->content_length->body.len, HDR_CONTENTLENGTH_T);
+								msg->content_length->body.len,
+								HDR_CONTENTLENGTH_T);
 			if (anchor==0) {
 				LOG(L_ERR, "adjust_clen: Can't remove original"
 							" Content-Length\n");
@@ -1443,7 +1473,7 @@ static inline int adjust_clen(struct sip_msg* msg, int body_delta, int proto)
 					HDR_CONTENTLENGTH_T) == 0)
 			goto error;
 	}
-
+	
 	return 0;
 error:
 	if (clen_buf) pkg_free(clen_buf);

+ 1 - 1
msg_translator.h

@@ -150,6 +150,6 @@ char * build_all( struct sip_msg* msg, int adjust_clen,
 			struct dest_info* send_info);
 
 /** cfg framework fixup */
-void fix_global_req_flags( str* name);
+void fix_global_req_flags(str* gname, str* name);
 
 #endif

+ 41 - 0
parser/case_path.h

@@ -0,0 +1,41 @@
+/* 
+ * $Id$ 
+ *
+ * Path Header Field Name Parsing Macros
+ *
+ * Copyright (C) 2009 iptelorg GmbH
+ *
+ * This file is part of ser, a free SIP server.
+ *
+ * ser is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * For a license to use the ser software under conditions
+ * other than those described here, or to purchase support for this
+ * software, please contact iptel.org by e-mail at the following addresses:
+ *    [email protected]
+ *
+ * ser is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+
+#ifndef CASE_PATH_H
+#define CASE_PATH_H
+
+
+#define path_CASE				\
+	hdr->type = HDR_PATH_T;		\
+	p += 4;						\
+	goto dc_end
+
+
+#endif /* CASE_PATH_H */

+ 2 - 2
parser/contact/contact.c

@@ -246,7 +246,7 @@ int parse_contacts(str* _s, contact_t** _c)
 			c->q = hooks.contact.q;
 			c->expires = hooks.contact.expires;
 			c->received = hooks.contact.received;
-			c->method = hooks.contact.method;
+			c->methods = hooks.contact.methods;
 			c->instance = hooks.contact.instance;
 
 			if (_s->len == 0) goto ok;
@@ -315,7 +315,7 @@ void print_contacts(FILE* _o, contact_t* _c)
 		fprintf(_o, "q       : %p\n", ptr->q);
 		fprintf(_o, "expires : %p\n", ptr->expires);
 		fprintf(_o, "received: %p\n", ptr->received);
-		fprintf(_o, "method  : %p\n", ptr->method);
+		fprintf(_o, "methods  : %p\n", ptr->methods);
 		fprintf(_o, "instance: %p\n", ptr->instance);
 		fprintf(_o, "len     : %d\n", ptr->len);
 		if (ptr->params) {

+ 1 - 1
parser/contact/contact.h

@@ -48,7 +48,7 @@ typedef struct contact {
 	str uri;                /* contact uri */
 	param_t* q;             /* q parameter hook */
 	param_t* expires;       /* expires parameter hook */
-	param_t* method;        /* method parameter hook */
+	param_t* methods;       /* methods parameter hook */
 	param_t* received;      /* received parameter hook */
 	param_t* instance;      /* sip.instance parameter hook */
 	param_t* params;        /* List of all parameters */

+ 3 - 0
parser/hf.c

@@ -52,6 +52,7 @@
 #include "parse_subscription_state.h"
 #include "contact/parse_contact.h"
 #include "parse_disposition.h"
+#include "parse_allow.h"
 #include "../ut.h"
 
 
@@ -138,6 +139,7 @@ void clean_hdr_field(struct hdr_field* hf)
 			break;
 
 		case HDR_ALLOW_T:
+			free_allow_header(hf);
 			break;
 
 		case HDR_EVENT_T:
@@ -211,6 +213,7 @@ void clean_hdr_field(struct hdr_field* hf)
 		case HDR_REQUESTDISPOSITION_T:
 		case HDR_WWW_AUTHENTICATE_T:
 		case HDR_PROXY_AUTHENTICATE_T:
+		case HDR_PATH_T:
 			break;
 		default:
 			LOG(L_CRIT, "BUG: clean_hdr_field: unknown header type %d\n",

+ 2 - 0
parser/hf.h

@@ -109,6 +109,7 @@ enum _hdr_types_t {
 	HDR_RETRY_AFTER_T		           /* Retry-After header field */,
 	HDR_PPI_T                          /**< P-Preferred-Identity header field */,
 	HDR_PAI_T                          /**< P-Asserted-Identity header field */,
+	HDR_PATH_T                         /**< Path header field */,
 	HDR_EOH_T					       /* End of message header */
 };
 
@@ -178,6 +179,7 @@ typedef unsigned long long hdr_flags_t;
 #define HDR_RETRY_AFTER_F			HDR_F_DEF(RETRY_AFTER)
 #define HDR_PPI_F                   HDR_F_DEF(PPI)
 #define HDR_PAI_F                   HDR_F_DEF(PAI)
+#define HDR_PATH_F                  HDR_F_DEF(PATH)
 
 #define HDR_OTHER_F					HDR_F_DEF(OTHER)
 

+ 1 - 0
parser/keys.h

@@ -108,6 +108,7 @@
 #define _iden_ 0x6e656469   /* "iden" */
 #define _tity_ 0x79746974   /* "tity" */
 #define _info_ 0x6f666e69   /* "info" */
+#define _path_ 0x68746170   /* "path" */
 
 #define _pt_l_ 0x6c2d7470   /* "pt-l" */
 #define _angu_ 0x75676e61   /* "angu" */

+ 27 - 0
parser/msg_parser.c

@@ -241,6 +241,7 @@ char* get_hdr_field(char* buf, char* end, struct hdr_field* hdr)
 		case HDR_REQUESTDISPOSITION_T:
 		case HDR_WWW_AUTHENTICATE_T:
 		case HDR_PROXY_AUTHENTICATE_T:
+	    case HDR_PATH_T:
 		case HDR_OTHER_T:
 			/* just skip over it */
 			hdr->body.s=tmp;
@@ -516,6 +517,10 @@ int parse_headers(struct sip_msg* msg, hdr_flags_t flags, int next)
 				if (msg->identity_info==0) msg->identity_info=hf;
 				msg->parsed_flag|=HDR_IDENTITY_INFO_F;
 				break;
+		    case HDR_PATH_T:
+				if (msg->path==0) msg->path=hf;
+				msg->parsed_flag|=HDR_PATH_F;
+				break;
 			default:
 				LOG(L_CRIT, "BUG: parse_headers: unknown header type %d\n",
 							hf->type);
@@ -738,3 +743,25 @@ void reset_dst_uri(struct sip_msg* msg)
 	msg->dst_uri.s = 0;
 	msg->dst_uri.len = 0;
 }
+
+
+struct hdr_field* get_hdr(struct sip_msg *msg, enum _hdr_types_t ht)
+{
+	struct hdr_field *hdr;
+
+	for(hdr = msg->headers; hdr; hdr = hdr->next) {
+		if(hdr->type == ht) return hdr;
+	}
+	return NULL;
+}
+
+
+struct hdr_field* next_sibling_hdr(struct hdr_field *hf)
+{	
+	struct hdr_field *hdr;
+	
+	for(hdr = hf->next; hdr; hdr = hdr->next) {
+		if(hdr->type == hf->type) return hdr;
+	}
+	return NULL;
+}

+ 4 - 0
parser/msg_parser.h

@@ -257,6 +257,7 @@ typedef struct sip_msg {
 	struct hdr_field* identity_info;
 	struct hdr_field* pai;
 	struct hdr_field* ppi;
+	struct hdr_field* path;
 
 	char* eoh;        /* pointer to the end of header (if found) or null */
 	char* unparsed;   /* here we stopped parsing*/
@@ -410,4 +411,7 @@ int set_dst_uri(struct sip_msg* msg, str* uri);
 /* If the dst_uri is set to an URI then reset it */
 void reset_dst_uri(struct sip_msg* msg);
 
+struct hdr_field* get_hdr(struct sip_msg *msg, enum _hdr_types_t ht);
+struct hdr_field* next_sibling_hdr(struct hdr_field *hf);
+
 #endif

+ 65 - 18
parser/parse_allow.c

@@ -43,41 +43,88 @@
  */
 int parse_allow_header(struct hdr_field* _hf)
 {
-	unsigned int* methods;
-	
+	struct allow_body* ab = 0;
+
 	if (!_hf) {
 		LOG(L_ERR, "parse_allow_header: Invalid parameter value\n");
 		return -1;
 	}
 	
-	     /* maybe the header is already parsed! */
+	/* maybe the header is already parsed! */
  	if (_hf->parsed) {
  		return 0;
 	}
 
-	     /* bad luck! :-( - we have to parse it */
-	methods = pkg_malloc(sizeof(unsigned int));
- 	if (methods == 0) {
- 		LOG(L_ERR, "ERROR:parse_allow_header: Out of pkg_memory\n");
- 		return -1;
- 	}
+	ab = (struct allow_body*)pkg_malloc(sizeof(struct allow_body));
+	if (ab == 0) {
+		LOG(L_ERR, "ERROR:parse_allow_header: out of pkg_memory\n");
+		return -1;
+	}
+	memset(ab,'\0', sizeof(struct allow_body));
+	
+	if (parse_methods(&(_hf->body), &(ab->allow)) !=0 ) {
+		LOG(L_ERR, "ERROR:parse_allow_header: bad allow body header\n");		
+		goto error;
+	}
+	
+	ab->allow_all = 0;	
+	_hf->parsed = (void*)ab;
+ 	return 0;
+
+error:
+	if (ab) pkg_free(ab);
+	return -1;
+}
+
+/*!
+ * \brief This method is used to parse all Allow HF body.
+ * \param msg sip msg
+ * \return 0 on success,-1 on failure.
+ */
+int parse_allow(struct sip_msg *msg)
+{       
+	unsigned int allow;
+	struct hdr_field  *hdr;
+
+	/* maybe the header is already parsed! */
+	if (msg->allow && msg->allow->parsed) {
+		return 0;
+	}
 
-	if (!parse_methods(&(_hf->body), methods)) {
- 		LOG(L_ERR, "ERROR:parse_allow_header: Bad allow header\n"); 
- 		pkg_free(methods);
+	/* parse to the end in order to get all ALLOW headers */
+	if (parse_headers(msg,HDR_EOH_F,0)==-1 || !msg->allow) {
 		return -1;
- 	}
+	}
+	allow = 0;
 
- 	_hf->parsed = methods;
- 	return 0;
+	for(hdr = msg->allow ; hdr ; hdr = next_sibling_hdr(hdr)) {
+		if (hdr->parsed == 0) {
+			if(parse_allow_header(hdr) < 0) {
+				return -1;
+			}
+		}
+
+		allow |= ((struct allow_body*)hdr->parsed)->allow;
+	}
+	
+	((struct allow_body*)msg->allow->parsed)->allow_all = allow;
+    return 0;
 }
 
 
 /*
  * Release memory
  */
-void free_allow(unsigned int** _methods)
+void free_allow_body(struct allow_body **ab)
+{
+	if (ab && *ab) {	
+		pkg_free(*ab);		
+		*ab = 0;
+	}
+}
+
+
+void free_allow_header(struct hdr_field* hf)
 {
-	if (_methods && *_methods) pkg_free(*_methods);
-	*_methods = 0;
+	free_allow_body((struct allow_body**)(void*)(&(hf->parsed)));
 }

+ 24 - 4
parser/parse_allow.h

@@ -29,23 +29,43 @@
 #define PARSE_ALLOW_H
  
 #include "hf.h"
+#include "msg_parser.h"
 
  
 /* 
- * casting macro for accessing RPID body 
+ * casting macro for accessing Allow body 
  */
-#define get_allow_methods(p_msg) (unsigned int)(p_msg)->allow->parsed)
+#define get_allow_methods(p_msg)							\
+	(((struct allow_body*)(p_msg)->allow->parsed)->allow_all)
+
+
+struct allow_body {
+	unsigned int allow;     /* allow mask for the current hdr */
+	unsigned int allow_all; /* allow mask for the all allow hdr - it's
+							 * set only for the first hdr in sibling
+							 * list*/
+};
+
+
+/*
+ * Parse all Allow HFs
+ */
+int parse_allow(struct sip_msg *msg);
 
 
 /*
  * Parse Allow HF body
  */
-int parse_allow(struct hdr_field* _h);
+int parse_allow_header(struct hdr_field* _h);
 
 
 /*
  * Release memory
  */
-void free_allow(unsigned int** _methods);
+void free_allow_body(struct allow_body **ab);
+
+void free_allow_header(struct hdr_field* hf);
+
+
 
 #endif /* PARSE_ALLOW_H */

+ 7 - 0
parser/parse_cseq.c

@@ -36,6 +36,7 @@
 #include "parser_f.h"  /* eat_space_end and so on */
 #include "../dprint.h"
 #include "parse_def.h"
+#include "parse_methods.h"
 #include "../mem/mem.h"
 
 /*
@@ -72,6 +73,12 @@ char* parse_cseq(char *buf, char* end, struct cseq_body* cb)
 	t=m_end;
 	cb->method.len=t-cb->method.s;
 
+	/* Cache method id */
+	if (parse_method(&cb->method, &cb->method_id) == 0) {
+		LOG(L_ERR, "ERROR: parse_cseq: Cannot parse method string\n");
+		goto error;
+	}
+
 	/* there may be trailing LWS 
 	 * (it was not my idea to put it in SIP; -jiri )
 	 */

+ 1 - 0
parser/parse_cseq.h

@@ -36,6 +36,7 @@ struct cseq_body{
 	int error;  /* Error code */
 	str number; /* CSeq number */
 	str method; /* Associated method */
+	unsigned int method_id; /* Associated method ID */
 };
 
 

+ 62 - 39
parser/parse_event.c

@@ -44,18 +44,19 @@
 #include <stdio.h>         /* printf */
 #include "../ut.h"
 
-
-#define PRES_STR "presence"
-#define PRES_STR_LEN 8
-
-#define PRES_WINFO_STR "presence.winfo"
-#define PRES_WINFO_STR_LEN 14
-
-#define PRES_XCAP_CHANGE_STR "xcap-change"
-#define PRES_XCAP_CHANGE_STR_LEN 11
-
-#define PRES_SIP_PROFILE_STR "sip-profile"
-#define PRES_SIP_PROFILE_STR_LEN 11
+static struct {
+	str name;
+	int type;	
+} events[] = {
+	{STR_STATIC_INIT("presence"),        EVENT_PRESENCE},
+	{STR_STATIC_INIT("presence.winfo"),  EVENT_PRESENCE_WINFO},
+	{STR_STATIC_INIT("xcap-change"),     EVENT_XCAP_CHANGE},
+	{STR_STATIC_INIT("sip-profile"),     EVENT_SIP_PROFILE},
+	{STR_STATIC_INIT("message-summary"), EVENT_MESSAGE_SUMMARY},
+	{STR_STATIC_INIT("dialog"),          EVENT_DIALOG},
+	/* The following must be the last element in the array */
+	{STR_NULL,                           EVENT_OTHER}
+};
 
 
 static inline char* skip_token(char* _b, int _l)
@@ -77,41 +78,58 @@ static inline char* skip_token(char* _b, int _l)
 }
 
 
-static inline int event_parser(char* _s, int _l, event_t* _e)
+int event_parser(char* s, int len, event_t* e)
 {
+	int i;
 	str tmp;
 	char* end;
+	param_hooks_t* phooks = NULL;
+	enum pclass pclass = CLASS_ANY;
 
-	tmp.s = _s;
-	tmp.len = _l;
+	if (e == NULL) {
+		ERR("event_parser: Invalid parameter value\n");
+		return -1;
+	}
 
+	tmp.s = s;
+	tmp.len = len;
 	trim_leading(&tmp);
 
 	if (tmp.len == 0) {
-		LOG(L_ERR, "event_parser(): Empty body\n");
+		LOG(L_ERR, "event_parser: Empty body\n");
 		return -1;
 	}
 
-	_e->text.s = tmp.s;
-
+	e->name.s = tmp.s;
 	end = skip_token(tmp.s, tmp.len);
+	e->name.len = end - tmp.s;
+
+	e->type = EVENT_OTHER;
+	for(i = 0; events[i].name.len; i++) {
+		if (e->name.len == events[i].name.len &&
+			!strncasecmp(e->name.s, events[i].name.s, e->name.len)) {
+			e->type = events[i].type;
+			break;
+		}
+	}
+
+	tmp.len -= end - tmp.s;
+	tmp.s = end;
+	trim_leading(&tmp);
+
+	if (tmp.s[0] == ';') {
+		/* We have parameters to parse */
+		if (e->type == EVENT_DIALOG) {
+			pclass = CLASS_EVENT_DIALOG;
+			phooks = (param_hooks_t*)&e->params.dialog;
+		}
 
-	_e->text.len = end - tmp.s;
-
-	if ((_e->text.len == PRES_STR_LEN) && 
-	    !strncasecmp(PRES_STR, tmp.s, _e->text.len)) {
-		_e->parsed = EVENT_PRESENCE;
-	} else if ((_e->text.len == PRES_XCAP_CHANGE_STR_LEN) && 
-		   !strncasecmp(PRES_XCAP_CHANGE_STR, tmp.s, _e->text.len)) {
-		_e->parsed = EVENT_XCAP_CHANGE;
-	} else if ((_e->text.len == PRES_WINFO_STR_LEN) && 
-		   !strncasecmp(PRES_WINFO_STR, tmp.s, _e->text.len)) {
-		_e->parsed = EVENT_PRESENCE_WINFO;
-	} else if ((_e->text.len == PRES_SIP_PROFILE_STR_LEN) && 
-		   !strncasecmp(PRES_SIP_PROFILE_STR, tmp.s, _e->text.len)) {
-		_e->parsed = EVENT_SIP_PROFILE;
+		if (parse_params(&tmp, pclass, phooks, &e->params.list) < 0) {
+			ERR("event_parser: Error while parsing parameters parameters\n");
+			return -1;
+		}
 	} else {
-		_e->parsed = EVENT_OTHER;
+		e->params.list = NULL;
 	}
 
 	return 0;
@@ -153,19 +171,24 @@ int parse_event(struct hdr_field* _h)
  */
 void free_event(event_t** _e)
 {
-	if (*_e) pkg_free(*_e);
-	*_e = 0;
+	if (*_e) {
+		if ((*_e)->params.list) free_params((*_e)->params.list);
+		pkg_free(*_e);
+		*_e = NULL;
+	}
 }
 
 
 /*
  * Print structure, for debugging only
  */
-void print_event(event_t* _e)
+void print_event(event_t* e)
 {
 	printf("===Event===\n");
-	printf("text  : \'%.*s\'\n", _e->text.len, ZSW(_e->text.s));
-	printf("parsed: %s\n", 
-	       (_e->parsed == EVENT_PRESENCE) ? ("EVENT_PRESENCE") : ("EVENT_OTHER"));
+	printf("name  : \'%.*s\'\n", STR_FMT(&e->name));
+	printf("type: %d\n", e->type);
+	if (e->params.list) {
+		print_params(stdout, e->params.list);
+	}
 	printf("===/Event===\n");
 }

+ 26 - 16
parser/parse_event.h

@@ -1,12 +1,6 @@
 /*
  * $Id$
  *
- * Event header field body parser
- * This parser was written for Presence Agent module only.
- * it recognizes presence package only, no subpackages, no parameters
- * It should be replaced by a more generic parser if subpackages or
- * parameters should be parsed too.
- *
  * Copyright (C) 2001-2003 FhG Fokus
  *
  * This file is part of ser, a free SIP server.
@@ -37,35 +31,51 @@
 
 #include "../str.h"
 #include "hf.h"
+#include "parse_param.h"
+
+/* Recognized event types */
+enum event_type {
+	EVENT_OTHER = 0,
+	EVENT_PRESENCE,
+	EVENT_PRESENCE_WINFO,
+	EVENT_SIP_PROFILE,
+	EVENT_XCAP_CHANGE,
+	EVENT_DIALOG,
+	EVENT_MESSAGE_SUMMARY
+};
+
+
+struct event_params {
+	struct event_dialog_hooks dialog; /* Well known dialog package params */
+	param_t* list; /* Linked list of all parsed parameters */
+};
 
-#define EVENT_OTHER          0
-#define EVENT_PRESENCE       1
-#define EVENT_PRESENCE_WINFO 2
-#define EVENT_SIP_PROFILE    3
-#define EVENT_XCAP_CHANGE    4
 
 typedef struct event {
-	str text;       /* Original string representation */
-	int parsed;     /* Parsed variant */
+	enum event_type type; /* Parsed variant */
+	str name;             /* Original string representation */
+	struct event_params params;
 } event_t;
 
 
 /*
  * Parse Event HF body
  */
-int parse_event(struct hdr_field* _h);
+int parse_event(struct hdr_field* hf);
 
 
 /*
  * Release memory
  */
-void free_event(event_t** _e);
+void free_event(event_t** e);
 
 
 /*
  * Print structure, for debugging only
  */
-void print_event(event_t* _e);
+void print_event(event_t* e);
+
+int event_parser(char* s, int l, event_t* e);
 
 
 #endif /* PARSE_EVENT_H */

+ 2 - 0
parser/parse_hname2.c

@@ -98,6 +98,7 @@ static inline char* skip_ws(char* p, unsigned int size)
 #include "case_date.h"     /* Date */
 #include "case_iden.h"     /* Identity, Identity-info */
 #include "case_retr.h"     /* Retry-After */
+#include "case_path.h"     /* Path */
 
 
 #define READ(val) \
@@ -143,6 +144,7 @@ static inline char* skip_ws(char* p, unsigned int size)
 	case _date_: date_CASE; \
 	case _iden_: iden_CASE; \
 	case _retr_: retr_CASE; \
+    case _path_: path_CASE;
 
 
 

+ 1 - 1
parser/parse_methods.c

@@ -49,7 +49,7 @@ static int token_char(char _c)
   * Parse a method pointed by _next, assign its enum bit to _method, and update
   * _next past the method. Returns 1 if parse succeeded and 0 otherwise.
   */
-static int parse_method(str* _next, unsigned int* _method) 
+int parse_method(str* _next, unsigned int* _method) 
  {
 	 if (!_next || !_method) {
 		 LOG(L_ERR, "parse_method: Invalid parameter value\n");

+ 2 - 0
parser/parse_methods.h

@@ -57,5 +57,7 @@ enum method {
  */
 int parse_methods(str* _body, unsigned int* _methods);
 
+int parse_method(str* _next, unsigned int* _method);
+
 
 #endif /* PARSE_METHODS_H */

+ 72 - 6
parser/parse_param.c

@@ -43,9 +43,69 @@
 #include "parse_param.h"
 
 
+static inline void parse_event_dialog_class(param_hooks_t* h, param_t* p)
+{
+
+	if (!p->name.s) {
+		LOG(L_ERR, "ERROR: parse_event_dialog_class: empty value\n");
+		return;
+	}
+	if (!h) {
+		LOG(L_CRIT, "BUG: parse_event_dialog_class: NULL param hook pointer\n");
+		return;
+	}
+	switch(p->name.s[0]) {
+	case 'c':
+	case 'C':
+		if ((p->name.len == 7) &&
+		    (!strncasecmp(p->name.s + 1, "all-id", 6))) {
+			p->type = P_CALL_ID;
+			h->event_dialog.call_id = p;
+		}
+		break;
+
+	case 'f':
+	case 'F':
+		if ((p->name.len == 8) &&
+		    (!strncasecmp(p->name.s + 1, "rom-tag", 7))) {
+			p->type = P_FROM_TAG;
+			h->event_dialog.from_tag = p;
+		}
+		break;
+
+	case 't':
+	case 'T':
+		if ((p->name.len == 6) &&
+		    (!strncasecmp(p->name.s + 1, "o-tag", 5))) {
+			p->type = P_TO_TAG;
+			h->event_dialog.to_tag = p;
+		}
+		break;
+
+	case 'i':
+	case 'I':
+		if ((p->name.len == 27) &&
+		    (!strncasecmp(p->name.s + 1, "nclude-session-description", 26))) {
+			p->type = P_ISD;
+			h->event_dialog.include_session_description = p;
+		}
+		break;
+
+	case 's':
+	case 'S':
+		if ((p->name.len == 3) &&
+		    (!strncasecmp(p->name.s + 1, "la", 2))) {
+			p->type = P_SLA;
+			h->event_dialog.sla = p;
+		}
+		break;
+	}
+}
+
+
 /*
  * Try to find out parameter name, recognized parameters
- * are q, expires and method
+ * are q, expires and methods
  */
 static inline void parse_contact_class(param_hooks_t* _h, param_t* _p)
 {
@@ -78,10 +138,10 @@ static inline void parse_contact_class(param_hooks_t* _h, param_t* _p)
 		
 	case 'm':
 	case 'M':
-		if ((_p->name.len == 6) &&
-		    (!strncasecmp(_p->name.s + 1, "ethod", 5))) {
-			_p->type = P_METHOD;
-			_h->contact.method = _p;
+		if ((_p->name.len == 7) &&
+		    (!strncasecmp(_p->name.s + 1, "ethods", 6))) {
+			_p->type = P_METHODS;
+			_h->contact.methods = _p;
 		}
 		break;
 		
@@ -328,6 +388,7 @@ static inline void parse_param_name(str* _s, pclass_t _c, param_hooks_t* _h, par
 	switch(_c) {
 	case CLASS_CONTACT: parse_contact_class(_h, _p); break;
 	case CLASS_URI:     parse_uri_class(_h, _p);     break;
+	case CLASS_EVENT_DIALOG: parse_event_dialog_class(_h, _p); break;
 	default: break;
 	}
 }
@@ -534,7 +595,7 @@ static inline void print_param(FILE* _o, param_t* _p)
 	case P_OTHER:     type = "P_OTHER";     break;
 	case P_Q:         type = "P_Q";         break;
 	case P_EXPIRES:   type = "P_EXPIRES";   break;
-	case P_METHOD:    type = "P_METHOD";    break;
+	case P_METHODS:   type = "P_METHODS";   break;
 	case P_TRANSPORT: type = "P_TRANSPORT"; break;
 	case P_LR:        type = "P_LR";        break;
 	case P_R2:        type = "P_R2";        break;
@@ -545,6 +606,11 @@ static inline void print_param(FILE* _o, param_t* _p)
 	case P_DSTPORT:   type = "P_DSTPORT";   break;
 	case P_INSTANCE:  type = "P_INSTANCE";  break;
 	case P_FTAG:      type = "P_FTAG";      break;
+	case P_CALL_ID:   type = "P_CALL_ID";   break;
+	case P_FROM_TAG:  type = "P_FROM_TAG";  break;
+	case P_TO_TAG:    type = "P_TO_TAG";    break;
+	case P_ISD:       type = "P_ISD";       break;
+	case P_SLA:       type = "P_SLA";       break;
 	default:          type = "UNKNOWN";     break;
 	}
 	

+ 21 - 6
parser/parse_param.h

@@ -46,7 +46,7 @@ typedef enum ptype {
 	P_OTHER = 0, /* Unknown parameter */
 	P_Q,         /* Contact: q parameter */
 	P_EXPIRES,   /* Contact: expires parameter */
-	P_METHOD,    /* Contact: method parameter */
+	P_METHODS,   /* Contact: methods parameter */
 	P_RECEIVED,  /* Contact: received parameter */
 	P_TRANSPORT, /* URI: transport parameter */
 	P_LR,        /* URI: lr parameter */
@@ -56,7 +56,12 @@ typedef enum ptype {
 	P_DSTIP,     /* URI: dstip parameter */
 	P_DSTPORT,   /* URi: dstport parameter */
 	P_INSTANCE,  /* Contact: sip.instance parameter */
-	P_FTAG       /* URI: ftag parameter */
+	P_FTAG,      /* URI: ftag parameter */
+	P_CALL_ID,   /* Dialog event package: call-id */
+	P_FROM_TAG,  /* Dialog event package: from-tag */
+	P_TO_TAG,    /* Dialog event package: to-tag */
+	P_ISD,       /* Dialog event package: include-session-description */
+	P_SLA        /* Dialog event package: sla */
 } ptype_t;
 
 
@@ -64,9 +69,10 @@ typedef enum ptype {
  * Class of parameters
  */
 typedef enum pclass {
-	CLASS_ANY = 0,  /* Any parameters, well-known hooks will be not used */
-	CLASS_CONTACT,  /* Contact parameters */
-	CLASS_URI       /* URI parameters */
+	CLASS_ANY = 0,      /* Any parameters, well-known hooks will be not used */
+	CLASS_CONTACT,      /* Contact parameters */
+	CLASS_URI,          /* URI parameters */
+	CLASS_EVENT_DIALOG  /* Event dialog parameters */
 } pclass_t;
 
 
@@ -88,7 +94,7 @@ typedef struct param {
 struct contact_hooks {
 	struct param* expires;  /* expires parameter */
 	struct param* q;        /* q parameter */
-	struct param* method;   /* method parameter */
+	struct param* methods;  /* methods parameter */
 	struct param* received; /* received parameter */
 	struct param* instance; /* sip.instance parameter */
 };
@@ -109,12 +115,21 @@ struct uri_hooks {
 };
 
 
+struct event_dialog_hooks {
+	struct param* call_id;
+	struct param* from_tag;
+	struct param* to_tag;
+	struct param* include_session_description;
+	struct param* sla;
+};
+
 /*
  * Union of hooks structures for all classes
  */
 typedef union param_hooks {
 	struct contact_hooks contact; /* Contact hooks */
 	struct uri_hooks uri;         /* URI hooks */
+	struct event_dialog_hooks event_dialog;
 } param_hooks_t;
 
 /**

+ 7 - 1
parser/parse_to.c

@@ -773,7 +773,7 @@ error:
 }
 
 
-void free_to(struct to_body* tb)
+void free_to_params(struct to_body* tb)
 {
 	struct to_param *tp=tb->param_lst;
 	struct to_param *foo;
@@ -782,5 +782,11 @@ void free_to(struct to_body* tb)
 		pkg_free(tp);
 		tp=foo;
 	}
+}
+
+
+void free_to(struct to_body* tb)
+{
+	free_to_params(tb);
 	pkg_free(tb);
 }

+ 1 - 0
parser/parse_to.h

@@ -65,6 +65,7 @@ struct to_body{
  */
 char* parse_to(char* buffer, char *end, struct to_body *to_b);
 
+void free_to_params(struct to_body* tb);
 
 void free_to(struct to_body* tb);
 

+ 4 - 4
parser/parse_uri.c

@@ -1431,10 +1431,10 @@ inline int normalize_tel_user(char* res, str* src) {
 }
 
 
-static str	s_sip  = STR_STATIC_INIT("sip");
-static str	s_sips = STR_STATIC_INIT("sips");
-static str	s_tel  = STR_STATIC_INIT("tel");
-static str	s_tels = STR_STATIC_INIT("tels");
+str	s_sip  = STR_STATIC_INIT("sip");
+str	s_sips = STR_STATIC_INIT("sips");
+str	s_tel  = STR_STATIC_INIT("tel");
+str	s_tels = STR_STATIC_INIT("tels");
 static str	s_null = STR_STATIC_INIT("");
 
 inline void uri_type_to_str(uri_type type, str *s) {

+ 1 - 0
parser/parse_uri.h

@@ -38,6 +38,7 @@
 #include "../parser/msg_parser.h"
 
 
+extern str	s_sip, s_sips, s_tel, s_tels;
 
 /* buf= pointer to begining of uri (sip:[email protected]:5060;a=b?h=i)
  * len= len of uri

+ 1 - 3
pkg/debian/rules

@@ -207,9 +207,7 @@ install: build
 	# install the *.sql files for ser_mysql.sh script
 	cp -f scripts/mysql/*.sql $(CURDIR)/debian/ser/usr/lib/ser/
 	# and fix path to the *.sql files in ser_mysql.sh script
-	sed -i 's#CREATE_SCRIPT=`dirname $$0`"/"$$DEFAULT_CREATE_SCRIPT#CREATE_SCRIPT="/usr/lib/ser/"\$$DEFAULT_CREATE_SCRIPT#' $(CURDIR)/debian/ser/usr/sbin/ser_mysql.sh
-	sed -i 's#DATA_SCRIPT=`dirname $$0`"/"$$DEFAULT_DATA_SCRIPT#DATA_SCRIPT="/usr/lib/ser/"$$DEFAULT_DATA_SCRIPT#' $(CURDIR)/debian/ser/usr/sbin/ser_mysql.sh
-	sed -i 's#DROP_SCRIPT=`dirname $$0`"/"$$DEFAULT_DROP_SCRIPT#DROP_SCRIPT="/usr/lib/ser/"$$DEFAULT_DROP_SCRIPT#' $(CURDIR)/debian/ser/usr/sbin/ser_mysql.sh
+	sed -i 's#DEFAULT_SCRIPT_DIR=.*#DEFAULT_SCRIPT_DIR="/usr/lib/ser/"#' $(CURDIR)/debian/ser/usr/sbin/ser_mysql.sh
 	# install advanced ser config file for ser-oob package
 	mkdir -p $(CURDIR)/debian/ser-oob/etc/ser
 	cp -f etc/ser-oob.cfg $(CURDIR)/debian/ser-oob/etc/ser/

+ 2 - 2
pt.c

@@ -522,7 +522,7 @@ end:
  * Per-child process callback that is called
  * when mem_dump_pkg cfg var is changed.
  */
-void mem_dump_pkg_cb(str *name)
+void mem_dump_pkg_cb(str *gname, str *name)
 {
 	int	old_memlog;
 
@@ -545,7 +545,7 @@ void mem_dump_pkg_cb(str *name)
  * fixup function that is called
  * when mem_dump_shm cfg var is set.
  */
-int mem_dump_shm_fixup(void *handle, str *name, void **val)
+int mem_dump_shm_fixup(void *handle, str *gname, str *name, void **val)
 {
 	int	old_memlog;
 

+ 2 - 2
pt.h

@@ -101,11 +101,11 @@ int fork_tcp_process(int child_id,char *desc,int r,int *reader_fd_1);
 #endif
 
 #ifdef PKG_MALLOC
-void mem_dump_pkg_cb(str *name);
+void mem_dump_pkg_cb(str *gname, str *name);
 #endif
 
 #ifdef SHM_MEM
-int mem_dump_shm_fixup(void *handle, str *name, void **val);
+int mem_dump_shm_fixup(void *handle, str *gname, str *name, void **val);
 #endif
 
 #endif

+ 1 - 1
receive.c

@@ -127,7 +127,7 @@ int receive_msg(char* buf, unsigned int len, struct receive_info* rcv_info)
 
 	if (msg->first_line.type==SIP_REQUEST){
 		if (!IS_SIP(msg)){
-			if (nonsip_msg_run_hooks(msg)!=NONSIP_MSG_ACCEPT);
+			if (nonsip_msg_run_hooks(msg)!=NONSIP_MSG_ACCEPT)
 				goto end; /* drop the message */
 		}
 		/* sanity checks */

+ 4 - 4
resolve.c

@@ -159,7 +159,7 @@ int resolv_init()
  * This function must be called by each child process whenever
  * a resolver option changes
  */
-void resolv_reinit(str *name)
+void resolv_reinit(str *gname, str *name)
 {
 	_resolv_init();
 
@@ -173,14 +173,14 @@ void resolv_reinit(str *name)
 /* fixup function for dns_reinit variable
  * (resets the variable to 0)
  */
-int dns_reinit_fixup(void *handle, str *name, void **val)
+int dns_reinit_fixup(void *handle, str *gname, str *name, void **val)
 {
 	*val = (void *)(long)0;
 	return 0;
 }
 
 /* wrapper function to recalculate the naptr protocol preferences */
-void reinit_naptr_proto_prefs(str *name)
+void reinit_naptr_proto_prefs(str *gname, str *name)
 {
 #ifdef USE_NAPTR
 	init_naptr_proto_prefs();
@@ -190,7 +190,7 @@ void reinit_naptr_proto_prefs(str *name)
 /* fixup function for dns_try_ipv6
  * verifies that SER really listens on an ipv6 interface
  */
-int dns_try_ipv6_fixup(void *handle, str *name, void **val)
+int dns_try_ipv6_fixup(void *handle, str *gname, str *name, void **val)
 {
 	if ((int)(long)(*val) && !(socket_types & SOCKET_T_IPV6)) {
 		LOG(L_ERR, "ERROR: dns_try_ipv6_fixup(): "

+ 4 - 4
resolve.h

@@ -408,10 +408,10 @@ skip_ipv4:
 int resolv_init();
 
 /* callback/fixup functions executed by the configuration framework */
-void resolv_reinit(str *name);
-int dns_reinit_fixup(void *handle, str *name, void **val);
-int dns_try_ipv6_fixup(void *handle, str *name, void **val);
-void reinit_naptr_proto_prefs(str *name);
+void resolv_reinit(str *gname, str *name);
+int dns_reinit_fixup(void *handle, str *gname, str *name, void **val);
+int dns_try_ipv6_fixup(void *handle, str *gname, str *name, void **val);
+void reinit_naptr_proto_prefs(str *gname, str *name);
 
 #ifdef DNS_WATCHDOG_SUPPORT
 /* callback function that is called by the child processes

+ 2 - 1
route_struct.h

@@ -70,7 +70,8 @@ enum { METHOD_O=1, URI_O, FROM_URI_O, TO_URI_O, SRCIP_O, SRCPORT_O,
 
 enum { FORWARD_T=1, SEND_T, DROP_T, LOG_T, ERROR_T, ROUTE_T, EXEC_T,
 		SET_HOST_T, SET_HOSTPORT_T, SET_USER_T, SET_USERPASS_T,
-		SET_PORT_T, SET_URI_T, SET_HOSTPORTTRANS_T,
+		SET_PORT_T, SET_URI_T, SET_HOSTPORTTRANS_T, SET_HOSTALL_T,
+		SET_USERPHONE_T,
 		IF_T, SWITCH_T /* only until fixup*/,
 		BLOCK_T, EVAL_T, SWITCH_JT_T, SWITCH_COND_T, MATCH_COND_T, WHILE_T,
 		MODULE_T, MODULE3_T, MODULE4_T, MODULE5_T, MODULE6_T, MODULEX_T,

+ 1 - 1
scripts/mysql/ser_mysql.sh

@@ -317,7 +317,7 @@ if [ -z "$SQLUSER" ] ; then SQLUSER="$DEFAULT_SQLUSER"; fi;
 if [ -z "$MYSQL" ] ; then MYSQL="$DEFAULT_MYSQL"; fi
 if [ -z "$MYSQLDUMP" ] ; then MYSQLDUMP="$DEFAULT_MYSQLDUMP"; fi
 if [ -z "$DUMP_OPTS" ] ; then DUMP_OPTS="$DEFAULT_DUMP_OPTS"; fi 
-if [ -z "SCRIPT_DIR" ] ; then SCRIPT_DIR="$DEFAULT_SCRIPT_DIR"; fi
+if [ -z "$SCRIPT_DIR" ] ; then SCRIPT_DIR="$DEFAULT_SCRIPT_DIR"; fi
 if [ -z "$CREATE_SCRIPT" ] ; then CREATE_SCRIPT="$DEFAULT_CREATE_SCRIPT"; fi
 if [ -z "$DATA_SCRIPT" ] ; then DATA_SCRIPT="$DEFAULT_DATA_SCRIPT"; fi
 if [ -z "$DROP_SCRIPT" ] ; then DROP_SCRIPT="$DEFAULT_DROP_SCRIPT"; fi

+ 3 - 3
select_core.c

@@ -236,8 +236,8 @@ int select_contact_params_spec(str* res, select_t* s, struct sip_msg* msg)
 		TEST_RET_res_body(c->q);
 	case SEL_PARAM_EXPIRES:
 		TEST_RET_res_body(c->expires);
-	case SEL_PARAM_METHOD:
-		TEST_RET_res_body(c->method);
+	case SEL_PARAM_METHODS:
+		TEST_RET_res_body(c->methods);
 	case SEL_PARAM_RECEIVED:
 		TEST_RET_res_body(c->received);
 	case SEL_PARAM_INSTANCE:
@@ -874,7 +874,7 @@ int select_event(str* res, select_t* s, struct sip_msg* msg)
 		return -1;
 	}
 
-	*res = ((event_t*)msg->event->parsed)->text;
+	*res = ((event_t*)msg->event->parsed)->name;
 	return 0;
 }
 

+ 2 - 2
select_core.h

@@ -41,7 +41,7 @@
 
 enum {
 	SEL_PARAM_TAG, 
-	SEL_PARAM_Q, SEL_PARAM_EXPIRES, SEL_PARAM_METHOD, SEL_PARAM_RECEIVED, SEL_PARAM_INSTANCE, 
+	SEL_PARAM_Q, SEL_PARAM_EXPIRES, SEL_PARAM_METHODS, SEL_PARAM_RECEIVED, SEL_PARAM_INSTANCE, 
 	SEL_PARAM_BRANCH, SEL_PARAM_RPORT, SEL_PARAM_I, SEL_PARAM_ALIAS
        };
 
@@ -251,7 +251,7 @@ static select_row_t select_core[] = {
 	{ select_contact, SEL_PARAM_STR, STR_STATIC_INIT("name"), select_contact_name, 0}, 
 	{ select_contact, SEL_PARAM_STR, STR_STATIC_INIT("q"), select_contact_params_spec, DIVERSION | SEL_PARAM_Q}, 
 	{ select_contact, SEL_PARAM_STR, STR_STATIC_INIT("expires"), select_contact_params_spec, DIVERSION | SEL_PARAM_EXPIRES}, 
-	{ select_contact, SEL_PARAM_STR, STR_STATIC_INIT("method"), select_contact_params_spec, DIVERSION | SEL_PARAM_METHOD}, 
+	{ select_contact, SEL_PARAM_STR, STR_STATIC_INIT("methods"), select_contact_params_spec, DIVERSION | SEL_PARAM_METHODS}, 
 	{ select_contact, SEL_PARAM_STR, STR_STATIC_INIT("received"), select_contact_params_spec, DIVERSION | SEL_PARAM_RECEIVED}, 
 	{ select_contact, SEL_PARAM_STR, STR_STATIC_INIT("instance"), select_contact_params_spec, DIVERSION | SEL_PARAM_INSTANCE}, 	
 	{ select_contact, SEL_PARAM_STR, STR_STATIC_INIT("params"), select_contact_params, CONSUME_NEXT_STR},

+ 39 - 0
socket_info.c

@@ -268,6 +268,7 @@ static void free_sock_info(struct socket_info* si)
 		if(si->address_str.s) pkg_free(si->address_str.s);
 		if(si->port_no_str.s) pkg_free(si->port_no_str.s);
 		if (si->addr_info_lst) free_addr_info_lst(&si->addr_info_lst);
+		if(si->sock_str.s) pkg_free(si->sock_str.s);
 	}
 }
 
@@ -298,6 +299,42 @@ static char* get_proto_name(unsigned short proto)
 }
 
 
+/* Fill si->sock_str with string representing the socket_info structure,
+ * format of the string is 'proto:address:port'. Returns 0 on success and
+ * negative number on failure.
+ */
+static int fix_sock_str(struct socket_info* si)
+{
+	char* p;
+	str proto;
+
+	if (si->sock_str.s) pkg_free(si->sock_str.s);
+	
+	proto.s = get_proto_name(si->proto);
+	proto.len = strlen(proto.s);
+	
+	si->sock_str.len = proto.len + si->address_str.len + 
+		si->port_no_str.len + 2;
+	
+	si->sock_str.s = pkg_malloc(si->sock_str.len + 1);
+	if (si->sock_str.s == NULL) {
+		LOG(L_ERR, "fix_sock_str: No pkg memory left\n");
+		return -1;
+	}
+	p = si->sock_str.s;
+	memcpy(p, proto.s, proto.len);
+	p += proto.len;
+	*p = ':'; p++;
+	memcpy(p, si->address_str.s, si->address_str.len);
+	p += si->address_str.len;
+	*p = ':'; p++;
+	memcpy(p, si->port_no_str.s, si->port_no_str.len);
+	p += si->port_no_str.len;
+	*p = '\0';
+
+	return 0;
+}
+
 
 /* returns 0 if support for the protocol is not compiled or if proto is 
    invalid */
@@ -1028,6 +1065,8 @@ static int fix_socket_list(struct socket_info **list, int* type_flags)
 						&ail->flags, type_flags, si) !=0 )
 				goto error;
 		}
+
+		if (fix_sock_str(si) < 0) goto error;
 		
 #ifdef EXTRA_DEBUG
 		printf("              %.*s [%s]:%s%s\n", si->name.len, 

+ 2 - 0
sr_module.h

@@ -58,6 +58,8 @@
 #ifndef sr_module_h
 #define sr_module_h
 
+#include <dlfcn.h>
+
 #include "parser/msg_parser.h" /* for sip_msg */
 #include "version.h"
 #include "rpc.h"

+ 18 - 8
tcp_conn.h

@@ -54,7 +54,6 @@
 /* maximum number of port aliases x search wildcard possibilities */
 #define TCP_CON_MAX_ALIASES (4*3) 
 
-#define TCP_BUF_SIZE	4096 
 #define TCP_CHILD_TIMEOUT 5 /* after 5 seconds, the child "returns" 
 							 the connection to the tcp master process */
 #define TCP_MAIN_SELECT_TIMEOUT 5 /* how often "tcp main" checks for timeout*/
@@ -89,9 +88,12 @@ enum tcp_req_states {	H_SKIP_EMPTY, H_SKIP_EMPTY_CR_FOUND, H_SKIP_EMPTY_CRLF_FOU
 		H_STUN_MSG, H_STUN_READ_BODY, H_STUN_FP, H_STUN_END, H_PING_CRLF
 	};
 
-enum tcp_conn_states { S_CONN_ERROR=-2, S_CONN_BAD=-1, S_CONN_OK=0, 
-						S_CONN_INIT, S_CONN_EOF, 
-						S_CONN_ACCEPT, S_CONN_CONNECT, S_CONN_PENDING };
+enum tcp_conn_states { S_CONN_ERROR=-2, S_CONN_BAD=-1,
+						S_CONN_OK=0, /* established (write or read) */
+						S_CONN_INIT, /* initial state (invalid) */
+						S_CONN_EOF,
+						S_CONN_ACCEPT, S_CONN_CONNECT
+					};
 
 
 /* fd communication commands */
@@ -104,20 +106,26 @@ enum conn_cmds { CONN_DESTROY=-3, CONN_ERROR=-2, CONN_EOF=-1, CONN_RELEASE,
 struct tcp_req{
 	struct tcp_req* next;
 	/* sockaddr ? */
-	char buf[TCP_BUF_SIZE+1]; /* bytes read so far (+0-terminator)*/
+	char* buf; /* bytes read so far (+0-terminator)*/
 	char* start; /* where the message starts, after all the empty lines are
 					skipped*/
 	char* pos; /* current position in buf */
 	char* parsed; /* last parsed position */
 	char* body; /* body position */
+	unsigned int b_size; /* buffer size-1 (extra space for 0-term)*/
 	int content_len;
-	int has_content_len; /* 1 if content_length was parsed ok*/
-	int complete; /* 1 if one req has been fully read, 0 otherwise*/
+	unsigned short flags; /* F_TCP_REQ_HAS_CLEN | F_TCP_REQ_COMPLETE */
 	int bytes_to_go; /* how many bytes we have still to read from the body*/
 	enum tcp_req_errors error;
 	enum tcp_req_states state;
 };
 
+/* tcp_req flags */
+#define F_TCP_REQ_HAS_CLEN 1
+#define F_TCP_REQ_COMPLETE 2
+
+#define TCP_REQ_HAS_CLEN(tr)  ((tr)->flags & F_TCP_REQ_HAS_CLEN)
+#define TCP_REQ_COMPLETE(tr)  ((tr)->flags & F_TCP_REQ_COMPLETE)
 
 
 struct tcp_connection;
@@ -187,9 +195,11 @@ struct tcp_connection{
 #define tcpconn_put(c) atomic_dec_and_test(&((c)->refcnt))
 
 
-#define init_tcp_req( r) \
+#define init_tcp_req( r, rd_buf, rd_buf_size) \
 	do{ \
 		memset( (r), 0, sizeof(struct tcp_req)); \
+		(r)->buf=(rd_buf) ;\
+		(r)->b_size=(rd_buf_size)-1; /* space for 0 term. */ \
 		(r)->parsed=(r)->pos=(r)->start=(r)->buf; \
 		(r)->error=TCP_REQ_OK;\
 		(r)->state=H_SKIP_EMPTY; \

+ 4 - 0
tcp_init.h

@@ -39,6 +39,10 @@
 										  time, timeout */
 #define DEFAULT_TCP_MAX_CONNECTIONS 2048 /* maximum connections */
 
+#define DEFAULT_TCP_BUF_SIZE	4096  /* buffer size used for reads */
+
+#define DEFAULT_TCP_WBUF_SIZE	2100 /*  after debugging switch to 4-16k */
+
 struct tcp_child{
 	pid_t pid;
 	int proc_no; /* ser proc_no, for debugging */

+ 45 - 36
tcp_main.c

@@ -98,6 +98,8 @@
  *              on write error check if there's still data in the socket 
  *               read buffer and process it first (andrei)
  *  2009-02-26  direct blacklist support (andrei)
+ *  2009-03-20  s/wq_timeout/send_timeout ; send_timeout is now in ticks
+ *              (andrei)
  */
 
 
@@ -208,7 +210,6 @@
 #define TCPCONN_WAIT_TIMEOUT 1 /* 1 tick */
 
 #ifdef TCP_ASYNC
-#define TCP_WBUF_SIZE	1024 /* FIXME: after debugging switch to 16-32k */
 static unsigned int* tcp_total_wq=0;
 #endif
 
@@ -628,7 +629,7 @@ inline static int _wbufq_add(struct  tcp_connection* c, char* data,
 					" (%d, total %d, last write %d s ago)\n",
 					size, q->queued, *tcp_total_wq,
 					TICKS_TO_S(t-q->wr_timeout-
-						cfg_get(tcp, tcp_cfg, tcp_wq_timeout)));
+						cfg_get(tcp, tcp_cfg, send_timeout)));
 #ifdef USE_DST_BLACKLIST
 		if (q->first && TICKS_LT(q->wr_timeout, t) &&
 				cfg_get(core, core_cfg, use_dst_blacklist)){
@@ -642,7 +643,7 @@ inline static int _wbufq_add(struct  tcp_connection* c, char* data,
 	}
 	
 	if (unlikely(q->last==0)){
-		wb_size=MAX_unsigned(TCP_WBUF_SIZE, size);
+		wb_size=MAX_unsigned(cfg_get(tcp, tcp_cfg, wq_blk_size), size);
 		wb=shm_malloc(sizeof(*wb)+wb_size-1);
 		if (unlikely(wb==0))
 			goto error;
@@ -652,7 +653,10 @@ inline static int _wbufq_add(struct  tcp_connection* c, char* data,
 		q->first=wb;
 		q->last_used=0;
 		q->offset=0;
-		q->wr_timeout=get_ticks_raw()+cfg_get(tcp, tcp_cfg, tcp_wq_timeout);
+		q->wr_timeout=get_ticks_raw()+
+			((c->state==S_CONN_CONNECT)?
+					S_TO_TICKS(cfg_get(tcp, tcp_cfg, connect_timeout_s)):
+					cfg_get(tcp, tcp_cfg, send_timeout));
 	}else{
 		wb=q->last;
 	}
@@ -660,7 +664,7 @@ inline static int _wbufq_add(struct  tcp_connection* c, char* data,
 	while(size){
 		last_free=wb->b_size-q->last_used;
 		if (last_free==0){
-			wb_size=MAX_unsigned(TCP_WBUF_SIZE, size);
+			wb_size=MAX_unsigned(cfg_get(tcp, tcp_cfg, wq_blk_size), size);
 			wb=shm_malloc(sizeof(*wb)+wb_size-1);
 			if (unlikely(wb==0))
 				goto error;
@@ -705,7 +709,7 @@ inline static int _wbufq_insert(struct  tcp_connection* c, char* data,
 					" (%d, total %d, last write %d s ago)\n",
 					size, q->queued, *tcp_total_wq,
 					TICKS_TO_S(get_ticks_raw()-q->wr_timeout-
-									cfg_get(tcp, tcp_cfg, tcp_wq_timeout)));
+									cfg_get(tcp, tcp_cfg, send_timeout)));
 		goto error;
 	}
 	if (unlikely(q->offset)){
@@ -774,12 +778,10 @@ inline static int wbufq_run(int fd, struct tcp_connection* c, int* empty)
 	int n;
 	int ret;
 	int block_size;
-	ticks_t t;
 	char* buf;
 	
 	*empty=0;
 	ret=0;
-	t=get_ticks_raw();
 	lock_get(&c->write_lock);
 	q=&c->wbuf_q;
 	while(q->first){
@@ -802,7 +804,6 @@ inline static int wbufq_run(int fd, struct tcp_connection* c, int* empty)
 				atomic_add_int((int*)tcp_total_wq, -n);
 				break;
 			}
-			q->wr_timeout=t+cfg_get(tcp, tcp_cfg, tcp_wq_timeout);
 		}else{
 			if (n<0){
 				/* EINTR is handled inside _tcpconn_write_nb */
@@ -835,9 +836,12 @@ inline static int wbufq_run(int fd, struct tcp_connection* c, int* empty)
 		q->offset=0;
 		*empty=1;
 	}
-	if (unlikely(c->state==S_CONN_CONNECT && (ret>0)))
-			c->state=S_CONN_OK;
 	lock_release(&c->write_lock);
+	if (likely(ret>0)){
+		q->wr_timeout=get_ticks_raw()+cfg_get(tcp, tcp_cfg, send_timeout);
+		if (unlikely(c->state==S_CONN_CONNECT || c->state==S_CONN_ACCEPT))
+			c->state=S_CONN_OK;
+	}
 	return ret;
 }
 
@@ -923,13 +927,15 @@ struct tcp_connection* tcpconn_new(int sock, union sockaddr_union* su,
 									int state)
 {
 	struct tcp_connection *c;
+	int rd_b_size;
 	
-	c=(struct tcp_connection*)shm_malloc(sizeof(struct tcp_connection));
+	rd_b_size=cfg_get(tcp, tcp_cfg, rd_buf_size);
+	c=shm_malloc(sizeof(struct tcp_connection) + rd_b_size);
 	if (c==0){
 		LOG(L_ERR, "ERROR: tcpconn_new: mem. allocation failure\n");
 		goto error;
 	}
-	memset(c, 0, sizeof(struct tcp_connection)); /* zero init */
+	memset(c, 0, sizeof(struct tcp_connection)); /* zero init (skip rd buf)*/
 	c->s=sock;
 	c->fd=-1; /* not initialized */
 	if (lock_init(&c->write_lock)==0){
@@ -953,7 +959,7 @@ struct tcp_connection* tcpconn_new(int sock, union sockaddr_union* su,
 	}
 	print_ip("tcpconn_new: new tcp connection: ", &c->rcv.src_ip, "\n");
 	DBG(     "tcpconn_new: on port %d, type %d\n", c->rcv.src_port, type);
-	init_tcp_req(&c->req);
+	init_tcp_req(&c->req, (char*)c+sizeof(struct tcp_connection), rd_b_size);
 	c->id=(*connection_id)++;
 	c->rcv.proto_reserved1=0; /* this will be filled before receive_message*/
 	c->rcv.proto_reserved2=0;
@@ -1021,10 +1027,10 @@ inline static int tcp_do_connect(	union sockaddr_union* server,
 	if (likely(cfg_get(tcp, tcp_cfg, async))){
 again:
 		n=connect(s, &server->s, sockaddru_len(*server));
-		if (unlikely(n==-1)){
-			if (errno==EINTR) goto again;
+		if (likely(n==-1)){ /*non-blocking => most probable EINPROGRESS*/
 			if (likely(errno==EINPROGRESS))
 				*state=S_CONN_CONNECT;
+			else if (errno==EINTR) goto again;
 			else if (errno!=EALREADY){
 #ifdef USE_DST_BLACKLIST
 				if (cfg_get(core, core_cfg, use_dst_blacklist))
@@ -1693,7 +1699,7 @@ no_id:
 					return -1;
 				}
 				c=tcpconn_new(-1, &dst->to, from, 0, dst->proto,
-								S_CONN_PENDING);
+								S_CONN_CONNECT);
 				if (unlikely(c==0)){
 					LOG(L_ERR, "ERROR: tcp_send %s: could not create new"
 							" connection\n",
@@ -1738,6 +1744,9 @@ no_id:
 						DBG("tcp_send: pending write on new connection %p "
 								" (%d/%d bytes written)\n", c, n, len);
 						if (n<0) n=0;
+						else 
+							c->state=S_CONN_OK; /* partial write => connect()
+													ended */
 						/* add to the write queue */
 						lock_get(&c->write_lock);
 							if (unlikely(_wbufq_insert(c, buf+n, len-n)<0)){
@@ -1785,6 +1794,7 @@ no_id:
 					goto conn_wait_error;
 				}
 				LOG(L_INFO, "tcp_send: quick connect for %p\n", c);
+				c->state=S_CONN_OK;
 				/* send to tcp_main */
 				response[0]=(long)c;
 				response[1]=CONN_NEW_COMPLETE;
@@ -1832,13 +1842,13 @@ get_fd:
 		if (unlikely(cfg_get(tcp, tcp_cfg, async) &&
 						(_wbufq_non_empty(c)
 #ifdef TCP_CONNECT_WAIT
-												|| (c->state==S_CONN_PENDING)
+											|| (c->flags&F_CONN_PENDING)
 #endif /* TCP_CONNECT_WAIT */
 						) )){
 			lock_get(&c->write_lock);
 				if (likely(_wbufq_non_empty(c)
 #ifdef TCP_CONNECT_WAIT
-							|| (c->state==S_CONN_PENDING)
+							|| (c->flags&F_CONN_PENDING)
 #endif /* TCP_CONNECT_WAIT */
 
 							)){
@@ -1916,7 +1926,7 @@ send_it:
 	if (likely(cfg_get(tcp, tcp_cfg, async))){
 		if (_wbufq_non_empty(c)
 #ifdef TCP_CONNECT_WAIT
-			|| (c->state==S_CONN_PENDING) 
+			|| (c->flags&F_CONN_PENDING) 
 #endif /* TCP_CONNECT_WAIT */
 			){
 			if (unlikely(_wbufq_add(c, buf, len)<0)){
@@ -1938,7 +1948,8 @@ send_it:
 #endif
 		/* n=tcp_blocking_write(c, fd, buf, len); */
 		n=tsend_stream(fd, buf, len,
-							cfg_get(tcp, tcp_cfg, send_timeout_s)*1000);
+						TICKS_TO_S(cfg_get(tcp, tcp_cfg, send_timeout)) *
+						1000);
 #ifdef TCP_ASYNC
 	}
 #else /* ! TCP_ASYNC */
@@ -1953,6 +1964,9 @@ send_it:
 				((n>=0) || errno==EAGAIN || errno==EWOULDBLOCK)){
 			enable_write_watch=_wbufq_empty(c);
 			if (n<0) n=0;
+			else if (unlikely(c->state==S_CONN_CONNECT ||
+						c->state==S_CONN_ACCEPT))
+				c->state=S_CONN_OK; /* something was written */
 			if (unlikely(_wbufq_add(c, buf+n, len-n)<0)){
 				lock_release(&c->write_lock);
 				n=-1;
@@ -2026,11 +2040,10 @@ error:
 	
 #ifdef TCP_ASYNC
 	lock_release(&c->write_lock);
-	if (likely(cfg_get(tcp, tcp_cfg, async))){
-		if (unlikely(c->state==S_CONN_CONNECT))
-			c->state=S_CONN_OK;
-	}
 #endif /* TCP_ASYNC */
+	/* in non-async mode here we're either in S_CONN_OK or S_CONN_ACCEPT*/
+	if (unlikely(c->state==S_CONN_CONNECT || c->state==S_CONN_ACCEPT))
+			c->state=S_CONN_OK;
 end:
 #ifdef TCP_FD_CACHE
 	if (unlikely((fd_cache_e==0) && use_fd_cache)){
@@ -2249,9 +2262,10 @@ inline static int tcpconn_chld_put(struct tcp_connection* tcpconn)
 				tcpconn->s, tcpconn->flags);
 		/* sanity checks */
 		membar_read_atomic_op(); /* make sure we see the current flags */
-		if (unlikely(!(tcpconn->flags & F_CONN_FD_CLOSED) || 
-			(tcpconn->flags & 
-				(F_CONN_HASHED|F_CONN_MAIN_TIMER|F_CONN_READ_W|F_CONN_WRITE_W)) )){
+		if (unlikely(!(tcpconn->flags & F_CONN_FD_CLOSED) ||
+			(tcpconn->flags &
+				(F_CONN_HASHED|F_CONN_MAIN_TIMER|
+				 F_CONN_READ_W|F_CONN_WRITE_W)) )){
 			LOG(L_CRIT, "BUG: tcpconn_chld_put: %p bad flags = %0x\n",
 					tcpconn, tcpconn->flags);
 			abort();
@@ -2712,7 +2726,7 @@ inline static int handle_tcp_child(struct tcp_child* tcp_c, int fd_i)
 					tcpconn->flags&=~F_CONN_WRITE_W;
 				}
 #endif /* TCP_ASYNC */
-				if (tcpconn_try_unhash(tcpconn));
+				if (tcpconn_try_unhash(tcpconn))
 					tcpconn_put_destroy(tcpconn);
 				break;
 			}
@@ -2978,8 +2992,8 @@ inline static int handle_ser_child(struct process_table* p, int fd_i)
 		case CONN_NEW_PENDING_WRITE:
 				/* received when a pending connect completes in the same
 				 * tcp_send() that initiated it
-				 * the connection is already in the hash with S_CONN_PENDING
-				 * state (added by tcp_send()) and refcnt at least 1 (for the
+				 * the connection is already in the hash with F_CONN_PENDING
+				 * flag (added by tcp_send()) and refcnt at least 1 (for the
 				 *  hash)*/
 			tcpconn->flags&=~(F_CONN_PENDING|F_CONN_FD_CLOSED);
 			if (unlikely((tcpconn->state==S_CONN_BAD) || (fd==-1))){
@@ -3003,7 +3017,6 @@ inline static int handle_ser_child(struct process_table* p, int fd_i)
 			tcpconn->timeout=t+con_lifetime;
 			nxt_timeout=con_lifetime;
 			if (unlikely(cmd==CONN_NEW_COMPLETE)){
-				tcpconn->state=S_CONN_OK;
 				/* check if needs to be watched for write */
 				lock_get(&tcpconn->write_lock);
 					/* if queue non empty watch it for write */
@@ -3023,10 +3036,6 @@ inline static int handle_ser_child(struct process_table* p, int fd_i)
 								F_CONN_WANTS_RD;
 			}else{
 				/* CONN_NEW_PENDING_WRITE */
-				/* we don't know if we successfully sent anything, but
-				   for sure we haven't sent all what we wanted, so consider
-				   the connection in "connecting" state */
-				tcpconn->state=S_CONN_CONNECT;
 				/* no need to check, we have something queued for write */
 				flags=POLLOUT;
 				if (TICKS_LT(tcpconn->wbuf_q.wr_timeout, tcpconn->timeout)

+ 65 - 70
tcp_options.c

@@ -37,38 +37,13 @@
    NOTE: all the options are initialized in init_tcp_options()
    depending on compile time defines */
 struct cfg_group_tcp tcp_default_cfg;
-#if 0
-{
-	1, /* fd_cache, default on */
-	/* tcp async options */
-	0, /* async / tcp_async, default off */
-	1, /* tcp_connect_wait - depends on tcp_async */
-	32*1024, /* tcpconn_wq_max - max. write queue len per connection (32k) */
-	10*1024*1024, /* tcp_wq_max - max.  overall queued bytes  (10MB)*/
-	S_TO_TICKS(tcp_send_timeout), /* tcp_wq_timeout - timeout for queued 
-									 writes, depends on tcp_send_timeout */
-	/* tcp socket options */
-	0, /* defer_accept - on/off*/
-	1, /* delayed_ack - delay ack on connect (on/off)*/
-	0, /* syncnt - numbers of SYNs retrs. before giving up (0 = OS default) */
-	0, /* linger2 - lifetime of orphaned FIN_WAIT2 sockets (0 = OS default)*/
-	1, /* keepalive - on/off */
-	0, /* keepidle - idle time (s) before tcp starts sending keepalives */
-	0, /* keepintvl - interval between keep alives (0 = OS default) */
-	0, /* keepcnt - maximum no. of keepalives (0 = OS default)*/
-	
-	/* other options */
-	1 /* crlf_ping - respond to double CRLF ping/keepalive (on/off) */
-	
-};
-#endif
 
 
 
-static int fix_connect_to(void* cfg_h, str* name, void** val);
-static int fix_send_to(void* cfg_h, str* name, void** val);
-static int fix_con_lt(void* cfg_h, str* name, void** val);
-static int fix_max_conns(void* cfg_h, str* name, void** val);
+static int fix_connect_to(void* cfg_h, str* gname, str* name, void** val);
+static int fix_send_to(void* cfg_h, str* gname, str* name, void** val);
+static int fix_con_lt(void* cfg_h, str* gname, str* name, void** val);
+static int fix_max_conns(void* cfg_h, str* gname, str* name, void** val);
 
 
 
@@ -80,10 +55,10 @@ static cfg_def_t tcp_cfg_def[] = {
 						TICKS_TO_S(MAX_TCP_CON_LIFETIME),  fix_connect_to,   0,
 		"used only in non-async mode, in seconds"},
 	{ "send_timeout", CFG_VAR_INT | CFG_ATOMIC,   -1,
-						TICKS_TO_S(MAX_TCP_CON_LIFETIME),   fix_send_to,     0,
+						MAX_TCP_CON_LIFETIME,               fix_send_to,     0,
 		"in seconds"},
 	{ "connection_lifetime", CFG_VAR_INT | CFG_ATOMIC,   -1,
-						TICKS_TO_S(MAX_TCP_CON_LIFETIME),   fix_con_lt,      0,
+						MAX_TCP_CON_LIFETIME,               fix_con_lt,      0,
 		"connection lifetime (in seconds)"},
 	{ "max_connections", CFG_VAR_INT | CFG_ATOMIC, 0, (1U<<31)-1,
 													       fix_max_conns,    0,
@@ -101,7 +76,7 @@ static cfg_def_t tcp_cfg_def[] = {
 		"maximum bytes queued for write per connection (depends on async)"},
 	{ "wq_max",       CFG_VAR_INT | CFG_ATOMIC,      0,  1<<30,    0,        0,
 		"maximum bytes queued for write allowed globally (depends on async)"},
-	/* see also wq_timeout below */
+	/* see also send_timeout above */
 	/* tcp socket options */
 	{ "defer_accept", CFG_VAR_INT | CFG_READONLY,    0,   3600,   0,         0,
 		"0/1 on linux, seconds on freebsd (see docs)"},
@@ -130,12 +105,10 @@ static cfg_def_t tcp_cfg_def[] = {
 		"flags for the def. aliases for a new conn. (FORCE_ADD:1, REPLACE:2 "},
 	/* internal and/or "fixed" versions of some vars
 	   (not supposed to be writeable, read will provide only debugging value*/
-	{ "wq_timeout_ticks",   CFG_VAR_INT | CFG_READONLY, 0,
-									MAX_TCP_CON_LIFETIME,         0,         0,
-		"internal send_timeout value in ticks, used in async. mode"},
-	{ "con_lifetime_ticks", CFG_VAR_INT | CFG_READONLY, 0,
-									MAX_TCP_CON_LIFETIME,         0,         0,
-		"internal connection_lifetime value, converted to ticks"},
+	{ "rd_buf_size", CFG_VAR_INT | CFG_ATOMIC,    512,    65536,  0,         0,
+		"internal read buffer size (should be > max. expected datagram)"},
+	{ "wq_blk_size", CFG_VAR_INT | CFG_ATOMIC,    1,    65535,  0,         0,
+		"internal async write block size (debugging use only for now)"},
 	{0, 0, 0, 0, 0, 0, 0}
 };
 
@@ -146,14 +119,13 @@ void* tcp_cfg; /* tcp config handle */
 void init_tcp_options()
 {
 	tcp_default_cfg.connect_timeout_s=DEFAULT_TCP_CONNECT_TIMEOUT;
-	tcp_default_cfg.send_timeout_s=DEFAULT_TCP_SEND_TIMEOUT;
-	tcp_default_cfg.con_lifetime_s=DEFAULT_TCP_CONNECTION_LIFETIME_S;
+	tcp_default_cfg.send_timeout=S_TO_TICKS(DEFAULT_TCP_SEND_TIMEOUT);
+	tcp_default_cfg.con_lifetime=S_TO_TICKS(DEFAULT_TCP_CONNECTION_LIFETIME_S);
 	tcp_default_cfg.max_connections=tcp_max_connections;
 #ifdef TCP_ASYNC
 	tcp_default_cfg.async=1;
 	tcp_default_cfg.tcpconn_wq_max=32*1024; /* 32 k */
 	tcp_default_cfg.tcp_wq_max=10*1024*1024; /* 10 MB */
-	tcp_default_cfg.tcp_wq_timeout=S_TO_TICKS(tcp_default_cfg.send_timeout_s);
 #ifdef TCP_CONNECT_WAIT
 	tcp_default_cfg.tcp_connect_wait=1;
 #endif /* TCP_CONNECT_WAIT */
@@ -178,6 +150,8 @@ void init_tcp_options()
 	tcp_default_cfg.alias_flags=TCP_ALIAS_FORCE_ADD;
 	/* flags used for adding the default aliases of a new tcp connection */
 	tcp_default_cfg.new_conn_alias_flags=TCP_ALIAS_REPLACE;
+	tcp_default_cfg.rd_buf_size=DEFAULT_TCP_BUF_SIZE;
+	tcp_default_cfg.wq_blk_size=DEFAULT_TCP_WBUF_SIZE;
 }
 
 
@@ -213,7 +187,7 @@ static void fix_timeout(char* name, int* to, int default_val, unsigned max_val)
 
 
 
-static int fix_connect_to(void* cfg_h, str* name, void** val)
+static int fix_connect_to(void* cfg_h, str* gname, str* name, void** val)
 {
 	int v;
 	v=(int)(long)*val;
@@ -224,36 +198,29 @@ static int fix_connect_to(void* cfg_h, str* name, void** val)
 }
 
 
-static int fix_send_to(void* cfg_h, str* name, void** val)
+static int fix_send_to(void* cfg_h, str* gname, str* name, void** val)
 {
 	int v;
-	v=(int)(long)*val;
-	fix_timeout("tcp_send_timeout", &v, DEFAULT_TCP_SEND_TIMEOUT,
-						TICKS_TO_S(MAX_TCP_CON_LIFETIME));
+	v=S_TO_TICKS((int)(long)*val);
+	fix_timeout("tcp_send_timeout", &v, S_TO_TICKS(DEFAULT_TCP_SEND_TIMEOUT),
+						MAX_TCP_CON_LIFETIME);
 	*val=(void*)(long)v;
-#ifdef TCP_ASYNC
-	((struct cfg_group_tcp*)cfg_h)->tcp_wq_timeout=S_TO_TICKS(v);
-#endif /* TCP_ASYNC */
 	return 0;
 }
 
 
-static int fix_con_lt(void* cfg_h, str* name, void** val)
+static int fix_con_lt(void* cfg_h, str* gname, str* name, void** val)
 {
 	int v;
-	v=(int)(long)*val;
-	fix_timeout("tcp_connection_lifetime", &v,
-						TICKS_TO_S(MAX_TCP_CON_LIFETIME),
-						TICKS_TO_S(MAX_TCP_CON_LIFETIME));
+	v=S_TO_TICKS((int)(long)*val);
+	fix_timeout("tcp_connection_lifetime", &v, 
+					MAX_TCP_CON_LIFETIME, MAX_TCP_CON_LIFETIME);
 	*val=(void*)(long)v;
-#ifdef TCP_ASYNC
-	((struct cfg_group_tcp*)cfg_h)->con_lifetime=S_TO_TICKS(v);
-#endif /* TCP_ASYNC */
 	return 0;
 }
 
 
-static int fix_max_conns(void* cfg_h, str* name, void** val)
+static int fix_max_conns(void* cfg_h, str* gname, str* name, void** val)
 {
 	int v;
 	v=(int)(long)*val;
@@ -268,6 +235,39 @@ static int fix_max_conns(void* cfg_h, str* name, void** val)
 
 
 
+/** fix *val according to the cfg entry "name".
+ * (*val must be integer)
+ * 1. check if *val is between name min..max and if not change it to
+ *    the corresp. value
+ * 2. call fixup callback if defined in the cfg
+ * @return 0 on success
+ */
+static int tcp_cfg_def_fix(char* name, int* val)
+{
+	cfg_def_t* c;
+	str s;
+	
+	for (c=&tcp_cfg_def[0]; c->name; c++){
+		if (strcmp(name, c->name)==0){
+			/* found */
+			if ((c->type & CFG_VAR_INT)  && (c->min || c->max)){
+				if (*val < c->min) *val=c->min;
+				else if (*val > c->max) *val=c->max;
+				if (c->on_change_cb){
+					s.s=c->name;
+					s.len=strlen(s.s);
+					return c->on_change_cb(&tcp_default_cfg, NULL, &s, (void*)val);
+				}
+			}
+			return 0;
+		}
+	}
+	WARN("tcp config option \"%s\" not found\n", name);
+	return -1; /* not found */
+}
+
+
+
 /* checks & warns if some tcp_option cannot be enabled */
 void tcp_options_check()
 {
@@ -279,7 +279,6 @@ void tcp_options_check()
 	W_OPT_NC(async);
 	W_OPT_NC(tcpconn_wq_max);
 	W_OPT_NC(tcp_wq_max);
-	W_OPT_NC(tcp_wq_timeout);
 #endif /* TCP_ASYNC */
 #ifndef TCP_CONNECT_WAIT
 	W_OPT_NC(tcp_connect_wait);
@@ -321,18 +320,14 @@ void tcp_options_check()
 	fix_timeout("tcp_connect_timeout", &tcp_default_cfg.connect_timeout_s,
 						DEFAULT_TCP_CONNECT_TIMEOUT,
 						TICKS_TO_S(MAX_TCP_CON_LIFETIME));
-	fix_timeout("tcp_send_timeout", &tcp_default_cfg.send_timeout_s,
-						DEFAULT_TCP_SEND_TIMEOUT,
-						TICKS_TO_S(MAX_TCP_CON_LIFETIME));
-	fix_timeout("tcp_connection_lifetime", &tcp_default_cfg.con_lifetime_s,
-						TICKS_TO_S(MAX_TCP_CON_LIFETIME),
-						TICKS_TO_S(MAX_TCP_CON_LIFETIME));
-	/* compute timeout in ticks */
-#ifdef TCP_ASYNC
-	tcp_default_cfg.tcp_wq_timeout=S_TO_TICKS(tcp_default_cfg.send_timeout_s);
-#endif /* TCP_ASYNC */
-	tcp_default_cfg.con_lifetime=S_TO_TICKS(tcp_default_cfg.con_lifetime_s);
+	fix_timeout("tcp_send_timeout", &tcp_default_cfg.send_timeout,
+						S_TO_TICKS(DEFAULT_TCP_SEND_TIMEOUT),
+						MAX_TCP_CON_LIFETIME);
+	fix_timeout("tcp_connection_lifetime", &tcp_default_cfg.con_lifetime,
+						MAX_TCP_CON_LIFETIME, MAX_TCP_CON_LIFETIME);
 	tcp_default_cfg.max_connections=tcp_max_connections;
+	tcp_cfg_def_fix("rd_buf_size", (int*)&tcp_default_cfg.rd_buf_size);
+	tcp_cfg_def_fix("wq_blk_size", (int*)&tcp_default_cfg.wq_blk_size);
 }
 
 

+ 5 - 5
tcp_options.h

@@ -111,9 +111,9 @@
 
 struct cfg_group_tcp{
 	/* ser tcp options, low level */
-	int connect_timeout_s; /* in s, used only in non-async mode */
-	int send_timeout_s; /* in s */
-	int con_lifetime_s; /* in s */
+	int connect_timeout_s; /* in s */
+	int send_timeout; /* in ticks (s fixed to ticks) */
+	int con_lifetime; /* in ticks (s fixed to ticks) */
 	int max_connections;
 	int no_connect; /* do not open any new tcp connection (but accept them) */
 	int fd_cache; /* on /off */
@@ -139,8 +139,8 @@ struct cfg_group_tcp{
 	int alias_flags;
 	int new_conn_alias_flags;
 	/* internal, "fixed" vars */
-	unsigned int tcp_wq_timeout; /* in ticks, timeout for queued writes */
-	unsigned int con_lifetime; /* in ticks, see con_lifetime_s */
+	unsigned int rd_buf_size; /* read buffer size (should be > max. datagram)*/
+	unsigned int wq_blk_size; /* async write block size (debugging use) */
 };
 
 extern struct cfg_group_tcp tcp_default_cfg;

+ 29 - 26
tcp_read.c

@@ -130,7 +130,7 @@ int tcp_read(struct tcp_connection *c, int* flags)
 
 	r=&c->req;
 	fd=c->fd;
-	bytes_free=TCP_BUF_SIZE- (int)(r->pos - r->buf);
+	bytes_free=r->b_size- (int)(r->pos - r->buf);
 	
 	if (bytes_free==0){
 		LOG(L_ERR, "ERROR: tcp_read: buffer overrun, dropping\n");
@@ -170,13 +170,13 @@ again:
 			*flags|=RD_CONN_EOF;
 			DBG("tcp_read: EOF on %p, FD %d\n", c, fd);
 		}else{
-			if (unlikely(c->state==S_CONN_CONNECT))
+			if (unlikely(c->state==S_CONN_CONNECT || c->state==S_CONN_ACCEPT))
 				c->state=S_CONN_OK;
 		}
 		/* short read */
 		*flags|=RD_CONN_SHORT_READ;
 	}else{ /* else normal full read */
-		if (unlikely(c->state==S_CONN_CONNECT))
+		if (unlikely(c->state==S_CONN_CONNECT || c->state==S_CONN_ACCEPT))
 			c->state=S_CONN_OK;
 	}
 #ifdef EXTRA_DEBUG
@@ -218,19 +218,19 @@ int tcp_read_headers(struct tcp_connection *c, int* read_flags)
 	#define content_len_beg_case \
 					case ' ': \
 					case '\t': \
-						if (!r->has_content_len) r->state=H_STARTWS; \
+						if (!TCP_REQ_HAS_CLEN(r)) r->state=H_STARTWS; \
 						else r->state=H_SKIP; \
 							/* not interested if we already found one */ \
 						break; \
 					case 'C': \
 					case 'c': \
-						if(!r->has_content_len) r->state=H_CONT_LEN1; \
+						if(!TCP_REQ_HAS_CLEN(r)) r->state=H_CONT_LEN1; \
 						else r->state=H_SKIP; \
 						break; \
 					case 'l': \
 					case 'L': \
 						/* short form for Content-Length */ \
-						if (!r->has_content_len) r->state=H_L_COLON; \
+						if (!TCP_REQ_HAS_CLEN(r)) r->state=H_L_COLON; \
 						else r->state=H_SKIP; \
 						break
 						
@@ -272,7 +272,7 @@ int tcp_read_headers(struct tcp_connection *c, int* read_flags)
 				r->bytes_to_go-=remaining;
 				p+=remaining;
 				if (r->bytes_to_go==0){
-					r->complete=1;
+					r->flags|=F_TCP_REQ_COMPLETE;
 					goto skip;
 				}
 				break;
@@ -298,11 +298,11 @@ int tcp_read_headers(struct tcp_connection *c, int* read_flags)
 					case '\n':
 						/* found LF LF */
 						r->state=H_BODY;
-						if (r->has_content_len){
+						if (TCP_REQ_HAS_CLEN(r)){
 							r->body=p+1;
 							r->bytes_to_go=r->content_len;
 							if (r->bytes_to_go==0){
-								r->complete=1;
+								r->flags|=F_TCP_REQ_COMPLETE;
 								p++;
 								goto skip;
 							}
@@ -322,11 +322,11 @@ int tcp_read_headers(struct tcp_connection *c, int* read_flags)
 				if (*p=='\n'){
 					/* found LF CR LF */
 					r->state=H_BODY;
-					if (r->has_content_len){
+					if (TCP_REQ_HAS_CLEN(r)){
 						r->body=p+1;
 						r->bytes_to_go=r->content_len;
 						if (r->bytes_to_go==0){
-							r->complete=1;
+							r->flags|=F_TCP_REQ_COMPLETE;
 							p++;
 							goto skip;
 						}
@@ -410,8 +410,8 @@ int tcp_read_headers(struct tcp_connection *c, int* read_flags)
 			case H_SKIP_EMPTY_CRLFCR_FOUND:
 				if (*p=='\n'){
 					r->state = H_PING_CRLF;
-					r->complete = 1;
-					r->has_content_len = 1; /* hack to avoid error check */
+					r->flags |= F_TCP_REQ_HAS_CLEN |
+							F_TCP_REQ_COMPLETE; /* hack to avoid error check */
 					p++;
 					goto skip;
 				}else{
@@ -437,7 +437,7 @@ int tcp_read_headers(struct tcp_connection *c, int* read_flags)
 					/* using has_content_len as a flag if there should be
 					 * fingerprint or no
 					 */
-					r->has_content_len = (mc == MAGIC_COOKIE) ? 1 : 0;
+					r->flags |= (mc == MAGIC_COOKIE) ? F_TCP_REQ_HAS_CLEN : 0;
 					
 					r->body += sizeof(struct stun_hdr);
 					p = r->body; 
@@ -485,8 +485,8 @@ int tcp_read_headers(struct tcp_connection *c, int* read_flags)
 					r->body += body_len;
 					p = r->body;
 					r->state = H_STUN_END;
-					r->complete = 1;
-					r->has_content_len = 1; /* hack to avoid error check */
+					r->flags |= F_TCP_REQ_COMPLETE |
+						F_TCP_REQ_HAS_CLEN; /* hack to avoid error check */
 					goto skip;
 				}
 				else {
@@ -563,12 +563,12 @@ int tcp_read_headers(struct tcp_connection *c, int* read_flags)
 					case ' ':
 					case '\t': /* FIXME: check if line contains only WS */
 						r->state=H_SKIP;
-						r->has_content_len=1;
+						r->flags|=F_TCP_REQ_HAS_CLEN;
 						break;
 					case '\n':
 						/* end of line, parse successful */
 						r->state=H_LF;
-						r->has_content_len=1;
+						r->flags|=F_TCP_REQ_HAS_CLEN;
 						break;
 					default:
 						LOG(L_ERR, "ERROR: tcp_read_headers: bad "
@@ -615,7 +615,8 @@ int tcp_read_req(struct tcp_connection* con, int* bytes_read, int* read_flags)
 				resp=CONN_ERROR;
 				goto end_req;
 			}
-			if(con->state!=S_CONN_OK) goto end_req; /* not enough data */
+			if (unlikely(con->state!=S_CONN_OK && con->state!=S_CONN_ACCEPT))
+				goto end_req; /* not enough data */
 		}
 #endif
 
@@ -642,7 +643,8 @@ again:
 			 * if req. is complete we might have a second unparsed
 			 * request after it, so postpone release_with_eof
 			 */
-			if (unlikely((con->state==S_CONN_EOF) && (req->complete==0))) {
+			if (unlikely((con->state==S_CONN_EOF) && 
+						(! TCP_REQ_COMPLETE(req)))) {
 				DBG( "tcp_read_req: EOF\n");
 				resp=CONN_EOF;
 				goto end_req;
@@ -659,7 +661,7 @@ again:
 			resp=CONN_ERROR;
 			goto end_req;
 		}
-		if (likely(req->complete)){
+		if (likely(TCP_REQ_COMPLETE(req))){
 #ifdef EXTRA_DEBUG
 			DBG("tcp_read_req: end of header part\n");
 			DBG("- received from: port %d\n", con->rcv.src_port);
@@ -667,7 +669,7 @@ again:
 			DBG("tcp_read_req: headers:\n%.*s.\n",
 					(int)(req->body-req->start), req->start);
 #endif
-			if (likely(req->has_content_len)){
+			if (likely(TCP_REQ_HAS_CLEN(req))){
 				DBG("tcp_read_req: content-length= %d\n", req->content_len);
 #ifdef EXTRA_DEBUG
 				DBG("tcp_read_req: body:\n%.*s\n", req->content_len,req->body);
@@ -732,7 +734,8 @@ again:
 			req->body=0;
 			req->error=TCP_REQ_OK;
 			req->state=H_SKIP_EMPTY;
-			req->complete=req->content_len=req->has_content_len=0;
+			req->flags=0;
+			req->content_len=0;
 			req->bytes_to_go=0;
 			req->pos=req->buf+size;
 			
@@ -1084,15 +1087,15 @@ error:
 #ifdef USE_STUN
 int is_msg_complete(struct tcp_req* r)
 {
-	if (r->has_content_len == 1) {
+	if (TCP_REQ_HAS_CLEN(r)) {
 		r->state = H_STUN_FP;
 		return 0;
 	}
 	else {
 		/* STUN message is complete */
 		r->state = H_STUN_END;
-		r->complete = 1;
-		r->has_content_len = 1; /* hack to avoid error check */
+		r->flags |= F_TCP_REQ_COMPLETE |
+					F_TCP_REQ_HAS_CLEN; /* hack to avoid error check */
 		return 1;
 	}
 }

+ 2 - 1
utils/sercmd/Makefile

@@ -20,7 +20,8 @@ endif
 endif #ifneq (,$(MAKECMDGOALS))
 
 
-
+# erase common DEFS (not needed)
+C_DEFS:=
 DEFS:= -DNAME='"$(NAME)"' -DVERSION='"$(RELEASE)"' \
 		$(filter -D%HAVE -DARCH% -DOS% -D__CPU% -D__OS%, $(DEFS))
 LIBS:=$(filter-out -lfl  -ldl -lpthread -lssl -lcrypto, $(LIBS))