Explorar o código

Merge branch 'master' into mariusbucur/dmq

Conflicts:
	modules_k/htable/ht_api.c
	modules_k/htable/ht_api.h
Marius Bucur %!s(int64=14) %!d(string=hai) anos
pai
achega
84b87a9afe
Modificáronse 100 ficheiros con 11740 adicións e 946 borrados
  1. 159 132
      Makefile.defs
  2. 16 3
      Makefile.radius
  3. 25 8
      cfg.lex
  4. 28 3
      cfg.y
  5. 22 0
      core_cmd.c
  6. 133 0
      doc/stylesheets/dbschema_k/xsl/db_sqlite.xsl
  7. 130 64
      etc/kamailio.cfg
  8. 2 2
      forward.c
  9. 1 0
      globals.h
  10. 5 4
      io_wait.h
  11. 2 2
      lib/kcore/kstats_wrapper.h
  12. 10 1
      lib/kcore/parser_helpers.c
  13. 3 0
      lib/srdb1/db_id.c
  14. 18 2
      lib/srdb1/schema/Makefile
  15. 1 1
      lib/srdb1/schema/htable.xml
  16. 1 5
      lib/srdb1/schema/lcr_gw.xml
  17. 2 2
      lib/srdb1/schema/pr_active_watchers.xml
  18. 1 1
      lib/srdb1/schema/pr_pua.xml
  19. 61 22
      main.c
  20. 29 7
      mem/mem.c
  21. 2 1
      mem/mem.h
  22. 16 4
      modules/app_lua/Makefile
  23. 2 0
      modules/auth/README
  24. 8 2
      modules/auth/auth_mod.c
  25. 9 0
      modules/auth/doc/functions.xml
  26. 16 2
      modules/carrierroute/carrierroute.c
  27. 2 2
      modules/carrierroute/cr_func.c
  28. 25 5
      modules/db_mysql/Makefile
  29. 44 3
      modules/dialplan/README
  30. 123 2
      modules/dialplan/dialplan.c
  31. 48 2
      modules/dialplan/doc/dialplan_admin.xml
  32. 14 6
      modules/geoip/README
  33. 12 1
      modules/geoip/doc/geoip_admin.xml
  34. 14 0
      modules/ipops/Makefile
  35. 279 0
      modules/ipops/README
  36. 21 0
      modules/ipops/compile_ip_parser.rl.sh
  37. 4 0
      modules/ipops/doc/Makefile
  38. 34 0
      modules/ipops/doc/ipops.xml
  39. 445 0
      modules/ipops/doc/ipops_admin.xml
  40. 5951 0
      modules/ipops/ip_parser.c
  41. 19 0
      modules/ipops/ip_parser.h
  42. 65 0
      modules/ipops/ip_parser.rl
  43. 437 0
      modules/ipops/ipops_mod.c
  44. 5 4
      modules/lcr/README
  45. 1 0
      modules/lcr/doc/lcr_admin.xml
  46. 1 1
      modules/mediaproxy/mediaproxy.c
  47. 3 3
      modules/ratelimit/ratelimit.c
  48. 84 70
      modules/rtpproxy/README
  49. 81 7
      modules/rtpproxy/doc/rtpproxy_admin.xml
  50. 124 13
      modules/rtpproxy/rtpproxy.c
  51. 34 13
      modules/sdpops/README
  52. 26 0
      modules/sdpops/doc/sdpops_admin.xml
  53. 220 0
      modules/sdpops/sdpops_data.c
  54. 33 0
      modules/sdpops/sdpops_data.h
  55. 53 27
      modules/sdpops/sdpops_mod.c
  56. 1 1
      modules/tls/Makefile
  57. 18 2
      modules/tm/h_table.c
  58. 2 0
      modules/tm/h_table.h
  59. 2 2
      modules/tm/tm.c
  60. 14 4
      modules/xmlops/Makefile
  61. 12 5
      modules_k/acc/acc_mod.c
  62. 1 1
      modules_k/acc_radius/acc_radius_mod.c
  63. 44 41
      modules_k/auth_radius/README
  64. 24 17
      modules_k/auth_radius/authorize.c
  65. 43 42
      modules_k/auth_radius/doc/auth_radius_admin.xml
  66. 25 0
      modules_k/db_sqlite/Makefile
  67. 69 0
      modules_k/db_sqlite/README
  68. 90 0
      modules_k/db_sqlite/db_sqlite.c
  69. 526 0
      modules_k/db_sqlite/dbase.c
  70. 72 0
      modules_k/db_sqlite/dbase.h
  71. 4 0
      modules_k/db_sqlite/doc/Makefile
  72. 45 0
      modules_k/db_sqlite/doc/db_sqlite.xml
  73. 78 0
      modules_k/db_sqlite/doc/db_sqlite_admin.xml
  74. 21 6
      modules_k/dialog/dialog.c
  75. 243 128
      modules_k/dialog/dlg_db_handler.c
  76. 22 3
      modules_k/dialog/dlg_db_handler.h
  77. 16 6
      modules_k/dialog/dlg_handlers.c
  78. 2 1
      modules_k/dialog/dlg_handlers.h
  79. 23 10
      modules_k/dialog/dlg_hash.c
  80. 6 1
      modules_k/dialog/dlg_hash.h
  81. 274 1
      modules_k/dialog/dlg_var.c
  82. 22 0
      modules_k/dialog/dlg_var.h
  83. 19 0
      modules_k/dialog/doc/dialog.xml
  84. 121 3
      modules_k/dialog/doc/dialog_admin.xml
  85. 2 1
      modules_k/dialog/doc/dialog_devel.xml
  86. 77 13
      modules_k/dispatcher/README
  87. 11 31
      modules_k/dispatcher/dispatch.c
  88. 34 0
      modules_k/dispatcher/dispatch.h
  89. 218 0
      modules_k/dispatcher/dispatcher.c
  90. 80 1
      modules_k/dispatcher/doc/dispatcher_admin.xml
  91. 1 0
      modules_k/dispatcher/ds_ht.c
  92. 49 11
      modules_k/domain/README
  93. 37 0
      modules_k/domain/doc/domain_admin.xml
  94. 88 0
      modules_k/domain/domain_mod.c
  95. 10 3
      modules_k/htable/README
  96. 19 0
      modules_k/htable/doc/htable_admin.xml
  97. 276 137
      modules_k/htable/ht_api.c
  98. 8 3
      modules_k/htable/ht_api.h
  99. 33 43
      modules_k/htable/ht_db.c
  100. 54 2
      modules_k/htable/ht_var.c

+ 159 - 132
Makefile.defs

@@ -162,7 +162,7 @@ INSTALL_FLAVOUR=$(FLAVOUR)
 VERSION = 3
 PATCHLEVEL = 2
 SUBLEVEL =  0
-EXTRAVERSION = -dev3
+EXTRAVERSION = -dev5
 
 # memory debugger switcher
 # 0 - off (release mode)
@@ -225,97 +225,6 @@ endif
 # extra CC command line options (e.g  -march=athlon-mp)
 CC_EXTRA_OPTS ?=
 
-# dirs 
-cfg_dir = etc/$(MAIN_NAME)/
-bin_dir = sbin/
-share_dir = share/$(MAIN_NAME)/
-# lib/$(MAIN_NAME)/modules , lib/$(MAIN_NAME)/modules-s, lib/$(MAIN_NAME)/modules-k
-modules_dir = lib/$(MAIN_NAME)/
-lib_dir = lib/$(MAIN_NAME)/
-
-doc_dir = doc/$(MAIN_NAME)/
-man_dir = man/
-data_dir = $(MAIN_NAME)/
-
-ifeq ($(OS), linux)
-	doc_dir = share/doc/$(MAIN_NAME)/
-	man_dir = share/man/
-	data_dir = share/$(MAIN_NAME)/
-	LOCALBASE ?= /usr/local
-endif
-
-ifeq ($(OS), freebsd)
-	doc_dir = share/doc/$(MAIN_NAME)/
-	man_dir = man/
-	data_dir = share/$(MAIN_NAME)/
-	LOCALBASE ?= /usr/local
-endif
-
-ifeq ($(OS), openbsd)
-	doc_dir = share/doc/$(MAIN_NAME)/
-	man_dir = man/
-	data_dir = share/$(MAIN_NAME)/
-	LOCALBASE ?= /usr/local
-endif
-
-ifeq ($(OS), netbsd)
-	doc_dir = share/doc/$(MAIN_NAME)/
-	man_dir = man/
-	data_dir = share/$(MAIN_NAME)/
-	LOCALBASE ?= /usr/pkg
-endif
-
-ifeq ($(OS), dragonfly)
-	doc_dir = share/doc/$(MAIN_NAME)/
-	man_dir = man/
-	data_dir = share/$(MAIN_NAME)/
-	LOCALBASE ?= /usr/pkg
-endif
-
-ifeq ($(OS), darwin)
-	doc_dir = share/doc/$(MAIN_NAME)/
-	man_dir = man/
-	data_dir = share/$(MAIN_NAME)/
-	LOCALBASE ?= /usr/local
-endif
-
-LOCALBASE ?= /usr/local
-
-# Doxygen directory
-doxygen_dir=doc/doxygen
-
-# install location
-PREFIX ?= $(LOCALBASE)
-prefix = $(PREFIX)
-# install path is $(basedir) $(prefix) 
-# example:
-#  creating a bin. archive in /tmp, which unpacks in /usr/local
-#  basedir=/tmp
-#  prefix=/usr/local
-
-BASEDIR ?= $(DESTDIR)
-basedir = $(BASEDIR)
-# install prefixes for various stuff
-cfg_prefix = $(basedir)$(prefix)
-bin_prefix = $(basedir)$(prefix)
-modules_prefix = $(basedir)$(prefix)
-lib_prefix = $(basedir)$(prefix)
-doc_prefix = $(basedir)$(prefix)
-man_prefix = $(basedir)$(prefix)
-ut_prefix = $(basedir)$(prefix)
-share_prefix = $(basedir)$(prefix)
-data_prefix = $(basedir)$(prefix)
-
-
-# target dirs for various stuff
-cfg_target = $(prefix)/$(cfg_dir)
-bin_target = $(prefix)/$(bin_dir)
-#modules_target = $(prefix)/$(modules_dir)
-lib_target = $(prefix)/$(lib_dir)
-doc_target = $(prefix)/$(doc_dir)
-data_target = $(prefix)/$(data_dir)
-
-
 
 ifeq ($(OS), solaris)
 #use GNU versions
@@ -375,12 +284,18 @@ ifneq (,$(findstring gcc, $(CC_LONGVER)))
 	#transform gcc version into 2.9x or 3.0
 	CC_SHORTVER:=$(shell echo "$(CC_VER)" | cut -d" " -f 2| \
 				 sed -e 's/[^0-9]*-\(.*\)/\1/'| \
-				 sed -e 's/2\.9.*/2.9x/' -e 's/3\.[0-3]\..*/3.0/' -e \
-				 	's/3\.[0-3]/3.0/' -e 's/3\.[4-9]\..*/3.4/' -e \
-					's/3\.[4-9]/3.4/' -e 's/4\.[0-1]\..*/4.x/' -e \
-					's/4\.[0-1]/4.x/' -e 's/4\.[2-9]\..*/4.2+/' -e \
-					's/4\.[2-9]$$/4.2+/')
-ifeq (,$(strip $(filter-out 3.0 3.4 4.x 4.2+,$(CC_SHORTVER))))
+				 sed -e 's/2\.9.*/2.9x/' \
+					-e 's/3\.[0-3]\..*/3.0/' \
+					-e 's/3\.[0-3]/3.0/' \
+					-e 's/3\.[4-9]\..*/3.4/' \
+					-e 's/3\.[4-9]/3.4/' \
+					-e 's/4\.[0-1]\..*/4.x/' \
+					-e 's/4\.[0-1]/4.x/' \
+					-e 's/4\.[2-46-9]\..*/4.2+/' \
+					-e 's/4\.[2-46-9]$$/4.2+/' \
+					-e 's/4\.5\..*/4.5/' \
+					-e 's/4\.5$$/4.5/')
+ifeq (,$(strip $(filter-out 3.0 3.4 4.x 4.2+ 4.5,$(CC_SHORTVER))))
 	# dependencies can be generated on-the-fly while compiling *.c
 	CC_MKDEP_OPTS=-MMD -MP
 endif # 3.0 <= $(CC_SHORTVER) <= 4.x
@@ -494,6 +409,107 @@ ARCH:=$(HOST_ARCH)
 endif
 $(info target architecture <$(ARCH)>, host architecture <$(HOST_ARCH)>)
 
+LIBDIR ?=
+ifeq ($(LIBDIR),)
+ARCHBSZ= $(shell echo $(ARCH) | sed -e 's/.*64.*/64b/')
+ifeq ($(ARCHBSZ),64b)
+	LIBDIR = lib64
+else
+	LIBDIR = lib
+endif
+endif
+
+# dirs
+cfg_dir = etc/$(MAIN_NAME)/
+bin_dir = sbin/
+share_dir = share/$(MAIN_NAME)/
+# lib/$(MAIN_NAME)/modules , lib/$(MAIN_NAME)/modules-s, lib/$(MAIN_NAME)/modules-k
+modules_dir = $(LIBDIR)/$(MAIN_NAME)/
+lib_dir = $(LIBDIR)/$(MAIN_NAME)/
+
+doc_dir = doc/$(MAIN_NAME)/
+man_dir = man/
+data_dir = $(MAIN_NAME)/
+
+ifeq ($(OS), linux)
+	doc_dir = share/doc/$(MAIN_NAME)/
+	man_dir = share/man/
+	data_dir = share/$(MAIN_NAME)/
+	LOCALBASE ?= /usr/local
+endif
+
+ifeq ($(OS), freebsd)
+	doc_dir = share/doc/$(MAIN_NAME)/
+	man_dir = man/
+	data_dir = share/$(MAIN_NAME)/
+	LOCALBASE ?= /usr/local
+endif
+
+ifeq ($(OS), openbsd)
+	doc_dir = share/doc/$(MAIN_NAME)/
+	man_dir = man/
+	data_dir = share/$(MAIN_NAME)/
+	LOCALBASE ?= /usr/local
+endif
+
+ifeq ($(OS), netbsd)
+	doc_dir = share/doc/$(MAIN_NAME)/
+	man_dir = man/
+	data_dir = share/$(MAIN_NAME)/
+	LOCALBASE ?= /usr/pkg
+endif
+
+ifeq ($(OS), dragonfly)
+	doc_dir = share/doc/$(MAIN_NAME)/
+	man_dir = man/
+	data_dir = share/$(MAIN_NAME)/
+	LOCALBASE ?= /usr/pkg
+endif
+
+ifeq ($(OS), darwin)
+	doc_dir = share/doc/$(MAIN_NAME)/
+	man_dir = man/
+	data_dir = share/$(MAIN_NAME)/
+	LOCALBASE ?= /usr/local
+endif
+
+LOCALBASE ?= /usr/local
+
+# Doxygen directory
+doxygen_dir=doc/doxygen
+
+# install location
+PREFIX ?= $(LOCALBASE)
+prefix = $(PREFIX)
+# install path is $(basedir) $(prefix)
+# example:
+#  creating a bin. archive in /tmp, which unpacks in /usr/local
+#  basedir=/tmp
+#  prefix=/usr/local
+
+BASEDIR ?= $(DESTDIR)
+basedir = $(BASEDIR)
+# install prefixes for various stuff
+cfg_prefix = $(basedir)$(prefix)
+bin_prefix = $(basedir)$(prefix)
+modules_prefix = $(basedir)$(prefix)
+lib_prefix = $(basedir)$(prefix)
+doc_prefix = $(basedir)$(prefix)
+man_prefix = $(basedir)$(prefix)
+ut_prefix = $(basedir)$(prefix)
+share_prefix = $(basedir)$(prefix)
+data_prefix = $(basedir)$(prefix)
+
+
+# target dirs for various stuff
+cfg_target = $(prefix)/$(cfg_dir)
+bin_target = $(prefix)/$(bin_dir)
+#modules_target = $(prefix)/$(modules_dir)
+lib_target = $(prefix)/$(lib_dir)
+doc_target = $(prefix)/$(doc_dir)
+data_target = $(prefix)/$(data_dir)
+
+
 # compile-time options
 #
 # -DSTATS
@@ -848,8 +864,8 @@ ifeq		($(CC_NAME), gcc)
 				C_DEFS+=-DCC_GCC_LIKE_ASM
 				#common stuff
 				CFLAGS=-g -O9 -funroll-loops  -Wcast-align $(PROFILE)
-			#if gcc 4.2+
-ifeq			($(CC_SHORTVER), 4.2+)
+			#if gcc 4.5 or 4.2+
+ifeq (,$(strip $(filter-out 4.2+ 4.5,$(CC_SHORTVER))))
 $(call				set_if_empty,CPU,athlon64)
 					CFLAGS+=-m32 -minline-all-stringops \
 							-falign-loops \
@@ -898,7 +914,7 @@ endif			# CC_SHORTVER, 2.9x
 endif			# CC_SHORTVER, 3.0
 endif			# CC_SHORTVER, 3.4
 endif			# CC_SHORTVER, 4.x
-endif			# CC_SHORTVER, 4.2+
+endif			# CC_SHORTVER, 4.5 or 4.2+
 
 else		# CC_NAME, gcc
 ifeq		($(CC_NAME), icc)
@@ -923,6 +939,16 @@ ifeq		($(CC_NAME), gcc)
 				C_DEFS+=-DCC_GCC_LIKE_ASM
 				#common stuff
 				CFLAGS=-g -O9 -funroll-loops  -Wcast-align $(PROFILE)
+			#if gcc 4.5
+			# don't add '-mtune=$(CPU)' - gcc failure
+ifeq			($(CC_SHORTVER), 4.5)
+$(call				set_if_empty,CPU,opteron)
+					CFLAGS+=-m64 -minline-all-stringops \
+							-falign-loops \
+							-ftree-vectorize \
+							-fno-strict-overflow
+					LDFLAGS+=-m64
+else
 			#if gcc 4.2+
 ifeq			($(CC_SHORTVER), 4.2+)
 $(call				set_if_empty,CPU,opteron)
@@ -974,6 +1000,7 @@ endif			# CC_SHORTVER, 3.0
 endif			# CC_SHORTVER, 3.4
 endif			# CC_SHORTVER, 4.x
 endif			# CC_SHORTVER, 4.2+
+endif			# CC_SHORTVER, 4.5
 
 else		# CC_NAME, gcc
 ifeq		($(CC_NAME), icc)
@@ -1000,8 +1027,8 @@ ifeq		($(CC_NAME), gcc)
 				CFLAGS=-g -O9 -funroll-loops  $(PROFILE) \
 					#-Wcast-align \
 					#-Wmissing-prototypes 
-				#if gcc 4.2+
-ifeq			($(CC_SHORTVER), 4.2+)
+				#if gcc 4.5 or 4.2+
+ifeq (,$(strip $(filter-out 4.2+ 4.5,$(CC_SHORTVER))))
 $(call				set_if_empty,CPU,ultrasparc)
 					#use 32bit for now
 					CFLAGS+=-m64 -mcpu=ultrasparc  \
@@ -1067,7 +1094,7 @@ endif			#CC_SHORTVER, 2.9x
 endif			#CC_SHORTVER, 3.0
 endif			#CC_SHORTVER, 3.4
 endif			#CC_SHORTVER, 4.x
-endif			#CC_SHORTVER, 4.2+
+endif			#CC_SHORTVER, 4.5 or 4.2+
 	
 else		#CC_NAME, gcc
 ifeq		($(CC_NAME), suncc)
@@ -1091,8 +1118,8 @@ ifeq		($(CC_NAME), gcc)
 				CFLAGS=-g -O9 -funroll-loops  $(PROFILE) \
 					#-Wcast-align \
 					#-Wmissing-prototypes 
-				#if gcc 4.2+
-ifeq			($(CC_SHORTVER), 4.2+)
+				#if gcc 4.5 or 4.2+
+ifeq (,$(strip $(filter-out 4.2+ 4.5,$(CC_SHORTVER))))
 $(call				set_if_empty,CPU,v8)
 					#use 32bit for now
 					CFLAGS+= -mtune=$(CPU) \
@@ -1133,7 +1160,7 @@ endif			#CC_SHORTVER, 2.9x
 endif			#CC_SHORTVER, 3.0
 endif			#CC_SHORTVER, 3.4
 endif			#CC_SHORTVER, 4.x
-endif			#CC_SHORTVER, 4.2+
+endif			#CC_SHORTVER, 4.5 or 4.2+
 	
 else		#CC_NAME, gcc
 ifeq		($(CC_NAME), suncc)
@@ -1154,8 +1181,8 @@ ifeq		($(CC_NAME), gcc)
 				C_DEFS+=-DCC_GCC_LIKE_ASM
 				#common stuff
 				CFLAGS=-O9 -funroll-loops -fsigned-char $(PROFILE)
-			#if gcc 4.2+
-ifeq			($(CC_SHORTVER), 4.2+)
+			#if gcc 4.5 or 4.2+
+ifeq (,$(strip $(filter-out 4.2+ 4.5,$(CC_SHORTVER))))
 					CFLAGS+= -ftree-vectorize -fno-strict-overflow
 					# not supported on arm: -minline-all-stringops 
 else
@@ -1187,7 +1214,7 @@ endif			# CC_SHORTVER, 2.9x
 endif			# CC_SHORTVER, 3.0
 endif			# CC_SHORTVER, 3.4
 endif			# CC_SHORTVER, 4.x
-endif			# CC_SHORTVER, 4.2+
+endif			# CC_SHORTVER, 4.5 or 4.2+
 	
 else		# CC_NAME, gcc
 				#other compilers
@@ -1203,8 +1230,8 @@ ifeq		($(CC_NAME), gcc)
 				#common stuff
 				CFLAGS=-march=armv6 -O9 -funroll-loops -fsigned-char \
 						$(PROFILE)
-			#if gcc 4.2+
-ifeq			($(CC_SHORTVER), 4.2+)
+			#if gcc 4.5 or 4.2+
+ifeq (,$(strip $(filter-out 4.2+ 4.5,$(CC_SHORTVER))))
 					CFLAGS+= -ftree-vectorize -fno-strict-overflow
 else
 			#if gcc 4.x+
@@ -1234,7 +1261,7 @@ endif			# CC_SHORTVER, 2.9x
 endif			# CC_SHORTVER, 3.0
 endif			# CC_SHORTVER, 3.4
 endif			# CC_SHORTVER, 4.x
-endif			# CC_SHORTVER, 4.2+
+endif			# CC_SHORTVER, 4.5 or 4.2+
 	
 else		# CC_NAME, gcc
 				#other compilers
@@ -1249,8 +1276,8 @@ ifeq		($(CC_NAME), gcc)
 				C_DEFS+=-DCC_GCC_LIKE_ASM
 				#common stuff
 				CFLAGS=-O9 -funroll-loops  $(PROFILE)
-			#if gcc 4.2+
-ifeq			($(CC_SHORTVER), 4.2+)
+			#if gcc 4.5 or 4.2+
+ifeq (,$(strip $(filter-out 4.2+ 4.5,$(CC_SHORTVER))))
 					CFLAGS+=-march=r3000 -minline-all-stringops \
 							-ftree-vectorize -fno-strict-overflow
 else
@@ -1281,7 +1308,7 @@ endif			# CC_SHORTVER, 2.9x
 endif			# CC_SHORTVER, 3.0
 endif			# CC_SHORTVER, 3.4
 endif			# CC_SHORTVER, 4.x
-endif			# CC_SHORTVER, 4.2+
+endif			# CC_SHORTVER, 4.5 or 4.2+
 	
 else		# CC_NAME, gcc
 				#other compilers
@@ -1296,8 +1323,8 @@ ifeq		($(CC_NAME), gcc)
 				C_DEFS+=-DCC_GCC_LIKE_ASM
 				#common stuff
 				CFLAGS= -mips2 -O9 -funroll-loops $(PROFILE)
-			#if gcc 4.2+
-ifeq			($(CC_SHORTVER), 4.2+)
+			#if gcc 4.5 or 4.2+
+ifeq (,$(strip $(filter-out 4.2+ 4.5,$(CC_SHORTVER))))
 					CFLAGS+=-minline-all-stringops -ftree-vectorize \
 							-fno-strict-overflow
 else
@@ -1326,7 +1353,7 @@ endif			# CC_SHORTVER, 2.9x
 endif			# CC_SHORTVER, 3.0
 endif			# CC_SHORTVER, 3.4
 endif			# CC_SHORTVER, 4.x
-endif			# CC_SHORTVER, 4.2+
+endif			# CC_SHORTVER, 4.5 or 4.2+
 	
 else		# CC_NAME, gcc
 				#other compilers
@@ -1341,8 +1368,8 @@ ifeq		($(CC_NAME), gcc)
 				C_DEFS+=-DCC_GCC_LIKE_ASM
 				#common stuff
 				CFLAGS= -mips64 -O9 -funroll-loops $(PROFILE)
-			#if gcc 4.2+
-ifeq			($(CC_SHORTVER), 4.2+)
+			#if gcc 4.5 or 4.2+
+ifeq (,$(strip $(filter-out 4.2+ 4.5,$(CC_SHORTVER))))
 					CFLAGS+=-minline-all-stringops -ftree-vectorize \
 							-fno-strict-overflow
 else
@@ -1371,7 +1398,7 @@ endif			# CC_SHORTVER, 2.9x
 endif			# CC_SHORTVER, 3.0
 endif			# CC_SHORTVER, 3.4
 endif			# CC_SHORTVER, 4.x
-endif			# CC_SHORTVER, 4.2+
+endif			# CC_SHORTVER, 4.5 or 4.2+
 	
 else		# CC_NAME, gcc
 				#other compilers
@@ -1386,8 +1413,8 @@ ifeq		($(CC_NAME), gcc)
 				C_DEFS+=-DCC_GCC_LIKE_ASM
 				#common stuff
 				CFLAGS= -O9 -funroll-loops $(PROFILE)
-			#if gcc 4.2+
-ifeq			($(CC_SHORTVER), 4.2+)
+			#if gcc 4.5 or 4.2+
+ifeq (,$(strip $(filter-out 4.2+ 4.5,$(CC_SHORTVER))))
 					CFLAGS+= -fno-strict-overflow
 					# not supported: -minline-all-stringops
 else
@@ -1417,7 +1444,7 @@ endif			# CC_SHORTVER, 2.9x
 endif			# CC_SHORTVER, 3.0
 endif			# CC_SHORTVER, 3.4
 endif			# CC_SHORTVER, 4.x
-endif			# CC_SHORTVER, 4.2+
+endif			# CC_SHORTVER, 4.5 or 4.2+
 	
 else		# CC_NAME, gcc
 				#other compilers
@@ -1432,8 +1459,8 @@ ifeq		($(CC_NAME), gcc)
 				C_DEFS+=-DCC_GCC_LIKE_ASM
 				#common stuff
 				CFLAGS= -O9 -funroll-loops -fsigned-char $(PROFILE)
-			#if gcc 4.2+
-ifeq			($(CC_SHORTVER), 4.2+)
+			#if gcc 4.5 or 4.2+
+ifeq (,$(strip $(filter-out 4.2+ 4.5,$(CC_SHORTVER))))
 $(call				set_if_empty,CPU,powerpc)
 					CFLAGS+=-ftree-vectorize \
 							-fno-strict-overflow \
@@ -1466,7 +1493,7 @@ endif			# CC_SHORTVER, 2.9x
 endif			# CC_SHORTVER, 3.0
 endif			# CC_SHORTVER, 3.4
 endif			# CC_SHORTVER, 4.x
-endif			# CC_SHORTVER, 4.2+
+endif			# CC_SHORTVER, 4.5 or 4.2+
 	
 else		# CC_NAME, gcc
 				#other compilers
@@ -1481,8 +1508,8 @@ ifeq		($(CC_NAME), gcc)
 				C_DEFS+=-DCC_GCC_LIKE_ASM
 				#common stuff
 				CFLAGS= -O9 -funroll-loops -fsigned-char $(PROFILE)
-			#if gcc 4.2+
-ifeq			($(CC_SHORTVER), 4.2+)
+			#if gcc 4.5 or 4.2+
+ifeq (,$(strip $(filter-out 4.2+ 4.5,$(CC_SHORTVER))))
 $(call				set_if_empty,CPU,powerpc64)
 					CFLAGS+=-ftree-vectorize \
 							-fno-strict-overflow \
@@ -1515,7 +1542,7 @@ endif			# CC_SHORTVER, 2.9x
 endif			# CC_SHORTVER, 3.0
 endif			# CC_SHORTVER, 3.4
 endif			# CC_SHORTVER, 4.x
-endif			# CC_SHORTVER, 4.2+
+endif			# CC_SHORTVER, 4.5 or 4.2+
 	
 else		# CC_NAME, gcc
 				#other compilers
@@ -2048,7 +2075,7 @@ saved_fixed_vars:=	MAIN_NAME  CFG_NAME SCR_NAME FLAVOUR INSTALL_FLAVOUR \
 # extra: prefix DESTDIR BASEDIR basedirt
 saved_chg_vars:=\
 		CC_EXTRA_OPTS CPU CFLAGS_RM CFLAGS MOD_CFLAGS LIB_CFLAGS UTILS_CFLAGS \
-		BASEDIR basedir DESTDIR \
+		BASEDIR basedir DESTDIR LIBDIR \
 		PREFIX prefix\
 		cfg_prefix cfg_dir bin_prefix bin_dir modules_prefix modules_dir \
 		doc_prefix doc_dir man_prefix man_dir ut_prefix ut_dir \

+ 16 - 3
Makefile.radius

@@ -6,9 +6,11 @@
 #
 # (To be included from Makefiles of radius related modules)
 #
-# The purpose of this makefile is to perform radiusclient library
-# detection and setup library and include paths in DEFS and LIBS
-# variables. In addition RADIUSCLIENT_NG_4 will be defined when
+# The purpose of this makefile is to perform RADIUS client library
+# selection (radiusclient-ng or freeradius-client) and setup
+# library and include paths in DEFS and LIBS variables.
+#
+# In addition RADIUSCLIENT_NG_4 will be defined when
 # libradiusclient-ng version 4 is detected. That means the module
 # should include radiusclient.h, otherwise radiusclient-ng.h
 # should be included. Variable RADIUSCLIENT_LIB contains the
@@ -21,6 +23,15 @@
 #
 INCLUDES+=-I$(LOCALBASE)/include
 
+ifeq ($(FREERADIUS),1)
+
+# - freeradius-client library
+DEFS+= -DUSE_FREERADIUS
+RADIUSCLIENT_LIB=freeradius-client
+
+else
+
+# - radiusclient-ng v5 or v4 library
 ifneq ($(radiusclient_ng), 4)
 
 # radiusclient-ng 5+
@@ -34,4 +45,6 @@ RADIUSCLIENT_LIB=radiusclient
 
 endif
 
+endif
+
 LIBS=-L$(LOCALBASE)/lib -l$(RADIUSCLIENT_LIB)

+ 25 - 8
cfg.lex

@@ -200,7 +200,9 @@ SEND_TCP	send_tcp
 LOG		log
 ERROR	error
 ROUTE	route
+ROUTE_REQUEST request_route
 ROUTE_FAILURE failure_route
+ROUTE_REPLY reply_route
 ROUTE_ONREPLY onreply_route
 ROUTE_BRANCH branch_route
 ROUTE_SEND onsend_route
@@ -300,6 +302,10 @@ LOG_AND		"and"|"&&"
 BIN_AND         "&"
 LOG_OR		"or"|"||"
 BIN_OR          "|"
+BIN_NOT     "~"
+BIN_XOR     "^"
+BIN_LSHIFT     "<<"
+BIN_RSHIFT     ">>"
 PLUS	"+"
 MINUS	"-"
 MODULO	"mod"
@@ -542,6 +548,9 @@ COM_LINE	#
 COM_START	"/\*"
 COM_END		"\*/"
 
+/* start of pre-processing directives */
+PREP_START	"#!"|"!!"
+
 DEFINE       "define"|"def"
 IFDEF        ifdef
 IFNDEF       ifndef
@@ -552,6 +561,7 @@ EAT_ABLE	[\ \t\b\r]
 
 /* pre-processing blocks */
 SUBST       subst
+SUBSTDEF    substdef
 
 %%
 
@@ -581,8 +591,10 @@ SUBST       subst
 <INITIAL>{AVPFLAGS_DECL}	{ count(); yylval.strval=yytext; return AVPFLAGS_DECL; }
 <INITIAL>{MSGLEN}	{ count(); yylval.strval=yytext; return MSGLEN; }
 <INITIAL>{ROUTE}	{ count(); yylval.strval=yytext; return ROUTE; }
+<INITIAL>{ROUTE_REQUEST}	{ count(); yylval.strval=yytext; return ROUTE_REQUEST; }
 <INITIAL>{ROUTE_ONREPLY}	{ count(); yylval.strval=yytext;
 								return ROUTE_ONREPLY; }
+<INITIAL>{ROUTE_REPLY}	{ count(); yylval.strval=yytext; return ROUTE_REPLY; }
 <INITIAL>{ROUTE_FAILURE}	{ count(); yylval.strval=yytext;
 								return ROUTE_FAILURE; }
 <INITIAL>{ROUTE_BRANCH} { count(); yylval.strval=yytext; return ROUTE_BRANCH; }
@@ -935,6 +947,10 @@ SUBST       subst
 <INITIAL>{BIN_AND}	{ count(); return BIN_AND; }
 <INITIAL>{LOG_OR}	{ count(); return LOG_OR;  }
 <INITIAL>{BIN_OR}	{ count(); return BIN_OR;  }
+<INITIAL>{BIN_NOT}	{ count(); return BIN_NOT;  }
+<INITIAL>{BIN_XOR}	{ count(); return BIN_XOR;  }
+<INITIAL>{BIN_LSHIFT}	{ count(); return BIN_LSHIFT;  }
+<INITIAL>{BIN_RSHIFT}	{ count(); return BIN_RSHIFT;  }
 <INITIAL>{PLUS}		{ count(); return PLUS; }
 <INITIAL>{MINUS}	{ count(); return MINUS; }
 <INITIAL>{MODULO}	{ count(); return MODULO; }
@@ -1195,7 +1211,7 @@ SUBST       subst
 <INITIAL>{COM_LINE}!{MAXCOMPAT_CFG}{CR}	{ count(); 
 												sr_cfg_compat=SR_COMPAT_MAX;}
 
-<INITIAL>{COM_LINE}!{DEFINE}{EAT_ABLE}+	{	count();
+<INITIAL>{PREP_START}{DEFINE}{EAT_ABLE}+	{	count();
 											state = DEFINE_S; BEGIN(DEFINE_ID); }
 <DEFINE_ID>{ID}                 {	count();
 									if (pp_define(yyleng, yytext)) return 1;
@@ -1214,12 +1230,13 @@ SUBST       subst
 <DEFINE_DATA>.          {	count();
 							addstr(&s_buf, yytext, yyleng); }
 
-<INITIAL>{COM_LINE}!{SUBST}	{ count();  return SUBST;}
+<INITIAL>{PREP_START}{SUBST}	{ count();  return SUBST;}
+<INITIAL>{PREP_START}{SUBSTDEF}	{ count();  return SUBSTDEF;}
 
-<INITIAL,IFDEF_SKIP>{COM_LINE}!{IFDEF}{EAT_ABLE}+    { count();
+<INITIAL,IFDEF_SKIP>{PREP_START}{IFDEF}{EAT_ABLE}+    { count();
 								if (pp_ifdef_type(1)) return 1;
 								state = IFDEF_S; BEGIN(IFDEF_ID); }
-<INITIAL,IFDEF_SKIP>{COM_LINE}!{IFNDEF}{EAT_ABLE}+    { count();
+<INITIAL,IFDEF_SKIP>{PREP_START}{IFNDEF}{EAT_ABLE}+    { count();
 								if (pp_ifdef_type(0)) return 1;
 								state = IFDEF_S; BEGIN(IFDEF_ID); }
 <IFDEF_ID>{ID}                { count();
@@ -1227,9 +1244,9 @@ SUBST       subst
                                 state = IFDEF_EOL_S; BEGIN(IFDEF_EOL); }
 <IFDEF_EOL>{EAT_ABLE}*{CR}    { count(); pp_ifdef(); }
 
-<INITIAL,IFDEF_SKIP>{COM_LINE}!{ELSE}{EAT_ABLE}*{CR}    { count(); pp_else(); }
+<INITIAL,IFDEF_SKIP>{PREP_START}{ELSE}{EAT_ABLE}*{CR}    { count(); pp_else(); }
 
-<INITIAL,IFDEF_SKIP>{COM_LINE}!{ENDIF}{EAT_ABLE}*{CR}    { count();
+<INITIAL,IFDEF_SKIP>{PREP_START}{ENDIF}{EAT_ABLE}*{CR}    { count();
 															pp_endif(); }
 
  /* we're in an ifdef that evaluated to false -- throw it away */
@@ -1648,7 +1665,7 @@ int pp_define(int len, const char * text)
 	return 0;
 }
 
-int  pp_define_set(int len, char *text)
+int pp_define_set(int len, char *text)
 {
 	if(len<=0) {
 		LOG(L_DBG, "no define value - ignoring\n");
@@ -1685,7 +1702,7 @@ int  pp_define_set(int len, char *text)
 	return 0;
 }
 
-static str  *pp_define_get(int len, const char * text)
+static str *pp_define_get(int len, const char * text)
 {
 	str var = {(char *)text, len};
 	int i;

+ 28 - 3
cfg.y

@@ -307,8 +307,10 @@ extern char *finame;
 %token LOG_TOK
 %token ERROR
 %token ROUTE
+%token ROUTE_REQUEST
 %token ROUTE_FAILURE
 %token ROUTE_ONREPLY
+%token ROUTE_REPLY
 %token ROUTE_BRANCH
 %token ROUTE_SEND
 %token ROUTE_EVENT
@@ -560,6 +562,7 @@ extern char *finame;
 
 /*pre-processor*/
 %token SUBST
+%token SUBSTDEF
 
 /* operators, C like precedence */
 %right EQUAL
@@ -567,11 +570,14 @@ extern char *finame;
 %left LOG_AND
 %left BIN_OR
 %left BIN_AND
+%left BIN_XOR
+%left BIN_LSHIFT
+%left BIN_RSHIFT
 %left EQUAL_T DIFF MATCH INTEQ INTDIFF STREQ STRDIFF
 %left GT LT GTE LTE
 %left PLUS MINUS
 %left STAR SLASH MODULO
-%right NOT UNARY
+%right NOT UNARY BIN_NOT
 %right DEFINED
 %right INTCAST STRCAST
 %left DOT
@@ -1766,8 +1772,13 @@ route_name:		NUMBER	{
 			|	STRING	{ $$=$1; }
 ;
 
+
+route_main:	ROUTE { ; }
+		  | ROUTE_REQUEST { ; }
+;
+
 route_stm:
-	ROUTE LBRACE actions RBRACE {
+	route_main LBRACE actions RBRACE {
 	#ifdef SHM_MEM
 		if (!shm_initialized() && init_shm()<0) {
 			yyerror("Can't initialize shared memory");
@@ -1795,6 +1806,7 @@ route_stm:
 		push($6, &main_rt.rlist[i_tmp]);
 	}
 	| ROUTE error { yyerror("invalid  route  statement"); }
+	| ROUTE_REQUEST error { yyerror("invalid  request_route  statement"); }
 	;
 failure_route_stm:
 	ROUTE_FAILURE LBRACE actions RBRACE {
@@ -1827,8 +1839,14 @@ failure_route_stm:
 	| ROUTE_FAILURE error { yyerror("invalid failure_route statement"); }
 	;
 
+
+route_reply_main:	ROUTE_ONREPLY { ; }
+		  | ROUTE_REPLY { ; }
+;
+
+
 onreply_route_stm:
-	ROUTE_ONREPLY LBRACE {rt=CORE_ONREPLY_ROUTE;} actions RBRACE {
+	route_reply_main LBRACE {rt=CORE_ONREPLY_ROUTE;} actions RBRACE {
 	#ifdef SHM_MEM
 		if (!shm_initialized() && init_shm()<0) {
 			yyerror("Can't initialize shared memory");
@@ -1838,6 +1856,7 @@ onreply_route_stm:
 		push($4, &onreply_rt.rlist[DEFAULT_RT]);
 	}
 	| ROUTE_ONREPLY error { yyerror("invalid onreply_route statement"); }
+	| ROUTE_REPLY error { yyerror("invalid onreply_route statement"); }
 	| ROUTE_ONREPLY LBRACK route_name RBRACK 
 		{rt=(*$3=='0' && $3[1]==0)?CORE_ONREPLY_ROUTE:TM_ONREPLY_ROUTE;}
 		LBRACE actions RBRACE {
@@ -1950,6 +1969,8 @@ event_route_stm: ROUTE_EVENT LBRACK EVENT_RT_NAME RBRACK LBRACE actions RBRACE {
 preprocess_stm:
 	SUBST STRING { if(pp_subst_add($2)<0) YYERROR; }
 	| SUBST error { yyerror("invalid subst preprocess statement"); }
+	| SUBSTDEF STRING { if(pp_substdef_add($2)<0) YYERROR; }
+	| SUBSTDEF error { yyerror("invalid substdef preprocess statement"); }
 	;
 
 /*exp:	rval_expr
@@ -2748,6 +2769,7 @@ rval: intno			{$$=mk_rve_rval(RV_INT, (void*)$1); }
 
 
 rve_un_op: NOT	{ $$=RVE_LNOT_OP; }
+		|  BIN_NOT 	{ $$=RVE_BNOT_OP; }
 		|  MINUS %prec UNARY	{ $$=RVE_UMINUS_OP; }
 		/* TODO: RVE_BOOL_OP, RVE_NOT_OP? */
 	;
@@ -2777,6 +2799,9 @@ rval_expr: rval						{ $$=$1;
 		| rval_expr MODULO rval_expr	{$$=mk_rve2(RVE_MOD_OP, $1, $3); }
 		| rval_expr BIN_OR rval_expr	{$$=mk_rve2(RVE_BOR_OP, $1,  $3); }
 		| rval_expr BIN_AND rval_expr	{$$=mk_rve2(RVE_BAND_OP, $1,  $3);}
+		| rval_expr BIN_XOR rval_expr	{$$=mk_rve2(RVE_BXOR_OP, $1,  $3);}
+		| rval_expr BIN_LSHIFT rval_expr {$$=mk_rve2(RVE_BLSHIFT_OP, $1,  $3);}
+		| rval_expr BIN_RSHIFT rval_expr {$$=mk_rve2(RVE_BRSHIFT_OP, $1,  $3);}
 		| rval_expr rve_cmpop rval_expr %prec GT { $$=mk_rve2( $2, $1, $3);}
 		| rval_expr rve_equalop rval_expr %prec EQUAL_T
 			{ $$=mk_rve2( $2, $1, $3);}

+ 22 - 0
core_cmd.c

@@ -412,6 +412,27 @@ static void core_ps(rpc_t* rpc, void* c)
 	}
 }
 
+static const char* core_psx_doc[] = {
+	"Returns the detailed description of running SER processes.",
+		/* Documentation string */
+	0	/* Method signature(s) */
+};
+
+
+static void core_psx(rpc_t* rpc, void* c)
+{
+	int p;
+	void *handle;
+
+	for (p=0; p<*process_count;p++) {
+		rpc->add(c, "{", &handle);
+		rpc->struct_add(handle, "dds",
+				"IDX", p,
+				"PID", pt[p].pid,
+				"DSC", pt[p].desc);
+	}
+}
+
 
 static const char* core_pwd_doc[] = {
 	"Returns the working directory of SER server.",    /* Documentation string */
@@ -889,6 +910,7 @@ static rpc_export_t core_rpc_methods[] = {
 		0        },
 	{"core.uptime",            core_uptime,            core_uptime_doc,            0        },
 	{"core.ps",                core_ps,                core_ps_doc,                RET_ARRAY},
+	{"core.psx",               core_psx,               core_psx_doc,                0},
 	{"core.pwd",               core_pwd,               core_pwd_doc,               RET_ARRAY},
 	{"core.arg",               core_arg,               core_arg_doc,               RET_ARRAY},
 	{"core.kill",              core_kill,              core_kill_doc,              0        },

+ 133 - 0
doc/stylesheets/dbschema_k/xsl/db_sqlite.xsl

@@ -0,0 +1,133 @@
+<?xml version='1.0'?>
+<!--
+ * XSL converter script for sqlite databases
+ *
+ * Copyright (C) 2001-2007 FhG Fokus
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+-->
+
+
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                version='1.0'
+                xmlns:xi="http://www.w3.org/2001/XInclude"
+>
+
+    <xsl:import href="sql.xsl"/>
+
+<!-- specify the table type -->
+    <xsl:template name="table.close">
+	<xsl:text>)</xsl:text>
+	<xsl:if test="type[@db=$db]">
+	    <xsl:text> Type=</xsl:text>
+	    <xsl:value-of select="normalize-space(type[@db=$db])"/>
+	</xsl:if>
+	<xsl:text>;&#x0A;&#x0A;</xsl:text>
+    </xsl:template>
+
+    <xsl:template name="column.type">
+	<xsl:variable name="type">
+	    <xsl:call-template name="get-type"/>
+	</xsl:variable>
+
+	<xsl:choose>
+	    <xsl:when test="type[@db=$db]">
+		<xsl:value-of select="normalize-space(type[@db=$db])"/>
+	    </xsl:when>
+	    <xsl:when test="$type='char'">
+		<xsl:text>SMALLINT</xsl:text>
+		<xsl:call-template name="column.trailing"/>
+	    </xsl:when>
+	    <xsl:when test="$type='short'">
+		<xsl:text>SMALLINT</xsl:text>
+		<xsl:call-template name="column.trailing"/>
+	    </xsl:when>
+	    <xsl:when test="$type='int'">
+			<xsl:if test="not(autoincrement)">
+				<xsl:text>INTEGER</xsl:text>
+			</xsl:if>
+		<xsl:call-template name="column.trailing"/>
+	    </xsl:when>
+	    <xsl:when test="$type='long'">
+		<xsl:text>BIGINT</xsl:text>
+		<xsl:call-template name="column.trailing"/>
+	    </xsl:when>
+	    <xsl:when test="$type='datetime'">
+		<xsl:text>TIMESTAMP</xsl:text>
+		<xsl:call-template name="column.trailing"/>
+	    </xsl:when>
+	    <xsl:when test="$type='double'">
+		<xsl:text>DOUBLE PRECISION</xsl:text>
+		<xsl:call-template name="column.trailing"/>
+	    </xsl:when>
+	    <xsl:when test="$type='float'">
+		<xsl:text>REAL</xsl:text>
+		<xsl:call-template name="column.trailing"/>
+	    </xsl:when>
+	    <xsl:when test="$type='string'">
+		<xsl:text>VARCHAR</xsl:text>
+		<xsl:call-template name="column.size"/>
+		<xsl:call-template name="column.trailing"/>
+	    </xsl:when>
+	    <xsl:when test="$type='binary'">
+		<xsl:text>BYTEA</xsl:text>
+		<xsl:call-template name="column.size"/>
+		<xsl:call-template name="column.trailing"/>
+	    </xsl:when>
+	    <xsl:when test="$type='text'">
+		<xsl:text>TEXT</xsl:text>
+		<xsl:call-template name="column.size"/>
+		<xsl:call-template name="column.trailing"/>
+	    </xsl:when>
+	    <xsl:otherwise>
+		<xsl:call-template name="type-error"/>
+	    </xsl:otherwise>
+	</xsl:choose>
+	</xsl:template>
+
+	<xsl:template name="column.trailing">
+	<xsl:variable name="column.type">
+	    <xsl:call-template name="get-type"/>
+	</xsl:variable>
+	<xsl:if test="$column.type='datetime'">
+	    <xsl:text> WITHOUT TIME ZONE</xsl:text>
+	</xsl:if>
+	<xsl:if test="autoincrement">
+		<xsl:text>INTEGER</xsl:text>
+	</xsl:if>
+	<!-- PRIMARY KEY column definition -->
+	<xsl:if test="primary">
+		<xsl:text> PRIMARY KEY</xsl:text>
+	</xsl:if>
+	</xsl:template>
+
+	<xsl:template name="get-index-name">
+	<xsl:variable name="index.name">
+	    <xsl:call-template name="get-name"/>
+	</xsl:variable>
+	<xsl:variable name="table.name">
+	    <xsl:call-template name="get-name">
+		<xsl:with-param name="select" select="parent::table"/>
+	    </xsl:call-template>
+	</xsl:variable>
+	<!-- because postgres don't like identical index names, even on table level -->
+	<xsl:value-of select="concat($table.name, '_', $index.name)"/>
+	</xsl:template>
+
+</xsl:stylesheet>

+ 130 - 64
etc/kamailio.cfg

@@ -51,6 +51,10 @@
 #     - enable mysql
 #     - define WITH_ALIASDB
 #
+# *** To enable speed dial lookup execute:
+#     - enable mysql
+#     - define WITH_SPEEDDIAL
+#
 # *** To enable multi-domain support execute:
 #     - enable mysql
 #     - define WITH_MULTIDOMAIN
@@ -68,6 +72,14 @@
 #       block if more than 16 requests in 2 seconds and ban for 300 seconds)
 #     - define WITH_ANTIFLOOD
 #
+# *** To block 3XX redirect replies execute:
+#     - define WITH_BLOCK3XX
+#
+# *** To enable VoiceMail routing execute:
+#     - define WITH_VOICEMAIL
+#     - set the value of voicemail.srv_ip
+#     - adjust the value of voicemail.srv_port
+#
 # *** To enhance accounting execute:
 #     - enable mysql
 #     - define WITH_ACCDB
@@ -170,6 +182,13 @@ enable_tls=yes
 pstn.gw_ip = "" desc "PSTN GW Address"
 #!endif
 
+#!ifdef WITH_VOICEMAIL
+# VoiceMail Routing on offline, busy or no answer
+#
+# - by default Voicemail server IP is empty to avoid misrouting
+voicemail.srv_ip = "" desc "VoiceMail IP Address"
+voicemail.srv_port = "5060" desc "VoiceMail Port"
+#!endif
 
 ####### Modules Section ########
 
@@ -214,6 +233,10 @@ loadmodule "permissions.so"
 loadmodule "alias_db.so"
 #!endif
 
+#!ifdef WITH_SPEEDDIAL
+loadmodule "speeddial.so"
+#!endif
+
 #!ifdef WITH_MULTIDOMAIN
 loadmodule "domain.so"
 #!endif
@@ -334,6 +357,13 @@ modparam("alias_db", "use_domain", MULTIDOMAIN)
 #!endif
 
 
+# ----- speedial params -----
+#!ifdef WITH_SPEEDDIAL
+modparam("speeddial", "db_url", DBURL)
+modparam("speeddial", "use_domain", MULTIDOMAIN)
+#!endif
+
+
 # ----- domain params -----
 #!ifdef WITH_MULTIDOMAIN
 modparam("domain", "db_url", DBURL)
@@ -408,7 +438,7 @@ route {
 	route(REQINIT);
 
 	# NAT detection
-	route(NAT);
+	route(NATDETECT);
 
 	# handle requests within SIP dialogs
 	route(WITHINDLG);
@@ -469,20 +499,15 @@ route {
 
 
 route[RELAY] {
-#!ifdef WITH_NAT
-	if (check_route_param("nat=yes")) {
-		setbflag(FLB_NATB);
-	}
-	if (isflagset(FLT_NATS) || isbflagset(FLB_NATB)) {
-		route(RTPPROXY);
-	}
-#!endif
 
-	/* example how to enable some additional event routes */
+	# enable additional event routes for forwarded requests
+	# - serial forking, RTP relaying handling, a.s.o.
+	if (is_method("INVITE|SUBSCRIBE")) {
+		t_on_branch("MANAGE_BRANCH");
+		t_on_reply("MANAGE_REPLY");
+	}
 	if (is_method("INVITE")) {
-		#t_on_branch("BRANCH_ONE");
-		t_on_reply("REPLY_ONE");
-		t_on_failure("FAIL_ONE");
+		t_on_failure("MANAGE_FAILURE");
 	}
 
 	if (!t_relay()) {
@@ -536,6 +561,10 @@ route[WITHINDLG] {
 				setflag(FLT_ACC); # do accounting ...
 				setflag(FLT_ACCFAILED); # ... even if the transaction fails
 			}
+			if ( is_method("ACK") ) {
+				# ACK is forwarded statelessy
+				route(NATMANAGE);
+			}
 			route(RELAY);
 		} else {
 			if (is_method("SUBSCRIBE") && uri == myself) {
@@ -581,20 +610,29 @@ route[REGISTRAR] {
 # USER location service
 route[LOCATION] {
 
+#!ifdef WITH_SPEEDIAL
+	# search for short dialing - 2-digit extension
+	if($rU=~"^[0-9][0-9]$")
+		sd_lookup("speed_dial");
+#!endif
+
 #!ifdef WITH_ALIASDB
 	# search in DB-based aliases
 	alias_db_lookup("dbaliases");
 #!endif
 
+	$avp(oexten) = $rU;
 	if (!lookup("location")) {
-		switch ($rc) {
+		$var(rc) = $rc;
+		route(TOVOICEMAIL);
+		t_newtran();
+		switch ($var(rc)) {
 			case -1:
 			case -3:
-				t_newtran();
-				t_reply("404", "Not Found");
+				send_reply("404", "Not Found");
 				exit;
 			case -2:
-				sl_send_reply("405", "Method Not Allowed");
+				send_reply("405", "Method Not Allowed");
 				exit;
 		}
 	}
@@ -715,11 +753,11 @@ route[AUTH] {
 }
 
 # Caller NAT detection route
-route[NAT] {
+route[NATDETECT] {
 #!ifdef WITH_NAT
 	force_rport();
 	if (nat_uac_test("19")) {
-		if (method=="REGISTER") {
+		if (is_method("REGISTER")) {
 			fix_nated_register();
 		} else {
 			fix_nated_contact();
@@ -731,14 +769,30 @@ route[NAT] {
 }
 
 # RTPProxy control
-route[RTPPROXY] {
+route[NATMANAGE] {
 #!ifdef WITH_NAT
-	if (is_method("BYE")) {
-		unforce_rtp_proxy();
-	} else if (is_method("INVITE")){
-		force_rtp_proxy();
+	if (is_request()) {
+		if(has_totag()) {
+			if(check_route_param("nat=yes")) {
+				setbflag(FLB_NATB);
+			}
+		}
+	}
+	if (!(isflagset(FLT_NATS) || isbflagset(FLB_NATB)))
+		return;
+
+	rtpproxy_manage();
+
+	if (is_request()) {
+		if (!has_totag()) {
+			add_rr_param(";nat=yes");
+		}
+	}
+	if (is_reply()) {
+		if(isbflagset(FLB_NATB)) {
+			fix_nated_contact();
+		}
 	}
-	if (!has_totag()) add_rr_param(";nat=yes");
 #!endif
 	return;
 }
@@ -784,8 +838,7 @@ route[PSTN] {
 
 # XMLRPC routing
 #!ifdef WITH_XMLRPC
-route[XMLRPC]
-{
+route[XMLRPC] {
 	# allow XMLRPC from localhost
 	if ((method=="POST" || method=="GET")
 			&& (src_ip==127.0.0.1)) {
@@ -802,51 +855,64 @@ route[XMLRPC]
 }
 #!endif
 
-# Sample branch router
-branch_route[BRANCH_ONE] {
-	xdbg("new branch at $ru\n");
-}
+# route to voicemail server
+route[TOVOICEMAIL] {
+#!ifdef WITH_VOICEMAIL
+	if(!is_method("INVITE"))
+		return;
 
-# Sample onreply route
-onreply_route[REPLY_ONE] {
-	xdbg("incoming reply\n");
-#!ifdef WITH_NAT
-	if ((isflagset(FLT_NATS) || isbflagset(FLB_NATB))
-			&& status=~"(183)|(2[0-9][0-9])") {
-		force_rtp_proxy();
-	}
-	if (isbflagset("6")) {
-		fix_nated_contact();
+	# check if VoiceMail server IP is defined
+	if (strempty($sel(cfg_get.voicemail.srv_ip))) {
+		xlog("SCRIPT: VoiceMail rotuing enabled but IP not defined\n");
+		return;
 	}
+	if($avp(oexten)==$null)
+		return;
+
+	$ru = "sip:" + $avp(oexten) + "@" + $sel(cfg_get.voicemail.srv_ip)
+				+ $sel(cfg_get.voicemail.srv_port);
+	route(RELAY);
+	exit;
 #!endif
+
+	return;
 }
 
-# Sample failure route
-failure_route[FAIL_ONE] {
-#!ifdef WITH_NAT
-	if (is_method("INVITE")
-			&& (isbflagset(FLB_NATB) || isflagset(FLT_NATS))) {
-		unforce_rtp_proxy();
-	}
-#!endif
+# manage outgoing branches
+branch_route[MANAGE_BRANCH] {
+	xdbg("new branch [$T_branch_idx] to $ru\n");
+	route(NATMANAGE);
+}
+
+# manage incoming replies
+onreply_route[MANAGE_REPLY] {
+	xdbg("incoming reply\n");
+	if(status=~"[12][0-9][0-9]")
+		route(NATMANAGE);
+}
+
+# manage failure routing cases
+failure_route[MANAGE_FAILURE] {
+	route(NATMANAGE);
 
 	if (t_is_canceled()) {
 		exit;
 	}
 
-	# uncomment the following lines if you want to block client 
-	# redirect based on 3xx replies.
-	##if (t_check_status("3[0-9][0-9]")) {
-	##t_reply("404","Not found");
-	##	exit;
-	##}
-
-	# uncomment the following lines if you want to redirect the failed 
-	# calls to a different new destination
-	##if (t_check_status("486|408")) {
-	##	sethostport("192.168.2.100:5060");
-	##	append_branch();
-	##	# do not set the missed call flag again
-	##	t_relay();
-	##}
+#!ifdef WITH_BLOCK3XX
+	# block call redirect based on 3xx replies.
+	if (t_check_status("3[0-9][0-9]")) {
+		t_reply("404","Not found");
+		exit;
+	}
+#!endif
+
+#!ifdef WITH_VOICEMAIL
+	# serial forking
+	# - route to voicemail on busy or no answer (timeout)
+	if (t_check_status("486|408")) {
+		route(TOVOICEMAIL);
+		exit;
+	}
+#!endif
 }

+ 2 - 2
forward.c

@@ -543,8 +543,8 @@ int forward_request(struct sip_msg* msg, str* dst, unsigned short port,
 	   value in there; better for performance
 	*/
 	if (syn_branch ) {
-		*msg->add_to_branch_s='0';
-		msg->add_to_branch_len=1;
+	        memcpy(msg->add_to_branch_s, "z9hG4bKcydzigwkX", 16);
+		msg->add_to_branch_len=16;
 	} else {
 		if (!char_msg_val( msg, md5 )) 	{ /* parses transaction key */
 			LOG(L_ERR, "ERROR: forward_request: char_msg_val failed\n");

+ 1 - 0
globals.h

@@ -150,6 +150,7 @@ extern int cfg_warnings;
 extern unsigned int msg_no;
 
 extern unsigned long shm_mem_size;
+extern unsigned long pkg_mem_size;
 
 /* AVP configuration */
 extern char *avp_db_url;  /* db url used by user preferences (AVPs) */

+ 5 - 4
io_wait.h

@@ -283,9 +283,9 @@ retry2:
 						io_wait_loop_kqueue EV_ERROR case */
 						if (unlikely(!(errno == EBADF || errno == ENOENT)))
 							BUG("kq_ev_change: kevent flush changes failed:"
-									" (unexpected error) %s [%d] (%d/%d)\n",
+									" (unexpected error) %s [%d] (%d/%lu)\n",
 										strerror(errno), errno,
-										r, h->kq_nchanges);
+										r, (unsigned long)h->kq_nchanges);
 						continue; /* skip over it */
 					}
 				}
@@ -1219,9 +1219,10 @@ again:
 					BUG("io_wait_loop_kqueue: unknown filter: kqueue: event "
 							"%d/%d: fd=%d, filter=%d, flags=0x%x, fflags=0x%x,"
 							" data=%lx, udata=%lx\n",
-					r, n, h->kq_array[r].ident, h->kq_array[r].filter,
+					r, n, (int)h->kq_array[r].ident, (int)h->kq_array[r].filter,
 					h->kq_array[r].flags, h->kq_array[r].fflags,
-					(long)h->kq_array[r].data, (long)h->kq_array[r].udata);
+					(unsigned long)h->kq_array[r].data,
+					(unsigned long)h->kq_array[r].udata);
 				}
 			}
 		}

+ 2 - 2
lib/kcore/kstats_wrapper.h

@@ -76,11 +76,11 @@ inline static stat_var* get_stat(str *name)
 
 
 
-inline static unsigned int get_stat_val(stat_var *v)
+inline static unsigned long get_stat_val(stat_var *v)
 {
 	counter_handle_t h;
 	h.id = (unsigned short)(unsigned long)v;
-	return counter_get_val(h);
+	return (unsigned long)counter_get_val(h);
 }
 
 

+ 10 - 1
lib/kcore/parser_helpers.c

@@ -12,7 +12,16 @@ struct sip_uri *parse_to_uri(struct sip_msg *msg)
 {
 	struct to_body *tb = NULL;
 	
-	if(msg==NULL || msg->to==NULL || msg->to->parsed==NULL)
+	if(msg==NULL)
+		return NULL;
+
+	if(parse_to_header(msg)<0)
+	{
+		LM_ERR("cannot parse TO header\n");
+		return NULL;
+	}
+
+	if(msg->to==NULL || get_to(msg)==NULL)
 		return NULL;
 
 	tb = get_to(msg);

+ 3 - 0
lib/srdb1/db_id.c

@@ -162,12 +162,14 @@ static int parse_db_url(struct db_id* id, const str* url)
 			case '@':
 				st = ST_HOST;
 				id->username = prev_token;
+				prev_token = 0;
 				if (dupl_string(&id->password, begin, url->s + i) < 0) goto err;
 				begin = url->s + i + 1;
 				break;
 
 			case '/':
 				id->host = prev_token;
+				prev_token = 0;
 				id->port = str2s(begin, url->s + i - begin, 0);
 				if (dupl_string(&id->database, url->s + i + 1, url->s + len) < 0) goto err;
 				return 0;
@@ -213,6 +215,7 @@ static int parse_db_url(struct db_id* id, const str* url)
 	if (id->password) pkg_free(id->password);
 	if (id->host) pkg_free(id->host);
 	if (id->database) pkg_free(id->database);
+	memset(id, 0, sizeof(struct db_id));
 	if (prev_token) pkg_free(prev_token);
  end:
 	return -1;

+ 18 - 2
lib/srdb1/schema/Makefile

@@ -21,6 +21,9 @@ DBTEXT_XSL = $(STYLESHEETS)/dbtext.xsl
 # Stylesheet used to generate berkeley database schema
 DB_BERKELEY_XSL = $(STYLESHEETS)/db_berkeley.xsl
 
+# Stylesheet used to generate sqlite database schema
+DB_SQLITE_XSL = $(STYLESHEETS)/db_sqlite.xsl
+
 # Stylesheet used to generate oracle database schema
 ORACLE_XSL = $(STYLESHEETS)/oracle.xsl
 
@@ -56,7 +59,7 @@ ifeq ($(VERBOSE), 1)
 	override XSLTPROC := $(XSLTPROC) --verbose
 endif
 
-all: mysql postgres dbtext db_berkeley docbook oracle #modules dbdoc
+all: mysql postgres dbtext db_berkeley db_sqlite docbook oracle #modules dbdoc
 
 .PHONY: mysql mysql_clean
 mysql:
@@ -148,6 +151,19 @@ db_berkeley_clean:
 	-@rm -f $(SCHEME)/db_berkeley/kamailio/*
 
 
+.PHONY: db_sqlite db_sqlite_clean
+db_sqlite:
+	for FILE in $(TABLES); do \
+		XML_CATALOG_FILES=$(CATALOG) $(XSLTPROC) $(XSLTPROC_FLAGS) \
+		--stringparam dir "$(SCHEME)/db_sqlite" \
+		--stringparam prefix "$$FILE-" \
+		--stringparam db "db_sqlite" \
+		$(DB_SQLITE_XSL) kamailio-"$$FILE".xml ; \
+	done
+
+db_sqlite_clean:
+	-@rm -f $(SCHEME)/db_sqlite/*
+
 .PHONY: docbook docbook_clean
 docbook:
 	for FILE in $(TABLES); do \
@@ -219,4 +235,4 @@ dbdoc_clean:
 	done
 
 .PHONY: clean
-clean: mysql_clean postgres_clean oracle_clean dbtext_clean db_berkeley_clean docbook_clean # modules_clean dbdoc_clean
+clean: mysql_clean postgres_clean oracle_clean dbtext_clean db_berkeley_clean db_sqlite_clean docbook_clean # modules_clean dbdoc_clean

+ 1 - 1
lib/srdb1/schema/htable.xml

@@ -12,7 +12,7 @@
     <version>1</version>
     <type db="mysql">&MYSQL_TABLE_TYPE;</type>
     <description>
-        <db:para>This table us used by the htabke module to load values in the hash table at start up. More information about the avpops module can be found at: &KAMAILIO_MOD_DOC;htable.html
+        <db:para>This table us used by the htable module to load values in the hash table at start up. More information about the htable module can be found at: &KAMAILIO_MOD_DOC;htable.html
         </db:para>
     </description>
 

+ 1 - 5
lib/srdb1/schema/lcr_gw.xml

@@ -129,12 +129,8 @@
     </column>
 
     <index>
-        <name>lcr_id_ip_addr_port_hostname_idx</name>
+        <name>lcr_id_idx</name>
         <colref linkend="lcr_id"/>
-        <colref linkend="ip_addr"/>
-        <colref linkend="port"/>
-        <colref linkend="hostname"/>
-        <unique/>
     </index>
 
 </table>

+ 2 - 2
lib/srdb1/schema/pr_active_watchers.xml

@@ -96,7 +96,7 @@
     <column id="callid">
         <name>callid</name>
         <type>string</type>
-        <size>&domain_len;</size>
+        <size>&uri_len;</size>
         <description>Call ID</description>
     </column>
 
@@ -117,7 +117,7 @@
     <column>
         <name>contact</name>
         <type>string</type>
-        <size>&domain_len;</size>
+        <size>&uri_len;</size>
         <description>Contact</description>
     </column>
 

+ 1 - 1
lib/srdb1/schema/pr_pua.xml

@@ -95,7 +95,7 @@
     <column>
         <name>call_id</name>
         <type>string</type>
-        <size>&domain_len;</size>
+        <size>&uri_len;</size>
         <description>Call ID</description>
     </column>
 

+ 61 - 22
main.c

@@ -245,6 +245,7 @@ Options:\n\
     -b nr        Maximum receive buffer size which will not be exceeded by\n\
                   auto-probing procedure even if  OS allows\n\
     -m nr        Size of shared memory allocated in Megabytes\n\
+    -M nr        Size of private memory allocated, in Megabytes\n\
     -w dir       Change the working directory to \"dir\" (default: \"/\")\n\
     -t dir       Chroot to \"dir\"\n\
     -u uid       Change uid \n\
@@ -273,7 +274,7 @@ void print_ct_constants()
 #endif
 */
 	printf("MAX_RECV_BUFFER_SIZE %d, MAX_LISTEN %d,"
-			" MAX_URI_SIZE %d, BUF_SIZE %d, PKG_SIZE %uMB\n",
+			" MAX_URI_SIZE %d, BUF_SIZE %d, DEFAULT PKG_SIZE %uMB\n",
 		MAX_RECV_BUFFER_SIZE, MAX_LISTEN, MAX_URI_SIZE,
 		BUF_SIZE, PKG_MEM_SIZE);
 #ifdef USE_TCP
@@ -488,6 +489,8 @@ int cfg_warnings=0;
 
 /* shared memory (in MB) */
 unsigned long shm_mem_size=0;
+/* private (pkg) memory (in MB) */
+unsigned long pkg_mem_size=0;
 
 /* export command-line to anywhere else */
 int my_argc;
@@ -590,6 +593,7 @@ void cleanup(show_status)
 	destroy_lock_ops();
 	if (pid_file) unlink(pid_file);
 	if (pgid_file) unlink(pgid_file);
+	destroy_pkg_mallocs();
 }
 
 
@@ -1750,7 +1754,52 @@ int main(int argc, char** argv)
 	dont_fork_cnt=0;
 
 	daemon_status_init();
-	/*init pkg mallocs (before parsing cfg or cmd line !)*/
+	/* command line options */
+	options=  ":f:cm:M:dVhEb:l:L:n:vrRDTN:W:w:t:u:g:P:G:SQ:O:a:A:"
+#ifdef STATS
+		"s:"
+#endif
+	;
+	/* Handle special command line arguments, that must be treated before
+	 * intializing the various subsystem or before parsing other arguments:
+	 *  - get the startup debug and log_stderr values
+	 *  - look if pkg mem size is overriden on the command line (-M) and get
+	 *    the new value here (before intializing pkg_mem).
+	 *  - look if there is a -h, e.g. -f -h construction won't be caught
+	 *    later
+	 */
+	opterr = 0;
+	while((c=getopt(argc,argv,options))!=-1) {
+		switch(c) {
+			case 'd':
+					debug_flag = 1;
+					default_core_cfg.debug++;
+					break;
+			case 'E':
+					log_stderr=1;
+					break;
+			case 'M':
+					pkg_mem_size=strtol(optarg, &tmp, 10) * 1024 * 1024;
+					if (tmp &&(*tmp)){
+						fprintf(stderr, "bad private mem size number: -M %s\n",
+											optarg);
+						goto error;
+					};
+					break;
+			default:
+					if (c == 'h' || (optarg && strcmp(optarg, "-h") == 0)) {
+						printf("version: %s\n", full_version);
+						printf("%s",help_msg);
+						exit(0);
+					}
+					break;
+		}
+	}
+	
+	/*init pkg mallocs (before parsing cfg or the rest of the cmd line !)*/
+	if (pkg_mem_size)
+		LOG(L_INFO, " private (per process) memory: %ld bytes\n",
+								pkg_mem_size );
 	if (init_pkg_mallocs()==-1)
 		goto error;
 
@@ -1759,11 +1808,6 @@ int main(int argc, char** argv)
 		"DBG_MSG_QA enabled, ser may exit abruptly\n");
 #endif
 
-	options=  ":f:cm:dVhEb:l:L:n:vrRDTN:W:w:t:u:g:P:G:SQ:O:a:A:"
-#ifdef STATS
-		"s:"
-#endif
-	;
 	/* init counters / stats */
 	if (init_counters() == -1)
 		goto error;
@@ -1773,16 +1817,6 @@ int main(int argc, char** argv)
 #ifdef USE_SCTP
 	init_sctp_options(); /* set defaults before the config */
 #endif
-	/* look if there is a -h, e.g. -f -h construction won't catch it later */
-	opterr = 0;
-	while((c=getopt(argc,argv,options))!=-1) {
-		if (c == 'h' || (optarg && strcmp(optarg, "-h") == 0)) {
-			printf("version: %s\n", full_version);
-			printf("%s",help_msg);
-			exit(0);
-			break;
-		}
-	}
 	/* process command line (cfg. file path etc) */
 	optind = 1;  /* reset getopt */
 	/* switches required before script processing */
@@ -1808,9 +1842,12 @@ int main(int argc, char** argv)
 					LOG(L_INFO, "ser: shared memory: %ld bytes\n",
 									shm_mem_size );
 					break;
+			case 'M':
+					/* ignore it, it was parsed immediately after startup,
+					   the pkg mem. is already initialized at this point */
+					break;
 			case 'd':
-					debug_flag = 1;
-					default_core_cfg.debug++;
+					/* ignore it, was parsed immediately after startup */
 					break;
 			case 'V':
 					printf("version: %s\n", full_version);
@@ -1829,7 +1866,7 @@ int main(int argc, char** argv)
 					exit(0);
 					break;
 			case 'E':
-					log_stderr=1;
+					/* ignore it, was parsed immediately after startup */
 					break;
 			case 'O':
 					scr_opt_lev=strtol(optarg, &tmp, 10);
@@ -1974,6 +2011,7 @@ try_again:
 			case 'f':
 			case 'c':
 			case 'm':
+			case 'M':
 			case 'd':
 			case 'V':
 			case 'h':
@@ -1981,7 +2019,8 @@ try_again:
 			case 'A':
 					break;
 			case 'E':
-					log_stderr=1;	// use in both getopt switches
+					log_stderr=1;	/* use in both getopt switches,
+									   takes priority over config */
 					break;
 			case 'b':
 					maxbuffer=strtol(optarg, &tmp, 10);
@@ -2322,7 +2361,7 @@ try_again:
 	}
 
 	if (disable_core_dump) set_core_dump(0, 0);
-	else set_core_dump(1, shm_mem_size+PKG_MEM_POOL_SIZE+4*1024*1024);
+	else set_core_dump(1, shm_mem_size+pkg_mem_size+4*1024*1024);
 	if (open_files_limit>0){
 		if(increase_open_fds(open_files_limit)<0){
 			fprintf(stderr, "ERROR: error could not increase file limits\n");

+ 29 - 7
mem/mem.c

@@ -26,6 +26,7 @@
 
 
 #include <stdio.h>
+#include <stdlib.h>
 #include "../config.h"
 #include "../dprint.h"
 #include "../globals.h"
@@ -41,15 +42,15 @@
 
 #ifdef PKG_MALLOC
 	#ifndef DL_MALLOC
-	char mem_pool[PKG_MEM_POOL_SIZE];
+	char* mem_pool = 0;
 	#endif
 
 	#ifdef F_MALLOC
-		struct fm_block* mem_block;
+		struct fm_block* mem_block = 0;
 	#elif defined DL_MALLOC
 		/* don't need this */
 	#else
-		struct qm_block* mem_block;
+		struct qm_block* mem_block = 0;
 	#endif
 #endif
 
@@ -58,18 +59,25 @@ int init_pkg_mallocs()
 {
 #ifdef PKG_MALLOC
 	/*init mem*/
+	#ifndef DL_MALLOC
+		if (pkg_mem_size == 0)
+			pkg_mem_size = PKG_MEM_POOL_SIZE;
+		mem_pool = malloc(pkg_mem_size);
+	#endif
 	#ifdef F_MALLOC
-		mem_block=fm_malloc_init(mem_pool, PKG_MEM_POOL_SIZE);
+		if (mem_pool)
+			mem_block=fm_malloc_init(mem_pool, pkg_mem_size);
 	#elif DL_MALLOC
 		/* don't need this */
 	#else
-		mem_block=qm_malloc_init(mem_pool, PKG_MEM_POOL_SIZE);
+		if (mem_pool)
+			mem_block=qm_malloc_init(mem_pool, pkg_mem_size);
 	#endif
 	#ifndef DL_MALLOC
 	if (mem_block==0){
 		LOG(L_CRIT, "could not initialize memory pool\n");
-		fprintf(stderr, "Too much pkg memory demanded: %d\n",
-			PKG_MEM_POOL_SIZE );
+		fprintf(stderr, "Too much pkg memory demanded: %ld bytes\n",
+						pkg_mem_size);
 		return -1;
 	}
 	#endif
@@ -79,6 +87,20 @@ int init_pkg_mallocs()
 
 
 
+void destroy_pkg_mallocs()
+{
+#ifdef PKG_MALLOC
+	#ifndef DL_MALLOC
+		if (mem_pool) {
+			free(mem_pool);
+			mem_pool = 0;
+		}
+	#endif
+#endif /* PKG_MALLOC */
+}
+
+
+
 int init_shm_mallocs(int force_alloc)
 {
 #ifdef SHM_MEM

+ 2 - 1
mem/mem.h

@@ -58,7 +58,7 @@
 		extern struct qm_block* mem_block;
 #	endif
 
-	extern char mem_pool[PKG_MEM_POOL_SIZE];
+	extern char* mem_pool;
 
 
 #	ifdef DBG_QM_MALLOC
@@ -133,6 +133,7 @@
 #endif
 
 int init_pkg_mallocs();
+void destroy_pkg_mallocs();
 int init_shm_mallocs(int force_alloc);
 
 /*! generic logging helper for allocation errors in private memory pool/ system */

+ 16 - 4
modules/app_lua/Makefile

@@ -13,13 +13,25 @@ BUILDER = $(shell which lua-config)
 ifeq ($(BUILDER),)
 	BUILDER = $(shell which pkg-config)
 	ifeq ($(BUILDER),)
-		DEFS+=-I/usr/include/lua5.1
-		LIBS= -llua5.1
+		LUA51 = $(shell ls /usr/lib/liblua* | grep liblua5.1)
+		ifeq ($(LUA51),)
+			DEFS+=-I/usr/include/lua
+			LIBS= -llua
+		else
+			DEFS+=-I/usr/include/lua5.1
+			LIBS= -llua5.1
+		endif
 	else
 		LUALIBS = $(shell pkg-config --silence-errors --libs lua)
 		ifeq ($(LUALIBS),)
-			DEFS+=-I/usr/include/lua5.1
-			LIBS= -llua5.1
+			LUA51 = $(shell ls /usr/lib/liblua* | grep liblua5.1)
+			ifeq ($(LUA51),)
+				DEFS+=-I/usr/include/lua
+				LIBS= -llua
+			else
+				DEFS+=-I/usr/include/lua5.1
+				LIBS= -llua5.1
+			endif
 		else
 			DEFS+ = $(shell pkg-config --cflags lua)
 			LIBS = $(shell pkg-config --libs lua)

+ 2 - 0
modules/auth/README

@@ -539,6 +539,7 @@ if (www_authenticate("realm", "subscriber)) {
           + 4 - do not send '500 Internal Server Error' reply
             automatically in failure cases (error code is returned to
             config)
+          + 16 - build challenge header with stale=true
 
    This function can be used from REQUEST_ROUTE.
 
@@ -607,6 +608,7 @@ if (!proxy_authenticate("$fd", "subscriber)) {
           + 2 - build challenge header with no qop and add it to avp
           + 4 - build challenge header with qop=auth and add it to avp
           + 8 - build challenge header with qop=auth-int and add it to avp
+          + 16 - build challenge header with stale=true
 
    When challenge header is built and stored in avp, append_to_reply() and
    sl reply functions can be used to send appropriate SIP reply to

+ 8 - 2
modules/auth/auth_mod.c

@@ -635,7 +635,7 @@ static int auth_send_reply(struct sip_msg *msg, int code, char *reason,
  */
 int auth_challenge(struct sip_msg *msg, str *realm, int flags, int hftype)
 {
-	int ret;
+    int ret, stale;
     str hf = {0, 0};
 	struct qp *qop = NULL;
 
@@ -646,7 +646,13 @@ int auth_challenge(struct sip_msg *msg, str *realm, int flags, int hftype)
 	} else if(flags&1) {
 		qop = &auth_qauth;
 	}
-	if (get_challenge_hf(msg, 0, realm, NULL, NULL, qop, hftype, &hf) < 0) {
+	if (flags & 16) {
+	    stale = 1;
+	} else {
+	    stale = 0;
+	}
+	if (get_challenge_hf(msg, stale, realm, NULL, NULL, qop, hftype, &hf)
+	    < 0) {
 		ERR("Error while creating challenge\n");
 		ret = -2;
 		goto error;

+ 9 - 0
modules/auth/doc/functions.xml

@@ -81,6 +81,10 @@ if (www_authenticate("realm", "subscriber)) {
 					Server Error' reply automatically in failure cases
 					(error code is returned to config)</para>
 			</listitem>
+			<listitem>
+				<para><emphasis>16</emphasis> - build challenge header with
+					stale=true</para>
+			</listitem>
 			</itemizedlist>
 		</listitem>
 		</itemizedlist>
@@ -214,6 +218,11 @@ if (!proxy_authenticate("$fd", "subscriber)) {
 				<para><emphasis>8</emphasis> - build challenge header with
 					qop=auth-int and add it to avp</para>
 			</listitem>
+			<listitem>
+				<para><emphasis>16</emphasis> - build challenge header with
+					stale=true</para>
+			</listitem>
+
 			</itemizedlist>
 		</listitem>
 		</itemizedlist>

+ 16 - 2
modules/carrierroute/carrierroute.c

@@ -40,6 +40,7 @@
 #include "../../sr_module.h"
 #include "../../str.h"
 #include "../../mem/mem.h"
+#include "../../ut.h" /* for user2uid() */
 #include "carrierroute.h"
 #include "cr_fixup.h"
 #include "cr_map.h"
@@ -154,6 +155,8 @@ struct module_exports exports = {
  */
 static int mod_init(void) {
 	struct stat fs;
+	extern char* user; /*from main.c*/
+	int uid, gid;
 
 	if(register_mi_mod(exports.name, mi_cmds)!=0)
 	{
@@ -197,9 +200,20 @@ static int mod_init(void) {
 		if(fs.st_mode & S_IWOTH){
 			LM_WARN("insecure file permissions, routing data is world writeable\n");
 		}
+
+		if (user){
+			if (user2uid(&uid, &gid, user)<0){
+				LM_ERR("bad user name/uid number: -u %s\n", user);
+				return -1;
+			}
+		} else {
+			uid = geteuid();
+			gid = getegid();
+		}
+
 		if( !( fs.st_mode & S_IWOTH) &&
-			!((fs.st_mode & S_IWGRP) && (fs.st_gid == getegid())) &&
-			!((fs.st_mode & S_IWUSR) && (fs.st_uid == geteuid())) ) {
+			!((fs.st_mode & S_IWGRP) && (fs.st_gid == uid)) &&
+			!((fs.st_mode & S_IWUSR) && (fs.st_uid == gid))) {
 				LM_ERR("config file %s not writable\n", config_file);
 				return -1;
 		}

+ 2 - 2
modules/carrierroute/cr_func.c

@@ -437,7 +437,7 @@ static int rewrite_on_rule(struct route_flags *rf_head, flag_t flags, str * dest
 			}
 			break;
 		case alg_crc32_nofallback:
-			if ((prob = (hash_func(msg, hash_source, rf->max_targets) + 1)) < 0) {
+			if ((prob = (hash_func(msg, hash_source, rf->max_targets))) < 0) {
 				LM_ERR("could not hash message with CRC32");
 				return -1;
 			}
@@ -445,7 +445,7 @@ static int rewrite_on_rule(struct route_flags *rf_head, flag_t flags, str * dest
 			 * this function just tries only a backup rule and otherwise
 			 * returns -1. This way we get an error
 			 */
-			if ((rr = get_rule_by_hash(rf, prob)) == NULL) {
+			if ((rr = get_rule_by_hash(rf, prob + 1)) == NULL) {
 				LM_CRIT("no route found\n");
 				return -1;
 			}

+ 25 - 5
modules/db_mysql/Makefile

@@ -6,18 +6,38 @@ include ../../Makefile.defs
 auto_gen=
 NAME=db_mysql.so
 
-# mysql.h locations (freebsd,openbsd  solaris)
-DEFS +=-DSER_MOD_INTERFACE -I$(LOCALBASE)/include -I$(LOCALBASE)/include/mysql \
+DEFS +=-DSER_MOD_INTERFACE
+
+# set CROSS_COMPILE to true if you want to skip
+# the autodetection
+# CROSS_COMPILE=true
+
+ifeq ($(CROSS_COMPILE),)
+MYSQLCFG=$(shell which mysql_config)
+endif
+
+ifneq ($(MYSQLCFG),)
+
+	# use autodetection
+	DEFS += $(shell $(MYSQLCFG) --include | sed 's/\(-I.*\)\/mysql/\1/g' )
+	LIBS = $(shell $(MYSQLCFG) --libs)
+
+else
+
+	# mysql.h locations (freebsd,openbsd  solaris)
+	DEFS +=-DSER_MOD_INTERFACE -I$(LOCALBASE)/include \
+		-I$(LOCALBASE)/include/mysql \
 		-I$(LOCALBASE)/mysql/include \
 		-I/usr/include/mysql
 
-# libmysqlclient locations on RH/Suse, Solaris /OpenBSD, FreeBSD
-# (Debian does the right thing and puts it in /usr/lib)
-LIBS=-L/usr/lib/mysql -L$(LOCALBASE)/lib -L$(LOCALBASE)/lib/mysql \
+	# libmysqlclient locations on RH/Suse, Solaris /OpenBSD, FreeBSD
+	# (Debian does the right thing and puts it in /usr/lib)
+	LIBS=-L/usr/lib/mysql -L$(LOCALBASE)/lib -L$(LOCALBASE)/lib/mysql \
 		-L$(LOCALBASE)/mysql/lib/mysql/ \
 		-L$(LOCALBASE)/mysql/lib \
 		-L/usr/lib64/mysql \
 		-lmysqlclient -lz
+endif
 
 SERLIBPATH=../../lib
 SER_LIBS=$(SERLIBPATH)/srdb2/srdb2 $(SERLIBPATH)/srdb1/srdb1

+ 44 - 3
modules/dialplan/README

@@ -56,7 +56,12 @@ Juha Heinanen
               7.1. dp_reload
               7.2. dp_translate
 
-        8. Installation
+        8. Exported RPC Commands
+
+              8.1. dialplan.reload
+              8.2. dialplan.translate
+
+        9. Installation
 
    2. Developer's Guide
 
@@ -113,7 +118,12 @@ Chapter 1. Admin Guide
         7.1. dp_reload
         7.2. dp_translate
 
-   8. Installation
+   8. Exported RPC Commands
+
+        8.1. dialplan.reload
+        8.2. dialplan.translate
+
+   9. Installation
 
 1. Overview
 
@@ -410,7 +420,38 @@ xlog("translated to var $var(y) \n");
             input
                 _empty_line_
 
-8. Installation
+8. Exported RPC Commands
+
+   8.1. dialplan.reload
+   8.2. dialplan.translate
+
+8.1. dialplan.reload
+
+   Forces an update of the translation rules from the database.
+
+   Name: dialplan.reload
+
+   Parameters: none
+
+   Example:
+                sercmd dialplan.reload
+
+8.2. dialplan.translate
+
+   Will apply a translation rule identified by a dialplan id and an input
+   string.
+
+   Name: dialplan.translate
+
+   Parameters: 2
+     * Dial plan ID
+     * Input String
+
+   Example:
+        # sercmd dp_translate dpid "input"
+        sercmd dp_translate 1 "abcdxyz"
+
+9. Installation
 
    The modules requires one table in Kamailio database: dialplan. The SQL
    syntax to create them can be found in dialplan-create.sql script in the

+ 123 - 2
modules/dialplan/dialplan.c

@@ -56,6 +56,8 @@
 #include "../../mem/mem.h"
 #include "../../lib/kmi/mi.h"
 #include "../../parser/parse_to.h"
+#include "../../rpc.h"
+#include "../../rpc_lookup.h"
 #include "../../lvalue.h"
 #include "dialplan.h"
 #include "dp_db.h"
@@ -69,6 +71,8 @@ static int child_init(int rank);
 static void mod_destroy();
 static int mi_child_init();
 
+static int dialplan_init_rpc(void);
+
 static struct mi_root * mi_reload_rules(struct mi_root *cmd_tree,void *param);
 static struct mi_root * mi_translate(struct mi_root *cmd_tree, void *param);
 static int dp_translate_f(struct sip_msg* msg, char* str1, char* str2);
@@ -107,9 +111,9 @@ static mi_export_t mi_cmds[] = {
 
 static cmd_export_t cmds[]={
 	{"dp_translate",(cmd_function)dp_translate_f,	2,	dp_trans_fixup,  0,
-				REQUEST_ROUTE|FAILURE_ROUTE|LOCAL_ROUTE|BRANCH_ROUTE},
+				ANY_ROUTE},
 	{"dp_translate",(cmd_function)dp_translate_f,	1,	dp_trans_fixup,  0,
-				REQUEST_ROUTE|FAILURE_ROUTE|LOCAL_ROUTE|BRANCH_ROUTE},
+				ANY_ROUTE},
 	{0,0,0,0,0,0}
 };
 
@@ -136,6 +140,12 @@ static int mod_init(void)
 		LM_ERR("failed to register MI commands\n");
 		return -1;
 	}
+	if(dialplan_init_rpc()!=0)
+	{
+		LM_ERR("failed to register RPC commands\n");
+		return -1;
+	}
+
 
 	dp_db_url.len = dp_db_url.s ? strlen(dp_db_url.s) : 0;
 	LM_DBG("db_url=%s/%d/%p\n", ZSW(dp_db_url.s), dp_db_url.len,dp_db_url.s);
@@ -564,3 +574,114 @@ error:
 	return 0;
 }
 
+static const char* dialplan_rpc_reload_doc[2] = {
+	"Reload dialplan table from database",
+	0
+};
+
+
+/*
+ * RPC command to reload dialplan table
+ */
+static void dialplan_rpc_reload(rpc_t* rpc, void* ctx)
+{
+	if (dp_connect_db() < 0) {
+	    LM_ERR("failed to reload rules fron database (db connect)\n");
+		rpc->fault(ctx, 500, "DB Connection Error");
+	    return;
+	}
+
+	if(dp_load_db() != 0){
+	    LM_ERR("failed to reload rules fron database (db load)\n");
+	    dp_disconnect_db();
+		rpc->fault(ctx, 500, "Dialplan Reload Failed");
+	    return;
+	}
+
+	dp_disconnect_db();
+	return;
+}
+
+
+
+static const char* dialplan_rpc_translate_doc[2] = {
+	"Perform dialplan translation",
+	0
+};
+
+
+/*
+ * RPC command to perform dialplan translation
+ */
+static void dialplan_rpc_translate(rpc_t* rpc, void* ctx)
+{
+	dpl_id_p idp;
+	str input;
+	int dpid;
+	str attrs  = {"", 0};
+	str output = {0, 0};
+	void* th;
+
+	if (rpc->scan(ctx, "dS", &dpid, &input) < 2)
+	{
+		rpc->fault(ctx, 500, "Invalid parameters");
+		return;
+	}
+
+	if ((idp = select_dpid(dpid)) == 0 ){
+		LM_ERR("no information available for dpid %i\n", dpid);
+		rpc->fault(ctx, 500, "Dialplan ID not matched");
+		return;
+	}
+
+	if(input.s == NULL || input.len== 0)	{
+		LM_ERR("empty input parameter\n");
+		rpc->fault(ctx, 500, "Empty input parameter");
+		return;
+	}
+
+	LM_DBG("trying to translate %.*s with dpid %i\n",
+			input.len, input.s, idp->dp_id);
+	if (translate(NULL, input, &output, idp, &attrs)!=0){
+		LM_DBG("could not translate %.*s with dpid %i\n",
+			input.len, input.s, idp->dp_id);
+		rpc->fault(ctx, 500, "No translation");
+		return;
+	}
+	LM_DBG("input %.*s with dpid %i => output %.*s\n",
+			input.len, input.s, idp->dp_id, output.len, output.s);
+
+	if (rpc->add(ctx, "{", &th) < 0)
+	{
+		rpc->fault(ctx, 500, "Internal error creating rpc");
+		return;
+	}
+	if(rpc->struct_add(th, "SS",
+			"Output", &output,
+			"Attributes", &attrs)<0)
+	{
+		rpc->fault(ctx, 500, "Internal error creating rpc");
+		return;
+	}
+
+	return;
+}
+
+
+rpc_export_t dialplan_rpc_list[] = {
+	{"dialplan.reload", dialplan_rpc_reload,
+		dialplan_rpc_reload_doc, 0},
+	{"dialplan.dump",   dialplan_rpc_translate,
+		dialplan_rpc_translate_doc, 0},
+	{0, 0, 0, 0}
+};
+
+static int dialplan_init_rpc(void)
+{
+	if (rpc_register_array(dialplan_rpc_list)!=0)
+	{
+		LM_ERR("failed to register RPC commands\n");
+		return -1;
+	}
+	return 0;
+}

+ 48 - 2
modules/dialplan/doc/dialplan_admin.xml

@@ -511,7 +511,55 @@ xlog("translated to var $var(y) \n");
 		</programlisting>
 		</section>
 	</section>
+
+	<section>
+	<title>Exported RPC Commands</title>
+
+		<section>
+			<title><varname>dialplan.reload</varname></title>
+			<para>
+			Forces an update of the translation rules from the database.
+			</para>
+		<para>
+		Name: <emphasis>dialplan.reload</emphasis>
+		</para>
+		<para>Parameters: <emphasis>none</emphasis></para>
+		<para>
+		Example:
+		</para>
+        <programlisting  format="linespecific">
+		sercmd dialplan.reload
+		</programlisting>
+		</section>
     
+    <section>
+			<title><varname>dialplan.translate</varname></title>
+			<para>
+                Will apply a translation rule identified by a dialplan
+                id and an input string.
+			</para>
+		<para>
+		Name: <emphasis>dialplan.translate</emphasis>
+		</para>
+        <para>Parameters: <emphasis>2</emphasis></para>
+        <itemizedlist>
+                <listitem>
+                <para><emphasis>Dial plan ID</emphasis></para>
+                </listitem>
+                <listitem>
+                <para><emphasis>Input String</emphasis></para>
+                </listitem>
+		</itemizedlist>
+		<para>
+		Example:
+		</para>
+        <programlisting  format="linespecific">
+        # sercmd dp_translate dpid "input"
+        sercmd dp_translate 1 "abcdxyz"
+		</programlisting>
+		</section>
+	</section>
+
     <section>
 	    <title>Installation</title>
 	    <para>
@@ -523,6 +571,4 @@ xlog("translated to var $var(y) \n");
         </para>
     </section>
 
-
-
 </chapter>

+ 14 - 6
modules/geoip/README

@@ -75,12 +75,20 @@ Chapter 1. Admin Guide
    identifying the physical location with which an IP host address is
    associated on a relatively granular level.
 
-   This database itself can be obtained on a free or commercial basis
-   here. The library that interfaces with the Max Mind API, as well as
-   scripts to automate downloading of the on-disk version of the
-   open-source database is also packaged by the Debian Linux distribution
-   and its derivatives as libgeoip, and probably by other distributions as
-   well.
+   This database itself can be obtained on a free or commercial basis from
+   http://www.maxmind.com/app/ip-location. The library that interfaces
+   with the Max Mind API, as well as scripts to automate downloading of
+   the on-disk version of the open-source database is also packaged by the
+   Debian Linux distribution and its derivatives as libgeoip, and probably
+   by other distributions as well.
+
+   Debian Linux squeeze includes already a database as dependency, but as
+   this contain the wrong data, it will not work correctly with the
+   module. More acurate, the module expect the GeoIP City Edition, and
+   will not work with the GeoIP Country Edition. In newer Debian Linux
+   releases the package geoip-database-contrib should contain the
+   necessary database. You can download the Lite edition of the DB from
+   http://www.maxmind.com/app/geolitecity.
 
    This module exports a new class of pseudo-variables - $gip(pvc=>key) -
    to enable access to the results of a query to the database.

+ 12 - 1
modules/geoip/doc/geoip_admin.xml

@@ -28,13 +28,24 @@
 	</para>
 	<para>
 		This database itself can be obtained on a free or commercial basis 
-		<ulink url="http://www.maxmind.com/app/ip-location">here</ulink>.  The 
+		from <ulink url="http://www.maxmind.com/app/ip-location">
+		http://www.maxmind.com/app/ip-location</ulink>. The 
 		library that interfaces with the Max Mind API, as well as scripts to
 		automate downloading of the on-disk version of the open-source 
 		database is also packaged by the Debian Linux distribution and 
 		its derivatives as <emphasis>libgeoip</emphasis>, and probably by
 		other distributions as well.
 	</para>
+	<para>
+		Debian Linux squeeze includes already a database as dependency, but as
+		this contain the wrong data, it will not work correctly with the module.
+		More acurate, the module expect the <emphasis>GeoIP City Edition</emphasis>,
+		and will not work with the <emphasis>GeoIP Country Edition</emphasis>. In
+		newer Debian Linux releases the package <emphasis>geoip-database-contrib</emphasis>
+		should contain the necessary database. You can download the Lite edition
+		of the DB from <ulink url="http://www.maxmind.com/app/geolitecity">
+		http://www.maxmind.com/app/geolitecity</ulink>.
+	</para>
 	<para>
 		This module exports a new class of pseudo-variables -
 		$gip(pvc=&gt;key) - to enable access to the results of a query to the

+ 14 - 0
modules/ipops/Makefile

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

+ 279 - 0
modules/ipops/README

@@ -0,0 +1,279 @@
+ipops Module
+
+Iñaki Baz Castillo
+
+   <[email protected]>
+
+Edited by
+
+Iñaki Baz Castillo
+
+   <[email protected]>
+
+   Copyright © 2011 Iñaki Baz Castillo
+     __________________________________________________________________
+
+   Table of Contents
+
+   1. Admin Guide
+
+        1. Overview
+        2. Dependencies
+
+              2.1. SIP Router Modules
+              2.2. External Libraries or Applications
+
+        3. Exported Parameters
+        4. Exported Functions
+
+              4.1. is_ip (ip)
+              4.2. is_pure_ip (ip)
+              4.3. is_ipv4 (ip)
+              4.4. is_ipv6 (ip)
+              4.5. is_ipv6_reference (ip)
+              4.6. ip_type (ip)
+              4.7. compare_ips (ip1, ip2)
+              4.8. compare_pure_ips (ip1, ip2)
+
+   List of Examples
+
+   1.1. is_ip usage
+   1.2. is_pure_ip usage
+   1.3. is_ipv4 usage
+   1.4. is_ipv6 usage
+   1.5. is_ipv6_reference usage
+   1.6. ip_type usage
+   1.7. compare_ips usage
+   1.8. compare_pure_ips usage
+
+Chapter 1. Admin Guide
+
+   Table of Contents
+
+   1. Overview
+   2. Dependencies
+
+        2.1. SIP Router Modules
+        2.2. External Libraries or Applications
+
+   3. Exported Parameters
+   4. Exported Functions
+
+        4.1. is_ip (ip)
+        4.2. is_pure_ip (ip)
+        4.3. is_ipv4 (ip)
+        4.4. is_ipv6 (ip)
+        4.5. is_ipv6_reference (ip)
+        4.6. ip_type (ip)
+        4.7. compare_ips (ip1, ip2)
+        4.8. compare_pure_ips (ip1, ip2)
+
+1. Overview
+
+   This module offers operations for IPv4 and IPv6.
+
+   IPv6 is defined in RFC 2460. The same IPv6 can be represented by
+   different ASCII strings, so binary comparison is required. For example,
+   the following IPv6 are equivalent:
+     * 1080:0000:0000:0000:0008:0800:200C:417A
+     * 1080:0:0:0:8:800:200C:417A
+     * 1080::8:800:200C:417A
+
+   When using IPv6 in an URI (i.e. a SIP URI) such IP must be written in
+   "IPv6 reference" format (which is the textual representation of the
+   IPv6 enclosed between [ ] symbols). An example is
+   “sip:alice@[1080:0:0:0:8:800:200C:417A]”. This module also allows
+   comparing a IPv6 with its IPv6 reference representation.
+
+2. Dependencies
+
+   2.1. SIP Router Modules
+   2.2. External Libraries or Applications
+
+2.1. SIP Router Modules
+
+   The following modules must be loaded before this module:
+     * No dependencies on other SIP Router modules
+
+2.2. External Libraries or Applications
+
+   The following libraries or applications must be installed before
+   running SIP Router with this module loaded:
+     * No dependencies on external libraries
+
+3. Exported Parameters
+
+4. Exported Functions
+
+   4.1. is_ip (ip)
+   4.2. is_pure_ip (ip)
+   4.3. is_ipv4 (ip)
+   4.4. is_ipv6 (ip)
+   4.5. is_ipv6_reference (ip)
+   4.6. ip_type (ip)
+   4.7. compare_ips (ip1, ip2)
+   4.8. compare_pure_ips (ip1, ip2)
+
+4.1.  is_ip (ip)
+
+   Returns TRUE if the argument is a valid IPv4, IPv6 or IPv6 reference.
+   FALSE otherwise.
+
+   Parameters:
+     * ip - String or pseudo-variable containing the IP to evaluate.
+
+   This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
+   ONREPLY_ROUTE, BRANCH_ROUTE and LOCAL_ROUTE.
+
+   Example 1.1.  is_ip usage
+...
+if (is_ip($rd)) {
+  xlog("L_INFO", "RURI domain is IP\n");
+}
+...
+
+4.2.  is_pure_ip (ip)
+
+   Returns TRUE if the argument is a valid IPv4 or IPv6. FALSE otherwise.
+
+   Parameters:
+     * ip - String or pseudo-variable containing the IP to evaluate.
+
+   This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
+   ONREPLY_ROUTE, BRANCH_ROUTE and LOCAL_ROUTE.
+
+   Example 1.2.  is_pure_ip usage
+...
+$var(ip) = "::1";
+if (is_pure_ip($var(ip))) {
+  xlog("L_INFO", "it's IPv4 or IPv6\n");
+}
+...
+
+4.3.  is_ipv4 (ip)
+
+   Returns TRUE if the argument is a valid IPv4. FALSE otherwise.
+
+   Parameters:
+     * ip - String or pseudo-variable containing the IP to evaluate.
+
+   This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
+   ONREPLY_ROUTE, BRANCH_ROUTE and LOCAL_ROUTE.
+
+   Example 1.3.  is_ipv4 usage
+...
+if (is_ipv4("1.2.3.4")) {
+  xlog("L_INFO", "it's IPv4\n");
+}
+...
+
+4.4.  is_ipv6 (ip)
+
+   Returns TRUE if the argument is a valid IPv6. FALSE otherwise.
+
+   Parameters:
+     * ip - String or pseudo-variable containing the IP to evaluate.
+
+   This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
+   ONREPLY_ROUTE, BRANCH_ROUTE and LOCAL_ROUTE.
+
+   Example 1.4.  is_ipv6 usage
+...
+if (is_ipv6("1080:0:0:0:8:800:200C:417A")) {
+  xlog("L_INFO", "it's IPv6\n");
+}
+...
+
+4.5.  is_ipv6_reference (ip)
+
+   Returns TRUE if the argument is a valid IPv6 reference. FALSE
+   otherwise.
+
+   Parameters:
+     * ip - String or pseudo-variable containing the IP to evaluate.
+
+   This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
+   ONREPLY_ROUTE, BRANCH_ROUTE and LOCAL_ROUTE.
+
+   Example 1.5.  is_ipv6_reference usage
+...
+if (is_ipv6_reference("[1080:0:0:0:8:800:200C:417A]")) {
+  xlog("L_INFO", "it's IPv6 reference\n");
+}
+...
+
+4.6.  ip_type (ip)
+
+   Returns the type of the given IP.
+
+   Parameters:
+     * ip - String or pseudo-variable containing the IP to evaluate.
+
+   Return value:
+     * 1 - IPv4
+     * 2 - IPv6
+     * 3 - IPv6 reference
+     * -1 - invalid IP
+
+   This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
+   ONREPLY_ROUTE, BRANCH_ROUTE and LOCAL_ROUTE.
+
+   Example 1.6.  ip_type usage
+...
+ip_type($var(myip));
+switch($rc) {
+  case 1:
+    xlog("L_INFO", "it's IPv4\n");
+    break;
+  case 2:
+    xlog("L_INFO", "it's IPv6\n");
+    break;
+  case 3:
+    xlog("L_INFO", "it's IPv6 reference\n");
+    break;
+  case -1:
+    xlog("L_INFO", it's type invalid\n");
+    break;
+}
+...
+
+4.7.  compare_ips (ip1, ip2)
+
+   Returns TRUE if both IP's are the same. FALSE otherwise. This function
+   also allows comparing an IPv6 against an IPv6 reference.
+
+   Parameters:
+     * ip1 - String or pseudo-variable containing the first IP to compare.
+     * ip2 - String or pseudo-variable containing the second IP to
+       compare.
+
+   This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
+   ONREPLY_ROUTE, BRANCH_ROUTE and LOCAL_ROUTE.
+
+   Example 1.7.  compare_ips usage
+...
+if (compare_ips("1080:0000:0000:0000:0008:0800:200C:417A", "[1080::8:800:200C:41
+7A]")) {
+  xlog("L_INFO", "both are the same IP\n");
+}
+...
+
+4.8.  compare_pure_ips (ip1, ip2)
+
+   Returns TRUE if both IP's are the same. FALSE otherwise. This function
+   does NOT allow comparing an IPv6 against an IPv6 reference.
+
+   Parameters:
+     * ip1 - String or pseudo-variable containing the first IP to compare.
+     * ip2 - String or pseudo-variable containing the second IP to
+       compare.
+
+   This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
+   ONREPLY_ROUTE, BRANCH_ROUTE and LOCAL_ROUTE.
+
+   Example 1.8.  compare_pure_ips usage
+...
+if (compare_pure_ips($si, "1080::8:800:200C:417A")) {
+  xlog("L_INFO", "both are the same IP\n");
+}
+...

+ 21 - 0
modules/ipops/compile_ip_parser.rl.sh

@@ -0,0 +1,21 @@
+#!/bin/bash
+
+
+which ragel >/dev/null
+if [ $? -ne 0 ] ; then
+  echo "ERROR. Ragel not installed, cannot compile the Ragel grammar." >&2
+  exit 1
+else
+  ragel -v
+  echo
+fi
+
+
+set -e
+
+RAGEL_FILE=ip_parser
+echo ">>> Compiling Ragel grammar $RAGEL_FILE.rl ..."
+ragel -G2 -C $RAGEL_FILE.rl
+echo
+echo "<<< OK: $RAGEL_FILE.c generated"
+echo

+ 4 - 0
modules/ipops/doc/Makefile

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

+ 34 - 0
modules/ipops/doc/ipops.xml

@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding='UTF-8'?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
+"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [
+
+ <!-- Include general documentation entities -->
+ <!ENTITY % docentities SYSTEM "../../../docbook/entities.xml">
+ %docentities;
+ 
+]>
+   
+<book xmlns:xi="http://www.w3.org/2001/XInclude">
+  <bookinfo>
+    <title>ipops Module</title>
+    <authorgroup>
+      <author>
+        <firstname>Iñaki</firstname>
+        <surname>Baz Castillo</surname>
+        <email>[email protected]</email>
+      </author>
+      <editor>
+        <firstname>Iñaki</firstname>
+        <surname>Baz Castillo</surname>
+        <email>[email protected]</email>
+      </editor>
+    </authorgroup>
+    <copyright>
+      <year>2011</year>
+      <holder>Iñaki Baz Castillo</holder>
+    </copyright>
+  </bookinfo>
+  <toc>
+  </toc>
+  <xi:include href="ipops_admin.xml"/>
+</book>

+ 445 - 0
modules/ipops/doc/ipops_admin.xml

@@ -0,0 +1,445 @@
+<?xml version="1.0" encoding='ISO-8859-1'?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
+"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [
+
+<!-- Include general documentation entities -->
+<!ENTITY % docentities SYSTEM "../../../docbook/entities.xml">
+%docentities;
+ 
+]>
+
+<!-- Module User's Guide -->
+     
+<chapter>
+
+  <title>&adminguide;</title>
+       
+  <section>
+         
+    <title>Overview</title>
+         
+    <para>
+      This module offers operations for IPv4 and IPv6.
+    </para>
+
+    <para>
+      IPv6 is defined in <ulink url="http://tools.ietf.org/html/rfc2460">RFC 2460</ulink>. The same IPv6 can be represented by different ASCII strings, so binary comparison is required. For example, the following IPv6 are equivalent:
+    </para>
+
+    <itemizedlist>
+      <listitem>
+        <para>1080:0000:0000:0000:0008:0800:200C:417A</para>
+      </listitem>
+      <listitem>
+        <para>1080:0:0:0:8:800:200C:417A</para>
+      </listitem>
+      <listitem>
+        <para>1080::8:800:200C:417A</para>
+      </listitem>
+    </itemizedlist>
+
+    <para>
+      When using IPv6 in an URI (i.e. a SIP URI) such IP must be written in "IPv6 reference" format (which is the textual representation of the IPv6 enclosed between [ ] symbols). An example is <quote>sip:alice@[1080:0:0:0:8:800:200C:417A]</quote>. This module also allows comparing a IPv6 with its IPv6 reference representation.
+    </para>
+           
+  </section>
+           
+  <section>
+             
+    <title>Dependencies</title>
+             
+    <section>
+      <title>&siprouter; Modules</title>
+      <para>
+        The following modules must be loaded before this module:
+        <itemizedlist>
+          <listitem>
+            <para>
+              <emphasis>No dependencies on other &siprouter; modules</emphasis>
+            </para>
+          </listitem>
+        </itemizedlist>
+      </para>
+    </section>
+               
+    <section>
+      <title>External Libraries or Applications</title>
+      <para>
+        The following libraries or applications must be installed before running &siprouter; with this module loaded:
+        <itemizedlist>
+          <listitem>
+            <para>
+              <emphasis>No dependencies on external libraries</emphasis>
+            </para>
+          </listitem>
+        </itemizedlist>
+      </para>
+    </section>
+             
+  </section>
+           
+  <section>
+
+    <title>Exported Parameters</title>
+             
+  </section>
+           
+  <section>
+
+    <title>Exported Functions</title>
+             
+    <section>
+      <title>
+        <function moreinfo="none">is_ip (ip)</function>
+      </title>
+
+      <para>
+        Returns TRUE if the argument is a valid IPv4, IPv6 or IPv6 reference. FALSE otherwise.
+      </para>
+
+      <para>Parameters:</para>
+
+      <itemizedlist>
+        <listitem>
+          <para>
+            <emphasis>ip</emphasis> - String or pseudo-variable containing the IP to evaluate.
+          </para>
+        </listitem>
+      </itemizedlist>
+
+      <para>
+        This function can be used from REQUEST_ROUTE, FAILURE_ROUTE, ONREPLY_ROUTE, BRANCH_ROUTE and LOCAL_ROUTE.
+      </para>
+
+      <example>
+        <title>
+          <function>is_ip</function> usage
+        </title>
+        <programlisting format="linespecific">
+...
+if (is_ip($rd)) {
+  xlog("L_INFO", "RURI domain is IP\n");
+}
+...
+        </programlisting>
+      </example>
+
+    </section>
+
+    <section>
+      <title>
+        <function moreinfo="none">is_pure_ip (ip)</function>
+      </title>
+
+      <para>
+        Returns TRUE if the argument is a valid IPv4 or IPv6. FALSE otherwise.
+      </para>
+
+      <para>Parameters:</para>
+
+      <itemizedlist>
+        <listitem>
+          <para>
+            <emphasis>ip</emphasis> - String or pseudo-variable containing the IP to evaluate.
+          </para>
+        </listitem>
+      </itemizedlist>
+
+      <para>
+        This function can be used from REQUEST_ROUTE, FAILURE_ROUTE, ONREPLY_ROUTE, BRANCH_ROUTE and LOCAL_ROUTE.
+      </para>
+
+      <example>
+        <title>
+          <function>is_pure_ip</function> usage
+        </title>
+        <programlisting format="linespecific">
+...
+$var(ip) = "::1";
+if (is_pure_ip($var(ip))) {
+  xlog("L_INFO", "it's IPv4 or IPv6\n");
+}
+...
+        </programlisting>
+      </example>
+
+    </section>
+
+    <section>
+      <title>
+        <function moreinfo="none">is_ipv4 (ip)</function>
+      </title>
+
+      <para>
+        Returns TRUE if the argument is a valid IPv4. FALSE otherwise.
+      </para>
+
+      <para>Parameters:</para>
+
+      <itemizedlist>
+        <listitem>
+          <para>
+            <emphasis>ip</emphasis> - String or pseudo-variable containing the IP to evaluate.
+          </para>
+        </listitem>
+      </itemizedlist>
+
+      <para>
+        This function can be used from REQUEST_ROUTE, FAILURE_ROUTE, ONREPLY_ROUTE, BRANCH_ROUTE and LOCAL_ROUTE.
+      </para>
+
+      <example>
+        <title>
+          <function>is_ipv4</function> usage
+        </title>
+        <programlisting format="linespecific">
+...
+if (is_ipv4("1.2.3.4")) {
+  xlog("L_INFO", "it's IPv4\n");
+}
+...
+        </programlisting>
+      </example>
+
+    </section>
+
+    <section>
+      <title>
+        <function moreinfo="none">is_ipv6 (ip)</function>
+      </title>
+
+      <para>
+        Returns TRUE if the argument is a valid IPv6. FALSE otherwise.
+      </para>
+
+      <para>Parameters:</para>
+
+      <itemizedlist>
+        <listitem>
+          <para>
+            <emphasis>ip</emphasis> - String or pseudo-variable containing the IP to evaluate.
+          </para>
+        </listitem>
+      </itemizedlist>
+
+      <para>
+        This function can be used from REQUEST_ROUTE, FAILURE_ROUTE, ONREPLY_ROUTE, BRANCH_ROUTE and LOCAL_ROUTE.
+      </para>
+
+      <example>
+        <title>
+          <function>is_ipv6</function> usage
+        </title>
+        <programlisting format="linespecific">
+...
+if (is_ipv6("1080:0:0:0:8:800:200C:417A")) {
+  xlog("L_INFO", "it's IPv6\n");
+}
+...
+        </programlisting>
+      </example>
+
+    </section>
+
+    <section>
+      <title>
+        <function moreinfo="none">is_ipv6_reference (ip)</function>
+      </title>
+
+      <para>
+        Returns TRUE if the argument is a valid IPv6 reference. FALSE otherwise.
+      </para>
+
+      <para>Parameters:</para>
+
+      <itemizedlist>
+        <listitem>
+          <para>
+            <emphasis>ip</emphasis> - String or pseudo-variable containing the IP to evaluate.
+          </para>
+        </listitem>
+      </itemizedlist>
+
+      <para>
+        This function can be used from REQUEST_ROUTE, FAILURE_ROUTE, ONREPLY_ROUTE, BRANCH_ROUTE and LOCAL_ROUTE.
+      </para>
+
+      <example>
+        <title>
+          <function>is_ipv6_reference</function> usage
+        </title>
+        <programlisting format="linespecific">
+...
+if (is_ipv6_reference("[1080:0:0:0:8:800:200C:417A]")) {
+  xlog("L_INFO", "it's IPv6 reference\n");
+}
+...
+        </programlisting>
+      </example>
+
+    </section>
+
+    <section>
+      <title>
+        <function moreinfo="none">ip_type (ip)</function>
+      </title>
+
+      <para>
+        Returns the type of the given IP.
+      </para>
+
+      <para>Parameters:</para>
+
+      <itemizedlist>
+        <listitem>
+          <para>
+            <emphasis>ip</emphasis> - String or pseudo-variable containing the IP to evaluate.
+          </para>
+        </listitem>
+      </itemizedlist>
+
+      <para>Return value:</para>
+
+      <itemizedlist>
+        <listitem>
+          <para>
+            <emphasis>1</emphasis> - IPv4
+          </para>
+        </listitem>
+        <listitem>
+          <para>
+            <emphasis>2</emphasis> - IPv6
+          </para>
+        </listitem>
+        <listitem>
+          <para>
+            <emphasis>3</emphasis> - IPv6 reference
+          </para>
+        </listitem>
+        <listitem>
+          <para>
+            <emphasis>-1</emphasis> - invalid IP
+          </para>
+        </listitem>
+      </itemizedlist>
+
+      <para>
+        This function can be used from REQUEST_ROUTE, FAILURE_ROUTE, ONREPLY_ROUTE, BRANCH_ROUTE and LOCAL_ROUTE.
+      </para>
+
+      <example>
+        <title>
+          <function>ip_type</function> usage
+        </title>
+        <programlisting format="linespecific">
+...
+ip_type($var(myip));
+switch($rc) {
+  case 1:
+    xlog("L_INFO", "it's IPv4\n");
+    break;
+  case 2:
+    xlog("L_INFO", "it's IPv6\n");
+    break;
+  case 3:
+    xlog("L_INFO", "it's IPv6 reference\n");
+    break;
+  case -1:
+    xlog("L_INFO", it's type invalid\n");
+    break;
+}
+...
+        </programlisting>
+      </example>
+
+    </section>
+
+    <section>
+      <title>
+        <function moreinfo="none">compare_ips (ip1, ip2)</function>
+      </title>
+
+      <para>
+        Returns TRUE if both IP's are the same. FALSE otherwise. This function also allows comparing an IPv6 against an IPv6 reference.
+      </para>
+
+      <para>Parameters:</para>
+
+      <itemizedlist>
+        <listitem>
+          <para>
+            <emphasis>ip1</emphasis> - String or pseudo-variable containing the first IP to compare.
+          </para>
+        </listitem>
+        <listitem>
+          <para>
+            <emphasis>ip2</emphasis> - String or pseudo-variable containing the second IP to compare.
+          </para>
+        </listitem>
+      </itemizedlist>
+
+      <para>
+        This function can be used from REQUEST_ROUTE, FAILURE_ROUTE, ONREPLY_ROUTE, BRANCH_ROUTE and LOCAL_ROUTE.
+      </para>
+
+      <example>
+        <title>
+          <function>compare_ips</function> usage
+        </title>
+        <programlisting format="linespecific">
+...
+if (compare_ips("1080:0000:0000:0000:0008:0800:200C:417A", "[1080::8:800:200C:417A]")) {
+  xlog("L_INFO", "both are the same IP\n");
+}
+...
+        </programlisting>
+      </example>
+
+    </section>
+
+    <section>
+      <title>
+        <function moreinfo="none">compare_pure_ips (ip1, ip2)</function>
+      </title>
+
+      <para>
+        Returns TRUE if both IP's are the same. FALSE otherwise. This function does NOT allow comparing an IPv6 against an IPv6 reference.
+      </para>
+
+      <para>Parameters:</para>
+
+      <itemizedlist>
+        <listitem>
+          <para>
+            <emphasis>ip1</emphasis> - String or pseudo-variable containing the first IP to compare.
+          </para>
+        </listitem>
+        <listitem>
+          <para>
+            <emphasis>ip2</emphasis> - String or pseudo-variable containing the second IP to compare.
+          </para>
+        </listitem>
+      </itemizedlist>
+
+      <para>
+        This function can be used from REQUEST_ROUTE, FAILURE_ROUTE, ONREPLY_ROUTE, BRANCH_ROUTE and LOCAL_ROUTE.
+      </para>
+
+      <example>
+        <title>
+          <function>compare_pure_ips</function> usage
+        </title>
+        <programlisting format="linespecific">
+...
+if (compare_pure_ips($si, "1080::8:800:200C:417A")) {
+  xlog("L_INFO", "both are the same IP\n");
+}
+...
+        </programlisting>
+      </example>
+
+    </section>
+
+  </section>
+ 
+</chapter>

+ 5951 - 0
modules/ipops/ip_parser.c

@@ -0,0 +1,5951 @@
+
+#line 1 "ip_parser.rl"
+#include "ip_parser.h"
+
+
+/** Ragel machine **/
+
+#line 41 "ip_parser.rl"
+
+
+/** Data **/
+
+#line 14 "ip_parser.c"
+static const int ip_parser_start = 1;
+static const int ip_parser_first_final = 237;
+static const int ip_parser_error = 0;
+
+static const int ip_parser_en_main = 1;
+
+
+#line 45 "ip_parser.rl"
+
+
+/** exec **/
+enum enum_ip_type ip_parser_execute(const char *str, size_t len)
+{
+  int cs = 0;
+  const char *p, *pe;
+  enum enum_ip_type ip_type = ip_type_error;
+
+  p = str;
+  pe = str+len;
+
+  
+#line 36 "ip_parser.c"
+	{
+	cs = ip_parser_start;
+	}
+
+#line 58 "ip_parser.rl"
+  
+#line 43 "ip_parser.c"
+	{
+	if ( p == pe )
+		goto _test_eof;
+	switch ( cs )
+	{
+case 1:
+	switch( (*p) ) {
+		case 48: goto st2;
+		case 49: goto st76;
+		case 50: goto st79;
+		case 58: goto st83;
+		case 91: goto st86;
+	}
+	if ( (*p) < 65 ) {
+		if ( 51 <= (*p) && (*p) <= 57 )
+			goto st82;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st85;
+	} else
+		goto st85;
+	goto st0;
+st0:
+cs = 0;
+	goto _out;
+st2:
+	if ( ++p == pe )
+		goto _test_eof2;
+case 2:
+	switch( (*p) ) {
+		case 46: goto st3;
+		case 58: goto st19;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st16;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st16;
+	} else
+		goto st16;
+	goto st0;
+st3:
+	if ( ++p == pe )
+		goto _test_eof3;
+case 3:
+	switch( (*p) ) {
+		case 48: goto st4;
+		case 49: goto st12;
+		case 50: goto st14;
+	}
+	if ( 51 <= (*p) && (*p) <= 57 )
+		goto st13;
+	goto st0;
+st4:
+	if ( ++p == pe )
+		goto _test_eof4;
+case 4:
+	if ( (*p) == 46 )
+		goto st5;
+	goto st0;
+st5:
+	if ( ++p == pe )
+		goto _test_eof5;
+case 5:
+	switch( (*p) ) {
+		case 48: goto st6;
+		case 49: goto st8;
+		case 50: goto st10;
+	}
+	if ( 51 <= (*p) && (*p) <= 57 )
+		goto st9;
+	goto st0;
+st6:
+	if ( ++p == pe )
+		goto _test_eof6;
+case 6:
+	if ( (*p) == 46 )
+		goto st7;
+	goto st0;
+st7:
+	if ( ++p == pe )
+		goto _test_eof7;
+case 7:
+	switch( (*p) ) {
+		case 48: goto tr21;
+		case 49: goto tr22;
+		case 50: goto tr23;
+	}
+	if ( 51 <= (*p) && (*p) <= 57 )
+		goto tr24;
+	goto st0;
+tr21:
+#line 8 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv4;
+  }
+	goto st237;
+tr78:
+#line 12 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv6;
+  }
+	goto st237;
+tr180:
+#line 16 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv6_reference;
+  }
+	goto st237;
+st237:
+	if ( ++p == pe )
+		goto _test_eof237;
+case 237:
+#line 158 "ip_parser.c"
+	goto st0;
+tr22:
+#line 8 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv4;
+  }
+	goto st238;
+st238:
+	if ( ++p == pe )
+		goto _test_eof238;
+case 238:
+#line 170 "ip_parser.c"
+	if ( 48 <= (*p) && (*p) <= 57 )
+		goto tr24;
+	goto st0;
+tr24:
+#line 8 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv4;
+  }
+	goto st239;
+st239:
+	if ( ++p == pe )
+		goto _test_eof239;
+case 239:
+#line 184 "ip_parser.c"
+	if ( 48 <= (*p) && (*p) <= 57 )
+		goto tr21;
+	goto st0;
+tr23:
+#line 8 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv4;
+  }
+	goto st240;
+st240:
+	if ( ++p == pe )
+		goto _test_eof240;
+case 240:
+#line 198 "ip_parser.c"
+	if ( (*p) == 53 )
+		goto tr272;
+	if ( (*p) > 52 ) {
+		if ( 54 <= (*p) && (*p) <= 57 )
+			goto tr21;
+	} else if ( (*p) >= 48 )
+		goto tr24;
+	goto st0;
+tr272:
+#line 8 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv4;
+  }
+	goto st241;
+st241:
+	if ( ++p == pe )
+		goto _test_eof241;
+case 241:
+#line 217 "ip_parser.c"
+	if ( 48 <= (*p) && (*p) <= 53 )
+		goto tr21;
+	goto st0;
+st8:
+	if ( ++p == pe )
+		goto _test_eof8;
+case 8:
+	if ( (*p) == 46 )
+		goto st7;
+	if ( 48 <= (*p) && (*p) <= 57 )
+		goto st9;
+	goto st0;
+st9:
+	if ( ++p == pe )
+		goto _test_eof9;
+case 9:
+	if ( (*p) == 46 )
+		goto st7;
+	if ( 48 <= (*p) && (*p) <= 57 )
+		goto st6;
+	goto st0;
+st10:
+	if ( ++p == pe )
+		goto _test_eof10;
+case 10:
+	switch( (*p) ) {
+		case 46: goto st7;
+		case 53: goto st11;
+	}
+	if ( (*p) > 52 ) {
+		if ( 54 <= (*p) && (*p) <= 57 )
+			goto st6;
+	} else if ( (*p) >= 48 )
+		goto st9;
+	goto st0;
+st11:
+	if ( ++p == pe )
+		goto _test_eof11;
+case 11:
+	if ( (*p) == 46 )
+		goto st7;
+	if ( 48 <= (*p) && (*p) <= 53 )
+		goto st6;
+	goto st0;
+st12:
+	if ( ++p == pe )
+		goto _test_eof12;
+case 12:
+	if ( (*p) == 46 )
+		goto st5;
+	if ( 48 <= (*p) && (*p) <= 57 )
+		goto st13;
+	goto st0;
+st13:
+	if ( ++p == pe )
+		goto _test_eof13;
+case 13:
+	if ( (*p) == 46 )
+		goto st5;
+	if ( 48 <= (*p) && (*p) <= 57 )
+		goto st4;
+	goto st0;
+st14:
+	if ( ++p == pe )
+		goto _test_eof14;
+case 14:
+	switch( (*p) ) {
+		case 46: goto st5;
+		case 53: goto st15;
+	}
+	if ( (*p) > 52 ) {
+		if ( 54 <= (*p) && (*p) <= 57 )
+			goto st4;
+	} else if ( (*p) >= 48 )
+		goto st13;
+	goto st0;
+st15:
+	if ( ++p == pe )
+		goto _test_eof15;
+case 15:
+	if ( (*p) == 46 )
+		goto st5;
+	if ( 48 <= (*p) && (*p) <= 53 )
+		goto st4;
+	goto st0;
+st16:
+	if ( ++p == pe )
+		goto _test_eof16;
+case 16:
+	if ( (*p) == 58 )
+		goto st19;
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st17;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st17;
+	} else
+		goto st17;
+	goto st0;
+st17:
+	if ( ++p == pe )
+		goto _test_eof17;
+case 17:
+	if ( (*p) == 58 )
+		goto st19;
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st18;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st18;
+	} else
+		goto st18;
+	goto st0;
+st18:
+	if ( ++p == pe )
+		goto _test_eof18;
+case 18:
+	if ( (*p) == 58 )
+		goto st19;
+	goto st0;
+st19:
+	if ( ++p == pe )
+		goto _test_eof19;
+case 19:
+	if ( (*p) == 58 )
+		goto tr30;
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st20;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st20;
+	} else
+		goto st20;
+	goto st0;
+st20:
+	if ( ++p == pe )
+		goto _test_eof20;
+case 20:
+	if ( (*p) == 58 )
+		goto st24;
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st21;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st21;
+	} else
+		goto st21;
+	goto st0;
+st21:
+	if ( ++p == pe )
+		goto _test_eof21;
+case 21:
+	if ( (*p) == 58 )
+		goto st24;
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st22;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st22;
+	} else
+		goto st22;
+	goto st0;
+st22:
+	if ( ++p == pe )
+		goto _test_eof22;
+case 22:
+	if ( (*p) == 58 )
+		goto st24;
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st23;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st23;
+	} else
+		goto st23;
+	goto st0;
+st23:
+	if ( ++p == pe )
+		goto _test_eof23;
+case 23:
+	if ( (*p) == 58 )
+		goto st24;
+	goto st0;
+st24:
+	if ( ++p == pe )
+		goto _test_eof24;
+case 24:
+	if ( (*p) == 58 )
+		goto tr36;
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st25;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st25;
+	} else
+		goto st25;
+	goto st0;
+st25:
+	if ( ++p == pe )
+		goto _test_eof25;
+case 25:
+	if ( (*p) == 58 )
+		goto st29;
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st26;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st26;
+	} else
+		goto st26;
+	goto st0;
+st26:
+	if ( ++p == pe )
+		goto _test_eof26;
+case 26:
+	if ( (*p) == 58 )
+		goto st29;
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st27;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st27;
+	} else
+		goto st27;
+	goto st0;
+st27:
+	if ( ++p == pe )
+		goto _test_eof27;
+case 27:
+	if ( (*p) == 58 )
+		goto st29;
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st28;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st28;
+	} else
+		goto st28;
+	goto st0;
+st28:
+	if ( ++p == pe )
+		goto _test_eof28;
+case 28:
+	if ( (*p) == 58 )
+		goto st29;
+	goto st0;
+st29:
+	if ( ++p == pe )
+		goto _test_eof29;
+case 29:
+	if ( (*p) == 58 )
+		goto tr42;
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st30;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st30;
+	} else
+		goto st30;
+	goto st0;
+st30:
+	if ( ++p == pe )
+		goto _test_eof30;
+case 30:
+	if ( (*p) == 58 )
+		goto st34;
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st31;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st31;
+	} else
+		goto st31;
+	goto st0;
+st31:
+	if ( ++p == pe )
+		goto _test_eof31;
+case 31:
+	if ( (*p) == 58 )
+		goto st34;
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st32;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st32;
+	} else
+		goto st32;
+	goto st0;
+st32:
+	if ( ++p == pe )
+		goto _test_eof32;
+case 32:
+	if ( (*p) == 58 )
+		goto st34;
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st33;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st33;
+	} else
+		goto st33;
+	goto st0;
+st33:
+	if ( ++p == pe )
+		goto _test_eof33;
+case 33:
+	if ( (*p) == 58 )
+		goto st34;
+	goto st0;
+st34:
+	if ( ++p == pe )
+		goto _test_eof34;
+case 34:
+	if ( (*p) == 58 )
+		goto tr48;
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st35;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st35;
+	} else
+		goto st35;
+	goto st0;
+st35:
+	if ( ++p == pe )
+		goto _test_eof35;
+case 35:
+	if ( (*p) == 58 )
+		goto st39;
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st36;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st36;
+	} else
+		goto st36;
+	goto st0;
+st36:
+	if ( ++p == pe )
+		goto _test_eof36;
+case 36:
+	if ( (*p) == 58 )
+		goto st39;
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st37;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st37;
+	} else
+		goto st37;
+	goto st0;
+st37:
+	if ( ++p == pe )
+		goto _test_eof37;
+case 37:
+	if ( (*p) == 58 )
+		goto st39;
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st38;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st38;
+	} else
+		goto st38;
+	goto st0;
+st38:
+	if ( ++p == pe )
+		goto _test_eof38;
+case 38:
+	if ( (*p) == 58 )
+		goto st39;
+	goto st0;
+st39:
+	if ( ++p == pe )
+		goto _test_eof39;
+case 39:
+	if ( (*p) == 58 )
+		goto tr54;
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st40;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st40;
+	} else
+		goto st40;
+	goto st0;
+st40:
+	if ( ++p == pe )
+		goto _test_eof40;
+case 40:
+	if ( (*p) == 58 )
+		goto st44;
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st41;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st41;
+	} else
+		goto st41;
+	goto st0;
+st41:
+	if ( ++p == pe )
+		goto _test_eof41;
+case 41:
+	if ( (*p) == 58 )
+		goto st44;
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st42;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st42;
+	} else
+		goto st42;
+	goto st0;
+st42:
+	if ( ++p == pe )
+		goto _test_eof42;
+case 42:
+	if ( (*p) == 58 )
+		goto st44;
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st43;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st43;
+	} else
+		goto st43;
+	goto st0;
+st43:
+	if ( ++p == pe )
+		goto _test_eof43;
+case 43:
+	if ( (*p) == 58 )
+		goto st44;
+	goto st0;
+st44:
+	if ( ++p == pe )
+		goto _test_eof44;
+case 44:
+	switch( (*p) ) {
+		case 48: goto st45;
+		case 49: goto st63;
+		case 50: goto st66;
+		case 58: goto tr63;
+	}
+	if ( (*p) < 65 ) {
+		if ( 51 <= (*p) && (*p) <= 57 )
+			goto st69;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st70;
+	} else
+		goto st70;
+	goto st0;
+st45:
+	if ( ++p == pe )
+		goto _test_eof45;
+case 45:
+	switch( (*p) ) {
+		case 46: goto st46;
+		case 58: goto st62;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st59;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st59;
+	} else
+		goto st59;
+	goto st0;
+st46:
+	if ( ++p == pe )
+		goto _test_eof46;
+case 46:
+	switch( (*p) ) {
+		case 48: goto st47;
+		case 49: goto st55;
+		case 50: goto st57;
+	}
+	if ( 51 <= (*p) && (*p) <= 57 )
+		goto st56;
+	goto st0;
+st47:
+	if ( ++p == pe )
+		goto _test_eof47;
+case 47:
+	if ( (*p) == 46 )
+		goto st48;
+	goto st0;
+st48:
+	if ( ++p == pe )
+		goto _test_eof48;
+case 48:
+	switch( (*p) ) {
+		case 48: goto st49;
+		case 49: goto st51;
+		case 50: goto st53;
+	}
+	if ( 51 <= (*p) && (*p) <= 57 )
+		goto st52;
+	goto st0;
+st49:
+	if ( ++p == pe )
+		goto _test_eof49;
+case 49:
+	if ( (*p) == 46 )
+		goto st50;
+	goto st0;
+st50:
+	if ( ++p == pe )
+		goto _test_eof50;
+case 50:
+	switch( (*p) ) {
+		case 48: goto tr78;
+		case 49: goto tr79;
+		case 50: goto tr80;
+	}
+	if ( 51 <= (*p) && (*p) <= 57 )
+		goto tr81;
+	goto st0;
+tr79:
+#line 12 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv6;
+  }
+	goto st242;
+st242:
+	if ( ++p == pe )
+		goto _test_eof242;
+case 242:
+#line 771 "ip_parser.c"
+	if ( 48 <= (*p) && (*p) <= 57 )
+		goto tr81;
+	goto st0;
+tr81:
+#line 12 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv6;
+  }
+	goto st243;
+st243:
+	if ( ++p == pe )
+		goto _test_eof243;
+case 243:
+#line 785 "ip_parser.c"
+	if ( 48 <= (*p) && (*p) <= 57 )
+		goto tr78;
+	goto st0;
+tr80:
+#line 12 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv6;
+  }
+	goto st244;
+st244:
+	if ( ++p == pe )
+		goto _test_eof244;
+case 244:
+#line 799 "ip_parser.c"
+	if ( (*p) == 53 )
+		goto tr273;
+	if ( (*p) > 52 ) {
+		if ( 54 <= (*p) && (*p) <= 57 )
+			goto tr78;
+	} else if ( (*p) >= 48 )
+		goto tr81;
+	goto st0;
+tr273:
+#line 12 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv6;
+  }
+	goto st245;
+st245:
+	if ( ++p == pe )
+		goto _test_eof245;
+case 245:
+#line 818 "ip_parser.c"
+	if ( 48 <= (*p) && (*p) <= 53 )
+		goto tr78;
+	goto st0;
+st51:
+	if ( ++p == pe )
+		goto _test_eof51;
+case 51:
+	if ( (*p) == 46 )
+		goto st50;
+	if ( 48 <= (*p) && (*p) <= 57 )
+		goto st52;
+	goto st0;
+st52:
+	if ( ++p == pe )
+		goto _test_eof52;
+case 52:
+	if ( (*p) == 46 )
+		goto st50;
+	if ( 48 <= (*p) && (*p) <= 57 )
+		goto st49;
+	goto st0;
+st53:
+	if ( ++p == pe )
+		goto _test_eof53;
+case 53:
+	switch( (*p) ) {
+		case 46: goto st50;
+		case 53: goto st54;
+	}
+	if ( (*p) > 52 ) {
+		if ( 54 <= (*p) && (*p) <= 57 )
+			goto st49;
+	} else if ( (*p) >= 48 )
+		goto st52;
+	goto st0;
+st54:
+	if ( ++p == pe )
+		goto _test_eof54;
+case 54:
+	if ( (*p) == 46 )
+		goto st50;
+	if ( 48 <= (*p) && (*p) <= 53 )
+		goto st49;
+	goto st0;
+st55:
+	if ( ++p == pe )
+		goto _test_eof55;
+case 55:
+	if ( (*p) == 46 )
+		goto st48;
+	if ( 48 <= (*p) && (*p) <= 57 )
+		goto st56;
+	goto st0;
+st56:
+	if ( ++p == pe )
+		goto _test_eof56;
+case 56:
+	if ( (*p) == 46 )
+		goto st48;
+	if ( 48 <= (*p) && (*p) <= 57 )
+		goto st47;
+	goto st0;
+st57:
+	if ( ++p == pe )
+		goto _test_eof57;
+case 57:
+	switch( (*p) ) {
+		case 46: goto st48;
+		case 53: goto st58;
+	}
+	if ( (*p) > 52 ) {
+		if ( 54 <= (*p) && (*p) <= 57 )
+			goto st47;
+	} else if ( (*p) >= 48 )
+		goto st56;
+	goto st0;
+st58:
+	if ( ++p == pe )
+		goto _test_eof58;
+case 58:
+	if ( (*p) == 46 )
+		goto st48;
+	if ( 48 <= (*p) && (*p) <= 53 )
+		goto st47;
+	goto st0;
+st59:
+	if ( ++p == pe )
+		goto _test_eof59;
+case 59:
+	if ( (*p) == 58 )
+		goto st62;
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st60;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st60;
+	} else
+		goto st60;
+	goto st0;
+st60:
+	if ( ++p == pe )
+		goto _test_eof60;
+case 60:
+	if ( (*p) == 58 )
+		goto st62;
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st61;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st61;
+	} else
+		goto st61;
+	goto st0;
+st61:
+	if ( ++p == pe )
+		goto _test_eof61;
+case 61:
+	if ( (*p) == 58 )
+		goto st62;
+	goto st0;
+st62:
+	if ( ++p == pe )
+		goto _test_eof62;
+case 62:
+	if ( (*p) == 58 )
+		goto tr78;
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto tr86;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto tr86;
+	} else
+		goto tr86;
+	goto st0;
+tr86:
+#line 12 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv6;
+  }
+	goto st246;
+st246:
+	if ( ++p == pe )
+		goto _test_eof246;
+case 246:
+#line 966 "ip_parser.c"
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto tr274;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto tr274;
+	} else
+		goto tr274;
+	goto st0;
+tr274:
+#line 12 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv6;
+  }
+	goto st247;
+st247:
+	if ( ++p == pe )
+		goto _test_eof247;
+case 247:
+#line 986 "ip_parser.c"
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto tr275;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto tr275;
+	} else
+		goto tr275;
+	goto st0;
+tr275:
+#line 12 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv6;
+  }
+	goto st248;
+st248:
+	if ( ++p == pe )
+		goto _test_eof248;
+case 248:
+#line 1006 "ip_parser.c"
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto tr78;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto tr78;
+	} else
+		goto tr78;
+	goto st0;
+st63:
+	if ( ++p == pe )
+		goto _test_eof63;
+case 63:
+	switch( (*p) ) {
+		case 46: goto st46;
+		case 58: goto st62;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st64;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st59;
+	} else
+		goto st59;
+	goto st0;
+st64:
+	if ( ++p == pe )
+		goto _test_eof64;
+case 64:
+	switch( (*p) ) {
+		case 46: goto st46;
+		case 58: goto st62;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st65;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st60;
+	} else
+		goto st60;
+	goto st0;
+st65:
+	if ( ++p == pe )
+		goto _test_eof65;
+case 65:
+	switch( (*p) ) {
+		case 46: goto st46;
+		case 58: goto st62;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st61;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st61;
+	} else
+		goto st61;
+	goto st0;
+st66:
+	if ( ++p == pe )
+		goto _test_eof66;
+case 66:
+	switch( (*p) ) {
+		case 46: goto st46;
+		case 53: goto st67;
+		case 58: goto st62;
+	}
+	if ( (*p) < 54 ) {
+		if ( 48 <= (*p) && (*p) <= 52 )
+			goto st64;
+	} else if ( (*p) > 57 ) {
+		if ( (*p) > 70 ) {
+			if ( 97 <= (*p) && (*p) <= 102 )
+				goto st59;
+		} else if ( (*p) >= 65 )
+			goto st59;
+	} else
+		goto st68;
+	goto st0;
+st67:
+	if ( ++p == pe )
+		goto _test_eof67;
+case 67:
+	switch( (*p) ) {
+		case 46: goto st46;
+		case 58: goto st62;
+	}
+	if ( (*p) < 54 ) {
+		if ( 48 <= (*p) && (*p) <= 53 )
+			goto st65;
+	} else if ( (*p) > 57 ) {
+		if ( (*p) > 70 ) {
+			if ( 97 <= (*p) && (*p) <= 102 )
+				goto st60;
+		} else if ( (*p) >= 65 )
+			goto st60;
+	} else
+		goto st60;
+	goto st0;
+st68:
+	if ( ++p == pe )
+		goto _test_eof68;
+case 68:
+	switch( (*p) ) {
+		case 46: goto st46;
+		case 58: goto st62;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st60;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st60;
+	} else
+		goto st60;
+	goto st0;
+st69:
+	if ( ++p == pe )
+		goto _test_eof69;
+case 69:
+	switch( (*p) ) {
+		case 46: goto st46;
+		case 58: goto st62;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st68;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st59;
+	} else
+		goto st59;
+	goto st0;
+tr63:
+#line 12 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv6;
+  }
+	goto st249;
+st249:
+	if ( ++p == pe )
+		goto _test_eof249;
+case 249:
+#line 1152 "ip_parser.c"
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto tr86;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto tr86;
+	} else
+		goto tr86;
+	goto st0;
+st70:
+	if ( ++p == pe )
+		goto _test_eof70;
+case 70:
+	if ( (*p) == 58 )
+		goto st62;
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st59;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st59;
+	} else
+		goto st59;
+	goto st0;
+tr54:
+#line 12 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv6;
+  }
+	goto st250;
+st250:
+	if ( ++p == pe )
+		goto _test_eof250;
+case 250:
+#line 1187 "ip_parser.c"
+	switch( (*p) ) {
+		case 48: goto tr91;
+		case 49: goto tr92;
+		case 50: goto tr93;
+	}
+	if ( (*p) < 65 ) {
+		if ( 51 <= (*p) && (*p) <= 57 )
+			goto tr94;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto tr95;
+	} else
+		goto tr95;
+	goto st0;
+tr91:
+#line 12 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv6;
+  }
+	goto st251;
+st251:
+	if ( ++p == pe )
+		goto _test_eof251;
+case 251:
+#line 1212 "ip_parser.c"
+	switch( (*p) ) {
+		case 46: goto st46;
+		case 58: goto st71;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto tr276;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto tr276;
+	} else
+		goto tr276;
+	goto st0;
+tr276:
+#line 12 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv6;
+  }
+	goto st252;
+st252:
+	if ( ++p == pe )
+		goto _test_eof252;
+case 252:
+#line 1236 "ip_parser.c"
+	if ( (*p) == 58 )
+		goto st71;
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto tr278;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto tr278;
+	} else
+		goto tr278;
+	goto st0;
+tr278:
+#line 12 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv6;
+  }
+	goto st253;
+st253:
+	if ( ++p == pe )
+		goto _test_eof253;
+case 253:
+#line 1258 "ip_parser.c"
+	if ( (*p) == 58 )
+		goto st71;
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto tr279;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto tr279;
+	} else
+		goto tr279;
+	goto st0;
+tr279:
+#line 12 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv6;
+  }
+	goto st254;
+st254:
+	if ( ++p == pe )
+		goto _test_eof254;
+case 254:
+#line 1280 "ip_parser.c"
+	if ( (*p) == 58 )
+		goto st71;
+	goto st0;
+st71:
+	if ( ++p == pe )
+		goto _test_eof71;
+case 71:
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto tr86;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto tr86;
+	} else
+		goto tr86;
+	goto st0;
+tr92:
+#line 12 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv6;
+  }
+	goto st255;
+st255:
+	if ( ++p == pe )
+		goto _test_eof255;
+case 255:
+#line 1307 "ip_parser.c"
+	switch( (*p) ) {
+		case 46: goto st46;
+		case 58: goto st71;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto tr280;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto tr276;
+	} else
+		goto tr276;
+	goto st0;
+tr280:
+#line 12 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv6;
+  }
+	goto st256;
+st256:
+	if ( ++p == pe )
+		goto _test_eof256;
+case 256:
+#line 1331 "ip_parser.c"
+	switch( (*p) ) {
+		case 46: goto st46;
+		case 58: goto st71;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto tr281;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto tr278;
+	} else
+		goto tr278;
+	goto st0;
+tr281:
+#line 12 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv6;
+  }
+	goto st257;
+st257:
+	if ( ++p == pe )
+		goto _test_eof257;
+case 257:
+#line 1355 "ip_parser.c"
+	switch( (*p) ) {
+		case 46: goto st46;
+		case 58: goto st71;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto tr279;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto tr279;
+	} else
+		goto tr279;
+	goto st0;
+tr93:
+#line 12 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv6;
+  }
+	goto st258;
+st258:
+	if ( ++p == pe )
+		goto _test_eof258;
+case 258:
+#line 1379 "ip_parser.c"
+	switch( (*p) ) {
+		case 46: goto st46;
+		case 53: goto tr282;
+		case 58: goto st71;
+	}
+	if ( (*p) < 54 ) {
+		if ( 48 <= (*p) && (*p) <= 52 )
+			goto tr280;
+	} else if ( (*p) > 57 ) {
+		if ( (*p) > 70 ) {
+			if ( 97 <= (*p) && (*p) <= 102 )
+				goto tr276;
+		} else if ( (*p) >= 65 )
+			goto tr276;
+	} else
+		goto tr283;
+	goto st0;
+tr282:
+#line 12 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv6;
+  }
+	goto st259;
+st259:
+	if ( ++p == pe )
+		goto _test_eof259;
+case 259:
+#line 1407 "ip_parser.c"
+	switch( (*p) ) {
+		case 46: goto st46;
+		case 58: goto st71;
+	}
+	if ( (*p) < 54 ) {
+		if ( 48 <= (*p) && (*p) <= 53 )
+			goto tr281;
+	} else if ( (*p) > 57 ) {
+		if ( (*p) > 70 ) {
+			if ( 97 <= (*p) && (*p) <= 102 )
+				goto tr278;
+		} else if ( (*p) >= 65 )
+			goto tr278;
+	} else
+		goto tr278;
+	goto st0;
+tr283:
+#line 12 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv6;
+  }
+	goto st260;
+st260:
+	if ( ++p == pe )
+		goto _test_eof260;
+case 260:
+#line 1434 "ip_parser.c"
+	switch( (*p) ) {
+		case 46: goto st46;
+		case 58: goto st71;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto tr278;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto tr278;
+	} else
+		goto tr278;
+	goto st0;
+tr94:
+#line 12 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv6;
+  }
+	goto st261;
+st261:
+	if ( ++p == pe )
+		goto _test_eof261;
+case 261:
+#line 1458 "ip_parser.c"
+	switch( (*p) ) {
+		case 46: goto st46;
+		case 58: goto st71;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto tr283;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto tr276;
+	} else
+		goto tr276;
+	goto st0;
+tr95:
+#line 12 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv6;
+  }
+	goto st262;
+st262:
+	if ( ++p == pe )
+		goto _test_eof262;
+case 262:
+#line 1482 "ip_parser.c"
+	if ( (*p) == 58 )
+		goto st71;
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto tr276;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto tr276;
+	} else
+		goto tr276;
+	goto st0;
+tr48:
+#line 12 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv6;
+  }
+	goto st263;
+st263:
+	if ( ++p == pe )
+		goto _test_eof263;
+case 263:
+#line 1504 "ip_parser.c"
+	switch( (*p) ) {
+		case 48: goto tr96;
+		case 49: goto tr97;
+		case 50: goto tr98;
+	}
+	if ( (*p) < 65 ) {
+		if ( 51 <= (*p) && (*p) <= 57 )
+			goto tr99;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto tr100;
+	} else
+		goto tr100;
+	goto st0;
+tr96:
+#line 12 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv6;
+  }
+	goto st264;
+st264:
+	if ( ++p == pe )
+		goto _test_eof264;
+case 264:
+#line 1529 "ip_parser.c"
+	switch( (*p) ) {
+		case 46: goto st46;
+		case 58: goto st72;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto tr284;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto tr284;
+	} else
+		goto tr284;
+	goto st0;
+tr284:
+#line 12 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv6;
+  }
+	goto st265;
+st265:
+	if ( ++p == pe )
+		goto _test_eof265;
+case 265:
+#line 1553 "ip_parser.c"
+	if ( (*p) == 58 )
+		goto st72;
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto tr286;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto tr286;
+	} else
+		goto tr286;
+	goto st0;
+tr286:
+#line 12 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv6;
+  }
+	goto st266;
+st266:
+	if ( ++p == pe )
+		goto _test_eof266;
+case 266:
+#line 1575 "ip_parser.c"
+	if ( (*p) == 58 )
+		goto st72;
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto tr287;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto tr287;
+	} else
+		goto tr287;
+	goto st0;
+tr287:
+#line 12 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv6;
+  }
+	goto st267;
+st267:
+	if ( ++p == pe )
+		goto _test_eof267;
+case 267:
+#line 1597 "ip_parser.c"
+	if ( (*p) == 58 )
+		goto st72;
+	goto st0;
+st72:
+	if ( ++p == pe )
+		goto _test_eof72;
+case 72:
+	switch( (*p) ) {
+		case 48: goto tr91;
+		case 49: goto tr92;
+		case 50: goto tr93;
+	}
+	if ( (*p) < 65 ) {
+		if ( 51 <= (*p) && (*p) <= 57 )
+			goto tr94;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto tr95;
+	} else
+		goto tr95;
+	goto st0;
+tr97:
+#line 12 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv6;
+  }
+	goto st268;
+st268:
+	if ( ++p == pe )
+		goto _test_eof268;
+case 268:
+#line 1629 "ip_parser.c"
+	switch( (*p) ) {
+		case 46: goto st46;
+		case 58: goto st72;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto tr288;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto tr284;
+	} else
+		goto tr284;
+	goto st0;
+tr288:
+#line 12 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv6;
+  }
+	goto st269;
+st269:
+	if ( ++p == pe )
+		goto _test_eof269;
+case 269:
+#line 1653 "ip_parser.c"
+	switch( (*p) ) {
+		case 46: goto st46;
+		case 58: goto st72;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto tr289;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto tr286;
+	} else
+		goto tr286;
+	goto st0;
+tr289:
+#line 12 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv6;
+  }
+	goto st270;
+st270:
+	if ( ++p == pe )
+		goto _test_eof270;
+case 270:
+#line 1677 "ip_parser.c"
+	switch( (*p) ) {
+		case 46: goto st46;
+		case 58: goto st72;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto tr287;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto tr287;
+	} else
+		goto tr287;
+	goto st0;
+tr98:
+#line 12 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv6;
+  }
+	goto st271;
+st271:
+	if ( ++p == pe )
+		goto _test_eof271;
+case 271:
+#line 1701 "ip_parser.c"
+	switch( (*p) ) {
+		case 46: goto st46;
+		case 53: goto tr290;
+		case 58: goto st72;
+	}
+	if ( (*p) < 54 ) {
+		if ( 48 <= (*p) && (*p) <= 52 )
+			goto tr288;
+	} else if ( (*p) > 57 ) {
+		if ( (*p) > 70 ) {
+			if ( 97 <= (*p) && (*p) <= 102 )
+				goto tr284;
+		} else if ( (*p) >= 65 )
+			goto tr284;
+	} else
+		goto tr291;
+	goto st0;
+tr290:
+#line 12 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv6;
+  }
+	goto st272;
+st272:
+	if ( ++p == pe )
+		goto _test_eof272;
+case 272:
+#line 1729 "ip_parser.c"
+	switch( (*p) ) {
+		case 46: goto st46;
+		case 58: goto st72;
+	}
+	if ( (*p) < 54 ) {
+		if ( 48 <= (*p) && (*p) <= 53 )
+			goto tr289;
+	} else if ( (*p) > 57 ) {
+		if ( (*p) > 70 ) {
+			if ( 97 <= (*p) && (*p) <= 102 )
+				goto tr286;
+		} else if ( (*p) >= 65 )
+			goto tr286;
+	} else
+		goto tr286;
+	goto st0;
+tr291:
+#line 12 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv6;
+  }
+	goto st273;
+st273:
+	if ( ++p == pe )
+		goto _test_eof273;
+case 273:
+#line 1756 "ip_parser.c"
+	switch( (*p) ) {
+		case 46: goto st46;
+		case 58: goto st72;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto tr286;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto tr286;
+	} else
+		goto tr286;
+	goto st0;
+tr99:
+#line 12 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv6;
+  }
+	goto st274;
+st274:
+	if ( ++p == pe )
+		goto _test_eof274;
+case 274:
+#line 1780 "ip_parser.c"
+	switch( (*p) ) {
+		case 46: goto st46;
+		case 58: goto st72;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto tr291;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto tr284;
+	} else
+		goto tr284;
+	goto st0;
+tr100:
+#line 12 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv6;
+  }
+	goto st275;
+st275:
+	if ( ++p == pe )
+		goto _test_eof275;
+case 275:
+#line 1804 "ip_parser.c"
+	if ( (*p) == 58 )
+		goto st72;
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto tr284;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto tr284;
+	} else
+		goto tr284;
+	goto st0;
+tr42:
+#line 12 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv6;
+  }
+	goto st276;
+st276:
+	if ( ++p == pe )
+		goto _test_eof276;
+case 276:
+#line 1826 "ip_parser.c"
+	switch( (*p) ) {
+		case 48: goto tr101;
+		case 49: goto tr102;
+		case 50: goto tr103;
+	}
+	if ( (*p) < 65 ) {
+		if ( 51 <= (*p) && (*p) <= 57 )
+			goto tr104;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto tr105;
+	} else
+		goto tr105;
+	goto st0;
+tr101:
+#line 12 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv6;
+  }
+	goto st277;
+st277:
+	if ( ++p == pe )
+		goto _test_eof277;
+case 277:
+#line 1851 "ip_parser.c"
+	switch( (*p) ) {
+		case 46: goto st46;
+		case 58: goto st73;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto tr292;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto tr292;
+	} else
+		goto tr292;
+	goto st0;
+tr292:
+#line 12 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv6;
+  }
+	goto st278;
+st278:
+	if ( ++p == pe )
+		goto _test_eof278;
+case 278:
+#line 1875 "ip_parser.c"
+	if ( (*p) == 58 )
+		goto st73;
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto tr294;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto tr294;
+	} else
+		goto tr294;
+	goto st0;
+tr294:
+#line 12 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv6;
+  }
+	goto st279;
+st279:
+	if ( ++p == pe )
+		goto _test_eof279;
+case 279:
+#line 1897 "ip_parser.c"
+	if ( (*p) == 58 )
+		goto st73;
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto tr295;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto tr295;
+	} else
+		goto tr295;
+	goto st0;
+tr295:
+#line 12 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv6;
+  }
+	goto st280;
+st280:
+	if ( ++p == pe )
+		goto _test_eof280;
+case 280:
+#line 1919 "ip_parser.c"
+	if ( (*p) == 58 )
+		goto st73;
+	goto st0;
+st73:
+	if ( ++p == pe )
+		goto _test_eof73;
+case 73:
+	switch( (*p) ) {
+		case 48: goto tr96;
+		case 49: goto tr97;
+		case 50: goto tr98;
+	}
+	if ( (*p) < 65 ) {
+		if ( 51 <= (*p) && (*p) <= 57 )
+			goto tr99;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto tr100;
+	} else
+		goto tr100;
+	goto st0;
+tr102:
+#line 12 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv6;
+  }
+	goto st281;
+st281:
+	if ( ++p == pe )
+		goto _test_eof281;
+case 281:
+#line 1951 "ip_parser.c"
+	switch( (*p) ) {
+		case 46: goto st46;
+		case 58: goto st73;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto tr296;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto tr292;
+	} else
+		goto tr292;
+	goto st0;
+tr296:
+#line 12 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv6;
+  }
+	goto st282;
+st282:
+	if ( ++p == pe )
+		goto _test_eof282;
+case 282:
+#line 1975 "ip_parser.c"
+	switch( (*p) ) {
+		case 46: goto st46;
+		case 58: goto st73;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto tr297;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto tr294;
+	} else
+		goto tr294;
+	goto st0;
+tr297:
+#line 12 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv6;
+  }
+	goto st283;
+st283:
+	if ( ++p == pe )
+		goto _test_eof283;
+case 283:
+#line 1999 "ip_parser.c"
+	switch( (*p) ) {
+		case 46: goto st46;
+		case 58: goto st73;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto tr295;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto tr295;
+	} else
+		goto tr295;
+	goto st0;
+tr103:
+#line 12 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv6;
+  }
+	goto st284;
+st284:
+	if ( ++p == pe )
+		goto _test_eof284;
+case 284:
+#line 2023 "ip_parser.c"
+	switch( (*p) ) {
+		case 46: goto st46;
+		case 53: goto tr298;
+		case 58: goto st73;
+	}
+	if ( (*p) < 54 ) {
+		if ( 48 <= (*p) && (*p) <= 52 )
+			goto tr296;
+	} else if ( (*p) > 57 ) {
+		if ( (*p) > 70 ) {
+			if ( 97 <= (*p) && (*p) <= 102 )
+				goto tr292;
+		} else if ( (*p) >= 65 )
+			goto tr292;
+	} else
+		goto tr299;
+	goto st0;
+tr298:
+#line 12 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv6;
+  }
+	goto st285;
+st285:
+	if ( ++p == pe )
+		goto _test_eof285;
+case 285:
+#line 2051 "ip_parser.c"
+	switch( (*p) ) {
+		case 46: goto st46;
+		case 58: goto st73;
+	}
+	if ( (*p) < 54 ) {
+		if ( 48 <= (*p) && (*p) <= 53 )
+			goto tr297;
+	} else if ( (*p) > 57 ) {
+		if ( (*p) > 70 ) {
+			if ( 97 <= (*p) && (*p) <= 102 )
+				goto tr294;
+		} else if ( (*p) >= 65 )
+			goto tr294;
+	} else
+		goto tr294;
+	goto st0;
+tr299:
+#line 12 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv6;
+  }
+	goto st286;
+st286:
+	if ( ++p == pe )
+		goto _test_eof286;
+case 286:
+#line 2078 "ip_parser.c"
+	switch( (*p) ) {
+		case 46: goto st46;
+		case 58: goto st73;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto tr294;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto tr294;
+	} else
+		goto tr294;
+	goto st0;
+tr104:
+#line 12 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv6;
+  }
+	goto st287;
+st287:
+	if ( ++p == pe )
+		goto _test_eof287;
+case 287:
+#line 2102 "ip_parser.c"
+	switch( (*p) ) {
+		case 46: goto st46;
+		case 58: goto st73;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto tr299;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto tr292;
+	} else
+		goto tr292;
+	goto st0;
+tr105:
+#line 12 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv6;
+  }
+	goto st288;
+st288:
+	if ( ++p == pe )
+		goto _test_eof288;
+case 288:
+#line 2126 "ip_parser.c"
+	if ( (*p) == 58 )
+		goto st73;
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto tr292;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto tr292;
+	} else
+		goto tr292;
+	goto st0;
+tr36:
+#line 12 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv6;
+  }
+	goto st289;
+st289:
+	if ( ++p == pe )
+		goto _test_eof289;
+case 289:
+#line 2148 "ip_parser.c"
+	switch( (*p) ) {
+		case 48: goto tr106;
+		case 49: goto tr107;
+		case 50: goto tr108;
+	}
+	if ( (*p) < 65 ) {
+		if ( 51 <= (*p) && (*p) <= 57 )
+			goto tr109;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto tr110;
+	} else
+		goto tr110;
+	goto st0;
+tr106:
+#line 12 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv6;
+  }
+	goto st290;
+st290:
+	if ( ++p == pe )
+		goto _test_eof290;
+case 290:
+#line 2173 "ip_parser.c"
+	switch( (*p) ) {
+		case 46: goto st46;
+		case 58: goto st74;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto tr300;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto tr300;
+	} else
+		goto tr300;
+	goto st0;
+tr300:
+#line 12 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv6;
+  }
+	goto st291;
+st291:
+	if ( ++p == pe )
+		goto _test_eof291;
+case 291:
+#line 2197 "ip_parser.c"
+	if ( (*p) == 58 )
+		goto st74;
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto tr302;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto tr302;
+	} else
+		goto tr302;
+	goto st0;
+tr302:
+#line 12 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv6;
+  }
+	goto st292;
+st292:
+	if ( ++p == pe )
+		goto _test_eof292;
+case 292:
+#line 2219 "ip_parser.c"
+	if ( (*p) == 58 )
+		goto st74;
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto tr303;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto tr303;
+	} else
+		goto tr303;
+	goto st0;
+tr303:
+#line 12 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv6;
+  }
+	goto st293;
+st293:
+	if ( ++p == pe )
+		goto _test_eof293;
+case 293:
+#line 2241 "ip_parser.c"
+	if ( (*p) == 58 )
+		goto st74;
+	goto st0;
+st74:
+	if ( ++p == pe )
+		goto _test_eof74;
+case 74:
+	switch( (*p) ) {
+		case 48: goto tr101;
+		case 49: goto tr102;
+		case 50: goto tr103;
+	}
+	if ( (*p) < 65 ) {
+		if ( 51 <= (*p) && (*p) <= 57 )
+			goto tr104;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto tr105;
+	} else
+		goto tr105;
+	goto st0;
+tr107:
+#line 12 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv6;
+  }
+	goto st294;
+st294:
+	if ( ++p == pe )
+		goto _test_eof294;
+case 294:
+#line 2273 "ip_parser.c"
+	switch( (*p) ) {
+		case 46: goto st46;
+		case 58: goto st74;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto tr304;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto tr300;
+	} else
+		goto tr300;
+	goto st0;
+tr304:
+#line 12 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv6;
+  }
+	goto st295;
+st295:
+	if ( ++p == pe )
+		goto _test_eof295;
+case 295:
+#line 2297 "ip_parser.c"
+	switch( (*p) ) {
+		case 46: goto st46;
+		case 58: goto st74;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto tr305;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto tr302;
+	} else
+		goto tr302;
+	goto st0;
+tr305:
+#line 12 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv6;
+  }
+	goto st296;
+st296:
+	if ( ++p == pe )
+		goto _test_eof296;
+case 296:
+#line 2321 "ip_parser.c"
+	switch( (*p) ) {
+		case 46: goto st46;
+		case 58: goto st74;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto tr303;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto tr303;
+	} else
+		goto tr303;
+	goto st0;
+tr108:
+#line 12 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv6;
+  }
+	goto st297;
+st297:
+	if ( ++p == pe )
+		goto _test_eof297;
+case 297:
+#line 2345 "ip_parser.c"
+	switch( (*p) ) {
+		case 46: goto st46;
+		case 53: goto tr306;
+		case 58: goto st74;
+	}
+	if ( (*p) < 54 ) {
+		if ( 48 <= (*p) && (*p) <= 52 )
+			goto tr304;
+	} else if ( (*p) > 57 ) {
+		if ( (*p) > 70 ) {
+			if ( 97 <= (*p) && (*p) <= 102 )
+				goto tr300;
+		} else if ( (*p) >= 65 )
+			goto tr300;
+	} else
+		goto tr307;
+	goto st0;
+tr306:
+#line 12 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv6;
+  }
+	goto st298;
+st298:
+	if ( ++p == pe )
+		goto _test_eof298;
+case 298:
+#line 2373 "ip_parser.c"
+	switch( (*p) ) {
+		case 46: goto st46;
+		case 58: goto st74;
+	}
+	if ( (*p) < 54 ) {
+		if ( 48 <= (*p) && (*p) <= 53 )
+			goto tr305;
+	} else if ( (*p) > 57 ) {
+		if ( (*p) > 70 ) {
+			if ( 97 <= (*p) && (*p) <= 102 )
+				goto tr302;
+		} else if ( (*p) >= 65 )
+			goto tr302;
+	} else
+		goto tr302;
+	goto st0;
+tr307:
+#line 12 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv6;
+  }
+	goto st299;
+st299:
+	if ( ++p == pe )
+		goto _test_eof299;
+case 299:
+#line 2400 "ip_parser.c"
+	switch( (*p) ) {
+		case 46: goto st46;
+		case 58: goto st74;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto tr302;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto tr302;
+	} else
+		goto tr302;
+	goto st0;
+tr109:
+#line 12 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv6;
+  }
+	goto st300;
+st300:
+	if ( ++p == pe )
+		goto _test_eof300;
+case 300:
+#line 2424 "ip_parser.c"
+	switch( (*p) ) {
+		case 46: goto st46;
+		case 58: goto st74;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto tr307;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto tr300;
+	} else
+		goto tr300;
+	goto st0;
+tr110:
+#line 12 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv6;
+  }
+	goto st301;
+st301:
+	if ( ++p == pe )
+		goto _test_eof301;
+case 301:
+#line 2448 "ip_parser.c"
+	if ( (*p) == 58 )
+		goto st74;
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto tr300;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto tr300;
+	} else
+		goto tr300;
+	goto st0;
+tr30:
+#line 12 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv6;
+  }
+	goto st302;
+st302:
+	if ( ++p == pe )
+		goto _test_eof302;
+case 302:
+#line 2470 "ip_parser.c"
+	switch( (*p) ) {
+		case 48: goto tr116;
+		case 49: goto tr117;
+		case 50: goto tr118;
+	}
+	if ( (*p) < 65 ) {
+		if ( 51 <= (*p) && (*p) <= 57 )
+			goto tr119;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto tr120;
+	} else
+		goto tr120;
+	goto st0;
+tr116:
+#line 12 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv6;
+  }
+	goto st303;
+st303:
+	if ( ++p == pe )
+		goto _test_eof303;
+case 303:
+#line 2495 "ip_parser.c"
+	switch( (*p) ) {
+		case 46: goto st46;
+		case 58: goto st75;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto tr308;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto tr308;
+	} else
+		goto tr308;
+	goto st0;
+tr308:
+#line 12 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv6;
+  }
+	goto st304;
+st304:
+	if ( ++p == pe )
+		goto _test_eof304;
+case 304:
+#line 2519 "ip_parser.c"
+	if ( (*p) == 58 )
+		goto st75;
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto tr310;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto tr310;
+	} else
+		goto tr310;
+	goto st0;
+tr310:
+#line 12 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv6;
+  }
+	goto st305;
+st305:
+	if ( ++p == pe )
+		goto _test_eof305;
+case 305:
+#line 2541 "ip_parser.c"
+	if ( (*p) == 58 )
+		goto st75;
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto tr311;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto tr311;
+	} else
+		goto tr311;
+	goto st0;
+tr311:
+#line 12 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv6;
+  }
+	goto st306;
+st306:
+	if ( ++p == pe )
+		goto _test_eof306;
+case 306:
+#line 2563 "ip_parser.c"
+	if ( (*p) == 58 )
+		goto st75;
+	goto st0;
+st75:
+	if ( ++p == pe )
+		goto _test_eof75;
+case 75:
+	switch( (*p) ) {
+		case 48: goto tr106;
+		case 49: goto tr107;
+		case 50: goto tr108;
+	}
+	if ( (*p) < 65 ) {
+		if ( 51 <= (*p) && (*p) <= 57 )
+			goto tr109;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto tr110;
+	} else
+		goto tr110;
+	goto st0;
+tr117:
+#line 12 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv6;
+  }
+	goto st307;
+st307:
+	if ( ++p == pe )
+		goto _test_eof307;
+case 307:
+#line 2595 "ip_parser.c"
+	switch( (*p) ) {
+		case 46: goto st46;
+		case 58: goto st75;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto tr312;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto tr308;
+	} else
+		goto tr308;
+	goto st0;
+tr312:
+#line 12 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv6;
+  }
+	goto st308;
+st308:
+	if ( ++p == pe )
+		goto _test_eof308;
+case 308:
+#line 2619 "ip_parser.c"
+	switch( (*p) ) {
+		case 46: goto st46;
+		case 58: goto st75;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto tr313;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto tr310;
+	} else
+		goto tr310;
+	goto st0;
+tr313:
+#line 12 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv6;
+  }
+	goto st309;
+st309:
+	if ( ++p == pe )
+		goto _test_eof309;
+case 309:
+#line 2643 "ip_parser.c"
+	switch( (*p) ) {
+		case 46: goto st46;
+		case 58: goto st75;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto tr311;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto tr311;
+	} else
+		goto tr311;
+	goto st0;
+tr118:
+#line 12 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv6;
+  }
+	goto st310;
+st310:
+	if ( ++p == pe )
+		goto _test_eof310;
+case 310:
+#line 2667 "ip_parser.c"
+	switch( (*p) ) {
+		case 46: goto st46;
+		case 53: goto tr314;
+		case 58: goto st75;
+	}
+	if ( (*p) < 54 ) {
+		if ( 48 <= (*p) && (*p) <= 52 )
+			goto tr312;
+	} else if ( (*p) > 57 ) {
+		if ( (*p) > 70 ) {
+			if ( 97 <= (*p) && (*p) <= 102 )
+				goto tr308;
+		} else if ( (*p) >= 65 )
+			goto tr308;
+	} else
+		goto tr315;
+	goto st0;
+tr314:
+#line 12 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv6;
+  }
+	goto st311;
+st311:
+	if ( ++p == pe )
+		goto _test_eof311;
+case 311:
+#line 2695 "ip_parser.c"
+	switch( (*p) ) {
+		case 46: goto st46;
+		case 58: goto st75;
+	}
+	if ( (*p) < 54 ) {
+		if ( 48 <= (*p) && (*p) <= 53 )
+			goto tr313;
+	} else if ( (*p) > 57 ) {
+		if ( (*p) > 70 ) {
+			if ( 97 <= (*p) && (*p) <= 102 )
+				goto tr310;
+		} else if ( (*p) >= 65 )
+			goto tr310;
+	} else
+		goto tr310;
+	goto st0;
+tr315:
+#line 12 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv6;
+  }
+	goto st312;
+st312:
+	if ( ++p == pe )
+		goto _test_eof312;
+case 312:
+#line 2722 "ip_parser.c"
+	switch( (*p) ) {
+		case 46: goto st46;
+		case 58: goto st75;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto tr310;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto tr310;
+	} else
+		goto tr310;
+	goto st0;
+tr119:
+#line 12 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv6;
+  }
+	goto st313;
+st313:
+	if ( ++p == pe )
+		goto _test_eof313;
+case 313:
+#line 2746 "ip_parser.c"
+	switch( (*p) ) {
+		case 46: goto st46;
+		case 58: goto st75;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto tr315;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto tr308;
+	} else
+		goto tr308;
+	goto st0;
+tr120:
+#line 12 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv6;
+  }
+	goto st314;
+st314:
+	if ( ++p == pe )
+		goto _test_eof314;
+case 314:
+#line 2770 "ip_parser.c"
+	if ( (*p) == 58 )
+		goto st75;
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto tr308;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto tr308;
+	} else
+		goto tr308;
+	goto st0;
+st76:
+	if ( ++p == pe )
+		goto _test_eof76;
+case 76:
+	switch( (*p) ) {
+		case 46: goto st3;
+		case 58: goto st19;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st77;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st16;
+	} else
+		goto st16;
+	goto st0;
+st77:
+	if ( ++p == pe )
+		goto _test_eof77;
+case 77:
+	switch( (*p) ) {
+		case 46: goto st3;
+		case 58: goto st19;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st78;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st17;
+	} else
+		goto st17;
+	goto st0;
+st78:
+	if ( ++p == pe )
+		goto _test_eof78;
+case 78:
+	switch( (*p) ) {
+		case 46: goto st3;
+		case 58: goto st19;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st18;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st18;
+	} else
+		goto st18;
+	goto st0;
+st79:
+	if ( ++p == pe )
+		goto _test_eof79;
+case 79:
+	switch( (*p) ) {
+		case 46: goto st3;
+		case 53: goto st80;
+		case 58: goto st19;
+	}
+	if ( (*p) < 54 ) {
+		if ( 48 <= (*p) && (*p) <= 52 )
+			goto st77;
+	} else if ( (*p) > 57 ) {
+		if ( (*p) > 70 ) {
+			if ( 97 <= (*p) && (*p) <= 102 )
+				goto st16;
+		} else if ( (*p) >= 65 )
+			goto st16;
+	} else
+		goto st81;
+	goto st0;
+st80:
+	if ( ++p == pe )
+		goto _test_eof80;
+case 80:
+	switch( (*p) ) {
+		case 46: goto st3;
+		case 58: goto st19;
+	}
+	if ( (*p) < 54 ) {
+		if ( 48 <= (*p) && (*p) <= 53 )
+			goto st78;
+	} else if ( (*p) > 57 ) {
+		if ( (*p) > 70 ) {
+			if ( 97 <= (*p) && (*p) <= 102 )
+				goto st17;
+		} else if ( (*p) >= 65 )
+			goto st17;
+	} else
+		goto st17;
+	goto st0;
+st81:
+	if ( ++p == pe )
+		goto _test_eof81;
+case 81:
+	switch( (*p) ) {
+		case 46: goto st3;
+		case 58: goto st19;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st17;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st17;
+	} else
+		goto st17;
+	goto st0;
+st82:
+	if ( ++p == pe )
+		goto _test_eof82;
+case 82:
+	switch( (*p) ) {
+		case 46: goto st3;
+		case 58: goto st19;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st81;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st16;
+	} else
+		goto st16;
+	goto st0;
+st83:
+	if ( ++p == pe )
+		goto _test_eof83;
+case 83:
+	if ( (*p) == 58 )
+		goto tr115;
+	goto st0;
+tr115:
+#line 12 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv6;
+  }
+	goto st315;
+st315:
+	if ( ++p == pe )
+		goto _test_eof315;
+case 315:
+#line 2925 "ip_parser.c"
+	switch( (*p) ) {
+		case 48: goto tr316;
+		case 49: goto tr317;
+		case 50: goto tr318;
+	}
+	if ( (*p) < 65 ) {
+		if ( 51 <= (*p) && (*p) <= 57 )
+			goto tr319;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto tr320;
+	} else
+		goto tr320;
+	goto st0;
+tr316:
+#line 12 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv6;
+  }
+	goto st316;
+st316:
+	if ( ++p == pe )
+		goto _test_eof316;
+case 316:
+#line 2950 "ip_parser.c"
+	switch( (*p) ) {
+		case 46: goto st46;
+		case 58: goto st84;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto tr321;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto tr321;
+	} else
+		goto tr321;
+	goto st0;
+tr321:
+#line 12 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv6;
+  }
+	goto st317;
+st317:
+	if ( ++p == pe )
+		goto _test_eof317;
+case 317:
+#line 2974 "ip_parser.c"
+	if ( (*p) == 58 )
+		goto st84;
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto tr323;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto tr323;
+	} else
+		goto tr323;
+	goto st0;
+tr323:
+#line 12 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv6;
+  }
+	goto st318;
+st318:
+	if ( ++p == pe )
+		goto _test_eof318;
+case 318:
+#line 2996 "ip_parser.c"
+	if ( (*p) == 58 )
+		goto st84;
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto tr324;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto tr324;
+	} else
+		goto tr324;
+	goto st0;
+tr324:
+#line 12 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv6;
+  }
+	goto st319;
+st319:
+	if ( ++p == pe )
+		goto _test_eof319;
+case 319:
+#line 3018 "ip_parser.c"
+	if ( (*p) == 58 )
+		goto st84;
+	goto st0;
+st84:
+	if ( ++p == pe )
+		goto _test_eof84;
+case 84:
+	switch( (*p) ) {
+		case 48: goto tr116;
+		case 49: goto tr117;
+		case 50: goto tr118;
+	}
+	if ( (*p) < 65 ) {
+		if ( 51 <= (*p) && (*p) <= 57 )
+			goto tr119;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto tr120;
+	} else
+		goto tr120;
+	goto st0;
+tr317:
+#line 12 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv6;
+  }
+	goto st320;
+st320:
+	if ( ++p == pe )
+		goto _test_eof320;
+case 320:
+#line 3050 "ip_parser.c"
+	switch( (*p) ) {
+		case 46: goto st46;
+		case 58: goto st84;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto tr325;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto tr321;
+	} else
+		goto tr321;
+	goto st0;
+tr325:
+#line 12 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv6;
+  }
+	goto st321;
+st321:
+	if ( ++p == pe )
+		goto _test_eof321;
+case 321:
+#line 3074 "ip_parser.c"
+	switch( (*p) ) {
+		case 46: goto st46;
+		case 58: goto st84;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto tr326;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto tr323;
+	} else
+		goto tr323;
+	goto st0;
+tr326:
+#line 12 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv6;
+  }
+	goto st322;
+st322:
+	if ( ++p == pe )
+		goto _test_eof322;
+case 322:
+#line 3098 "ip_parser.c"
+	switch( (*p) ) {
+		case 46: goto st46;
+		case 58: goto st84;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto tr324;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto tr324;
+	} else
+		goto tr324;
+	goto st0;
+tr318:
+#line 12 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv6;
+  }
+	goto st323;
+st323:
+	if ( ++p == pe )
+		goto _test_eof323;
+case 323:
+#line 3122 "ip_parser.c"
+	switch( (*p) ) {
+		case 46: goto st46;
+		case 53: goto tr327;
+		case 58: goto st84;
+	}
+	if ( (*p) < 54 ) {
+		if ( 48 <= (*p) && (*p) <= 52 )
+			goto tr325;
+	} else if ( (*p) > 57 ) {
+		if ( (*p) > 70 ) {
+			if ( 97 <= (*p) && (*p) <= 102 )
+				goto tr321;
+		} else if ( (*p) >= 65 )
+			goto tr321;
+	} else
+		goto tr328;
+	goto st0;
+tr327:
+#line 12 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv6;
+  }
+	goto st324;
+st324:
+	if ( ++p == pe )
+		goto _test_eof324;
+case 324:
+#line 3150 "ip_parser.c"
+	switch( (*p) ) {
+		case 46: goto st46;
+		case 58: goto st84;
+	}
+	if ( (*p) < 54 ) {
+		if ( 48 <= (*p) && (*p) <= 53 )
+			goto tr326;
+	} else if ( (*p) > 57 ) {
+		if ( (*p) > 70 ) {
+			if ( 97 <= (*p) && (*p) <= 102 )
+				goto tr323;
+		} else if ( (*p) >= 65 )
+			goto tr323;
+	} else
+		goto tr323;
+	goto st0;
+tr328:
+#line 12 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv6;
+  }
+	goto st325;
+st325:
+	if ( ++p == pe )
+		goto _test_eof325;
+case 325:
+#line 3177 "ip_parser.c"
+	switch( (*p) ) {
+		case 46: goto st46;
+		case 58: goto st84;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto tr323;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto tr323;
+	} else
+		goto tr323;
+	goto st0;
+tr319:
+#line 12 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv6;
+  }
+	goto st326;
+st326:
+	if ( ++p == pe )
+		goto _test_eof326;
+case 326:
+#line 3201 "ip_parser.c"
+	switch( (*p) ) {
+		case 46: goto st46;
+		case 58: goto st84;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto tr328;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto tr321;
+	} else
+		goto tr321;
+	goto st0;
+tr320:
+#line 12 "ip_parser.rl"
+	{
+    ip_type = ip_type_ipv6;
+  }
+	goto st327;
+st327:
+	if ( ++p == pe )
+		goto _test_eof327;
+case 327:
+#line 3225 "ip_parser.c"
+	if ( (*p) == 58 )
+		goto st84;
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto tr321;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto tr321;
+	} else
+		goto tr321;
+	goto st0;
+st85:
+	if ( ++p == pe )
+		goto _test_eof85;
+case 85:
+	if ( (*p) == 58 )
+		goto st19;
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st16;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st16;
+	} else
+		goto st16;
+	goto st0;
+st86:
+	if ( ++p == pe )
+		goto _test_eof86;
+case 86:
+	if ( (*p) == 58 )
+		goto st222;
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st87;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st87;
+	} else
+		goto st87;
+	goto st0;
+st87:
+	if ( ++p == pe )
+		goto _test_eof87;
+case 87:
+	if ( (*p) == 58 )
+		goto st91;
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st88;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st88;
+	} else
+		goto st88;
+	goto st0;
+st88:
+	if ( ++p == pe )
+		goto _test_eof88;
+case 88:
+	if ( (*p) == 58 )
+		goto st91;
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st89;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st89;
+	} else
+		goto st89;
+	goto st0;
+st89:
+	if ( ++p == pe )
+		goto _test_eof89;
+case 89:
+	if ( (*p) == 58 )
+		goto st91;
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st90;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st90;
+	} else
+		goto st90;
+	goto st0;
+st90:
+	if ( ++p == pe )
+		goto _test_eof90;
+case 90:
+	if ( (*p) == 58 )
+		goto st91;
+	goto st0;
+st91:
+	if ( ++p == pe )
+		goto _test_eof91;
+case 91:
+	if ( (*p) == 58 )
+		goto st208;
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st92;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st92;
+	} else
+		goto st92;
+	goto st0;
+st92:
+	if ( ++p == pe )
+		goto _test_eof92;
+case 92:
+	if ( (*p) == 58 )
+		goto st96;
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st93;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st93;
+	} else
+		goto st93;
+	goto st0;
+st93:
+	if ( ++p == pe )
+		goto _test_eof93;
+case 93:
+	if ( (*p) == 58 )
+		goto st96;
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st94;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st94;
+	} else
+		goto st94;
+	goto st0;
+st94:
+	if ( ++p == pe )
+		goto _test_eof94;
+case 94:
+	if ( (*p) == 58 )
+		goto st96;
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st95;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st95;
+	} else
+		goto st95;
+	goto st0;
+st95:
+	if ( ++p == pe )
+		goto _test_eof95;
+case 95:
+	if ( (*p) == 58 )
+		goto st96;
+	goto st0;
+st96:
+	if ( ++p == pe )
+		goto _test_eof96;
+case 96:
+	if ( (*p) == 58 )
+		goto st194;
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st97;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st97;
+	} else
+		goto st97;
+	goto st0;
+st97:
+	if ( ++p == pe )
+		goto _test_eof97;
+case 97:
+	if ( (*p) == 58 )
+		goto st101;
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st98;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st98;
+	} else
+		goto st98;
+	goto st0;
+st98:
+	if ( ++p == pe )
+		goto _test_eof98;
+case 98:
+	if ( (*p) == 58 )
+		goto st101;
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st99;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st99;
+	} else
+		goto st99;
+	goto st0;
+st99:
+	if ( ++p == pe )
+		goto _test_eof99;
+case 99:
+	if ( (*p) == 58 )
+		goto st101;
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st100;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st100;
+	} else
+		goto st100;
+	goto st0;
+st100:
+	if ( ++p == pe )
+		goto _test_eof100;
+case 100:
+	if ( (*p) == 58 )
+		goto st101;
+	goto st0;
+st101:
+	if ( ++p == pe )
+		goto _test_eof101;
+case 101:
+	if ( (*p) == 58 )
+		goto st180;
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st102;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st102;
+	} else
+		goto st102;
+	goto st0;
+st102:
+	if ( ++p == pe )
+		goto _test_eof102;
+case 102:
+	if ( (*p) == 58 )
+		goto st106;
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st103;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st103;
+	} else
+		goto st103;
+	goto st0;
+st103:
+	if ( ++p == pe )
+		goto _test_eof103;
+case 103:
+	if ( (*p) == 58 )
+		goto st106;
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st104;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st104;
+	} else
+		goto st104;
+	goto st0;
+st104:
+	if ( ++p == pe )
+		goto _test_eof104;
+case 104:
+	if ( (*p) == 58 )
+		goto st106;
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st105;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st105;
+	} else
+		goto st105;
+	goto st0;
+st105:
+	if ( ++p == pe )
+		goto _test_eof105;
+case 105:
+	if ( (*p) == 58 )
+		goto st106;
+	goto st0;
+st106:
+	if ( ++p == pe )
+		goto _test_eof106;
+case 106:
+	if ( (*p) == 58 )
+		goto st166;
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st107;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st107;
+	} else
+		goto st107;
+	goto st0;
+st107:
+	if ( ++p == pe )
+		goto _test_eof107;
+case 107:
+	if ( (*p) == 58 )
+		goto st111;
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st108;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st108;
+	} else
+		goto st108;
+	goto st0;
+st108:
+	if ( ++p == pe )
+		goto _test_eof108;
+case 108:
+	if ( (*p) == 58 )
+		goto st111;
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st109;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st109;
+	} else
+		goto st109;
+	goto st0;
+st109:
+	if ( ++p == pe )
+		goto _test_eof109;
+case 109:
+	if ( (*p) == 58 )
+		goto st111;
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st110;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st110;
+	} else
+		goto st110;
+	goto st0;
+st110:
+	if ( ++p == pe )
+		goto _test_eof110;
+case 110:
+	if ( (*p) == 58 )
+		goto st111;
+	goto st0;
+st111:
+	if ( ++p == pe )
+		goto _test_eof111;
+case 111:
+	if ( (*p) == 58 )
+		goto st152;
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st112;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st112;
+	} else
+		goto st112;
+	goto st0;
+st112:
+	if ( ++p == pe )
+		goto _test_eof112;
+case 112:
+	if ( (*p) == 58 )
+		goto st116;
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st113;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st113;
+	} else
+		goto st113;
+	goto st0;
+st113:
+	if ( ++p == pe )
+		goto _test_eof113;
+case 113:
+	if ( (*p) == 58 )
+		goto st116;
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st114;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st114;
+	} else
+		goto st114;
+	goto st0;
+st114:
+	if ( ++p == pe )
+		goto _test_eof114;
+case 114:
+	if ( (*p) == 58 )
+		goto st116;
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st115;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st115;
+	} else
+		goto st115;
+	goto st0;
+st115:
+	if ( ++p == pe )
+		goto _test_eof115;
+case 115:
+	if ( (*p) == 58 )
+		goto st116;
+	goto st0;
+st116:
+	if ( ++p == pe )
+		goto _test_eof116;
+case 116:
+	switch( (*p) ) {
+		case 48: goto st117;
+		case 49: goto st143;
+		case 50: goto st146;
+		case 58: goto st150;
+	}
+	if ( (*p) < 65 ) {
+		if ( 51 <= (*p) && (*p) <= 57 )
+			goto st149;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st151;
+	} else
+		goto st151;
+	goto st0;
+st117:
+	if ( ++p == pe )
+		goto _test_eof117;
+case 117:
+	switch( (*p) ) {
+		case 46: goto st118;
+		case 58: goto st139;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st136;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st136;
+	} else
+		goto st136;
+	goto st0;
+st118:
+	if ( ++p == pe )
+		goto _test_eof118;
+case 118:
+	switch( (*p) ) {
+		case 48: goto st119;
+		case 49: goto st132;
+		case 50: goto st134;
+	}
+	if ( 51 <= (*p) && (*p) <= 57 )
+		goto st133;
+	goto st0;
+st119:
+	if ( ++p == pe )
+		goto _test_eof119;
+case 119:
+	if ( (*p) == 46 )
+		goto st120;
+	goto st0;
+st120:
+	if ( ++p == pe )
+		goto _test_eof120;
+case 120:
+	switch( (*p) ) {
+		case 48: goto st121;
+		case 49: goto st128;
+		case 50: goto st130;
+	}
+	if ( 51 <= (*p) && (*p) <= 57 )
+		goto st129;
+	goto st0;
+st121:
+	if ( ++p == pe )
+		goto _test_eof121;
+case 121:
+	if ( (*p) == 46 )
+		goto st122;
+	goto st0;
+st122:
+	if ( ++p == pe )
+		goto _test_eof122;
+case 122:
+	switch( (*p) ) {
+		case 48: goto st123;
+		case 49: goto st124;
+		case 50: goto st126;
+	}
+	if ( 51 <= (*p) && (*p) <= 57 )
+		goto st125;
+	goto st0;
+st123:
+	if ( ++p == pe )
+		goto _test_eof123;
+case 123:
+	if ( (*p) == 93 )
+		goto tr180;
+	goto st0;
+st124:
+	if ( ++p == pe )
+		goto _test_eof124;
+case 124:
+	if ( (*p) == 93 )
+		goto tr180;
+	if ( 48 <= (*p) && (*p) <= 57 )
+		goto st125;
+	goto st0;
+st125:
+	if ( ++p == pe )
+		goto _test_eof125;
+case 125:
+	if ( (*p) == 93 )
+		goto tr180;
+	if ( 48 <= (*p) && (*p) <= 57 )
+		goto st123;
+	goto st0;
+st126:
+	if ( ++p == pe )
+		goto _test_eof126;
+case 126:
+	switch( (*p) ) {
+		case 53: goto st127;
+		case 93: goto tr180;
+	}
+	if ( (*p) > 52 ) {
+		if ( 54 <= (*p) && (*p) <= 57 )
+			goto st123;
+	} else if ( (*p) >= 48 )
+		goto st125;
+	goto st0;
+st127:
+	if ( ++p == pe )
+		goto _test_eof127;
+case 127:
+	if ( (*p) == 93 )
+		goto tr180;
+	if ( 48 <= (*p) && (*p) <= 53 )
+		goto st123;
+	goto st0;
+st128:
+	if ( ++p == pe )
+		goto _test_eof128;
+case 128:
+	if ( (*p) == 46 )
+		goto st122;
+	if ( 48 <= (*p) && (*p) <= 57 )
+		goto st129;
+	goto st0;
+st129:
+	if ( ++p == pe )
+		goto _test_eof129;
+case 129:
+	if ( (*p) == 46 )
+		goto st122;
+	if ( 48 <= (*p) && (*p) <= 57 )
+		goto st121;
+	goto st0;
+st130:
+	if ( ++p == pe )
+		goto _test_eof130;
+case 130:
+	switch( (*p) ) {
+		case 46: goto st122;
+		case 53: goto st131;
+	}
+	if ( (*p) > 52 ) {
+		if ( 54 <= (*p) && (*p) <= 57 )
+			goto st121;
+	} else if ( (*p) >= 48 )
+		goto st129;
+	goto st0;
+st131:
+	if ( ++p == pe )
+		goto _test_eof131;
+case 131:
+	if ( (*p) == 46 )
+		goto st122;
+	if ( 48 <= (*p) && (*p) <= 53 )
+		goto st121;
+	goto st0;
+st132:
+	if ( ++p == pe )
+		goto _test_eof132;
+case 132:
+	if ( (*p) == 46 )
+		goto st120;
+	if ( 48 <= (*p) && (*p) <= 57 )
+		goto st133;
+	goto st0;
+st133:
+	if ( ++p == pe )
+		goto _test_eof133;
+case 133:
+	if ( (*p) == 46 )
+		goto st120;
+	if ( 48 <= (*p) && (*p) <= 57 )
+		goto st119;
+	goto st0;
+st134:
+	if ( ++p == pe )
+		goto _test_eof134;
+case 134:
+	switch( (*p) ) {
+		case 46: goto st120;
+		case 53: goto st135;
+	}
+	if ( (*p) > 52 ) {
+		if ( 54 <= (*p) && (*p) <= 57 )
+			goto st119;
+	} else if ( (*p) >= 48 )
+		goto st133;
+	goto st0;
+st135:
+	if ( ++p == pe )
+		goto _test_eof135;
+case 135:
+	if ( (*p) == 46 )
+		goto st120;
+	if ( 48 <= (*p) && (*p) <= 53 )
+		goto st119;
+	goto st0;
+st136:
+	if ( ++p == pe )
+		goto _test_eof136;
+case 136:
+	if ( (*p) == 58 )
+		goto st139;
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st137;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st137;
+	} else
+		goto st137;
+	goto st0;
+st137:
+	if ( ++p == pe )
+		goto _test_eof137;
+case 137:
+	if ( (*p) == 58 )
+		goto st139;
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st138;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st138;
+	} else
+		goto st138;
+	goto st0;
+st138:
+	if ( ++p == pe )
+		goto _test_eof138;
+case 138:
+	if ( (*p) == 58 )
+		goto st139;
+	goto st0;
+st139:
+	if ( ++p == pe )
+		goto _test_eof139;
+case 139:
+	if ( (*p) == 58 )
+		goto st123;
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st140;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st140;
+	} else
+		goto st140;
+	goto st0;
+st140:
+	if ( ++p == pe )
+		goto _test_eof140;
+case 140:
+	if ( (*p) == 93 )
+		goto tr180;
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st141;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st141;
+	} else
+		goto st141;
+	goto st0;
+st141:
+	if ( ++p == pe )
+		goto _test_eof141;
+case 141:
+	if ( (*p) == 93 )
+		goto tr180;
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st142;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st142;
+	} else
+		goto st142;
+	goto st0;
+st142:
+	if ( ++p == pe )
+		goto _test_eof142;
+case 142:
+	if ( (*p) == 93 )
+		goto tr180;
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st123;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st123;
+	} else
+		goto st123;
+	goto st0;
+st143:
+	if ( ++p == pe )
+		goto _test_eof143;
+case 143:
+	switch( (*p) ) {
+		case 46: goto st118;
+		case 58: goto st139;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st144;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st136;
+	} else
+		goto st136;
+	goto st0;
+st144:
+	if ( ++p == pe )
+		goto _test_eof144;
+case 144:
+	switch( (*p) ) {
+		case 46: goto st118;
+		case 58: goto st139;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st145;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st137;
+	} else
+		goto st137;
+	goto st0;
+st145:
+	if ( ++p == pe )
+		goto _test_eof145;
+case 145:
+	switch( (*p) ) {
+		case 46: goto st118;
+		case 58: goto st139;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st138;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st138;
+	} else
+		goto st138;
+	goto st0;
+st146:
+	if ( ++p == pe )
+		goto _test_eof146;
+case 146:
+	switch( (*p) ) {
+		case 46: goto st118;
+		case 53: goto st147;
+		case 58: goto st139;
+	}
+	if ( (*p) < 54 ) {
+		if ( 48 <= (*p) && (*p) <= 52 )
+			goto st144;
+	} else if ( (*p) > 57 ) {
+		if ( (*p) > 70 ) {
+			if ( 97 <= (*p) && (*p) <= 102 )
+				goto st136;
+		} else if ( (*p) >= 65 )
+			goto st136;
+	} else
+		goto st148;
+	goto st0;
+st147:
+	if ( ++p == pe )
+		goto _test_eof147;
+case 147:
+	switch( (*p) ) {
+		case 46: goto st118;
+		case 58: goto st139;
+	}
+	if ( (*p) < 54 ) {
+		if ( 48 <= (*p) && (*p) <= 53 )
+			goto st145;
+	} else if ( (*p) > 57 ) {
+		if ( (*p) > 70 ) {
+			if ( 97 <= (*p) && (*p) <= 102 )
+				goto st137;
+		} else if ( (*p) >= 65 )
+			goto st137;
+	} else
+		goto st137;
+	goto st0;
+st148:
+	if ( ++p == pe )
+		goto _test_eof148;
+case 148:
+	switch( (*p) ) {
+		case 46: goto st118;
+		case 58: goto st139;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st137;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st137;
+	} else
+		goto st137;
+	goto st0;
+st149:
+	if ( ++p == pe )
+		goto _test_eof149;
+case 149:
+	switch( (*p) ) {
+		case 46: goto st118;
+		case 58: goto st139;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st148;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st136;
+	} else
+		goto st136;
+	goto st0;
+st150:
+	if ( ++p == pe )
+		goto _test_eof150;
+case 150:
+	if ( (*p) == 93 )
+		goto tr180;
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st140;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st140;
+	} else
+		goto st140;
+	goto st0;
+st151:
+	if ( ++p == pe )
+		goto _test_eof151;
+case 151:
+	if ( (*p) == 58 )
+		goto st139;
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st136;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st136;
+	} else
+		goto st136;
+	goto st0;
+st152:
+	if ( ++p == pe )
+		goto _test_eof152;
+case 152:
+	switch( (*p) ) {
+		case 48: goto st153;
+		case 49: goto st158;
+		case 50: goto st161;
+		case 93: goto tr180;
+	}
+	if ( (*p) < 65 ) {
+		if ( 51 <= (*p) && (*p) <= 57 )
+			goto st164;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st165;
+	} else
+		goto st165;
+	goto st0;
+st153:
+	if ( ++p == pe )
+		goto _test_eof153;
+case 153:
+	switch( (*p) ) {
+		case 46: goto st118;
+		case 58: goto st157;
+		case 93: goto tr180;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st154;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st154;
+	} else
+		goto st154;
+	goto st0;
+st154:
+	if ( ++p == pe )
+		goto _test_eof154;
+case 154:
+	switch( (*p) ) {
+		case 58: goto st157;
+		case 93: goto tr180;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st155;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st155;
+	} else
+		goto st155;
+	goto st0;
+st155:
+	if ( ++p == pe )
+		goto _test_eof155;
+case 155:
+	switch( (*p) ) {
+		case 58: goto st157;
+		case 93: goto tr180;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st156;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st156;
+	} else
+		goto st156;
+	goto st0;
+st156:
+	if ( ++p == pe )
+		goto _test_eof156;
+case 156:
+	switch( (*p) ) {
+		case 58: goto st157;
+		case 93: goto tr180;
+	}
+	goto st0;
+st157:
+	if ( ++p == pe )
+		goto _test_eof157;
+case 157:
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st140;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st140;
+	} else
+		goto st140;
+	goto st0;
+st158:
+	if ( ++p == pe )
+		goto _test_eof158;
+case 158:
+	switch( (*p) ) {
+		case 46: goto st118;
+		case 58: goto st157;
+		case 93: goto tr180;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st159;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st154;
+	} else
+		goto st154;
+	goto st0;
+st159:
+	if ( ++p == pe )
+		goto _test_eof159;
+case 159:
+	switch( (*p) ) {
+		case 46: goto st118;
+		case 58: goto st157;
+		case 93: goto tr180;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st160;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st155;
+	} else
+		goto st155;
+	goto st0;
+st160:
+	if ( ++p == pe )
+		goto _test_eof160;
+case 160:
+	switch( (*p) ) {
+		case 46: goto st118;
+		case 58: goto st157;
+		case 93: goto tr180;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st156;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st156;
+	} else
+		goto st156;
+	goto st0;
+st161:
+	if ( ++p == pe )
+		goto _test_eof161;
+case 161:
+	switch( (*p) ) {
+		case 46: goto st118;
+		case 53: goto st162;
+		case 58: goto st157;
+		case 93: goto tr180;
+	}
+	if ( (*p) < 54 ) {
+		if ( 48 <= (*p) && (*p) <= 52 )
+			goto st159;
+	} else if ( (*p) > 57 ) {
+		if ( (*p) > 70 ) {
+			if ( 97 <= (*p) && (*p) <= 102 )
+				goto st154;
+		} else if ( (*p) >= 65 )
+			goto st154;
+	} else
+		goto st163;
+	goto st0;
+st162:
+	if ( ++p == pe )
+		goto _test_eof162;
+case 162:
+	switch( (*p) ) {
+		case 46: goto st118;
+		case 58: goto st157;
+		case 93: goto tr180;
+	}
+	if ( (*p) < 54 ) {
+		if ( 48 <= (*p) && (*p) <= 53 )
+			goto st160;
+	} else if ( (*p) > 57 ) {
+		if ( (*p) > 70 ) {
+			if ( 97 <= (*p) && (*p) <= 102 )
+				goto st155;
+		} else if ( (*p) >= 65 )
+			goto st155;
+	} else
+		goto st155;
+	goto st0;
+st163:
+	if ( ++p == pe )
+		goto _test_eof163;
+case 163:
+	switch( (*p) ) {
+		case 46: goto st118;
+		case 58: goto st157;
+		case 93: goto tr180;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st155;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st155;
+	} else
+		goto st155;
+	goto st0;
+st164:
+	if ( ++p == pe )
+		goto _test_eof164;
+case 164:
+	switch( (*p) ) {
+		case 46: goto st118;
+		case 58: goto st157;
+		case 93: goto tr180;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st163;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st154;
+	} else
+		goto st154;
+	goto st0;
+st165:
+	if ( ++p == pe )
+		goto _test_eof165;
+case 165:
+	switch( (*p) ) {
+		case 58: goto st157;
+		case 93: goto tr180;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st154;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st154;
+	} else
+		goto st154;
+	goto st0;
+st166:
+	if ( ++p == pe )
+		goto _test_eof166;
+case 166:
+	switch( (*p) ) {
+		case 48: goto st167;
+		case 49: goto st172;
+		case 50: goto st175;
+		case 93: goto tr180;
+	}
+	if ( (*p) < 65 ) {
+		if ( 51 <= (*p) && (*p) <= 57 )
+			goto st178;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st179;
+	} else
+		goto st179;
+	goto st0;
+st167:
+	if ( ++p == pe )
+		goto _test_eof167;
+case 167:
+	switch( (*p) ) {
+		case 46: goto st118;
+		case 58: goto st171;
+		case 93: goto tr180;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st168;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st168;
+	} else
+		goto st168;
+	goto st0;
+st168:
+	if ( ++p == pe )
+		goto _test_eof168;
+case 168:
+	switch( (*p) ) {
+		case 58: goto st171;
+		case 93: goto tr180;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st169;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st169;
+	} else
+		goto st169;
+	goto st0;
+st169:
+	if ( ++p == pe )
+		goto _test_eof169;
+case 169:
+	switch( (*p) ) {
+		case 58: goto st171;
+		case 93: goto tr180;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st170;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st170;
+	} else
+		goto st170;
+	goto st0;
+st170:
+	if ( ++p == pe )
+		goto _test_eof170;
+case 170:
+	switch( (*p) ) {
+		case 58: goto st171;
+		case 93: goto tr180;
+	}
+	goto st0;
+st171:
+	if ( ++p == pe )
+		goto _test_eof171;
+case 171:
+	switch( (*p) ) {
+		case 48: goto st153;
+		case 49: goto st158;
+		case 50: goto st161;
+	}
+	if ( (*p) < 65 ) {
+		if ( 51 <= (*p) && (*p) <= 57 )
+			goto st164;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st165;
+	} else
+		goto st165;
+	goto st0;
+st172:
+	if ( ++p == pe )
+		goto _test_eof172;
+case 172:
+	switch( (*p) ) {
+		case 46: goto st118;
+		case 58: goto st171;
+		case 93: goto tr180;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st173;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st168;
+	} else
+		goto st168;
+	goto st0;
+st173:
+	if ( ++p == pe )
+		goto _test_eof173;
+case 173:
+	switch( (*p) ) {
+		case 46: goto st118;
+		case 58: goto st171;
+		case 93: goto tr180;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st174;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st169;
+	} else
+		goto st169;
+	goto st0;
+st174:
+	if ( ++p == pe )
+		goto _test_eof174;
+case 174:
+	switch( (*p) ) {
+		case 46: goto st118;
+		case 58: goto st171;
+		case 93: goto tr180;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st170;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st170;
+	} else
+		goto st170;
+	goto st0;
+st175:
+	if ( ++p == pe )
+		goto _test_eof175;
+case 175:
+	switch( (*p) ) {
+		case 46: goto st118;
+		case 53: goto st176;
+		case 58: goto st171;
+		case 93: goto tr180;
+	}
+	if ( (*p) < 54 ) {
+		if ( 48 <= (*p) && (*p) <= 52 )
+			goto st173;
+	} else if ( (*p) > 57 ) {
+		if ( (*p) > 70 ) {
+			if ( 97 <= (*p) && (*p) <= 102 )
+				goto st168;
+		} else if ( (*p) >= 65 )
+			goto st168;
+	} else
+		goto st177;
+	goto st0;
+st176:
+	if ( ++p == pe )
+		goto _test_eof176;
+case 176:
+	switch( (*p) ) {
+		case 46: goto st118;
+		case 58: goto st171;
+		case 93: goto tr180;
+	}
+	if ( (*p) < 54 ) {
+		if ( 48 <= (*p) && (*p) <= 53 )
+			goto st174;
+	} else if ( (*p) > 57 ) {
+		if ( (*p) > 70 ) {
+			if ( 97 <= (*p) && (*p) <= 102 )
+				goto st169;
+		} else if ( (*p) >= 65 )
+			goto st169;
+	} else
+		goto st169;
+	goto st0;
+st177:
+	if ( ++p == pe )
+		goto _test_eof177;
+case 177:
+	switch( (*p) ) {
+		case 46: goto st118;
+		case 58: goto st171;
+		case 93: goto tr180;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st169;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st169;
+	} else
+		goto st169;
+	goto st0;
+st178:
+	if ( ++p == pe )
+		goto _test_eof178;
+case 178:
+	switch( (*p) ) {
+		case 46: goto st118;
+		case 58: goto st171;
+		case 93: goto tr180;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st177;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st168;
+	} else
+		goto st168;
+	goto st0;
+st179:
+	if ( ++p == pe )
+		goto _test_eof179;
+case 179:
+	switch( (*p) ) {
+		case 58: goto st171;
+		case 93: goto tr180;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st168;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st168;
+	} else
+		goto st168;
+	goto st0;
+st180:
+	if ( ++p == pe )
+		goto _test_eof180;
+case 180:
+	switch( (*p) ) {
+		case 48: goto st181;
+		case 49: goto st186;
+		case 50: goto st189;
+		case 93: goto tr180;
+	}
+	if ( (*p) < 65 ) {
+		if ( 51 <= (*p) && (*p) <= 57 )
+			goto st192;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st193;
+	} else
+		goto st193;
+	goto st0;
+st181:
+	if ( ++p == pe )
+		goto _test_eof181;
+case 181:
+	switch( (*p) ) {
+		case 46: goto st118;
+		case 58: goto st185;
+		case 93: goto tr180;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st182;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st182;
+	} else
+		goto st182;
+	goto st0;
+st182:
+	if ( ++p == pe )
+		goto _test_eof182;
+case 182:
+	switch( (*p) ) {
+		case 58: goto st185;
+		case 93: goto tr180;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st183;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st183;
+	} else
+		goto st183;
+	goto st0;
+st183:
+	if ( ++p == pe )
+		goto _test_eof183;
+case 183:
+	switch( (*p) ) {
+		case 58: goto st185;
+		case 93: goto tr180;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st184;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st184;
+	} else
+		goto st184;
+	goto st0;
+st184:
+	if ( ++p == pe )
+		goto _test_eof184;
+case 184:
+	switch( (*p) ) {
+		case 58: goto st185;
+		case 93: goto tr180;
+	}
+	goto st0;
+st185:
+	if ( ++p == pe )
+		goto _test_eof185;
+case 185:
+	switch( (*p) ) {
+		case 48: goto st167;
+		case 49: goto st172;
+		case 50: goto st175;
+	}
+	if ( (*p) < 65 ) {
+		if ( 51 <= (*p) && (*p) <= 57 )
+			goto st178;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st179;
+	} else
+		goto st179;
+	goto st0;
+st186:
+	if ( ++p == pe )
+		goto _test_eof186;
+case 186:
+	switch( (*p) ) {
+		case 46: goto st118;
+		case 58: goto st185;
+		case 93: goto tr180;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st187;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st182;
+	} else
+		goto st182;
+	goto st0;
+st187:
+	if ( ++p == pe )
+		goto _test_eof187;
+case 187:
+	switch( (*p) ) {
+		case 46: goto st118;
+		case 58: goto st185;
+		case 93: goto tr180;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st188;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st183;
+	} else
+		goto st183;
+	goto st0;
+st188:
+	if ( ++p == pe )
+		goto _test_eof188;
+case 188:
+	switch( (*p) ) {
+		case 46: goto st118;
+		case 58: goto st185;
+		case 93: goto tr180;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st184;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st184;
+	} else
+		goto st184;
+	goto st0;
+st189:
+	if ( ++p == pe )
+		goto _test_eof189;
+case 189:
+	switch( (*p) ) {
+		case 46: goto st118;
+		case 53: goto st190;
+		case 58: goto st185;
+		case 93: goto tr180;
+	}
+	if ( (*p) < 54 ) {
+		if ( 48 <= (*p) && (*p) <= 52 )
+			goto st187;
+	} else if ( (*p) > 57 ) {
+		if ( (*p) > 70 ) {
+			if ( 97 <= (*p) && (*p) <= 102 )
+				goto st182;
+		} else if ( (*p) >= 65 )
+			goto st182;
+	} else
+		goto st191;
+	goto st0;
+st190:
+	if ( ++p == pe )
+		goto _test_eof190;
+case 190:
+	switch( (*p) ) {
+		case 46: goto st118;
+		case 58: goto st185;
+		case 93: goto tr180;
+	}
+	if ( (*p) < 54 ) {
+		if ( 48 <= (*p) && (*p) <= 53 )
+			goto st188;
+	} else if ( (*p) > 57 ) {
+		if ( (*p) > 70 ) {
+			if ( 97 <= (*p) && (*p) <= 102 )
+				goto st183;
+		} else if ( (*p) >= 65 )
+			goto st183;
+	} else
+		goto st183;
+	goto st0;
+st191:
+	if ( ++p == pe )
+		goto _test_eof191;
+case 191:
+	switch( (*p) ) {
+		case 46: goto st118;
+		case 58: goto st185;
+		case 93: goto tr180;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st183;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st183;
+	} else
+		goto st183;
+	goto st0;
+st192:
+	if ( ++p == pe )
+		goto _test_eof192;
+case 192:
+	switch( (*p) ) {
+		case 46: goto st118;
+		case 58: goto st185;
+		case 93: goto tr180;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st191;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st182;
+	} else
+		goto st182;
+	goto st0;
+st193:
+	if ( ++p == pe )
+		goto _test_eof193;
+case 193:
+	switch( (*p) ) {
+		case 58: goto st185;
+		case 93: goto tr180;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st182;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st182;
+	} else
+		goto st182;
+	goto st0;
+st194:
+	if ( ++p == pe )
+		goto _test_eof194;
+case 194:
+	switch( (*p) ) {
+		case 48: goto st195;
+		case 49: goto st200;
+		case 50: goto st203;
+		case 93: goto tr180;
+	}
+	if ( (*p) < 65 ) {
+		if ( 51 <= (*p) && (*p) <= 57 )
+			goto st206;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st207;
+	} else
+		goto st207;
+	goto st0;
+st195:
+	if ( ++p == pe )
+		goto _test_eof195;
+case 195:
+	switch( (*p) ) {
+		case 46: goto st118;
+		case 58: goto st199;
+		case 93: goto tr180;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st196;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st196;
+	} else
+		goto st196;
+	goto st0;
+st196:
+	if ( ++p == pe )
+		goto _test_eof196;
+case 196:
+	switch( (*p) ) {
+		case 58: goto st199;
+		case 93: goto tr180;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st197;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st197;
+	} else
+		goto st197;
+	goto st0;
+st197:
+	if ( ++p == pe )
+		goto _test_eof197;
+case 197:
+	switch( (*p) ) {
+		case 58: goto st199;
+		case 93: goto tr180;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st198;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st198;
+	} else
+		goto st198;
+	goto st0;
+st198:
+	if ( ++p == pe )
+		goto _test_eof198;
+case 198:
+	switch( (*p) ) {
+		case 58: goto st199;
+		case 93: goto tr180;
+	}
+	goto st0;
+st199:
+	if ( ++p == pe )
+		goto _test_eof199;
+case 199:
+	switch( (*p) ) {
+		case 48: goto st181;
+		case 49: goto st186;
+		case 50: goto st189;
+	}
+	if ( (*p) < 65 ) {
+		if ( 51 <= (*p) && (*p) <= 57 )
+			goto st192;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st193;
+	} else
+		goto st193;
+	goto st0;
+st200:
+	if ( ++p == pe )
+		goto _test_eof200;
+case 200:
+	switch( (*p) ) {
+		case 46: goto st118;
+		case 58: goto st199;
+		case 93: goto tr180;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st201;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st196;
+	} else
+		goto st196;
+	goto st0;
+st201:
+	if ( ++p == pe )
+		goto _test_eof201;
+case 201:
+	switch( (*p) ) {
+		case 46: goto st118;
+		case 58: goto st199;
+		case 93: goto tr180;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st202;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st197;
+	} else
+		goto st197;
+	goto st0;
+st202:
+	if ( ++p == pe )
+		goto _test_eof202;
+case 202:
+	switch( (*p) ) {
+		case 46: goto st118;
+		case 58: goto st199;
+		case 93: goto tr180;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st198;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st198;
+	} else
+		goto st198;
+	goto st0;
+st203:
+	if ( ++p == pe )
+		goto _test_eof203;
+case 203:
+	switch( (*p) ) {
+		case 46: goto st118;
+		case 53: goto st204;
+		case 58: goto st199;
+		case 93: goto tr180;
+	}
+	if ( (*p) < 54 ) {
+		if ( 48 <= (*p) && (*p) <= 52 )
+			goto st201;
+	} else if ( (*p) > 57 ) {
+		if ( (*p) > 70 ) {
+			if ( 97 <= (*p) && (*p) <= 102 )
+				goto st196;
+		} else if ( (*p) >= 65 )
+			goto st196;
+	} else
+		goto st205;
+	goto st0;
+st204:
+	if ( ++p == pe )
+		goto _test_eof204;
+case 204:
+	switch( (*p) ) {
+		case 46: goto st118;
+		case 58: goto st199;
+		case 93: goto tr180;
+	}
+	if ( (*p) < 54 ) {
+		if ( 48 <= (*p) && (*p) <= 53 )
+			goto st202;
+	} else if ( (*p) > 57 ) {
+		if ( (*p) > 70 ) {
+			if ( 97 <= (*p) && (*p) <= 102 )
+				goto st197;
+		} else if ( (*p) >= 65 )
+			goto st197;
+	} else
+		goto st197;
+	goto st0;
+st205:
+	if ( ++p == pe )
+		goto _test_eof205;
+case 205:
+	switch( (*p) ) {
+		case 46: goto st118;
+		case 58: goto st199;
+		case 93: goto tr180;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st197;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st197;
+	} else
+		goto st197;
+	goto st0;
+st206:
+	if ( ++p == pe )
+		goto _test_eof206;
+case 206:
+	switch( (*p) ) {
+		case 46: goto st118;
+		case 58: goto st199;
+		case 93: goto tr180;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st205;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st196;
+	} else
+		goto st196;
+	goto st0;
+st207:
+	if ( ++p == pe )
+		goto _test_eof207;
+case 207:
+	switch( (*p) ) {
+		case 58: goto st199;
+		case 93: goto tr180;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st196;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st196;
+	} else
+		goto st196;
+	goto st0;
+st208:
+	if ( ++p == pe )
+		goto _test_eof208;
+case 208:
+	switch( (*p) ) {
+		case 48: goto st209;
+		case 49: goto st214;
+		case 50: goto st217;
+		case 93: goto tr180;
+	}
+	if ( (*p) < 65 ) {
+		if ( 51 <= (*p) && (*p) <= 57 )
+			goto st220;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st221;
+	} else
+		goto st221;
+	goto st0;
+st209:
+	if ( ++p == pe )
+		goto _test_eof209;
+case 209:
+	switch( (*p) ) {
+		case 46: goto st118;
+		case 58: goto st213;
+		case 93: goto tr180;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st210;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st210;
+	} else
+		goto st210;
+	goto st0;
+st210:
+	if ( ++p == pe )
+		goto _test_eof210;
+case 210:
+	switch( (*p) ) {
+		case 58: goto st213;
+		case 93: goto tr180;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st211;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st211;
+	} else
+		goto st211;
+	goto st0;
+st211:
+	if ( ++p == pe )
+		goto _test_eof211;
+case 211:
+	switch( (*p) ) {
+		case 58: goto st213;
+		case 93: goto tr180;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st212;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st212;
+	} else
+		goto st212;
+	goto st0;
+st212:
+	if ( ++p == pe )
+		goto _test_eof212;
+case 212:
+	switch( (*p) ) {
+		case 58: goto st213;
+		case 93: goto tr180;
+	}
+	goto st0;
+st213:
+	if ( ++p == pe )
+		goto _test_eof213;
+case 213:
+	switch( (*p) ) {
+		case 48: goto st195;
+		case 49: goto st200;
+		case 50: goto st203;
+	}
+	if ( (*p) < 65 ) {
+		if ( 51 <= (*p) && (*p) <= 57 )
+			goto st206;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st207;
+	} else
+		goto st207;
+	goto st0;
+st214:
+	if ( ++p == pe )
+		goto _test_eof214;
+case 214:
+	switch( (*p) ) {
+		case 46: goto st118;
+		case 58: goto st213;
+		case 93: goto tr180;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st215;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st210;
+	} else
+		goto st210;
+	goto st0;
+st215:
+	if ( ++p == pe )
+		goto _test_eof215;
+case 215:
+	switch( (*p) ) {
+		case 46: goto st118;
+		case 58: goto st213;
+		case 93: goto tr180;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st216;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st211;
+	} else
+		goto st211;
+	goto st0;
+st216:
+	if ( ++p == pe )
+		goto _test_eof216;
+case 216:
+	switch( (*p) ) {
+		case 46: goto st118;
+		case 58: goto st213;
+		case 93: goto tr180;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st212;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st212;
+	} else
+		goto st212;
+	goto st0;
+st217:
+	if ( ++p == pe )
+		goto _test_eof217;
+case 217:
+	switch( (*p) ) {
+		case 46: goto st118;
+		case 53: goto st218;
+		case 58: goto st213;
+		case 93: goto tr180;
+	}
+	if ( (*p) < 54 ) {
+		if ( 48 <= (*p) && (*p) <= 52 )
+			goto st215;
+	} else if ( (*p) > 57 ) {
+		if ( (*p) > 70 ) {
+			if ( 97 <= (*p) && (*p) <= 102 )
+				goto st210;
+		} else if ( (*p) >= 65 )
+			goto st210;
+	} else
+		goto st219;
+	goto st0;
+st218:
+	if ( ++p == pe )
+		goto _test_eof218;
+case 218:
+	switch( (*p) ) {
+		case 46: goto st118;
+		case 58: goto st213;
+		case 93: goto tr180;
+	}
+	if ( (*p) < 54 ) {
+		if ( 48 <= (*p) && (*p) <= 53 )
+			goto st216;
+	} else if ( (*p) > 57 ) {
+		if ( (*p) > 70 ) {
+			if ( 97 <= (*p) && (*p) <= 102 )
+				goto st211;
+		} else if ( (*p) >= 65 )
+			goto st211;
+	} else
+		goto st211;
+	goto st0;
+st219:
+	if ( ++p == pe )
+		goto _test_eof219;
+case 219:
+	switch( (*p) ) {
+		case 46: goto st118;
+		case 58: goto st213;
+		case 93: goto tr180;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st211;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st211;
+	} else
+		goto st211;
+	goto st0;
+st220:
+	if ( ++p == pe )
+		goto _test_eof220;
+case 220:
+	switch( (*p) ) {
+		case 46: goto st118;
+		case 58: goto st213;
+		case 93: goto tr180;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st219;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st210;
+	} else
+		goto st210;
+	goto st0;
+st221:
+	if ( ++p == pe )
+		goto _test_eof221;
+case 221:
+	switch( (*p) ) {
+		case 58: goto st213;
+		case 93: goto tr180;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st210;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st210;
+	} else
+		goto st210;
+	goto st0;
+st222:
+	if ( ++p == pe )
+		goto _test_eof222;
+case 222:
+	if ( (*p) == 58 )
+		goto st223;
+	goto st0;
+st223:
+	if ( ++p == pe )
+		goto _test_eof223;
+case 223:
+	switch( (*p) ) {
+		case 48: goto st224;
+		case 49: goto st229;
+		case 50: goto st232;
+		case 93: goto tr180;
+	}
+	if ( (*p) < 65 ) {
+		if ( 51 <= (*p) && (*p) <= 57 )
+			goto st235;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st236;
+	} else
+		goto st236;
+	goto st0;
+st224:
+	if ( ++p == pe )
+		goto _test_eof224;
+case 224:
+	switch( (*p) ) {
+		case 46: goto st118;
+		case 58: goto st228;
+		case 93: goto tr180;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st225;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st225;
+	} else
+		goto st225;
+	goto st0;
+st225:
+	if ( ++p == pe )
+		goto _test_eof225;
+case 225:
+	switch( (*p) ) {
+		case 58: goto st228;
+		case 93: goto tr180;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st226;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st226;
+	} else
+		goto st226;
+	goto st0;
+st226:
+	if ( ++p == pe )
+		goto _test_eof226;
+case 226:
+	switch( (*p) ) {
+		case 58: goto st228;
+		case 93: goto tr180;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st227;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st227;
+	} else
+		goto st227;
+	goto st0;
+st227:
+	if ( ++p == pe )
+		goto _test_eof227;
+case 227:
+	switch( (*p) ) {
+		case 58: goto st228;
+		case 93: goto tr180;
+	}
+	goto st0;
+st228:
+	if ( ++p == pe )
+		goto _test_eof228;
+case 228:
+	switch( (*p) ) {
+		case 48: goto st209;
+		case 49: goto st214;
+		case 50: goto st217;
+	}
+	if ( (*p) < 65 ) {
+		if ( 51 <= (*p) && (*p) <= 57 )
+			goto st220;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st221;
+	} else
+		goto st221;
+	goto st0;
+st229:
+	if ( ++p == pe )
+		goto _test_eof229;
+case 229:
+	switch( (*p) ) {
+		case 46: goto st118;
+		case 58: goto st228;
+		case 93: goto tr180;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st230;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st225;
+	} else
+		goto st225;
+	goto st0;
+st230:
+	if ( ++p == pe )
+		goto _test_eof230;
+case 230:
+	switch( (*p) ) {
+		case 46: goto st118;
+		case 58: goto st228;
+		case 93: goto tr180;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st231;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st226;
+	} else
+		goto st226;
+	goto st0;
+st231:
+	if ( ++p == pe )
+		goto _test_eof231;
+case 231:
+	switch( (*p) ) {
+		case 46: goto st118;
+		case 58: goto st228;
+		case 93: goto tr180;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st227;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st227;
+	} else
+		goto st227;
+	goto st0;
+st232:
+	if ( ++p == pe )
+		goto _test_eof232;
+case 232:
+	switch( (*p) ) {
+		case 46: goto st118;
+		case 53: goto st233;
+		case 58: goto st228;
+		case 93: goto tr180;
+	}
+	if ( (*p) < 54 ) {
+		if ( 48 <= (*p) && (*p) <= 52 )
+			goto st230;
+	} else if ( (*p) > 57 ) {
+		if ( (*p) > 70 ) {
+			if ( 97 <= (*p) && (*p) <= 102 )
+				goto st225;
+		} else if ( (*p) >= 65 )
+			goto st225;
+	} else
+		goto st234;
+	goto st0;
+st233:
+	if ( ++p == pe )
+		goto _test_eof233;
+case 233:
+	switch( (*p) ) {
+		case 46: goto st118;
+		case 58: goto st228;
+		case 93: goto tr180;
+	}
+	if ( (*p) < 54 ) {
+		if ( 48 <= (*p) && (*p) <= 53 )
+			goto st231;
+	} else if ( (*p) > 57 ) {
+		if ( (*p) > 70 ) {
+			if ( 97 <= (*p) && (*p) <= 102 )
+				goto st226;
+		} else if ( (*p) >= 65 )
+			goto st226;
+	} else
+		goto st226;
+	goto st0;
+st234:
+	if ( ++p == pe )
+		goto _test_eof234;
+case 234:
+	switch( (*p) ) {
+		case 46: goto st118;
+		case 58: goto st228;
+		case 93: goto tr180;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st226;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st226;
+	} else
+		goto st226;
+	goto st0;
+st235:
+	if ( ++p == pe )
+		goto _test_eof235;
+case 235:
+	switch( (*p) ) {
+		case 46: goto st118;
+		case 58: goto st228;
+		case 93: goto tr180;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st234;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st225;
+	} else
+		goto st225;
+	goto st0;
+st236:
+	if ( ++p == pe )
+		goto _test_eof236;
+case 236:
+	switch( (*p) ) {
+		case 58: goto st228;
+		case 93: goto tr180;
+	}
+	if ( (*p) < 65 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto st225;
+	} else if ( (*p) > 70 ) {
+		if ( 97 <= (*p) && (*p) <= 102 )
+			goto st225;
+	} else
+		goto st225;
+	goto st0;
+	}
+	_test_eof2: cs = 2; goto _test_eof; 
+	_test_eof3: cs = 3; goto _test_eof; 
+	_test_eof4: cs = 4; goto _test_eof; 
+	_test_eof5: cs = 5; goto _test_eof; 
+	_test_eof6: cs = 6; goto _test_eof; 
+	_test_eof7: cs = 7; goto _test_eof; 
+	_test_eof237: cs = 237; goto _test_eof; 
+	_test_eof238: cs = 238; goto _test_eof; 
+	_test_eof239: cs = 239; goto _test_eof; 
+	_test_eof240: cs = 240; goto _test_eof; 
+	_test_eof241: cs = 241; goto _test_eof; 
+	_test_eof8: cs = 8; goto _test_eof; 
+	_test_eof9: cs = 9; goto _test_eof; 
+	_test_eof10: cs = 10; goto _test_eof; 
+	_test_eof11: cs = 11; goto _test_eof; 
+	_test_eof12: cs = 12; goto _test_eof; 
+	_test_eof13: cs = 13; goto _test_eof; 
+	_test_eof14: cs = 14; goto _test_eof; 
+	_test_eof15: cs = 15; goto _test_eof; 
+	_test_eof16: cs = 16; goto _test_eof; 
+	_test_eof17: cs = 17; goto _test_eof; 
+	_test_eof18: cs = 18; goto _test_eof; 
+	_test_eof19: cs = 19; goto _test_eof; 
+	_test_eof20: cs = 20; goto _test_eof; 
+	_test_eof21: cs = 21; goto _test_eof; 
+	_test_eof22: cs = 22; goto _test_eof; 
+	_test_eof23: cs = 23; goto _test_eof; 
+	_test_eof24: cs = 24; goto _test_eof; 
+	_test_eof25: cs = 25; goto _test_eof; 
+	_test_eof26: cs = 26; goto _test_eof; 
+	_test_eof27: cs = 27; goto _test_eof; 
+	_test_eof28: cs = 28; goto _test_eof; 
+	_test_eof29: cs = 29; goto _test_eof; 
+	_test_eof30: cs = 30; goto _test_eof; 
+	_test_eof31: cs = 31; goto _test_eof; 
+	_test_eof32: cs = 32; goto _test_eof; 
+	_test_eof33: cs = 33; goto _test_eof; 
+	_test_eof34: cs = 34; goto _test_eof; 
+	_test_eof35: cs = 35; goto _test_eof; 
+	_test_eof36: cs = 36; goto _test_eof; 
+	_test_eof37: cs = 37; goto _test_eof; 
+	_test_eof38: cs = 38; goto _test_eof; 
+	_test_eof39: cs = 39; goto _test_eof; 
+	_test_eof40: cs = 40; goto _test_eof; 
+	_test_eof41: cs = 41; goto _test_eof; 
+	_test_eof42: cs = 42; goto _test_eof; 
+	_test_eof43: cs = 43; goto _test_eof; 
+	_test_eof44: cs = 44; goto _test_eof; 
+	_test_eof45: cs = 45; goto _test_eof; 
+	_test_eof46: cs = 46; goto _test_eof; 
+	_test_eof47: cs = 47; goto _test_eof; 
+	_test_eof48: cs = 48; goto _test_eof; 
+	_test_eof49: cs = 49; goto _test_eof; 
+	_test_eof50: cs = 50; goto _test_eof; 
+	_test_eof242: cs = 242; goto _test_eof; 
+	_test_eof243: cs = 243; goto _test_eof; 
+	_test_eof244: cs = 244; goto _test_eof; 
+	_test_eof245: cs = 245; goto _test_eof; 
+	_test_eof51: cs = 51; goto _test_eof; 
+	_test_eof52: cs = 52; goto _test_eof; 
+	_test_eof53: cs = 53; goto _test_eof; 
+	_test_eof54: cs = 54; goto _test_eof; 
+	_test_eof55: cs = 55; goto _test_eof; 
+	_test_eof56: cs = 56; goto _test_eof; 
+	_test_eof57: cs = 57; goto _test_eof; 
+	_test_eof58: cs = 58; goto _test_eof; 
+	_test_eof59: cs = 59; goto _test_eof; 
+	_test_eof60: cs = 60; goto _test_eof; 
+	_test_eof61: cs = 61; goto _test_eof; 
+	_test_eof62: cs = 62; goto _test_eof; 
+	_test_eof246: cs = 246; goto _test_eof; 
+	_test_eof247: cs = 247; goto _test_eof; 
+	_test_eof248: cs = 248; goto _test_eof; 
+	_test_eof63: cs = 63; goto _test_eof; 
+	_test_eof64: cs = 64; goto _test_eof; 
+	_test_eof65: cs = 65; goto _test_eof; 
+	_test_eof66: cs = 66; goto _test_eof; 
+	_test_eof67: cs = 67; goto _test_eof; 
+	_test_eof68: cs = 68; goto _test_eof; 
+	_test_eof69: cs = 69; goto _test_eof; 
+	_test_eof249: cs = 249; goto _test_eof; 
+	_test_eof70: cs = 70; goto _test_eof; 
+	_test_eof250: cs = 250; goto _test_eof; 
+	_test_eof251: cs = 251; goto _test_eof; 
+	_test_eof252: cs = 252; goto _test_eof; 
+	_test_eof253: cs = 253; goto _test_eof; 
+	_test_eof254: cs = 254; goto _test_eof; 
+	_test_eof71: cs = 71; goto _test_eof; 
+	_test_eof255: cs = 255; goto _test_eof; 
+	_test_eof256: cs = 256; goto _test_eof; 
+	_test_eof257: cs = 257; goto _test_eof; 
+	_test_eof258: cs = 258; goto _test_eof; 
+	_test_eof259: cs = 259; goto _test_eof; 
+	_test_eof260: cs = 260; goto _test_eof; 
+	_test_eof261: cs = 261; goto _test_eof; 
+	_test_eof262: cs = 262; goto _test_eof; 
+	_test_eof263: cs = 263; goto _test_eof; 
+	_test_eof264: cs = 264; goto _test_eof; 
+	_test_eof265: cs = 265; goto _test_eof; 
+	_test_eof266: cs = 266; goto _test_eof; 
+	_test_eof267: cs = 267; goto _test_eof; 
+	_test_eof72: cs = 72; goto _test_eof; 
+	_test_eof268: cs = 268; goto _test_eof; 
+	_test_eof269: cs = 269; goto _test_eof; 
+	_test_eof270: cs = 270; goto _test_eof; 
+	_test_eof271: cs = 271; goto _test_eof; 
+	_test_eof272: cs = 272; goto _test_eof; 
+	_test_eof273: cs = 273; goto _test_eof; 
+	_test_eof274: cs = 274; goto _test_eof; 
+	_test_eof275: cs = 275; goto _test_eof; 
+	_test_eof276: cs = 276; goto _test_eof; 
+	_test_eof277: cs = 277; goto _test_eof; 
+	_test_eof278: cs = 278; goto _test_eof; 
+	_test_eof279: cs = 279; goto _test_eof; 
+	_test_eof280: cs = 280; goto _test_eof; 
+	_test_eof73: cs = 73; goto _test_eof; 
+	_test_eof281: cs = 281; goto _test_eof; 
+	_test_eof282: cs = 282; goto _test_eof; 
+	_test_eof283: cs = 283; goto _test_eof; 
+	_test_eof284: cs = 284; goto _test_eof; 
+	_test_eof285: cs = 285; goto _test_eof; 
+	_test_eof286: cs = 286; goto _test_eof; 
+	_test_eof287: cs = 287; goto _test_eof; 
+	_test_eof288: cs = 288; goto _test_eof; 
+	_test_eof289: cs = 289; goto _test_eof; 
+	_test_eof290: cs = 290; goto _test_eof; 
+	_test_eof291: cs = 291; goto _test_eof; 
+	_test_eof292: cs = 292; goto _test_eof; 
+	_test_eof293: cs = 293; goto _test_eof; 
+	_test_eof74: cs = 74; goto _test_eof; 
+	_test_eof294: cs = 294; goto _test_eof; 
+	_test_eof295: cs = 295; goto _test_eof; 
+	_test_eof296: cs = 296; goto _test_eof; 
+	_test_eof297: cs = 297; goto _test_eof; 
+	_test_eof298: cs = 298; goto _test_eof; 
+	_test_eof299: cs = 299; goto _test_eof; 
+	_test_eof300: cs = 300; goto _test_eof; 
+	_test_eof301: cs = 301; goto _test_eof; 
+	_test_eof302: cs = 302; goto _test_eof; 
+	_test_eof303: cs = 303; goto _test_eof; 
+	_test_eof304: cs = 304; goto _test_eof; 
+	_test_eof305: cs = 305; goto _test_eof; 
+	_test_eof306: cs = 306; goto _test_eof; 
+	_test_eof75: cs = 75; goto _test_eof; 
+	_test_eof307: cs = 307; goto _test_eof; 
+	_test_eof308: cs = 308; goto _test_eof; 
+	_test_eof309: cs = 309; goto _test_eof; 
+	_test_eof310: cs = 310; goto _test_eof; 
+	_test_eof311: cs = 311; goto _test_eof; 
+	_test_eof312: cs = 312; goto _test_eof; 
+	_test_eof313: cs = 313; goto _test_eof; 
+	_test_eof314: cs = 314; goto _test_eof; 
+	_test_eof76: cs = 76; goto _test_eof; 
+	_test_eof77: cs = 77; goto _test_eof; 
+	_test_eof78: cs = 78; goto _test_eof; 
+	_test_eof79: cs = 79; goto _test_eof; 
+	_test_eof80: cs = 80; goto _test_eof; 
+	_test_eof81: cs = 81; goto _test_eof; 
+	_test_eof82: cs = 82; goto _test_eof; 
+	_test_eof83: cs = 83; goto _test_eof; 
+	_test_eof315: cs = 315; goto _test_eof; 
+	_test_eof316: cs = 316; goto _test_eof; 
+	_test_eof317: cs = 317; goto _test_eof; 
+	_test_eof318: cs = 318; goto _test_eof; 
+	_test_eof319: cs = 319; goto _test_eof; 
+	_test_eof84: cs = 84; goto _test_eof; 
+	_test_eof320: cs = 320; goto _test_eof; 
+	_test_eof321: cs = 321; goto _test_eof; 
+	_test_eof322: cs = 322; goto _test_eof; 
+	_test_eof323: cs = 323; goto _test_eof; 
+	_test_eof324: cs = 324; goto _test_eof; 
+	_test_eof325: cs = 325; goto _test_eof; 
+	_test_eof326: cs = 326; goto _test_eof; 
+	_test_eof327: cs = 327; goto _test_eof; 
+	_test_eof85: cs = 85; goto _test_eof; 
+	_test_eof86: cs = 86; goto _test_eof; 
+	_test_eof87: cs = 87; goto _test_eof; 
+	_test_eof88: cs = 88; goto _test_eof; 
+	_test_eof89: cs = 89; goto _test_eof; 
+	_test_eof90: cs = 90; goto _test_eof; 
+	_test_eof91: cs = 91; goto _test_eof; 
+	_test_eof92: cs = 92; goto _test_eof; 
+	_test_eof93: cs = 93; goto _test_eof; 
+	_test_eof94: cs = 94; goto _test_eof; 
+	_test_eof95: cs = 95; goto _test_eof; 
+	_test_eof96: cs = 96; goto _test_eof; 
+	_test_eof97: cs = 97; goto _test_eof; 
+	_test_eof98: cs = 98; goto _test_eof; 
+	_test_eof99: cs = 99; goto _test_eof; 
+	_test_eof100: cs = 100; goto _test_eof; 
+	_test_eof101: cs = 101; goto _test_eof; 
+	_test_eof102: cs = 102; goto _test_eof; 
+	_test_eof103: cs = 103; goto _test_eof; 
+	_test_eof104: cs = 104; goto _test_eof; 
+	_test_eof105: cs = 105; goto _test_eof; 
+	_test_eof106: cs = 106; goto _test_eof; 
+	_test_eof107: cs = 107; goto _test_eof; 
+	_test_eof108: cs = 108; goto _test_eof; 
+	_test_eof109: cs = 109; goto _test_eof; 
+	_test_eof110: cs = 110; goto _test_eof; 
+	_test_eof111: cs = 111; goto _test_eof; 
+	_test_eof112: cs = 112; goto _test_eof; 
+	_test_eof113: cs = 113; goto _test_eof; 
+	_test_eof114: cs = 114; goto _test_eof; 
+	_test_eof115: cs = 115; goto _test_eof; 
+	_test_eof116: cs = 116; goto _test_eof; 
+	_test_eof117: cs = 117; goto _test_eof; 
+	_test_eof118: cs = 118; goto _test_eof; 
+	_test_eof119: cs = 119; goto _test_eof; 
+	_test_eof120: cs = 120; goto _test_eof; 
+	_test_eof121: cs = 121; goto _test_eof; 
+	_test_eof122: cs = 122; goto _test_eof; 
+	_test_eof123: cs = 123; goto _test_eof; 
+	_test_eof124: cs = 124; goto _test_eof; 
+	_test_eof125: cs = 125; goto _test_eof; 
+	_test_eof126: cs = 126; goto _test_eof; 
+	_test_eof127: cs = 127; goto _test_eof; 
+	_test_eof128: cs = 128; goto _test_eof; 
+	_test_eof129: cs = 129; goto _test_eof; 
+	_test_eof130: cs = 130; goto _test_eof; 
+	_test_eof131: cs = 131; goto _test_eof; 
+	_test_eof132: cs = 132; goto _test_eof; 
+	_test_eof133: cs = 133; goto _test_eof; 
+	_test_eof134: cs = 134; goto _test_eof; 
+	_test_eof135: cs = 135; goto _test_eof; 
+	_test_eof136: cs = 136; goto _test_eof; 
+	_test_eof137: cs = 137; goto _test_eof; 
+	_test_eof138: cs = 138; goto _test_eof; 
+	_test_eof139: cs = 139; goto _test_eof; 
+	_test_eof140: cs = 140; goto _test_eof; 
+	_test_eof141: cs = 141; goto _test_eof; 
+	_test_eof142: cs = 142; goto _test_eof; 
+	_test_eof143: cs = 143; goto _test_eof; 
+	_test_eof144: cs = 144; goto _test_eof; 
+	_test_eof145: cs = 145; goto _test_eof; 
+	_test_eof146: cs = 146; goto _test_eof; 
+	_test_eof147: cs = 147; goto _test_eof; 
+	_test_eof148: cs = 148; goto _test_eof; 
+	_test_eof149: cs = 149; goto _test_eof; 
+	_test_eof150: cs = 150; goto _test_eof; 
+	_test_eof151: cs = 151; goto _test_eof; 
+	_test_eof152: cs = 152; goto _test_eof; 
+	_test_eof153: cs = 153; goto _test_eof; 
+	_test_eof154: cs = 154; goto _test_eof; 
+	_test_eof155: cs = 155; goto _test_eof; 
+	_test_eof156: cs = 156; goto _test_eof; 
+	_test_eof157: cs = 157; goto _test_eof; 
+	_test_eof158: cs = 158; goto _test_eof; 
+	_test_eof159: cs = 159; goto _test_eof; 
+	_test_eof160: cs = 160; goto _test_eof; 
+	_test_eof161: cs = 161; goto _test_eof; 
+	_test_eof162: cs = 162; goto _test_eof; 
+	_test_eof163: cs = 163; goto _test_eof; 
+	_test_eof164: cs = 164; goto _test_eof; 
+	_test_eof165: cs = 165; goto _test_eof; 
+	_test_eof166: cs = 166; goto _test_eof; 
+	_test_eof167: cs = 167; goto _test_eof; 
+	_test_eof168: cs = 168; goto _test_eof; 
+	_test_eof169: cs = 169; goto _test_eof; 
+	_test_eof170: cs = 170; goto _test_eof; 
+	_test_eof171: cs = 171; goto _test_eof; 
+	_test_eof172: cs = 172; goto _test_eof; 
+	_test_eof173: cs = 173; goto _test_eof; 
+	_test_eof174: cs = 174; goto _test_eof; 
+	_test_eof175: cs = 175; goto _test_eof; 
+	_test_eof176: cs = 176; goto _test_eof; 
+	_test_eof177: cs = 177; goto _test_eof; 
+	_test_eof178: cs = 178; goto _test_eof; 
+	_test_eof179: cs = 179; goto _test_eof; 
+	_test_eof180: cs = 180; goto _test_eof; 
+	_test_eof181: cs = 181; goto _test_eof; 
+	_test_eof182: cs = 182; goto _test_eof; 
+	_test_eof183: cs = 183; goto _test_eof; 
+	_test_eof184: cs = 184; goto _test_eof; 
+	_test_eof185: cs = 185; goto _test_eof; 
+	_test_eof186: cs = 186; goto _test_eof; 
+	_test_eof187: cs = 187; goto _test_eof; 
+	_test_eof188: cs = 188; goto _test_eof; 
+	_test_eof189: cs = 189; goto _test_eof; 
+	_test_eof190: cs = 190; goto _test_eof; 
+	_test_eof191: cs = 191; goto _test_eof; 
+	_test_eof192: cs = 192; goto _test_eof; 
+	_test_eof193: cs = 193; goto _test_eof; 
+	_test_eof194: cs = 194; goto _test_eof; 
+	_test_eof195: cs = 195; goto _test_eof; 
+	_test_eof196: cs = 196; goto _test_eof; 
+	_test_eof197: cs = 197; goto _test_eof; 
+	_test_eof198: cs = 198; goto _test_eof; 
+	_test_eof199: cs = 199; goto _test_eof; 
+	_test_eof200: cs = 200; goto _test_eof; 
+	_test_eof201: cs = 201; goto _test_eof; 
+	_test_eof202: cs = 202; goto _test_eof; 
+	_test_eof203: cs = 203; goto _test_eof; 
+	_test_eof204: cs = 204; goto _test_eof; 
+	_test_eof205: cs = 205; goto _test_eof; 
+	_test_eof206: cs = 206; goto _test_eof; 
+	_test_eof207: cs = 207; goto _test_eof; 
+	_test_eof208: cs = 208; goto _test_eof; 
+	_test_eof209: cs = 209; goto _test_eof; 
+	_test_eof210: cs = 210; goto _test_eof; 
+	_test_eof211: cs = 211; goto _test_eof; 
+	_test_eof212: cs = 212; goto _test_eof; 
+	_test_eof213: cs = 213; goto _test_eof; 
+	_test_eof214: cs = 214; goto _test_eof; 
+	_test_eof215: cs = 215; goto _test_eof; 
+	_test_eof216: cs = 216; goto _test_eof; 
+	_test_eof217: cs = 217; goto _test_eof; 
+	_test_eof218: cs = 218; goto _test_eof; 
+	_test_eof219: cs = 219; goto _test_eof; 
+	_test_eof220: cs = 220; goto _test_eof; 
+	_test_eof221: cs = 221; goto _test_eof; 
+	_test_eof222: cs = 222; goto _test_eof; 
+	_test_eof223: cs = 223; goto _test_eof; 
+	_test_eof224: cs = 224; goto _test_eof; 
+	_test_eof225: cs = 225; goto _test_eof; 
+	_test_eof226: cs = 226; goto _test_eof; 
+	_test_eof227: cs = 227; goto _test_eof; 
+	_test_eof228: cs = 228; goto _test_eof; 
+	_test_eof229: cs = 229; goto _test_eof; 
+	_test_eof230: cs = 230; goto _test_eof; 
+	_test_eof231: cs = 231; goto _test_eof; 
+	_test_eof232: cs = 232; goto _test_eof; 
+	_test_eof233: cs = 233; goto _test_eof; 
+	_test_eof234: cs = 234; goto _test_eof; 
+	_test_eof235: cs = 235; goto _test_eof; 
+	_test_eof236: cs = 236; goto _test_eof; 
+
+	_test_eof: {}
+	_out: {}
+	}
+
+#line 59 "ip_parser.rl"
+
+  if(len != p-str)
+    return ip_type_error;
+  else
+    return ip_type;
+}
+

+ 19 - 0
modules/ipops/ip_parser.h

@@ -0,0 +1,19 @@
+#ifndef ip_parser_h
+#define ip_parser_h
+
+
+#include <sys/types.h>
+
+
+enum enum_ip_type {
+  ip_type_ipv4 = 1,
+  ip_type_ipv6,
+  ip_type_ipv6_reference,
+  ip_type_error
+};
+
+
+enum enum_ip_type ip_parser_execute(const char *str, size_t len);
+
+
+#endif

+ 65 - 0
modules/ipops/ip_parser.rl

@@ -0,0 +1,65 @@
+#include "ip_parser.h"
+
+
+/** Ragel machine **/
+%%{
+  machine ip_parser;
+
+  action is_ipv4 {
+    ip_type = ip_type_ipv4;
+  }
+
+  action is_ipv6 {
+    ip_type = ip_type_ipv6;
+  }
+
+  action is_ipv6_reference {
+    ip_type = ip_type_ipv6_reference;
+  }
+
+  DIGIT                = "0".."9";
+  HEXDIG               = DIGIT | "A"i | "B"i | "C"i | "D"i | "E"i | "F"i;
+  dec_octet            = DIGIT | ( 0x31..0x39 DIGIT ) | ( "1" DIGIT{2} ) |
+                         ( "2" 0x30..0x34 DIGIT ) | ( "25" 0x30..0x35 );
+  IPv4address          = dec_octet "." dec_octet "." dec_octet "." dec_octet;
+  h16                  = HEXDIG{1,4};
+  ls32                 = ( h16 ":" h16 ) | IPv4address;
+  IPv6address          = ( ( h16 ":" ){6} ls32 ) |
+                         ( "::" ( h16 ":" ){5} ls32 ) |
+                         ( h16? "::" ( h16 ":" ){4} ls32 ) |
+                         ( ( ( h16 ":" )? h16 )? "::" ( h16 ":" ){3} ls32 ) |
+                         ( ( ( h16 ":" ){,2} h16 )? "::" ( h16 ":" ){2} ls32 ) |
+                         ( ( ( h16 ":" ){,3} h16 )? "::" h16 ":" ls32 ) |
+                         ( ( ( h16 ":" ){,4} h16 )? "::" ls32 ) |
+                         ( ( ( h16 ":" ){,5} h16 )? "::" h16 ) |
+                         ( ( ( h16 ":" ){,6} h16 )? "::" );
+  IPv6reference        = "[" IPv6address "]";
+
+  main                := IPv4address @is_ipv4 |
+                         IPv6address @is_ipv6 |
+                         IPv6reference @is_ipv6_reference;
+}%%
+
+/** Data **/
+%% write data;
+
+
+/** exec **/
+enum enum_ip_type ip_parser_execute(const char *str, size_t len)
+{
+  int cs = 0;
+  const char *p, *pe;
+  enum enum_ip_type ip_type = ip_type_error;
+
+  p = str;
+  pe = str+len;
+
+  %% write init;
+  %% write exec;
+
+  if(len != p-str)
+    return ip_type_error;
+  else
+    return ip_type;
+}
+

+ 437 - 0
modules/ipops/ipops_mod.c

@@ -0,0 +1,437 @@
+/*
+ * ipops module - IPv4 and Ipv6 operations
+ *
+ * Copyright (C) 2011 Iñaki Baz Castillo
+ *
+ * This file is part of SIP Router, a free SIP server.
+ *
+ * SIP Router 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
+ *
+ * SIP Router 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
+ *
+ * History:
+ * -------
+ *  2011-04-27: Initial version (ibc)
+ */
+/*!
+ * \file
+ * \brief SIP-router ipops :: Module interface
+ * \ingroup ipops
+ * Copyright (C) 2011 Iñaki Baz Castillo
+ * Module: \ref ipops
+ */
+
+/*! \defgroup ipops SIP-router ipops Module
+ *
+ * The ipops module provide IPv4 and IPv6 operations.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <arpa/inet.h>
+#include "../../sr_module.h"
+#include "../../dprint.h"
+#include "../../str.h"
+#include "../../mod_fix.h"
+#include "../../pvar.h"
+#include "ip_parser.h"
+
+
+MODULE_VERSION
+
+
+/*
+ * Module parameter variables
+ */
+
+
+/*
+ * Module core functions
+ */
+
+
+/*
+ * Module internal functions
+ */
+static int _compare_ips(char*, size_t, enum enum_ip_type, char*, size_t, enum enum_ip_type);
+
+
+/*
+ * Script functions
+ */
+static int w_is_ip(struct sip_msg*, char*);
+static int w_is_pure_ip(struct sip_msg*, char*);
+static int w_is_ipv4(struct sip_msg*, char*);
+static int w_is_ipv6(struct sip_msg*, char*);
+static int w_is_ipv6_reference(struct sip_msg*, char*);
+static int w_ip_type(struct sip_msg*, char*);
+static int w_compare_ips(struct sip_msg*, char*, char*);
+static int w_compare_pure_ips(struct sip_msg*, char*, char*);
+
+
+/*
+ * Exported functions
+ */
+static cmd_export_t cmds[] =
+{
+  { "is_ip", (cmd_function)w_is_ip, 1, fixup_spve_null, 0,
+  REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE },
+  { "is_pure_ip", (cmd_function)w_is_pure_ip, 1, fixup_spve_null, 0,
+  REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE },
+  { "is_ipv4", (cmd_function)w_is_ipv4, 1, fixup_spve_null, 0,
+  REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE },
+  { "is_ipv6", (cmd_function)w_is_ipv6, 1, fixup_spve_null, 0,
+  REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE },
+  { "is_ipv6_reference", (cmd_function)w_is_ipv6_reference, 1, fixup_spve_null, 0,
+  REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE },
+  { "ip_type", (cmd_function)w_ip_type, 1, fixup_spve_null, 0,
+  REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE },
+  { "compare_ips", (cmd_function)w_compare_ips, 2, fixup_spve_spve, 0,
+  REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE },
+  { "compare_pure_ips", (cmd_function)w_compare_pure_ips, 2, fixup_spve_spve, 0,
+  REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE },
+  { 0, 0, 0, 0, 0, 0 }
+};
+
+
+/*
+ * Module interface
+ */
+struct module_exports exports = {
+  "ipops",                   /*!< module name */
+  DEFAULT_DLFLAGS,           /*!< dlopen flags */
+  cmds,                      /*!< exported functions */
+  0,                         /*!< exported parameters */
+  0,                         /*!< exported statistics */
+  0,                         /*!< exported MI functions */
+  0,                         /*!< exported pseudo-variables */
+  0,                         /*!< extra processes */
+  0,                         /*!< module initialization function */
+  (response_function) 0,     /*!< response handling function */
+  0,                         /*!< destroy function */
+  0                          /*!< per-child init function */
+};
+
+
+/*
+ * Module internal functions
+ */
+
+/*! \brief Return 1 if both pure IP's are equal, 0 otherwise. */
+static int _compare_ips(char *ip1, size_t len1, enum enum_ip_type ip1_type, char *ip2, size_t len2, enum enum_ip_type ip2_type)
+{
+  struct in_addr in_addr1, in_addr2;
+  struct in6_addr in6_addr1, in6_addr2;
+  char _ip1[INET6_ADDRSTRLEN], _ip2[INET6_ADDRSTRLEN];
+  
+  // Not same IP type, return false.
+  if (ip1_type != ip2_type)
+    return 0;
+
+  memcpy(_ip1, ip1, len1);
+  _ip1[len1] = '\0';
+  memcpy(_ip2, ip2, len2);
+  _ip2[len2] = '\0';
+
+  switch(ip1_type) {
+    // Comparing IPv4 with IPv4.
+    case(ip_type_ipv4):
+      if (inet_pton(AF_INET, _ip1, &in_addr1) == 0)  return 0;
+      if (inet_pton(AF_INET, _ip2, &in_addr2) == 0)  return 0;
+      if (in_addr1.s_addr == in_addr2.s_addr)
+        return 1;
+      else
+        return 0;
+      break;
+    // Comparing IPv6 with IPv6.
+    case(ip_type_ipv6):
+      if (inet_pton(AF_INET6, _ip1, &in6_addr1) != 1)  return 0;
+      if (inet_pton(AF_INET6, _ip2, &in6_addr2) != 1)  return 0;
+      if (memcmp(in6_addr1.s6_addr, in6_addr2.s6_addr, sizeof(in6_addr1.s6_addr)) == 0)
+        return 1;
+      else
+        return 0;
+      break;
+    default:
+      return 0;
+      break;
+  }
+}
+
+
+
+/*
+ * Script functions
+ */
+
+/*! \brief Return true if the given argument (string or pv) is a valid IPv4, IPv6 or IPv6 reference. */
+static int w_is_ip(struct sip_msg* _msg, char* _s)
+{
+  str string;
+  
+  if (_s == NULL) {
+    LM_ERR("bad parameter\n");
+    return -2;
+  }
+  
+  if (fixup_get_svalue(_msg, (gparam_p)_s, &string))
+  {
+    LM_ERR("cannot print the format for string\n");
+    return -3;
+  }
+  
+  if (ip_parser_execute(string.s, string.len) != ip_type_error)
+    return 1;
+  else
+    return -1;
+}
+
+
+/*! \brief Return true if the given argument (string or pv) is a valid IPv4 or IPv6. */
+static int w_is_pure_ip(struct sip_msg* _msg, char* _s)
+{
+  str string;
+  
+  if (_s == NULL) {
+    LM_ERR("bad parameter\n");
+    return -2;
+  }
+  
+  if (fixup_get_svalue(_msg, (gparam_p)_s, &string))
+  {
+    LM_ERR("cannot print the format for string\n");
+    return -3;
+  }
+
+  switch(ip_parser_execute(string.s, string.len)) {
+    case(ip_type_ipv4):
+      return 1;
+      break;
+    case(ip_type_ipv6):
+      return 1;
+      break;
+    default:
+      return -1;
+      break;
+  }
+}
+
+
+/*! \brief Return true if the given argument (string or pv) is a valid IPv4. */
+static int w_is_ipv4(struct sip_msg* _msg, char* _s)
+{
+  str string;
+  
+  if (_s == NULL) {
+    LM_ERR("bad parameter\n");
+    return -2;
+  }
+  
+  if (fixup_get_svalue(_msg, (gparam_p)_s, &string))
+  {
+    LM_ERR("cannot print the format for string\n");
+    return -3;
+  }
+
+  if (ip_parser_execute(string.s, string.len) == ip_type_ipv4)
+    return 1;
+  else
+    return -1;
+}
+
+
+/*! \brief Return true if the given argument (string or pv) is a valid IPv6. */
+static int w_is_ipv6(struct sip_msg* _msg, char* _s)
+{
+  str string;
+  
+  if (_s == NULL) {
+    LM_ERR("bad parameter\n");
+    return -2;
+  }
+  
+  if (fixup_get_svalue(_msg, (gparam_p)_s, &string))
+  {
+    LM_ERR("cannot print the format for string\n");
+    return -3;
+  }
+  
+  if (ip_parser_execute(string.s, string.len) == ip_type_ipv6)
+    return 1;
+  else
+    return -1;
+}
+
+
+/*! \brief Return true if the given argument (string or pv) is a valid IPv6 reference. */
+static int w_is_ipv6_reference(struct sip_msg* _msg, char* _s)
+{
+  str string;
+  
+  if (_s == NULL) {
+    LM_ERR("bad parameter\n");
+    return -2;
+  }
+  
+  if (fixup_get_svalue(_msg, (gparam_p)_s, &string))
+  {
+    LM_ERR("cannot print the format for string\n");
+    return -3;
+  }
+  
+  if (ip_parser_execute(string.s, string.len) == ip_type_ipv6_reference)
+    return 1;
+  else
+    return -1;
+}
+
+
+/*! \brief Return the IP type of the given argument (string or pv): 1 = IPv4, 2 = IPv6, 3 = IPv6 refenrece, -1 = invalid IP. */
+static int w_ip_type(struct sip_msg* _msg, char* _s)
+{
+  str string;
+  
+  if (_s == NULL) {
+    LM_ERR("bad parameter\n");
+    return -2;
+  }
+  
+  if (fixup_get_svalue(_msg, (gparam_p)_s, &string))
+  {
+    LM_ERR("cannot print the format for string\n");
+    return -3;
+  }
+  
+  switch (ip_parser_execute(string.s, string.len)) {
+    case(ip_type_ipv4):
+      return 1;
+      break;
+    case(ip_type_ipv6):
+      return 2;
+      break;
+    case(ip_type_ipv6_reference):
+      return 3;
+      break;
+    default:
+      return -1;
+      break;
+  }
+}
+
+
+/*! \brief Return true if both IP's (string or pv) are equal. This function also allows comparing an IPv6 with an IPv6 reference. */
+static int w_compare_ips(struct sip_msg* _msg, char* _s1, char* _s2)
+{
+  str string1, string2;
+  enum enum_ip_type ip1_type, ip2_type;
+  
+  if (_s1 == NULL || _s2 == NULL ) {
+    LM_ERR("bad parameters\n");
+    return -2;
+  }
+  
+  if (fixup_get_svalue(_msg, (gparam_p)_s1, &string1))
+  {
+    LM_ERR("cannot print the format for first string\n");
+    return -3;
+  }
+
+  if (fixup_get_svalue(_msg, (gparam_p)_s2, &string2))
+  {
+    LM_ERR("cannot print the format for second string\n");
+    return -3;
+  }
+
+  switch(ip1_type = ip_parser_execute(string1.s, string1.len)) {
+    case(ip_type_error):
+      return -1;
+      break;
+    case(ip_type_ipv6_reference):
+      string1.s += 1;
+      string1.len -= 2;
+      ip1_type = ip_type_ipv6;
+      break;
+    default:
+      break;
+  }
+  switch(ip2_type = ip_parser_execute(string2.s, string2.len)) {
+    case(ip_type_error):
+      return -1;
+      break;
+    case(ip_type_ipv6_reference):
+      string2.s += 1;
+      string2.len -= 2;
+      ip2_type = ip_type_ipv6;
+      break;
+    default:
+      break;
+  }
+
+  if (_compare_ips(string1.s, string1.len, ip1_type, string2.s, string2.len, ip2_type))
+    return 1;
+  else
+    return -1;
+}
+
+
+/*! \brief Return true if both pure IP's (string or pv) are equal. IPv6 references not allowed. */
+static int w_compare_pure_ips(struct sip_msg* _msg, char* _s1, char* _s2)
+{
+  str string1, string2;
+  enum enum_ip_type ip1_type, ip2_type;
+  
+  if (_s1 == NULL || _s2 == NULL ) {
+    LM_ERR("bad parameters\n");
+    return -2;
+  }
+  
+  if (fixup_get_svalue(_msg, (gparam_p)_s1, &string1))
+  {
+    LM_ERR("cannot print the format for first string\n");
+    return -3;
+  }
+  
+  if (fixup_get_svalue(_msg, (gparam_p)_s2, &string2))
+  {
+    LM_ERR("cannot print the format for second string\n");
+    return -3;
+  }
+
+  switch(ip1_type = ip_parser_execute(string1.s, string1.len)) {
+    case(ip_type_error):
+      return -1;
+      break;
+    case(ip_type_ipv6_reference):
+      return -1;
+      break;
+    default:
+      break;
+  }
+  switch(ip2_type = ip_parser_execute(string2.s, string2.len)) {
+    case(ip_type_error):
+      return -1;
+      break;
+    case(ip_type_ipv6_reference):
+      return -1;
+      break;
+    default:
+      break;
+  }
+  
+  if (_compare_ips(string1.s, string1.len, ip1_type, string2.s, string2.len, ip2_type))
+    return 1;
+  else
+    return -1;
+}
+

+ 5 - 4
modules/lcr/README

@@ -841,10 +841,11 @@ if (!next_gw()) {
 
 4.3.  defunct_gw(period)
 
-   Defuncts gateway denoted by lcr_id_avp and defunct_gw_avp for a period
-   of seconds given as argument. Argument must be a positive integer
-   constant or a pseudo variable with positive integer value. Value of
-   defunct column in database is not updated.
+   Defuncts gateway denoted by lcr_id_avp and defunct_gw_avp (which were
+   set by previuos next_gw() call) for a period of seconds given as
+   argument. Argument must be a positive integer constant or a pseudo
+   variable with positive integer value. Value of defunct column in
+   database is not updated.
 
    Returns 1 on success and -1 in case of error (see syslog).
 

+ 1 - 0
modules/lcr/doc/lcr_admin.xml

@@ -1077,6 +1077,7 @@ if (!next_gw()) {
 		</title>	
 		<para>
 		Defuncts gateway denoted by lcr_id_avp and defunct_gw_avp
+		(which were set by previuos next_gw() call)
 		for a period of seconds given as argument.  Argument 
 		must be a positive integer constant or a pseudo variable
 		with positive integer value.  Value of defunct column in

+ 1 - 1
modules/mediaproxy/mediaproxy.c

@@ -1563,7 +1563,7 @@ use_media_proxy(struct sip_msg *msg, char *dialog_id, ice_candidate_data *ice_da
     str callid, cseq, from_uri, to_uri, from_tag, to_tag, user_agent;
     str signaling_ip, media_relay, sdp, str_buf, tokens[MAX_STREAMS+1];
     str priority_str, candidate;
-    char request[8192], media_str[4096], buf[64], *result, *type;
+    char request[8192], media_str[4096], buf[128], *result, *type;
     int i, j, port, len, status;
     Bool removed_session_ip, have_sdp;
     SessionInfo session;

+ 3 - 3
modules/ratelimit/ratelimit.c

@@ -63,8 +63,8 @@ MODULE_VERSION
  */
 #define RL_TIMER_INTERVAL 10
 
-#define RXLS(m, str, i) (m)[i].rm_eo - (m)[i].rm_so, (str) + (m)[i].rm_so
-#define RXL(m, str, i) (m)[i].rm_eo - (m)[i].rm_so
+#define RXLS(m, str, i) (int)((m)[i].rm_eo - (m)[i].rm_so), (str) + (m)[i].rm_so
+#define RXL(m, str, i) (int)((m)[i].rm_eo - (m)[i].rm_so)
 #define RXS(m, str, i) (str) + (m)[i].rm_so
 
 static inline int str_cmp(const str * a, const str * b);
@@ -424,7 +424,7 @@ static int mod_init(void)
 		return -1;
 	}
 	timer_init(rl_timer, rl_timer_handle, 0, F_TIMER_FAST);
-	timer_add(rl_timer, MS_TO_TICKS(1500)); /* Start it after 1500ms */
+	timer_add(rl_timer, MS_TO_TICKS(1000*timer_interval));
 
 	network_load_value = shm_malloc(sizeof(int));
 	if (network_load_value==NULL) {

+ 84 - 70
modules/rtpproxy/README

@@ -24,13 +24,13 @@ Edited by
 
 Sas Ovidiu
 
-   Copyright © 2003-2008 Sippy Software, Inc.
+   Copyright © 2003-2008 Sippy Software, Inc.
 
-   Copyright © 2005 voice-system.ro
+   Copyright © 2005 voice-system.ro
 
-   Copyright © 2009 TuTPro Inc.
+   Copyright © 2009 TuTPro Inc.
 
-   Copyright © 2010 VoIPEmbedded Inc.
+   Copyright © 2010 VoIPEmbedded Inc.
    Revision History
    Revision $Revision$ $Date$
      __________________________________________________________________
@@ -55,19 +55,20 @@ Sas Ovidiu
               4.5. force_socket (string)
               4.6. nortpproxy_str (string)
               4.7. timeout_socket (string)
-              4.8. timeout_socket_type (int)
 
         5. Exported Functions
 
               5.1. set_rtp_proxy_set()
               5.2. rtpproxy_offer([flags [, ip_address]])
               5.3. rtpproxy_answer([flags [, ip_address]])
-              5.4. unforce_rtp_proxy()
-              5.5. rtpproxy_stream2uac(prompt_name, count),
+              5.4. rtpproxy_destroy()
+              5.5. unforce_rtp_proxy()
+              5.6. rtpproxy_manage([flags [, ip_address]])
+              5.7. rtpproxy_stream2uac(prompt_name, count),
                       rtpproxy_stream2uas(prompt_name, count)
 
-              5.6. rtpproxy_stop_stream2uac(), rtpproxy_stop_stream2uas()
-              5.7. start_recording()
+              5.8. rtpproxy_stop_stream2uac(), rtpproxy_stop_stream2uas()
+              5.9. start_recording()
 
         6. Exported Pseudo Variables
 
@@ -89,11 +90,11 @@ Sas Ovidiu
    1.5. Set force_socket parameter
    1.6. Set nortpproxy_str parameter
    1.7. Set timeout_socket parameter
-   1.8. Set timeout_socket_type parameter
-   1.9. fix_nated_contact usage
-   1.10. rtpproxy_offer usage
-   1.11. rtpproxy_answer usage
-   1.12. unforce_rtp_proxy usage
+   1.8. fix_nated_contact usage
+   1.9. rtpproxy_offer usage
+   1.10. rtpproxy_answer usage
+   1.11. rtpproxy_destroy usage
+   1.12. rtpproxy_manage usage
    1.13. rtpproxy_stream2xxx usage
    1.14. start_recording usage
    1.15. $rtpstat-Usage
@@ -120,19 +121,20 @@ Chapter 1. Admin Guide
         4.5. force_socket (string)
         4.6. nortpproxy_str (string)
         4.7. timeout_socket (string)
-        4.8. timeout_socket_type (int)
 
    5. Exported Functions
 
         5.1. set_rtp_proxy_set()
         5.2. rtpproxy_offer([flags [, ip_address]])
         5.3. rtpproxy_answer([flags [, ip_address]])
-        5.4. unforce_rtp_proxy()
-        5.5. rtpproxy_stream2uac(prompt_name, count),
+        5.4. rtpproxy_destroy()
+        5.5. unforce_rtp_proxy()
+        5.6. rtpproxy_manage([flags [, ip_address]])
+        5.7. rtpproxy_stream2uac(prompt_name, count),
                 rtpproxy_stream2uas(prompt_name, count)
 
-        5.6. rtpproxy_stop_stream2uac(), rtpproxy_stop_stream2uas()
-        5.7. start_recording()
+        5.8. rtpproxy_stop_stream2uac(), rtpproxy_stop_stream2uas()
+        5.9. start_recording()
 
    6. Exported Pseudo Variables
 
@@ -162,7 +164,7 @@ Chapter 1. Admin Guide
    load-balancing will be performed over a set and the user has the
    ability to choose what set should be used. The set is selected via its
    id - the id being defined along with the set. Refer to the
-   "rtpproxy_sock" module parameter definition for syntax description.
+   “rtpproxy_sock� module parameter definition for syntax description.
 
    The balancing inside a set is done automatically by the module based on
    the weight of each rtpproxy from the set.
@@ -186,7 +188,8 @@ Chapter 1. Admin Guide
 3.1. Kamailio Modules
 
    The following modules must be loaded before this module:
-     * None
+     * tm module - (optional) if you want to have rtpproxy_manage() fully
+       functional
 
 3.2. External Libraries or Applications
 
@@ -203,14 +206,13 @@ Chapter 1. Admin Guide
    4.5. force_socket (string)
    4.6. nortpproxy_str (string)
    4.7. timeout_socket (string)
-   4.8. timeout_socket_type (int)
 
 4.1. rtpproxy_sock (string)
 
    Definition of socket(s) used to connect to (a set) RTPProxy. It may
    specify a UNIX socket or an IPv4/IPv6 UDP socket.
 
-   Default value is "NONE" (disabled).
+   Default value is “NONE� (disabled).
 
    Example 1.1. Set rtpproxy_sock parameter
 ...
@@ -232,7 +234,7 @@ modparam("rtpproxy", "rtpproxy_sock",
    will not attempt to establish communication to RTPProxy for
    rtpproxy_disable_tout seconds.
 
-   Default value is "60".
+   Default value is “60�.
 
    Example 1.2. Set rtpproxy_disable_tout parameter
 ...
@@ -243,7 +245,7 @@ modparam("rtpproxy", "rtpproxy_disable_tout", 20)
 
    Timeout value in waiting for reply from RTPProxy.
 
-   Default value is "1".
+   Default value is “1�.
 
    Example 1.3. Set rtpproxy_tout parameter
 ...
@@ -255,7 +257,7 @@ modparam("rtpproxy", "rtpproxy_tout", 2)
    How many times rtpproxy should retry to send and receive after timeout
    was generated.
 
-   Default value is "5".
+   Default value is “5�.
 
    Example 1.4. Set rtpproxy_retr parameter
 ...
@@ -267,7 +269,7 @@ modparam("rtpproxy", "rtpproxy_retr", 2)
    Socket to be forced in communicating to RTPProxy. It makes sense only
    for UDP communication. If no one specified, the OS will choose.
 
-   Default value is "NULL".
+   Default value is “NULL�.
 
    Example 1.5. Set force_socket parameter
 ...
@@ -285,7 +287,7 @@ Note
 
    The string must be a complete SDP line, including the EOH (\r\n).
 
-   Default value is "a=nortpproxy:yes\r\n".
+   Default value is “a=nortpproxy:yes\r\n�.
 
    Example 1.6. Set nortpproxy_str parameter
 ...
@@ -300,43 +302,26 @@ modparam("rtpproxy", "nortpproxy_str", "a=sdpmangled:yes\r\n")
    If it is an empty string, no timeout socket will be transmitted to the
    RTP-Proxy.
 
-   Default value is "".
+   Default value is “� (nothing).
 
    Example 1.7. Set timeout_socket parameter
 ...
-modparam("nathelper", "timeout_socket", "http://127.0.0.1:8000/RPC2")
+modparam("nathelper", "timeout_socket", "xmlrpc:http://127.0.0.1:8000/RPC2")
 ...
 
-4.8. timeout_socket_type (int)
-
-   The parameter sets type of the timeout socket, which is transmitted to
-   the RTP-Proxy.
-
-   If it is not set, type 1 (Kamailio XML-RPC-Socket) is transmitted to
-   the RTP-Proxy.
-
-   Default value is "1".
-
-   Example 1.8. Set timeout_socket_type parameter
-...
-modparam("nathelper", "timeout_socket_type", 42)
-...
-
-   The only supported Type on the RTP-Proxy is currently "1" or "0" which
-   is the default socket-type of the RTP-Proxy which is not compatible to
-   Kamailio.
-
 5. Exported Functions
 
    5.1. set_rtp_proxy_set()
    5.2. rtpproxy_offer([flags [, ip_address]])
    5.3. rtpproxy_answer([flags [, ip_address]])
-   5.4. unforce_rtp_proxy()
-   5.5. rtpproxy_stream2uac(prompt_name, count),
+   5.4. rtpproxy_destroy()
+   5.5. unforce_rtp_proxy()
+   5.6. rtpproxy_manage([flags [, ip_address]])
+   5.7. rtpproxy_stream2uac(prompt_name, count),
           rtpproxy_stream2uas(prompt_name, count)
 
-   5.6. rtpproxy_stop_stream2uac(), rtpproxy_stop_stream2uas()
-   5.7. start_recording()
+   5.8. rtpproxy_stop_stream2uac(), rtpproxy_stop_stream2uas()
+   5.9. start_recording()
 
 5.1.  set_rtp_proxy_set()
 
@@ -346,7 +331,7 @@ modparam("nathelper", "timeout_socket_type", 42)
    This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
    BRANCH_ROUTE.
 
-   Example 1.9. fix_nated_contact usage
+   Example 1.8. fix_nated_contact usage
 ...
 set_rtp_proxy_set("2");
 rtpproxy_offer();
@@ -362,7 +347,7 @@ rtpproxy_offer();
      * flags - flags to turn on some features.
           + a - flags that UA from which message is received doesn't
             support symmetric RTP. (automatically sets the 'r' flag)
-          + l - force "lookup", that is, only rewrite SDP when
+          + l - force “lookup�, that is, only rewrite SDP when
             corresponding session is already exists in the RTP proxy. By
             default is on when the session is to be completed.
           + i, e - these flags specify the direction of the SIP message.
@@ -406,10 +391,9 @@ rtpproxy_offer();
             100ms saves two thirds of the network bandwith.
      * ip_address - new SDP IP address.
 
-   This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
-   FAILURE_ROUTE, BRANCH_ROUTE.
+   This function can be used from ANY_ROUTE.
 
-   Example 1.10. rtpproxy_offer usage
+   Example 1.9. rtpproxy_offer usage
 route {
 ...
     if (is_method("INVITE")) {
@@ -453,23 +437,53 @@ onreply_route[2]
    This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
    FAILURE_ROUTE, BRANCH_ROUTE.
 
-   Example 1.11. rtpproxy_answer usage
+   Example 1.10. rtpproxy_answer usage
 
    See rtpproxy_offer() function example above for example.
 
-5.4.  unforce_rtp_proxy()
+5.4.  rtpproxy_destroy()
 
    Tears down the RTPProxy session for the current call.
 
-   This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
-   FAILURE_ROUTE, BRANCH_ROUTE.
+   This function can be used from ANY_ROUTE.
+
+   Example 1.11. rtpproxy_destroy usage
+...
+rtpproxy_destroy();
+...
+
+5.5.  unforce_rtp_proxy()
+
+   Same as rtpproxy_destroy().
+
+5.6.  rtpproxy_manage([flags [, ip_address]])
+
+   Manage the RTPProxy session - it combines the functionality of
+   rtpproxy_offer(), rtpproxy_answer() and unfroce_rtpproxy(), detecting
+   internally based on message type and metod which one to execute.
+
+   It can take same kind of parameters as rtpproxy_offer().
+
+   Functinality:
+     * if INVITE with SDP, then do rtpproxy offer
+     * if INVITE with SDP, when tm is loaded, mark transaction with
+       internal flag FL_SDP_BODY to know that the 1xx and 2xx are for
+       rtpproxy answer
+     * if ACK with SDP, then do rtpproxy answer
+     * if BYE or CANCEL, then do unforce rtpproxy
+     * if reply to INVITE with code >= 300 do unfrce rtp proxy
+     * if reply with SDP to INVITE having code 1xx and 2xx, then do
+       rtpproxy answer if the request had SDP or tm is not loaded,
+       otherwise do rtpproxy offer
+
+   This function can be used from ANY_ROUTE.
 
-   Example 1.12. unforce_rtp_proxy usage
+   Example 1.12. rtpproxy_manage usage
 ...
-unforce_rtp_proxy();
+rtpproxy_manage();
 ...
 
-5.5.  rtpproxy_stream2uac(prompt_name, count),
+5.7.  rtpproxy_stream2uac(prompt_name, count),
 rtpproxy_stream2uas(prompt_name, count)
 
    Instruct the RTPproxy to stream prompt/announcement pre-encoded with
@@ -512,7 +526,7 @@ rtpproxy_stream2uas(prompt_name, count)
     };
 ...
 
-5.6.  rtpproxy_stop_stream2uac(), rtpproxy_stop_stream2uas()
+5.8.  rtpproxy_stop_stream2uac(), rtpproxy_stop_stream2uas()
 
    Stop streaming of announcement/prompt/MOH started previously by the
    respective rtpproxy_stream2xxx. The uac/uas suffix selects whose
@@ -521,7 +535,7 @@ rtpproxy_stream2uas(prompt_name, count)
 
    These functions can be used from REQUEST_ROUTE, ONREPLY_ROUTE.
 
-5.7.  start_recording()
+5.9.  start_recording()
 
    This command will send a signal to the RTP-Proxy to record the RTP
    stream on the RTP-Proxy.
@@ -586,16 +600,16 @@ $ kamctl fifo nh_show_rtpp
 
 Chapter 2. Frequently Asked Questions
 
-   2.1. What happend with "rtpproxy_disable" parameter?
+   2.1. What happend with “rtpproxy_disable� parameter?
    2.2. Where can I find more about Kamailio?
    2.3. Where can I post a question about this module?
    2.4. How can I report a bug?
 
    2.1.
 
-       What happend with "rtpproxy_disable" parameter?
+       What happend with “rtpproxy_disable� parameter?
 
-       It was removed as it became obsolete - now "rtpproxy_sock" can take
+       It was removed as it became obsolete - now “rtpproxy_sock� can take
        empty value to disable the rtpproxy functionality.
 
    2.2.

+ 81 - 7
modules/rtpproxy/doc/rtpproxy_admin.xml

@@ -72,7 +72,8 @@
 			<itemizedlist>
 			<listitem>
 			<para>
-				<emphasis>None</emphasis>
+				<emphasis>tm module</emphasis> - (optional) if you want to
+				have rtpproxy_manage() fully functional
 			</para>
 			</listitem>
 			</itemizedlist>
@@ -367,8 +368,7 @@ rtpproxy_offer();
 		</para></listitem>
 		</itemizedlist>
 		<para>
-		This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
-		FAILURE_ROUTE, BRANCH_ROUTE.
+		This function can be used from ANY_ROUTE.
                 </para>
 		<example>
 		<title><function>rtpproxy_offer</function> usage</title>
@@ -433,23 +433,97 @@ onreply_route[2]
         </section>
 	<section>
 		<title>
-		<function moreinfo="none">unforce_rtp_proxy()</function>
+		<function moreinfo="none">rtpproxy_destroy()</function>
 		</title>
 		<para>
 		Tears down the RTPProxy session for the current call.
 		</para>
 		<para>
-		This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE, FAILURE_ROUTE, BRANCH_ROUTE.
+		This function can be used from ANY_ROUTE.
 		</para>
 		<example>
-		<title><function>unforce_rtp_proxy</function> usage</title>
+		<title><function>rtpproxy_destroy</function> usage</title>
 		<programlisting format="linespecific">
 ...
-unforce_rtp_proxy();
+rtpproxy_destroy();
 ...
 </programlisting>
 		</example>
 	</section>
+	<section>
+		<title>
+		<function moreinfo="none">unforce_rtp_proxy()</function>
+		</title>
+		<para>
+			Same as rtpproxy_destroy().
+		</para>
+	</section>
+
+    <section>
+        <title>
+        <function moreinfo="none">rtpproxy_manage([flags [, ip_address]])</function>
+        </title>
+		<para>
+		Manage the RTPProxy session - it combines the functionality of
+		rtpproxy_offer(), rtpproxy_answer() and unfroce_rtpproxy(), detecting
+		internally based on message type and metod which one to execute.
+		</para>
+		<para>
+		It can take same kind of parameters as rtpproxy_offer().
+		</para>
+		<para>
+		Functinality:
+		</para>
+		<itemizedlist>
+		<listitem>
+			<para>
+			if INVITE with SDP, then do rtpproxy offer
+			</para>
+		</listitem>
+		<listitem>
+			<para>
+			if INVITE with SDP, when tm is loaded, mark transaction with
+			internal flag FL_SDP_BODY to know that the 1xx and 2xx are for
+			rtpproxy answer
+			</para>
+		</listitem>
+		<listitem>
+			<para>
+			if ACK with SDP, then do rtpproxy answer
+			</para>
+		</listitem>
+		<listitem>
+			<para>
+			if BYE or CANCEL, then do unforce rtpproxy
+			</para>
+		</listitem>
+		<listitem>
+			<para>
+			if reply to INVITE with code >= 300 do unfrce rtp proxy
+			</para>
+		</listitem>
+		<listitem>
+			<para>
+			if reply with SDP to INVITE having code 1xx and 2xx, then
+			do rtpproxy answer if the request had SDP or tm is not loaded,
+			otherwise do rtpproxy offer
+			</para>
+		</listitem>
+	</itemizedlist>
+
+		<para>
+		This function can be used from ANY_ROUTE.
+		</para>
+		<example>
+		 <title><function>rtpproxy_manage</function> usage</title>
+		<programlisting format="linespecific">
+...
+rtpproxy_manage();
+...
+</programlisting>
+		</example>
+        </section>
+
 	<section id="rtpproxy_stream2xxx">
 	<title>
 	    <function>rtpproxy_stream2uac(prompt_name, count)</function>,

+ 124 - 13
modules/rtpproxy/rtpproxy.c

@@ -219,6 +219,8 @@
 #include "../../socket_info.h"
 #include "../../mod_fix.h"
 #include "../../dset.h"
+#include "../../route.h"
+#include "../../modules/tm/tm_load.h"
 #include "rtpproxy.h"
 #include "rtpproxy_funcs.h"
 #include "rtpproxy_stream.h"
@@ -290,6 +292,9 @@ static int rtpproxy_answer1_f(struct sip_msg *, char *, char *);
 static int rtpproxy_answer2_f(struct sip_msg *, char *, char *);
 static int rtpproxy_offer1_f(struct sip_msg *, char *, char *);
 static int rtpproxy_offer2_f(struct sip_msg *, char *, char *);
+static int rtpproxy_manage0(struct sip_msg *msg, char *flags, char *ip);
+static int rtpproxy_manage1(struct sip_msg *msg, char *flags, char *ip);
+static int rtpproxy_manage2(struct sip_msg *msg, char *flags, char *ip);
 
 static int add_rtpproxy_socks(struct rtpp_set * rtpp_list, char * rtpproxy);
 static int fixup_set_id(void ** param, int param_no);
@@ -334,6 +339,9 @@ static unsigned int rtpp_no = 0;
 static int *rtpp_socks = 0;
 
 
+/* tm */
+static struct tm_binds tmb;
+
 /*0-> disabled, 1 ->enabled*/
 unsigned int *natping_state=0;
 
@@ -342,43 +350,55 @@ static str timeout_socket_str = {0, 0};
 static cmd_export_t cmds[] = {
 	{"set_rtp_proxy_set",  (cmd_function)set_rtp_proxy_set_f,    1,
 		fixup_set_id, 0,
-		REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE},
+		ANY_ROUTE},
 	{"unforce_rtp_proxy",  (cmd_function)unforce_rtp_proxy_f,    0,
 		0, 0,
-		REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE},
+		ANY_ROUTE},
+	{"rtpproxy_destroy",   (cmd_function)unforce_rtp_proxy_f,    0,
+		0, 0,
+		ANY_ROUTE},
 	{"start_recording",    (cmd_function)start_recording_f,      0,
 		0, 0,
-		REQUEST_ROUTE | ONREPLY_ROUTE },
+		ANY_ROUTE },
 	{"rtpproxy_offer",	(cmd_function)rtpproxy_offer1_f,     0,
 		0, 0,
-		REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE},
+		ANY_ROUTE},
 	{"rtpproxy_offer",	(cmd_function)rtpproxy_offer1_f,     1,
 		0, 0,
-		REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE},
+		ANY_ROUTE},
 	{"rtpproxy_offer",	(cmd_function)rtpproxy_offer2_f,     2,
 		0, 0,
-		REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE},
+		ANY_ROUTE},
 	{"rtpproxy_answer",	(cmd_function)rtpproxy_answer1_f,    0,
 		0, 0,
-		REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE},
+		ANY_ROUTE},
 	{"rtpproxy_answer",	(cmd_function)rtpproxy_answer1_f,    1,
 		0, 0,
-		REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE},
+		ANY_ROUTE},
 	{"rtpproxy_answer",	(cmd_function)rtpproxy_answer2_f,    2,
 		0, 0,
-		REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE},
+		ANY_ROUTE},
 	{"rtpproxy_stream2uac",(cmd_function)rtpproxy_stream2uac2_f, 2,
 		fixup_var_str_int, 0,
-		REQUEST_ROUTE | ONREPLY_ROUTE },
+		ANY_ROUTE },
 	{"rtpproxy_stream2uas",(cmd_function)rtpproxy_stream2uas2_f, 2,
 		fixup_var_str_int, 0,
-		REQUEST_ROUTE | ONREPLY_ROUTE },
+		ANY_ROUTE },
 	{"rtpproxy_stop_stream2uac",(cmd_function)rtpproxy_stop_stream2uac2_f,0,
 		NULL, 0,
-		REQUEST_ROUTE | ONREPLY_ROUTE },
+		ANY_ROUTE },
 	{"rtpproxy_stop_stream2uas",(cmd_function)rtpproxy_stop_stream2uas2_f,0,
 		NULL, 0,
-		REQUEST_ROUTE | ONREPLY_ROUTE },
+		ANY_ROUTE },
+	{"rtpproxy_manage",	(cmd_function)rtpproxy_manage0,     0,
+		0, 0,
+		ANY_ROUTE},
+	{"rtpproxy_manage",	(cmd_function)rtpproxy_manage1,     1,
+		0, 0,
+		ANY_ROUTE},
+	{"rtpproxy_manage",	(cmd_function)rtpproxy_manage2,     2,
+		0, 0,
+		ANY_ROUTE},
 	{0, 0, 0, 0, 0, 0}
 };
 
@@ -860,6 +880,12 @@ mod_init(void)
 	if (rtpp_strings)
 		pkg_free(rtpp_strings);
 
+	if (load_tm_api( &tmb ) < 0)
+	{
+		LM_DBG("could not load the TM-functions - answer-offer model"
+				" auto-detection is disabled\n");
+		memset(&tmb, 0, sizeof(struct tm_binds));
+	}
 
 	return 0;
 }
@@ -1662,6 +1688,91 @@ set_rtp_proxy_set_f(struct sip_msg * msg, char * str1, char * str2)
 	return 1;
 }
 
+static int
+rtpproxy_manage(struct sip_msg *msg, char *flags, char *ip)
+{
+	char *cp = NULL;
+	char newip[IP_ADDR_MAX_STR_SIZE];
+	int method;
+	int nosdp;
+
+	if(msg->cseq==NULL && ((parse_headers(msg, HDR_CSEQ_F, 0)==-1)
+				|| (msg->cseq==NULL)))
+	{
+		LM_ERR("no CSEQ header\n");
+		return -1;
+	}
+
+	method = get_cseq(msg)->method_id;
+
+	if(!(method==METHOD_INVITE || method==METHOD_ACK || method==METHOD_CANCEL
+				|| method==METHOD_BYE))
+		return -1;
+
+	if(method==METHOD_CANCEL || method==METHOD_BYE)
+		return unforce_rtp_proxy_f(msg, 0, 0);
+
+	if(ip==NULL)
+	{
+		cp = ip_addr2a(&msg->rcv.dst_ip);
+		strcpy(newip, cp);
+	}
+
+	if(msg->msg_flags & FL_SDP_BODY)
+		nosdp = 0;
+	else
+		nosdp = parse_sdp(msg);
+
+	if(msg->first_line.type == SIP_REQUEST) {
+		if(method==METHOD_ACK && nosdp==0)
+			return force_rtp_proxy(msg, flags, (cp!=NULL)?newip:ip, 0,
+					(ip!=NULL)?1:0);
+		if(method==METHOD_INVITE && nosdp==0) {
+			msg->msg_flags |= FL_SDP_BODY;
+			if(tmb.t_gett!=NULL && tmb.t_gett()!=NULL
+					&& tmb.t_gett()!=T_UNDEFINED)
+				tmb.t_gett()->uas.request->msg_flags |= FL_SDP_BODY;
+			if(route_type==FAILURE_ROUTE)
+				return unforce_rtp_proxy_f(msg, 0, 0);
+			return force_rtp_proxy(msg, flags, (cp!=NULL)?newip:ip, 1,
+					(ip!=NULL)?1:0);
+		}
+	} else if(msg->first_line.type == SIP_REPLY) {
+		if(msg->first_line.u.reply.statuscode>=300)
+			return unforce_rtp_proxy_f(msg, 0, 0);
+		if(nosdp==0) {
+			if(tmb.t_gett==NULL || tmb.t_gett()==NULL
+					|| tmb.t_gett()==T_UNDEFINED)
+				return force_rtp_proxy(msg, flags, (cp!=NULL)?newip:ip, 0,
+					(ip!=NULL)?1:0);
+			if(tmb.t_gett()->uas.request->msg_flags & FL_SDP_BODY)
+				return force_rtp_proxy(msg, flags, (cp!=NULL)?newip:ip, 0,
+					(ip!=NULL)?1:0);
+			return force_rtp_proxy(msg, flags, (cp!=NULL)?newip:ip, 1,
+					(ip!=NULL)?1:0);
+		}
+	}
+	return -1;
+}
+
+static int
+rtpproxy_manage0(struct sip_msg *msg, char *flags, char *ip)
+{
+	return rtpproxy_manage(msg, 0, 0);
+}
+
+static int
+rtpproxy_manage1(struct sip_msg *msg, char *flags, char *ip)
+{
+	return rtpproxy_manage(msg, flags, 0);
+}
+
+static int
+rtpproxy_manage2(struct sip_msg *msg, char *flags, char *ip)
+{
+	return rtpproxy_manage(msg, flags, ip);
+}
+
 static int
 rtpproxy_offer1_f(struct sip_msg *msg, char *str1, char *str2)
 {

+ 34 - 13
modules/sdpops/README

@@ -10,7 +10,7 @@ Daniel-Constantin Mierla
 
    <[email protected]>
 
-   Copyright © 2011 asipto.com
+   Copyright © 2011 asipto.com
      __________________________________________________________________
 
    Table of Contents
@@ -27,14 +27,16 @@ Daniel-Constantin Mierla
         4. Exported Functions
 
               4.1. sdp_remove_codecs_by_id(list)
-              4.2. sdp_with_media(type)
-              4.3. sdp_print(level)
+              4.2. sdp_remove_codecs_by_name(list)
+              4.3. sdp_with_media(type)
+              4.4. sdp_print(level)
 
    List of Examples
 
    1.1. sdp_remove_codecs_by_id usage
-   1.2. sdp_with_media usage
-   1.3. sdp_print usage
+   1.2. sdp_remove_codecs_by_name usage
+   1.3. sdp_with_media usage
+   1.4. sdp_print usage
 
 Chapter 1. Admin Guide
 
@@ -50,8 +52,9 @@ Chapter 1. Admin Guide
    4. Exported Functions
 
         4.1. sdp_remove_codecs_by_id(list)
-        4.2. sdp_with_media(type)
-        4.3. sdp_print(level)
+        4.2. sdp_remove_codecs_by_name(list)
+        4.3. sdp_with_media(type)
+        4.4. sdp_print(level)
 
 1. Overview
 
@@ -86,8 +89,9 @@ Chapter 1. Admin Guide
 4. Exported Functions
 
    4.1. sdp_remove_codecs_by_id(list)
-   4.2. sdp_with_media(type)
-   4.3. sdp_print(level)
+   4.2. sdp_remove_codecs_by_name(list)
+   4.3. sdp_with_media(type)
+   4.4. sdp_print(level)
 
 4.1.  sdp_remove_codecs_by_id(list)
 
@@ -106,7 +110,24 @@ sdp_remove_codecs_by_id("0");
 sdp_remove_codecs_by_id("0,8,3");
 ...
 
-4.2.  sdp_with_media(type)
+4.2.  sdp_remove_codecs_by_name(list)
+
+   Remove the codecs provided in the parameter 'list' from all media
+   streams found in SDP payload. The parameter 'list' must be one or a
+   comma separated list of codec names. The parameter can be a static
+   string or a variable holding the list of codec names.
+
+   This function can be used from ANY_ROUTE.
+
+   Example 1.2. sdp_remove_codecs_by_name usage
+...
+# remove PCMU
+sdp_remove_codecs_by_name("PCMU");
+# remove PCMU, PCMA and GSM
+sdp_remove_codecs_by_name("PCMU,PCMA,GSM");
+...
+
+4.3.  sdp_with_media(type)
 
    Return true of the SDP has 'media=type ...' line. Useful to check the
    content of the RTP sessions, such as 'audio' or 'video'. The parameter
@@ -114,7 +135,7 @@ sdp_remove_codecs_by_id("0,8,3");
 
    This function can be used from ANY_ROUTE.
 
-   Example 1.2. sdp_with_media usage
+   Example 1.3. sdp_with_media usage
 ...
 # check for video stream
 if(sdp_with_media("video"))
@@ -123,14 +144,14 @@ if(sdp_with_media("video"))
 }
 ...
 
-4.3.  sdp_print(level)
+4.4.  sdp_print(level)
 
    Print the SDP internal structure to log 'level'. The parameter can be
    static integer or variable holding the integer value of the log level.
 
    This function can be used from ANY_ROUTE.
 
-   Example 1.3. sdp_print usage
+   Example 1.4. sdp_print usage
 ...
 # print the SDP
 sdp_print("1");

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

@@ -90,6 +90,32 @@ sdp_remove_codecs_by_id("0");
 # remove PCMU, PCMA and GSM
 sdp_remove_codecs_by_id("0,8,3");
 ...
+</programlisting>
+	    </example>
+	</section>
+	<section>
+	    <title>
+		<function moreinfo="none">sdp_remove_codecs_by_name(list)</function>
+	    </title>
+	    <para>
+			Remove the codecs provided in the parameter 'list' from all
+			media streams found in SDP payload. The parameter 'list' must
+			be one or a comma separated list of codec names. The
+			parameter can be a static string or a variable holding the
+			list of codec names.
+	    </para>
+		<para>
+			This function can be used from ANY_ROUTE.
+	    </para>
+		<example>
+		<title><function>sdp_remove_codecs_by_name</function> usage</title>
+		<programlisting format="linespecific">
+...
+# remove PCMU
+sdp_remove_codecs_by_name("PCMU");
+# remove PCMU, PCMA and GSM
+sdp_remove_codecs_by_name("PCMU,PCMA,GSM");
+...
 </programlisting>
 	    </example>
 	</section>

+ 220 - 0
modules/sdpops/sdpops_data.c

@@ -0,0 +1,220 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2011 Daniel-Constantin Mierla (asipto.com)
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "../../dprint.h"
+#include "../../trim.h"
+#include "sdpops_data.h"
+
+/*
+
+http://www.iana.org/assignments/rtp-parameters
+
+Registry Name: RTP Payload types (PT) for standard audio and video encodings - Closed
+Reference: [RFC3551]
+Registration Procedures: Registry closed; see [RFC3551], Section 3
+
+Note:
+The RFC "RTP Profile for Audio and Video Conferences with Minimal
+Control" [RFC3551] specifies an initial set "payload types".  This
+list maintains and extends that list.
+
+Registry:
+PT        encoding name   audio/video (A/V)  clock rate (Hz)  channels (audio)  Reference
+--------  --------------  -----------------  ---------------  ----------------  ---------
+0         PCMU            A                  8000             1                 [RFC3551]
+1         Reserved	  
+2         Reserved
+3         GSM             A                  8000             1                 [RFC3551]
+4         G723            A                  8000             1                 [Kumar][RFC3551]
+5         DVI4            A                  8000             1                 [RFC3551]
+6         DVI4            A                  16000            1                 [RFC3551]
+7         LPC             A                  8000             1                 [RFC3551]
+8         PCMA            A                  8000             1                 [RFC3551]
+9         G722            A                  8000             1                 [RFC3551]
+10        L16             A                  44100            2                 [RFC3551]
+11        L16             A                  44100            1                 [RFC3551]
+12        QCELP           A                  8000             1                 [RFC3551]
+13        CN              A                  8000             1                 [RFC3389]
+14        MPA             A                  90000                              [RFC3551][RFC2250]
+15        G728            A                  8000             1                 [RFC3551]
+16        DVI4            A                  11025            1                 [DiPol]
+17        DVI4            A                  22050            1                 [DiPol]
+18        G729            A                  8000             1                 [RFC3551]
+19        Reserved        A
+20        Unassigned      A
+21        Unassigned      A
+22        Unassigned      A
+23        Unassigned      A
+24        Unassigned      V
+25        CelB            V                  90000                              [RFC2029]
+26        JPEG            V                  90000                              [RFC2435]
+27        Unassigned      V
+28        nv              V                  90000                              [RFC3551]
+29        Unassigned      V
+30        Unassigned      V
+31        H261            V                  90000                              [RFC4587]
+32        MPV             V                  90000                              [RFC2250]
+33        MP2T            AV                 90000                              [RFC2250]
+34        H263            V                  90000                              [Zhu]
+35-71     Unassigned      ?
+72-76     Reserved for RTCP conflict avoidance                                  [RFC3551]
+77-95     Unassigned      ?
+96-127    dynamic         ?                                                     [RFC3551] 
+
+
+Registry Name: RTP Payload Format media types
+Reference: [RFC4855]
+Registration Procedures: Standards Action Process or expert approval
+
+*/
+
+typedef struct _codecsmap {
+	str name;
+	str ids;
+} codecsmap_t;
+
+codecsmap_t sdpops_codecsmap_table[] = {
+	{ {"PCMU",  4},  {"0",         1} },
+	{ {"GSM",   3},  {"3",         1} },
+	{ {"G723",  4},  {"4",         1} },
+	{ {"DVI4",  4},  {"5,6,16,17", 9} },
+	{ {"LPC",   3},  {"7",         1} },
+	{ {"PCMA",  4},  {"8",         1} },
+	{ {"G722",  4},  {"9",         1} },
+	{ {"L16",   3},  {"10,11",     5} },
+	{ {"QCELP", 5},  {"12",        2} },
+	{ {"CN",    2},  {"13",        5} },
+	{ {"MPA",   3},  {"14",        2} },
+	{ {"G728",  4},  {"15",        2} },
+	{ {"G729",  4},  {"18",        2} },
+	{ {0, 0}, {0, 0} }
+};
+
+/**
+ * set the string with the IDs mapped to codec name
+ * - return 0 if found, -1 if not found
+ */
+int sdpops_get_ids_by_name(str *name, str *ids)
+{
+	int i;
+	for(i=0; sdpops_codecsmap_table[i].name.s!=0; i++)
+	{
+		if(name->len==sdpops_codecsmap_table[i].name.len
+				&& strncasecmp(sdpops_codecsmap_table[i].name.s, name->s,
+					name->len)==0)
+		{
+			*ids = sdpops_codecsmap_table[i].ids;
+			return 0;
+		}
+	}
+	ids->s = NULL;
+	ids->len = 0;
+	return -1;
+}
+
+/**
+ * build the csv list of ids from csv list of names
+ */
+int sdpops_build_ids_list(str *names, str *ids)
+{
+#define SDPOPS_MAX_LIST_SIZE	64
+	static char _local_idslist[SDPOPS_MAX_LIST_SIZE];
+	str tmp;
+	str codec;
+	str cids;
+	char *p;
+
+	tmp = *names;
+	ids->len = 0;
+	ids->s   = 0;
+	p = _local_idslist;
+	while(str_find_token(&tmp, &codec, ',')==0
+		&& codec.len>0)
+	{
+		tmp.len -= (int)(&codec.s[codec.len]-codec.s);
+		tmp.s = codec.s + codec.len;
+
+		if( sdpops_get_ids_by_name(&codec, &cids)==0) {
+			LM_DBG("codecs list [%.*s] - at name [%.*s] with ids [%.*s]\n",
+				names->len, names->s,
+				codec.len, codec.s,
+				cids.len,  cids.s);
+			if(ids->len + cids.len>=SDPOPS_MAX_LIST_SIZE)
+			{
+				LM_ERR("the list with codecs ids is too big\n");
+				ids->len = 0;
+				ids->s = 0;
+				return -1;
+			}
+			strncpy(p, cids.s, cids.len);
+			p += cids.len;
+			*p = ',';
+			p++;
+			ids->len += cids.len + 1;
+		}
+	}
+	if(ids->len>0)
+	{
+		p--;
+		ids->len--;
+		*p = '\0';
+		ids->s = _local_idslist;
+		LM_DBG("codecs list [%.*s] - ids list [%.*s]\n",
+				names->len, names->s,
+				ids->len, ids->s);
+		return 0;
+	}
+	return -1;
+}
+
+
+/**
+ *
+ */
+int str_find_token(str *text, str *result, char delim)
+{
+	int i;
+	if(text==NULL || result==NULL)
+		return -1;
+	if(text->s[0] == delim)
+	{
+		 text->s += 1;
+		 text->len -= 1;
+	}
+	trim_leading(text);
+	result->s = text->s;
+	result->len = 0;
+	for (i=0; i<text->len; i++)
+	{
+		if(result->s[i]==delim || result->s[i]=='\0'
+				|| result->s[i]=='\r' || result->s[i]=='\n')
+			return 0;
+		result->len++;
+	}
+	return 0;
+}

+ 33 - 0
modules/sdpops/sdpops_data.h

@@ -0,0 +1,33 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2011 Daniel-Constantin Mierla (asipto.com)
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+
+#ifndef _SDPOPS_DATA_H_
+#define _SDPOPS_DATA_H_
+#include "../../str.h"
+
+int sdpops_get_ids_by_name(str *name, str *ids);
+int str_find_token(str *text, str *result, char delim);
+int sdpops_build_ids_list(str *names, str *ids);
+
+#endif

+ 53 - 27
modules/sdpops/sdpops_mod.c

@@ -30,14 +30,16 @@
 #include "../../dprint.h"
 #include "../../mod_fix.h"
 #include "../../pvar.h"
-#include "../../trim.h"
 #include "../../parser/sdp/sdp.h"
+#include "../../trim.h"
 #include "../../data_lump.h"
 
+#include "sdpops_data.h"
 
 MODULE_VERSION
 
 static int w_sdp_remove_codecs_by_id(sip_msg_t* msg, char* codecs, char *bar);
+static int w_sdp_remove_codecs_by_name(sip_msg_t* msg, char* codecs, char *bar);
 static int w_sdp_with_media(sip_msg_t* msg, char* media, char *bar);
 static int w_sdp_print(sip_msg_t* msg, char* level, char *bar);
 
@@ -46,6 +48,8 @@ static int mod_init(void);
 static cmd_export_t cmds[] = {
 	{"sdp_remove_codecs_by_id",    (cmd_function)w_sdp_remove_codecs_by_id,
 		1, fixup_spve_null,  0, ANY_ROUTE},
+	{"sdp_remove_codecs_by_name",  (cmd_function)w_sdp_remove_codecs_by_name,
+		1, fixup_spve_null,  0, ANY_ROUTE},
 	{"sdp_with_media",             (cmd_function)w_sdp_with_media,
 		1, fixup_spve_null,  0, ANY_ROUTE},
 	{"sdp_print",                  (cmd_function)w_sdp_print,
@@ -93,32 +97,6 @@ static int mod_init(void)
 }
 
 
-/**
- *
- */
-int str_find_token(str *text, str *result, char delim)
-{
-	int i;
-	if(text==NULL || result==NULL)
-		return -1;
-	if(text->s[0] == delim)
-	{
-		 text->s += 1;
-		 text->len -= 1;
-	}
-	trim_leading(text);
-	result->s = text->s;
-	result->len = 0;
-	for (i=0; i<text->len; i++)
-	{
-		if(result->s[i]==delim || result->s[i]=='\0'
-				|| result->s[i]=='\r' || result->s[i]=='\n')
-			return 0;
-		result->len++;
-	}
-	return 0;
-}
-
 /**
  *
  */
@@ -316,6 +294,54 @@ static int w_sdp_remove_codecs_by_id(sip_msg_t* msg, char* codecs, char* bar)
 	return 1;
 }
 
+/**
+ *
+ */
+int sdp_remove_codecs_by_name(sip_msg_t* msg, str* codecs)
+{
+	str idslist;
+
+	if(parse_sdp(msg) < 0) {
+		LM_ERR("Unable to parse sdp\n");
+		return -1;
+	}
+
+	LM_ERR("attempting to remove codecs from sdp: [%.*s]\n",
+			codecs->len, codecs->s);
+
+	if(sdpops_build_ids_list(codecs, &idslist)<0)
+		return -1;
+
+	if(sdp_remove_codecs_by_id(msg, &idslist)<0)
+		return -1;
+
+	return 0;
+
+}
+/**
+ *
+ */
+static int w_sdp_remove_codecs_by_name(sip_msg_t* msg, char* codecs, char* bar)
+{
+	str lcodecs = {0, 0};
+
+	if(codecs==0)
+	{
+		LM_ERR("invalid parameters\n");
+		return -1;
+	}
+
+	if(fixup_get_svalue(msg, (gparam_p)codecs, &lcodecs)!=0)
+	{
+		LM_ERR("unable to get the list of codecs\n");
+		return -1;
+	}
+
+	if(sdp_remove_codecs_by_name(msg, &lcodecs)<0)
+		return -1;
+	return 1;
+}
+
 
 /** 
  * @brief check 'media' matches the value of any 'm=value ...' lines

+ 1 - 1
modules/tls/Makefile

@@ -32,7 +32,7 @@ install-tls-cert: $(cfg_prefix)/$(cfg_dir)
 install-cfg:  install-tls-cert
 	@$(call try_err, $(INSTALL_TOUCH) \
 			"$(cfg_prefix)/$(cfg_dir)tls.cfg.sample" )
-	@sed -e "s#\./modules/tls/#$(cfg_prefix)/$(cfg_dir)#g" \
+	@sed -e "s#\./modules/tls/#$(cfg_target)#g" \
 			-e "s#ser-selfsigned#$(MAIN_NAME)-selfsigned#g" \
 				< ./tls.cfg > "$(cfg_prefix)/$(cfg_dir)tls.cfg.sample"
 	@if [ -z "${skip_cfg_install}" -a \

+ 18 - 2
modules/tm/h_table.c

@@ -97,13 +97,29 @@ enum kill_reason get_kr() {
 
 void lock_hash(int i) 
 {
-	lock(&_tm_table->entries[i].mutex);
+
+	int mypid;
+
+	mypid = my_pid();
+	if (likely(atomic_get(&_tm_table->entries[i].locker_pid) != mypid)) {
+		lock(&_tm_table->entries[i].mutex);
+		atomic_set(&_tm_table->entries[i].locker_pid, mypid);
+	} else {
+		/* locked within the same process that called us*/
+		_tm_table->entries[i].rec_lock_level++;
+	}
 }
 
 
 void unlock_hash(int i) 
 {
-	unlock(&_tm_table->entries[i].mutex);
+	if (likely(_tm_table->entries[i].rec_lock_level == 0)) {
+		atomic_set(&_tm_table->entries[i].locker_pid, 0);
+		unlock(&_tm_table->entries[i].mutex);
+	} else  {
+		/* recursive locked => decrease rec. lock count */
+		_tm_table->entries[i].rec_lock_level--;
+	}
 }
 
 

+ 2 - 0
modules/tm/h_table.h

@@ -429,6 +429,8 @@ typedef struct entry
 	struct cell*    prev_c;
 	/* sync mutex */
 	ser_lock_t      mutex;
+	atomic_t locker_pid; /* pid of the process that holds the lock */
+	int rec_lock_level; /* recursive lock count */
 	/* currently highest sequence number in a synonym list */
 	unsigned int    next_label;
 #ifdef TM_HASH_STATS

+ 2 - 2
modules/tm/tm.c

@@ -402,9 +402,9 @@ static cmd_export_t cmds[]={
 	{"t_relay_cancel",     w_t_relay_cancel,        0, 0,
 			REQUEST_ROUTE},
 	{"t_on_failure",       w_t_on_negative,         1, fixup_on_failure,
-			REQUEST_ROUTE | FAILURE_ROUTE | TM_ONREPLY_ROUTE },
+			REQUEST_ROUTE | FAILURE_ROUTE | TM_ONREPLY_ROUTE | BRANCH_ROUTE },
 	{"t_on_reply",         w_t_on_reply,            1, fixup_on_reply,
-			REQUEST_ROUTE | FAILURE_ROUTE | TM_ONREPLY_ROUTE },
+			REQUEST_ROUTE | FAILURE_ROUTE | TM_ONREPLY_ROUTE | BRANCH_ROUTE },
 	{"t_on_branch",       w_t_on_branch,         1, fixup_on_branch,
 			REQUEST_ROUTE | FAILURE_ROUTE },
 	{"t_check_status",     t_check_status,          1, fixup_t_check_status,

+ 14 - 4
modules/xmlops/Makefile

@@ -1,4 +1,3 @@
-# $Id$
 #
 # XML operations 
 # 
@@ -10,9 +9,20 @@ auto_gen=
 NAME=xmlops.so
 LIBS=
 
-DEFS+=-I/usr/include/libxml2 -I$(LOCALBASE)/include/libxml2 \
-      -I$(LOCALBASE)/include
-LIBS+=-L$(SYSBASE)/include/lib  -L$(LOCALBASE)/lib -lxml2
+XML2CFG=$(shell which xml2-config)
+
+ifneq ($(XML2CFG),)
+
+	DEFS += $(shell $(XML2CFG) --cflags )
+	LIBS += $(shell $(XML2CFG) --libs)
+
+else
+
+	DEFS+=-I/usr/include/libxml2 -I$(LOCALBASE)/include/libxml2 \
+		-I$(LOCALBASE)/include
+	LIBS+=-L$(LOCALBASE)/lib -lxml2
+
+endif
 
 DEFS+=-DOPENSER_MOD_INTERFACE
 

+ 12 - 5
modules_k/acc/acc_mod.c

@@ -403,8 +403,13 @@ static int mod_init( void )
 		return -1;
 
 #ifdef SQL_ACC
-	if (db_url.s)
+	if (db_url.s) {
 		db_url.len = strlen(db_url.s);
+		if(db_url.len<=0) {
+			db_url.s = NULL;
+			db_url.len = 0;
+		}
+	}
 	db_table_acc.len = strlen(db_table_acc.s);
 	db_table_mc.len = strlen(db_table_mc.s);
 	acc_method_col.len = strlen(acc_method_col.s);
@@ -523,8 +528,10 @@ static int mod_init( void )
 			return -1;
 		}
 	} else {
-		db_flag = 0;
-		db_missed_flag = 0;
+		db_url.s = NULL;
+		db_url.len = 0;
+		db_flag = -1;
+		db_missed_flag = -1;
 	}
 #endif
 
@@ -555,8 +562,8 @@ static int mod_init( void )
 		}
 	} else {
 		radius_config = 0;
-		radius_flag = 0;
-		radius_missed_flag = 0;
+		radius_flag = -1;
+		radius_missed_flag = -1;
 	}
 #endif
 

+ 1 - 1
modules_k/acc_radius/acc_radius_mod.c

@@ -88,7 +88,7 @@ acc_extra_t *rad_extra = 0;
 static cmd_export_t cmds[] = {
 	{"acc_rad_request", (cmd_function)w_acc_radius_request, 1,
 		acc_api_fixup, free_acc_api_fixup,
-		REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE},
+		ANY_ROUTE},
 	{0, 0, 0, 0, 0, 0}
 };
 

+ 44 - 41
modules_k/auth_radius/README

@@ -224,17 +224,18 @@ modparam("auth_radius", "use_ruri_flag", 22)
    respond with 401 that includes this header, which will challenge the
    user again.
 
-   Negative codes may be interpreted as follows:
-     * -5 (internal error) - some internal error occurred;
-     * -4 (no credentials) - credentials were not found in request;
-     * -3 (stale nonce) - stale nonce;
-     * -2 (bad request) - something wrong in request, for example,
-       credentials were not filled properly;
-     * -1 (authorization failed) - RADIUS responded with Access Reject
-
-   This function will, in fact, perform sanity checks over the received
-   credentials and then pass them along to the radius server which will
-   verify the credentials and return whether they are valid or not.
+   Negative result codes may be interpreted as follows:
+     * -7 (internal error) - some internal error occurred (see syslog);
+     * -6 (nonce reused) - nonce is used more than once;
+     * -5 (no credentials) - credentials were not found in request;
+     * -4 (stale nonce) - stale nonce;
+     * -3 (authorization failed) - RADIUS responded with Access Reject
+       which may be, for example, due to user not found or wrong password;
+     * -1 (error) - some error occured during authorization (see syslog);
+
+   This function will perform sanity checks over the received credentials
+   and then pass them along to RADIUS server which will verify the
+   credentials and return whether they are valid or not.
 
    Meaning of the parameter is as follows:
      * realm - Realm is a opaque string that the user agent should present
@@ -247,21 +248,22 @@ modparam("auth_radius", "use_ruri_flag", 22)
    Example 1.6. radius_www_authorize usage
 ...
     if (!radius_www_authorize("$td")) {
-    switch ($rc) {
-    case -5:
-        send_reply("500", "Server Internal Error");
+        switch ($rc) {
+        case -7:
+            send_reply("500", "Server Internal Error");
+            exit;
+        case -1:
+            send_reply("400", "Bad Request");
+            exit;
+        default:
+        };
+        if (defined($avp(digest_challenge)) &&
+                ($avp(digest_challenge) != "")) {
+            append_to_reply("$avp(digest_challenge)");
+        };
+        send_reply("401", "Unauthorized");
         exit;
-    case -2:
-        send_reply("400", "Bad Request");
-        exit;
-    default:
-    };
-    if (defined($avp(digest_challenge)) &&
-            ($avp(digest_challenge) != "")) {
-        append_to_reply("$avp(digest_challenge)");
     };
-    send_reply("401", "Unauthorized");
-    exit;
 ...
 
 5.2. radius_proxy_authorize(realm [, uri_user])
@@ -275,11 +277,11 @@ modparam("auth_radius", "use_ruri_flag", 22)
    it fails and assigns a Proxy-Authorize header containing a new
    challenge to digest_challenge AVP. The script should then respond with
    407 that includes this header, which will challenge the user again. For
-   more about the negative return codes, see the above function.
+   negative result codes, see the above function.
 
-   This function will, in fact, perform sanity checks over the received
-   credentials and then pass them along to the radius server which will
-   verify the credentials and return whether they are valid or not.
+   This function will perform sanity checks over the received credentials
+   and then pass them along to RADIUS server which will verify the
+   credentials and return whether they are valid or not.
 
    Meaning of the parameters is as follows:
      * realm - Realm is a opaque string that the user agent should present
@@ -298,19 +300,20 @@ modparam("auth_radius", "use_ruri_flag", 22)
    Example 1.7. proxy_authorize usage
 ...
     if (!radius_proxy_authorize("$pd", "$pU")) { # Realm and URI user are taken
-    switch ($rc) {                               # from P-Preferred-Identity
-    case -5:                                     # header field
-        send_reply("500", "Server Internal Error");
+        switch ($rc) {                           # from P-Preferred-Identity
+        case -7:                                 # header field
+            send_reply("500", "Server Internal Error");
+            exit;
+        case -1:
+            send_reply("400", "Bad Request");
+            exit;
+        default:
+        };
+        if (defined($avp(digest_challenge)) &&
+                ($avp(digest_challenge) != "")) {
+            append_to_reply("$avp(digest_challenge)");
+        };
+        send_reply("407", "Proxy Authentication Required");
         exit;
-    case -2:
-        send_reply("400", "Bad Request");
-        exit;
-    default:
-    };
-    if (defined($avp(digest_challenge)) &&
-            ($avp(digest_challenge) != "")) {
-        append_to_reply("$avp(digest_challenge)");
     };
-    send_reply("407", "Proxy Authentication Required");
-    exit;
 ...

+ 24 - 17
modules_k/auth_radius/authorize.c

@@ -110,23 +110,32 @@ static inline int authorize(struct sip_msg* _msg, pv_elem_t* _realm,
 #ifdef EXTRA_DEBUG
 	abort();
 #endif
-	ret = -5;
+	ret = -7;
 	goto end;
 
-    case ERROR:
-    case BAD_CREDENTIALS:
-	ret = -2;
+    case NONCE_REUSED:
+	ret = AUTH_NONCE_REUSED;
+	goto end;
+
+    case STALE_NONCE:
+	ret = AUTH_STALE_NONCE;
 	goto end;
 	
+    case ERROR:
+    case BAD_CREDENTIALS:
     case NOT_AUTHENTICATED:
-	ret = -4;
+	ret = AUTH_ERROR;
+	goto end;
+
+    case NO_CREDENTIALS:
+	ret = AUTH_NO_CREDENTIALS;
 	goto end;
 	
     case DO_AUTHENTICATION:
 	break;
 	
     case AUTHENTICATED:
-	ret = 1;
+	ret = AUTH_OK;
 	goto end;
     }
 
@@ -143,24 +152,24 @@ static inline int authorize(struct sip_msg* _msg, pv_elem_t* _realm,
 					       &pv_val.rs);
 	    } else {
 		LM_ERR("uri_user pvar value is not string\n");
-		ret = -5;
+		ret = AUTH_ERROR;
 		goto end;
 	    }
 	} else {
 	    LM_ERR("cannot get uri_user pvar value\n");
-	    ret = -5;
+	    ret = AUTH_ERROR;
 	    goto end;
 	}
     } else {
 	if (get_uri_user(_msg, &uri_user) < 0) {
 	    LM_ERR("To/From URI not found\n");
-	    ret = -2;
+	    ret = AUTH_ERROR;;
 	    goto end;
 	}
 	user.s = (char *)pkg_malloc(uri_user->len);
 	if (user.s == NULL) {
 	    LM_ERR("no pkg memory left for user\n");
-	    ret = -5;
+	    ret = -7;
 	    goto end;
 	}
 	un_escape(uri_user, &user);
@@ -177,20 +186,18 @@ static inline int authorize(struct sip_msg* _msg, pv_elem_t* _realm,
 #ifdef EXTRA_DEBUG
 	    abort();
 #endif
-	    ret = -5;
+	    ret = -7;
 	    break;
 	case ERROR:             
-	    ret = -2;
-	    break;
 	case NOT_AUTHENTICATED:
-	    ret = -3;
+	    ret = AUTH_ERROR;
 	    break;
 	case AUTHENTICATED:
-	    ret = 1;
+	    ret = AUTH_OK;
 	    break;
 	}
     } else {
-	ret = -1;
+	ret = AUTH_INVALID_PASSWORD;
     }
 
  end:
@@ -199,7 +206,7 @@ static inline int authorize(struct sip_msg* _msg, pv_elem_t* _realm,
 	if (auth_api.build_challenge(_msg, (cred ? cred->stale : 0), &domain,
 				     NULL, NULL, _hftype) < 0) {
 	    LM_ERR("while creating challenge\n");
-	    ret = -5;
+	    ret = -7;
 	}
     }
     return ret;

+ 43 - 42
modules_k/auth_radius/doc/auth_radius_admin.xml

@@ -210,32 +210,32 @@ modparam("auth_radius", "use_ruri_flag", 22)
 	then respond with 401 that includes this header, which will
 	challenge the user again.
 		</para>
-		<para>Negative codes may be interpreted as follows:</para>
+		<para>Negative result codes may be interpreted as follows:</para>
 		<itemizedlist>
 			<listitem><para>
-			<emphasis>-5 (internal error)</emphasis> - some
-			internal error occurred;
+			<emphasis>-7 (internal error)</emphasis> - some
+			internal error occurred (see syslog);
 			</para></listitem>
 			<listitem><para>
-			<emphasis>-4 (no credentials)</emphasis> -
-			credentials were not found in request;
+			<emphasis>-6 (nonce reused)</emphasis> - nonce is used more than once;
 			</para></listitem>
 			<listitem><para>
-			<emphasis>-3 (stale nonce)</emphasis> - stale nonce;
+			<emphasis>-5 (no credentials)</emphasis> - credentials were not found in request;
 			</para></listitem>
 			<listitem><para>
-			<emphasis>-2 (bad request)</emphasis> -
-			something wrong in request, for example, credentials were not filled properly;
+			<emphasis>-4 (stale nonce)</emphasis> - stale nonce;
 			</para></listitem>
 			<listitem><para>
-			<emphasis>-1 (authorization failed)</emphasis> -
-			RADIUS responded with Access Reject
+			<emphasis>-3 (authorization failed)</emphasis> - RADIUS responded with Access Reject which may be, for example, due to user not found or wrong password;
+			</para></listitem>
+			<listitem><para>
+			<emphasis>-1 (error)</emphasis> - some error occured during authorization (see syslog);
 			</para></listitem>
 		</itemizedlist>
 		<para>
-		This function will, in fact, perform sanity checks over
+		This function will perform sanity checks over
 	the received  
-		credentials and then pass them along to the radius
+		credentials and then pass them along to RADIUS
 	server which will  
 		verify the credentials and return whether they are valid or not.
 		</para>
@@ -262,21 +262,22 @@ modparam("auth_radius", "use_ruri_flag", 22)
 		<programlisting format="linespecific">
 ...
     if (!radius_www_authorize("$td")) {
-    switch ($rc) {
-    case -5:
-	send_reply("500", "Server Internal Error");
-	exit;
-    case -2:
-        send_reply("400", "Bad Request");
+        switch ($rc) {
+        case -7:
+	    send_reply("500", "Server Internal Error");
+	    exit;
+        case -1:
+	    send_reply("400", "Bad Request");
+	    exit;
+        default:
+        };
+        if (defined($avp(digest_challenge)) &amp;&amp;
+                ($avp(digest_challenge) != "")) {
+            append_to_reply("$avp(digest_challenge)");
+        };
+        send_reply("401", "Unauthorized");
         exit;
-    default:
     };
-    if (defined($avp(digest_challenge)) &amp;&amp;
-            ($avp(digest_challenge) != "")) {
-        append_to_reply("$avp(digest_challenge)");
-    };
-    send_reply("401", "Unauthorized");
-    exit;
 ...
 </programlisting>
 		</example>
@@ -298,12 +299,11 @@ modparam("auth_radius", "use_ruri_flag", 22)
 	challenge to digest_challenge AVP.  The script should
 	then respond with 407 that includes this header, which will
 	challenge the user again.
-		For more about the negative return 
-		codes, see the above function.
+		For negative result codes, see the above function.
 		</para>
 		<para>
-		This function will, in fact, perform sanity checks over the received 
-		credentials and then pass them along to the radius server which will 
+		This function will perform sanity checks over the received 
+		credentials and then pass them along to RADIUS server which will 
 		verify the credentials and return whether they are valid or not.
 		</para>
 		<para>Meaning of the parameters is as follows:</para>
@@ -339,21 +339,22 @@ modparam("auth_radius", "use_ruri_flag", 22)
 		<programlisting format="linespecific">
 ...
     if (!radius_proxy_authorize("$pd", "$pU")) { # Realm and URI user are taken
-    switch ($rc) {                               # from P-Preferred-Identity
-    case -5:                                     # header field
-	send_reply("500", "Server Internal Error");
-	exit;
-    case -2:
-        send_reply("400", "Bad Request");
+        switch ($rc) {                           # from P-Preferred-Identity
+        case -7:                                 # header field
+	    send_reply("500", "Server Internal Error");
+	    exit;
+        case -1:
+	    send_reply("400", "Bad Request");
+	    exit;
+        default:
+        };
+        if (defined($avp(digest_challenge)) &amp;&amp;
+                ($avp(digest_challenge) != "")) {
+            append_to_reply("$avp(digest_challenge)");
+        };
+        send_reply("407", "Proxy Authentication Required");
         exit;
-    default:
-    };
-    if (defined($avp(digest_challenge)) &amp;&amp;
-            ($avp(digest_challenge) != "")) {
-        append_to_reply("$avp(digest_challenge)");
     };
-    send_reply("407", "Proxy Authentication Required");
-    exit;
 ...
 </programlisting>
 		</example>

+ 25 - 0
modules_k/db_sqlite/Makefile

@@ -0,0 +1,25 @@
+# $Id$
+#
+# WARNING: do not run this directly, it should be run by the master Makefile
+
+include ../../Makefile.defs
+auto_gen=
+NAME=db_sqlite.so
+
+LIBS +=-lsqlite3
+
+DEFS+=-DOPENSER_MOD_INTERFACE
+
+SERLIBPATH=../../lib
+SER_LIBS+=$(SERLIBPATH)/srdb1/srdb1
+include ../../Makefile.modules
+
+ifeq ($(INSTALL_FLAVOUR),kamailio)
+# extra install for kamailio
+
+install-sqlite-scripts: $(bin_prefix)/$(bin_dir)
+		SQLITEON=yes make -C ../../utils/kamctl/ install-modules
+
+install-scripts: install-sqlite-scripts
+
+endif # INSTALL_FLAVOUR

+ 69 - 0
modules_k/db_sqlite/README

@@ -0,0 +1,69 @@
+SQlite Module
+
+Timo Teräs
+
+Edited by
+
+Timo Teräs
+
+   Copyright © 2011 Timo Teräs
+   Revision History
+   Revision $Revision$ $Date$
+     __________________________________________________________________
+
+   Table of Contents
+
+   1. Admin Guide
+
+        1. Overview
+        2. Dependencies
+
+              2.1. Kamailio Modules
+              2.2. External Libraries or Applications
+
+        3. Exported Parameters
+        4. Exported Functions
+
+Chapter 1. Admin Guide
+
+   Table of Contents
+
+   1. Overview
+   2. Dependencies
+
+        2.1. Kamailio Modules
+        2.2. External Libraries or Applications
+
+   3. Exported Parameters
+   4. Exported Functions
+
+1. Overview
+
+   The module is an implementation of the internal DB API v1 connector for
+   SQlite 3 file.
+
+2. Dependencies
+
+   2.1. Kamailio Modules
+   2.2. External Libraries or Applications
+
+2.1. Kamailio Modules
+
+   The following modules must be loaded before this module:
+     * No dependencies on other Kamailio modules.
+
+2.2. External Libraries or Applications
+
+   The following libraries or applications must be installed before
+   running Kamailio with this module loaded:
+     * SQlite 3 library - e.g., libsqlite3-0
+     * SQlite 3 devel library - to compile the module e.g. libsqlite3-dev
+     * SQlite 3 utilities - for kamdbctl e.g. sqlite3
+
+3. Exported Parameters
+
+   NONE
+
+4. Exported Functions
+
+   NONE

+ 90 - 0
modules_k/db_sqlite/db_sqlite.c

@@ -0,0 +1,90 @@
+/*
+ * $Id$
+ *
+ * SQlite module interface
+ *
+ * Copyright (C) 2010 Timo Teräs
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <sys/time.h>
+#include <sqlite3.h>
+
+#include "../../sr_module.h"
+#include "../../lib/srdb1/db.h"
+#include "dbase.h"
+
+MODULE_VERSION
+
+static int sqlite_bind_api(db_func_t *dbb)
+{
+	if(dbb==NULL)
+		return -1;
+
+	memset(dbb, 0, sizeof(db_func_t));
+
+	dbb->use_table		= db_sqlite_use_table;
+	dbb->init		= db_sqlite_init;
+	dbb->close		= db_sqlite_close;
+	dbb->free_result	= db_sqlite_free_result;
+	dbb->query		= db_sqlite_query;
+	dbb->insert		= db_sqlite_insert;
+	dbb->delete		= db_sqlite_delete;
+	dbb->update		= db_sqlite_update;
+	dbb->raw_query		= db_sqlite_raw_query;
+
+	return 0;
+}
+
+static cmd_export_t cmds[] = {
+	{"db_bind_api", (cmd_function)sqlite_bind_api, 0, 0, 0, 0},
+	{0, 0, 0, 0, 0, 0}
+};
+
+static int sqlite_mod_init(void)
+{
+	sqlite3_initialize();
+
+	LM_INFO("SQlite library version %s (compiled using %s)\n",
+		sqlite3_libversion(),
+		SQLITE_VERSION);
+	return 0;
+}
+
+
+static void sqlite_mod_destroy(void)
+{
+	LM_INFO("SQlite terminate\n");
+
+	sqlite3_shutdown();
+}
+
+struct module_exports exports = {
+	"db_sqlite",
+	DEFAULT_DLFLAGS,	/* dlopen flags */
+	cmds,			/* module commands */
+	0,			/* module parameters */
+	0,			/* exported statistics */
+	0,			/* exported MI functions */
+	0,			/* exported pseudo-variables */
+	0,			/* extra processes */
+	sqlite_mod_init,	/* module initialization function */
+	0,			/* response function*/
+	sqlite_mod_destroy,	/* destroy function */
+	0			/* per-child init function */
+};

+ 526 - 0
modules_k/db_sqlite/dbase.c

@@ -0,0 +1,526 @@
+/*
+ * $Id$
+ *
+ * SQlite module core functions
+ *
+ * Copyright (C) 2010 Timo Teräs
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "../../mem/mem.h"
+#include "../../dprint.h"
+#include "../../lib/srdb1/db_pool.h"
+#include "../../lib/srdb1/db_ut.h"
+#include "../../lib/srdb1/db_res.h"
+#include "../../lib/srdb1/db_query.h"
+#include "dbase.h"
+
+static time_t sqlite_to_timet(double rT)
+{
+	return 86400.0*(rT - 2440587.5) + 0.5;
+}
+
+static double timet_to_sqlite(time_t t)
+{
+	return ((((double) t) - 0.5) / 86400.0) + 2440587.5;
+}
+
+/*
+ * Initialize database module
+ * No function should be called before this
+ */
+
+static struct sqlite_connection * db_sqlite_new_connection(const struct db_id* id)
+{
+	struct sqlite_connection *con;
+	int rc;
+
+	con = pkg_malloc(sizeof(*con));
+	if (!con) {
+		LM_ERR("failed to allocate driver connection\n");
+		return NULL;
+	}
+
+	memset(con, 0, sizeof(*con));
+	con->hdr.ref = 1;
+	con->hdr.id = (struct db_id*) id; /* set here - freed on error */
+
+	rc = sqlite3_open_v2(id->database, &con->conn,
+		SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL);
+	if (rc != SQLITE_OK) {
+		pkg_free(con);
+		LM_ERR("failed to open sqlite database '%s'\n", id->database);
+		return NULL;
+	}
+
+	return con;
+}
+
+db1_con_t* db_sqlite_init(const str* _url)
+{
+	return db_do_init(_url, (void *) db_sqlite_new_connection);
+}
+
+
+/*
+ * Shut down database module
+ * No function should be called after this
+ */
+
+static void db_sqlite_free_connection(struct sqlite_connection* con)
+{
+	if (!con) return;
+
+	sqlite3_close(con->conn);
+	free_db_id(con->hdr.id);
+	pkg_free(con);
+}
+
+void db_sqlite_close(db1_con_t* _h)
+{
+	db_do_close(_h, db_sqlite_free_connection);
+}
+
+/*
+ * Release a result set from memory
+ */
+int db_sqlite_free_result(db1_con_t* _h, db1_res_t* _r)
+{
+	if (!_h || !_r) {
+		LM_ERR("invalid parameter value\n");
+		return -1;
+	}
+
+	if (db_free_result(_r) < 0)
+	{
+		LM_ERR("failed to free result structure\n");
+		return -1;
+	}
+	return 0;
+}
+
+/*
+ * Store name of table that will be used by
+ * subsequent database functions
+ */
+int db_sqlite_use_table(db1_con_t* _h, const str* _t)
+{
+	return db_use_table(_h, _t);
+}
+
+/*
+ * Reset query context
+ */
+static void db_sqlite_cleanup_query(const db1_con_t* _c)
+{
+	struct sqlite_connection *conn = CON_SQLITE(_c);
+	int rc;
+
+	if (conn->stmt != NULL) {
+		rc = sqlite3_finalize(conn->stmt);
+		if (rc != SQLITE_OK)
+			LM_ERR("finalize failed: %s\n",
+				sqlite3_errmsg(conn->conn));
+	}
+
+	conn->stmt = NULL;
+	conn->bindpos = 0;
+}
+
+/*
+ * Convert value to sql-string as db bind index
+ */
+static int db_sqlite_val2str(const db1_con_t* _c, const db_val_t* _v, char* _s, int* _len)
+{
+	struct sqlite_connection *conn;
+	int ret;
+
+	if (!_c || !_v || !_s || !_len || *_len <= 0) {
+		LM_ERR("invalid parameter value\n");
+		return -1;
+	}
+
+	conn = CON_SQLITE(_c);
+	if (conn->bindpos >= DB_SQLITE_MAX_BINDS) {
+		LM_ERR("too many bindings, recompile with larger DB_SQLITE_MAX_BINDS\n");
+		return -2;
+	}
+
+	conn->bindarg[conn->bindpos] = _v;
+	ret = snprintf(_s, *_len, "?%u", ++conn->bindpos);
+	if ((unsigned)ret >= (unsigned) *_len)
+		return -11;
+
+	*_len = ret;
+	return 0;
+}
+
+/*
+ * Send an SQL query to the server
+ */
+static int db_sqlite_submit_query(const db1_con_t* _h, const str* _s)
+{
+	struct sqlite_connection *conn = CON_SQLITE(_h);
+	sqlite3_stmt *stmt;
+	const db_val_t *val;
+	int rc, i;
+
+	LM_DBG("submit_query: %.*s\n", _s->len, _s->s);
+
+	rc = sqlite3_prepare_v2(conn->conn, _s->s, _s->len, &stmt, NULL);
+	if (rc != SQLITE_OK) {
+		LM_ERR("failed to prepare statement: %s\n",
+			sqlite3_errmsg(conn->conn));
+		return -1;
+	}
+	conn->stmt = stmt;
+
+	for (i = 1; i <= conn->bindpos; i++) {
+		val = conn->bindarg[i-1];
+		if (VAL_NULL(val)) {
+			rc = sqlite3_bind_null(stmt, i);
+		} else switch (VAL_TYPE(val)) {
+		case DB1_INT:
+			rc = sqlite3_bind_int(stmt, i, VAL_INT(val));
+			break;
+		case DB1_BIGINT:
+			rc = sqlite3_bind_int64(stmt, i, VAL_BIGINT(val));
+			break;
+		case DB1_DOUBLE:
+			rc = sqlite3_bind_double(stmt, i, VAL_DOUBLE(val));
+			break;
+		case DB1_STRING:
+			rc = sqlite3_bind_text(stmt, i,
+				VAL_STRING(val), -1, NULL);
+			break;
+		case DB1_STR:
+			rc = sqlite3_bind_text(stmt, i,
+				VAL_STR(val).s, VAL_STR(val).len, NULL);
+			break;
+		case DB1_DATETIME:
+			rc = sqlite3_bind_double(stmt, i, timet_to_sqlite(VAL_TIME(val)));
+			break;
+		case DB1_BLOB:
+			rc = sqlite3_bind_blob(stmt, i,
+				VAL_BLOB(val).s, VAL_BLOB(val).len,
+				NULL);
+			break;
+		case DB1_BITMAP:
+			rc = sqlite3_bind_int(stmt, i, VAL_BITMAP(val));
+			break;
+		default:
+			LM_ERR("unknown bind value type %d\n", VAL_TYPE(val));
+			return -1;
+		}
+		if (rc != SQLITE_OK) {
+			LM_ERR("Parameter bind failed: %s\n",
+				sqlite3_errmsg(conn->conn));
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+static int decltype_to_dbtype(const char *decltype)
+{
+	/* SQlite3 has dynamic typing. It does not store the actual
+	 * exact type, instead it uses 'affinity' depending on the
+	 * value. We have to go through the declaration types to see
+	 * what to return. */
+	if (strstr(decltype, "INT") != NULL ||
+	    strncasecmp(decltype, "SERIAL", 6) == 0)
+		return DB1_INT;
+	if (strstr(decltype, "CHAR") != NULL)
+		return DB1_STRING;
+	if (strstr(decltype, "TEXT") != NULL)
+		return DB1_STR;
+	if (strstr(decltype, "REAL") != NULL ||
+	    strstr(decltype, "FLOA") != NULL ||
+	    strstr(decltype, "DOUB") != NULL)
+		return DB1_DOUBLE;
+	if (strstr(decltype, "BLOB") != NULL)
+		return DB1_BLOB;
+	if (strncasecmp(decltype, "TIME", 4) == 0 ||
+	    strncasecmp(decltype, "DATE", 4) == 0)
+		return DB1_DATETIME;
+
+	LM_ERR("sqlite decltype '%s' not recognized, defaulting to int",
+	       decltype);
+	return DB1_INT;
+}
+
+static str* str_dup(const char *_s)
+{
+	str *s;
+	int len = strlen(_s);
+
+	s = (str*) pkg_malloc(sizeof(str)+len+1);
+	if (!s)
+		return NULL;
+
+	s->len = len;
+	s->s = ((char*)s) + sizeof(str);
+	memcpy(s->s, _s, len);
+	s->s[len] = '\0';
+
+	return s;
+}
+
+static void str_assign(str* s, const char *_s, int len)
+{
+	s->s = (char *) pkg_malloc(len + 1);
+	if (s->s) {
+		s->len = len;
+		memcpy(s->s, _s, len);
+		s->s[len] = 0;
+	}
+}
+
+/*
+ * Read database answer and fill the structure
+ */
+int db_sqlite_store_result(const db1_con_t* _h, db1_res_t** _r)
+{
+	struct sqlite_connection *conn = CON_SQLITE(_h);
+	db1_res_t *res;
+	int i, rc, num_rows = 0, num_alloc = 0;
+	db_row_t *rows = NULL, *row;
+	db_val_t *val;
+
+	res = db_new_result();
+	if (res == NULL)
+		goto no_mem;
+
+	while (1) {
+		rc = sqlite3_step(conn->stmt);
+		if (rc == SQLITE_DONE) {
+			*_r = res;
+			return 0;
+		}
+		if (rc != SQLITE_ROW) {
+			LM_INFO("sqlite3_step failed: %s\n", sqlite3_errmsg(conn->conn));
+			goto err;
+		}
+		if (num_rows == 0) {
+			/* get column types */
+			rc = sqlite3_column_count(conn->stmt);
+			if (db_allocate_columns(res, rc) != 0)
+				goto err;
+			RES_COL_N(res) = rc;
+
+			for (i = 0; i < RES_COL_N(res); i++) {
+				RES_NAMES(res)[i] = str_dup(sqlite3_column_name(conn->stmt, i));
+				if (RES_NAMES(res)[i] == NULL)
+					goto no_mem;
+				RES_TYPES(res)[i] = decltype_to_dbtype(sqlite3_column_decltype(conn->stmt, i));
+			}
+		}
+		if (num_rows >= num_alloc) {
+			if (num_alloc)
+				num_alloc *= 2;
+			else
+				num_alloc = 8;
+			rows = pkg_realloc(rows, sizeof(db_row_t) * num_alloc);
+			if (rows == NULL)
+				goto no_mem;
+			RES_ROWS(res) = rows;
+		}
+
+		row = &RES_ROWS(res)[num_rows];
+		num_rows++;
+		RES_ROW_N(res) = num_rows;		/* rows in this result set */
+		RES_NUM_ROWS(res) = num_rows;		/* rows in total */
+
+		if (db_allocate_row(res, row) != 0)
+			goto no_mem;
+
+		for (i = 0, val = ROW_VALUES(row); i < RES_COL_N(res); i++, val++) {
+			VAL_TYPE(val) = RES_TYPES(res)[i];
+			VAL_NULL(val) = 0;
+			VAL_FREE(val) = 0;
+			if (sqlite3_column_type(conn->stmt, i) == SQLITE_NULL) {
+				VAL_NULL(val) = 1;
+			} else switch (VAL_TYPE(val)) {
+			case DB1_INT:
+				VAL_INT(val) = sqlite3_column_int(conn->stmt, i);
+				break;
+			case DB1_BIGINT:
+				VAL_BIGINT(val) = sqlite3_column_int64(conn->stmt, i);
+				break;
+			case DB1_STRING:
+				/* first field of struct str* is the char* so we can just
+				 * do whatever DB1_STR case does */
+			case DB1_STR:
+				str_assign(&VAL_STR(val),
+					(const char*) sqlite3_column_text(conn->stmt, i),
+					sqlite3_column_bytes(conn->stmt, i));
+				if (!VAL_STR(val).s)
+					goto no_mem;
+				VAL_FREE(val) = 1;
+				break;
+			case DB1_DOUBLE:
+				VAL_DOUBLE(val) = sqlite3_column_double(conn->stmt, i);
+				break;
+			case DB1_DATETIME:
+				VAL_TIME(val) = sqlite_to_timet(sqlite3_column_double(conn->stmt, i));
+				break;
+			case DB1_BLOB:
+				str_assign(&VAL_BLOB(val),
+					(const char*) sqlite3_column_blob(conn->stmt, i),
+					sqlite3_column_bytes(conn->stmt, i));
+				if (!VAL_STR(val).s)
+					goto no_mem;
+				VAL_FREE(val) = 1;
+				break;
+			default:
+				LM_ERR("unhandled db-type\n");
+				goto err;
+			}
+		}
+	}
+
+no_mem:
+	LM_ERR("no private memory left\n");
+err:
+	if (res)
+		db_free_result(res);
+	return -1;
+}
+
+/*
+ * Query table for specified rows
+ * _h: structure representing database connection
+ * _k: key names
+ * _op: operators
+ * _v: values of the keys that must match
+ * _c: column names to return
+ * _n: number of key=values pairs to compare
+ * _nc: number of columns to return
+ * _o: order by the specified column
+ */
+int db_sqlite_query(const db1_con_t* _h, const db_key_t* _k, const db_op_t* _op,
+		const db_val_t* _v, const db_key_t* _c, int _n, int _nc,
+		const db_key_t _o, db1_res_t** _r)
+{
+	int rc;
+
+	rc = db_do_query(_h, _k, _op, _v, _c, _n, _nc, _o, _r,
+			 db_sqlite_val2str,
+			 db_sqlite_submit_query,
+			 db_sqlite_store_result);
+	db_sqlite_cleanup_query(_h);
+
+	return rc;
+}
+
+static int db_sqlite_commit(const db1_con_t* _h)
+{
+	struct sqlite_connection *conn = CON_SQLITE(_h);
+	int rc;
+
+	rc = sqlite3_step(conn->stmt);
+	if (rc != SQLITE_DONE && rc != SQLITE_OK) {
+		LM_ERR("sqlite commit failed: %s\n",
+		       sqlite3_errmsg(conn->conn));
+		return -1;
+	}
+
+	return 0;
+}
+
+/*
+ * Insert a row into specified table
+ * _h: structure representing database connection
+ * _k: key names
+ * _v: values of the keys
+ * _n: number of key=value pairs
+ */
+int db_sqlite_insert(const db1_con_t* _h, const db_key_t* _k, const db_val_t* _v,
+		int _n)
+{
+	int rc = -1;
+
+	rc = db_do_insert(_h, _k, _v, _n,
+			  db_sqlite_val2str,
+			  db_sqlite_submit_query);
+	if (rc == 0)
+		rc = db_sqlite_commit(_h);
+	db_sqlite_cleanup_query(_h);
+
+	return rc;
+}
+
+
+/*
+ * Delete a row from the specified table
+ * _h: structure representing database connection
+ * _k: key names
+ * _o: operators
+ * _v: values of the keys that must match
+ * _n: number of key=value pairs
+ */
+int db_sqlite_delete(const db1_con_t* _h, const db_key_t* _k, const db_op_t* _o,
+		const db_val_t* _v, int _n)
+{
+	int rc;
+
+	rc = db_do_delete(_h, _k, _o, _v, _n,
+			  db_sqlite_val2str,
+			  db_sqlite_submit_query);
+	if (rc == 0)
+		rc = db_sqlite_commit(_h);
+	db_sqlite_cleanup_query(_h);
+
+	return rc;
+}
+
+
+/*
+ * Update some rows in the specified table
+ * _h: structure representing database connection
+ * _k: key names
+ * _o: operators
+ * _v: values of the keys that must match
+ * _uk: updated columns
+ * _uv: updated values of the columns
+ * _n: number of key=value pairs
+ * _un: number of columns to update
+ */
+int db_sqlite_update(const db1_con_t* _h, const db_key_t* _k, const db_op_t* _o,
+		const db_val_t* _v, const db_key_t* _uk, const db_val_t* _uv,
+		int _n, int _un)
+{
+	int rc;
+
+	rc = db_do_update(_h, _k, _o, _v, _uk, _uv, _n, _un,
+			  db_sqlite_val2str,
+			  db_sqlite_submit_query);
+	if (rc == 0)
+		rc = db_sqlite_commit(_h);
+	db_sqlite_cleanup_query(_h);
+
+	return rc;
+}
+
+int db_sqlite_raw_query(const db1_con_t* _h, const str* _s, db1_res_t** _r)
+{
+	return db_do_raw_query(_h, _s, _r,
+			       db_sqlite_submit_query,
+			       db_sqlite_store_result);
+}

+ 72 - 0
modules_k/db_sqlite/dbase.h

@@ -0,0 +1,72 @@
+/*
+ * $Id$
+ *
+ * SQlite module core functions
+ *
+ * Copyright (C) 2010 Timo Teräs
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+
+#ifndef DBASE_H
+#define DBASE_H
+
+#include <sqlite3.h>
+
+#include "../../lib/srdb1/db_pool.h"
+#include "../../lib/srdb1/db_con.h"
+#include "../../lib/srdb1/db_res.h"
+#include "../../lib/srdb1/db_key.h"
+#include "../../lib/srdb1/db_op.h"
+#include "../../lib/srdb1/db_val.h"
+
+#define DB_SQLITE_MAX_BINDS 64
+
+struct sqlite_connection {
+	struct pool_con hdr;
+
+	sqlite3 *conn;
+	int bindpos;
+
+	sqlite3_stmt *stmt;
+	const db_val_t *bindarg[DB_SQLITE_MAX_BINDS];
+};
+
+#define CON_SQLITE(db_con)	((struct sqlite_connection *) db_con->tail)
+
+db1_con_t* db_sqlite_init(const str* _sqlurl);
+void db_sqlite_close(db1_con_t* _h);
+
+int db_sqlite_free_result(db1_con_t* _h, db1_res_t* _r);
+
+int db_sqlite_query(const db1_con_t* _h, const db_key_t* _k, const db_op_t* _op,
+		const db_val_t* _v, const db_key_t* _c, int _n, int _nc,
+		const db_key_t _o, db1_res_t** _r);
+int db_sqlite_insert(const db1_con_t* _h, const db_key_t* _k, const db_val_t* _v,
+		int _n);
+int db_sqlite_delete(const db1_con_t* _h, const db_key_t* _k, const db_op_t* _o,
+		const db_val_t* _v, int _n);
+int db_sqlite_update(const db1_con_t* _h, const db_key_t* _k, const db_op_t* _o,
+		const db_val_t* _v, const db_key_t* _uk, const db_val_t* _uv,
+		int _n, int _un);
+int db_sqlite_raw_query(const db1_con_t* _h, const str* _s, db1_res_t** _r);
+
+int db_sqlite_use_table(db1_con_t* _h, const str* _t);
+
+
+#endif /* DBASE_H */

+ 4 - 0
modules_k/db_sqlite/doc/Makefile

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

+ 45 - 0
modules_k/db_sqlite/doc/db_sqlite.xml

@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding='ISO-8859-1'?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
+"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [
+
+<!-- Include general documentation entities -->
+<!ENTITY % docentities SYSTEM "../../../docbook/entities.xml">
+%docentities;
+
+]>
+
+<book xmlns:xi="http://www.w3.org/2001/XInclude">
+    <bookinfo>
+	<title>SQlite Module</title>
+	<productname class="trade">&kamailioname;</productname>
+	<authorgroup>
+	    <author>
+		<firstname>Timo</firstname>
+		<surname>Teräs</surname>
+		<address>
+		    <email>[email protected]</email>
+		</address>
+	    </author>
+	    <editor>
+		<firstname>Timo</firstname>
+		<surname>Teräs</surname>
+		<address>
+		    <email>[email protected]</email>
+		</address>
+	    </editor>
+	</authorgroup>
+	<copyright>
+	    <year>2011</year>
+	    <holder>Timo Teräs</holder>
+	</copyright>
+	<revhistory>
+	    <revision>
+		<revnumber>$Revision$</revnumber>
+		<date>$Date$</date>
+	    </revision>
+	</revhistory>
+    </bookinfo>
+    <toc></toc>
+
+	<xi:include href="db_sqlite_admin.xml"/>
+</book>

+ 78 - 0
modules_k/db_sqlite/doc/db_sqlite_admin.xml

@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding='ISO-8859-1'?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
+"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [
+
+<!-- Include general documentation entities -->
+<!ENTITY % docentities SYSTEM "../../../docbook/entities.xml">
+%docentities;
+
+]>
+
+<!-- Module User's Guide -->
+
+<chapter>
+	<title>&adminguide;</title>
+
+	<section>
+	<title>Overview</title>
+	<para>The module is an implementation of the internal DB API v1 connector
+		for SQlite 3 file.</para>
+	</section>
+	<section>
+	<title>Dependencies</title>
+	<section>
+		<title>&kamailio; Modules</title>
+		<para>
+		The following modules must be loaded before this module:
+			<itemizedlist>
+			<listitem>
+			<para>
+				<emphasis>No dependencies on other &kamailio; modules</emphasis>.
+			</para>
+			</listitem>
+			</itemizedlist>
+		</para>
+	</section>
+	<section>
+		<title>External Libraries or Applications</title>
+		<para>
+		The following libraries or applications must be installed before running
+		&kamailio; with this module loaded:
+			<itemizedlist>
+			<listitem>
+			<para>
+				<emphasis>SQlite 3 library</emphasis> - e.g., libsqlite3-0
+			</para>
+			</listitem>
+			<listitem>
+			<para>
+				<emphasis>SQlite 3 devel library</emphasis> - to compile
+				the module e.g. libsqlite3-dev
+			</para>
+			</listitem>
+			<listitem>
+			<para>
+				<emphasis>SQlite 3 utilities</emphasis> - for kamdbctl
+				e.g. sqlite3
+			</para>
+			</listitem>
+			</itemizedlist>
+		</para>
+	</section>
+	</section>
+
+	<section>
+	<title>Exported Parameters</title>
+		<para>
+		NONE
+		</para>
+	</section>
+
+	<section>
+	<title>Exported Functions</title>
+		<para>
+		NONE
+		</para>
+	</section>
+</chapter>
+

+ 21 - 6
modules_k/dialog/dialog.c

@@ -4,6 +4,7 @@
  * dialog module - basic support for dialog tracking
  *
  * Copyright (C) 2006 Voice Sistem SRL
+ * Copyright (C) 2011 Carsten Bock, [email protected]
  *
  * This file is part of Kamailio, a free SIP server.
  *
@@ -85,12 +86,12 @@ static char* rr_param = "did";
 static int dlg_flag = -1;
 static str timeout_spec = {NULL, 0};
 static int default_timeout = 60 * 60 * 12;  /* 12 hours */
+static int seq_match_mode = SEQ_MATCH_STRICT_ID;
 static char* profiles_wv_s = NULL;
 static char* profiles_nv_s = NULL;
 str dlg_extra_hdrs = {NULL,0};
 static int db_fetch_rows = 200;
 
-int seq_match_mode = SEQ_MATCH_STRICT_ID;
 str dlg_bridge_controller = {"sip:[email protected]", 27};
 
 str ruri_pvar_param = {"$ru", 3};
@@ -214,6 +215,13 @@ static param_export_t mod_params[]={
 	{ "from_sock_column",      STR_PARAM, &from_sock_column.s       },
 	{ "sflags_column",         STR_PARAM, &sflags_column.s          },
 	{ "toroute_name_column",   STR_PARAM, &toroute_name_column.s    },
+
+	{ "vars_table_name",       STR_PARAM, &dialog_vars_table_name   },
+	{ "vars_h_id_column",      STR_PARAM, &vars_h_id_column.s       },
+	{ "vars_h_entry_column",   STR_PARAM, &vars_h_entry_column.s    },
+	{ "vars_key_column",       STR_PARAM, &vars_key_column.s        },
+	{ "vars_value_column",     STR_PARAM, &vars_value_column.s      },
+
 	{ "db_update_period",      INT_PARAM, &db_update_period         },
 	{ "db_fetch_rows",         INT_PARAM, &db_fetch_rows            },
 	{ "profiles_with_value",   STR_PARAM, &profiles_wv_s            },
@@ -259,6 +267,8 @@ static pv_export_t mod_items[] = {
 		pv_set_dlg_ctx, pv_parse_dlg_ctx_name, 0, 0, 0 },
 	{ {"dlg",  sizeof("dlg")-1}, PVT_OTHER, pv_get_dlg,
 		0, pv_parse_dlg_name, 0, 0, 0 },
+	{ {"dlg_var", sizeof("dlg_var")-1}, PVT_OTHER, pv_get_dlg_variable,
+		pv_set_dlg_variable,    pv_parse_dialog_var_name, 0, 0, 0},
 	{ {0, 0}, 0, 0, 0, 0, 0, 0, 0 }
 };
 
@@ -430,6 +440,12 @@ static int mod_init(void)
 	toroute_name_column.len = strlen(toroute_name_column.s);
 	dialog_table_name.len = strlen(dialog_table_name.s);
 
+	dialog_vars_table_name.len = strlen(dialog_vars_table_name.s);
+	vars_h_id_column.len = strlen(vars_h_id_column.s);
+	vars_h_entry_column.len = strlen(vars_h_entry_column.s);
+	vars_key_column.len = strlen(vars_key_column.s);
+	vars_value_column.len = strlen(vars_value_column.s);
+
 	/* param checkings */
 	if (dlg_flag==-1) {
 		LM_ERR("no dlg flag set!!\n");
@@ -551,7 +567,7 @@ static int mod_init(void)
 
 	/* init handlers */
 	init_dlg_handlers( rr_param, dlg_flag,
-		timeout_spec.s?&timeout_avp:0, default_timeout);
+		timeout_spec.s?&timeout_avp:0, default_timeout, seq_match_mode);
 
 	/* init timer */
 	if (init_dlg_timer(dlg_ontimeout)!=0) {
@@ -612,10 +628,9 @@ static int child_init(int rank)
 		if_update_stat(dlg_enable_stats, early_dlgs, early_dlgs_cnt);
 	}
 
-	if ( ((dlg_db_mode==DB_MODE_REALTIME || dlg_db_mode==DB_MODE_DELAYED)
-				&& (rank>0 || rank==PROC_TIMER || rank==PROC_MAIN))
-			|| (dlg_db_mode==DB_MODE_SHUTDOWN && (rank==PROC_MAIN)) )
-	{
+	if ( ((dlg_db_mode==DB_MODE_REALTIME || dlg_db_mode==DB_MODE_DELAYED) &&
+	(rank>0 || rank==PROC_TIMER)) ||
+	(dlg_db_mode==DB_MODE_SHUTDOWN && (rank==PROC_MAIN)) ) {
 		if ( dlg_connect_db(&db_url) ) {
 			LM_ERR("failed to connect to database (rank=%d)\n",rank);
 			return -1;

+ 243 - 128
modules_k/dialog/dlg_db_handler.c

@@ -2,6 +2,7 @@
  * $Id$
  *
  * Copyright (C) 2007 Voice System SRL
+ * Copyright (C) 2011 Carsten Bock, [email protected]
  *
  * This file is part of Kamailio, a free SIP server.
  *
@@ -37,6 +38,7 @@
 #include "../../str.h"
 #include "../../socket_info.h"
 #include "dlg_hash.h"
+#include "dlg_var.h"
 #include "dlg_db_handler.h"
 
 
@@ -64,6 +66,12 @@ str req_uri_column			=	str_init(REQ_URI_COL);
 str dialog_table_name		=	str_init(DIALOG_TABLE_NAME);
 int dlg_db_mode				=	DB_MODE_NONE;
 
+str vars_h_id_column		=	str_init(VARS_HASH_ID_COL);
+str vars_h_entry_column		=	str_init(VARS_HASH_ENTRY_COL);
+str vars_key_column		=	str_init(VARS_KEY_COL);
+str vars_value_column		=	str_init(VARS_VALUE_COL);
+str dialog_vars_table_name	=	str_init(DIALOG_VARS_TABLE_NAME);
+
 static db1_con_t* dialog_db_handle    = 0; /* database connection handle */
 static db_func_t dialog_dbf;
 
@@ -109,15 +117,16 @@ extern int early_dlgs_cnt;
 
 
 static int load_dialog_info_from_db(int dlg_hash_size, int fetch_num_rows);
-
+static int load_dialog_vars_from_db(int fetch_num_rows);
 
 int dlg_connect_db(const str *db_url)
 {
-	dialog_db_handle = dialog_dbf.init(db_url);
-	if(dialog_db_handle == 0) {
-		LM_ERR("unable to connect to database\n");
+	if (dialog_db_handle) {
+		LM_CRIT("BUG - db connection found already open\n");
 		return -1;
 	}
+	if ((dialog_db_handle = dialog_dbf.init(db_url)) == 0)
+		return -1;
 	return 0;
 }
 
@@ -136,7 +145,12 @@ int init_dlg_db(const str *db_url, int dlg_hash_size , int db_update_period, int
 	}
 
 	if(db_check_table_version(&dialog_dbf, dialog_db_handle, &dialog_table_name, DLG_TABLE_VERSION) < 0) {
-		LM_ERR("error during table version check.\n");
+		LM_ERR("error during dialog-table version check.\n");
+		return -1;
+	}
+
+	if(db_check_table_version(&dialog_dbf, dialog_db_handle, &dialog_vars_table_name, DLG_VARS_TABLE_VERSION) < 0) {
+		LM_ERR("error during dialog-vars version check.\n");
 		return -1;
 	}
 
@@ -150,6 +164,10 @@ int init_dlg_db(const str *db_url, int dlg_hash_size , int db_update_period, int
 		LM_ERR("unable to load the dialog data\n");
 		return -1;
 	}
+	if( (load_dialog_vars_from_db(fetch_num_rows) ) !=0 ){
+		LM_ERR("unable to load the dialog data\n");
+		return -1;
+	}
 
 	dialog_dbf.close(dialog_db_handle);
 	dialog_db_handle = 0;
@@ -185,6 +203,21 @@ static int use_dialog_table(void)
 	return 0;
 }
 
+static int use_dialog_vars_table(void)
+{
+	if(!dialog_db_handle){
+		LM_ERR("invalid database handle\n");
+		return -1;
+	}
+
+	if (dialog_dbf.use_table(dialog_db_handle, &dialog_vars_table_name) < 0) {
+		LM_ERR("Error in use_table\n");
+		return -1;
+	}
+
+	return 0;
+}
+
 
 
 static int select_entire_dialog_table(db1_res_t ** res, int fetch_num_rows)
@@ -414,11 +447,120 @@ error:
 
 
 
+static int select_entire_dialog_vars_table(db1_res_t ** res, int fetch_num_rows)
+{
+	db_key_t query_cols[DIALOG_VARS_TABLE_COL_NO] = {	&vars_h_entry_column,
+			&vars_h_id_column,	&vars_key_column,	&vars_value_column };
+
+	if(use_dialog_vars_table() != 0){
+		return -1;
+	}
+
+	/* select the whole tabel and all the columns */
+	if (DB_CAPABILITY(dialog_dbf, DB_CAP_FETCH) && (fetch_num_rows > 0)) {
+		if(dialog_dbf.query(dialog_db_handle,0,0,0,query_cols, 0, 
+		DIALOG_VARS_TABLE_COL_NO, 0, 0) < 0) {
+			LM_ERR("Error while querying (fetch) database\n");
+			return -1;
+		}
+		if(dialog_dbf.fetch_result(dialog_db_handle, res, fetch_num_rows) < 0) {
+			LM_ERR("fetching rows failed\n");
+			return -1;
+		}
+	} else {
+		if(dialog_dbf.query(dialog_db_handle,0,0,0,query_cols, 0,
+		DIALOG_VARS_TABLE_COL_NO, 0, res) < 0) {
+			LM_ERR("Error while querying database\n");
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+static int load_dialog_vars_from_db(int fetch_num_rows)
+{
+	db1_res_t * res;
+	db_val_t * values;
+	db_row_t * rows;
+	struct dlg_cell  * dlg; 
+	int i, nr_rows;
+
+	res = 0;
+	if((nr_rows = select_entire_dialog_vars_table(&res, fetch_num_rows)) < 0)
+		goto end;
+
+	nr_rows = RES_ROW_N(res);
+
+	LM_DBG("the database has information about %i dialog variables\n", nr_rows);
+
+	rows = RES_ROWS(res);
+
+	do {
+		/* for every row---dialog */
+		for(i=0; i<nr_rows; i++){
+
+			values = ROW_VALUES(rows + i);
+
+			if (VAL_NULL(values) || VAL_NULL(values+1)) {
+				LM_ERR("columns %.*s or/and %.*s cannot be null -> skipping\n",
+					vars_h_entry_column.len, vars_h_entry_column.s,
+					vars_h_id_column.len, vars_h_id_column.s);
+				continue;
+			}
+
+			if (VAL_NULL(values+2) || VAL_NULL(values+3)) {
+				LM_ERR("columns %.*s or/and %.*s cannot be null -> skipping\n",
+					vars_key_column.len, vars_key_column.s,
+					vars_value_column.len, vars_value_column.s);
+				continue;
+			}
+			if (VAL_INT(values) < d_table->size) {
+				dlg = (d_table->entries)[VAL_INT(values)].first;
+				while (dlg) {
+					if (dlg->h_id == VAL_INT(values+1)) {
+						set_dlg_variable_unsafe(dlg, &VAL_STR(values+2), &VAL_STR(values+3), 0);
+						continue;
+					}
+					dlg = dlg->next;
+					if (!dlg) {
+						LM_WARN("insonsistent data: the dialog h_entry/h_id does not exist!\n");
+					}
+				}
+			} else {
+				LM_WARN("insonsistent data: the h_entry in the DB does not exist!\n");
+			}
+		}
+
+		/* any more data to be fetched ?*/
+		if (DB_CAPABILITY(dialog_dbf, DB_CAP_FETCH) && (fetch_num_rows > 0)) {
+			if(dialog_dbf.fetch_result(dialog_db_handle, &res, fetch_num_rows) < 0) {
+				LM_ERR("re-fetching rows failed\n");
+				goto error;
+			}
+			nr_rows = RES_ROW_N(res);
+			rows = RES_ROWS(res);
+		} else {
+			nr_rows = 0;
+		}
+
+	}while (nr_rows>0);
+
+end:
+	dialog_dbf.free_result(dialog_db_handle, res);
+	return 0;
+error:
+	dialog_dbf.free_result(dialog_db_handle, res);
+	return -1;
+
+}
+
 /*this is only called from destroy_dlg, where the cell's entry lock is acquired*/
 int remove_dialog_from_db(struct dlg_cell * cell)
 {
 	db_val_t values[2];
 	db_key_t match_keys[2] = { &h_entry_column, &h_id_column};
+	db_key_t vars_match_keys[2] = { &vars_h_entry_column, &vars_h_id_column};
 
 	/*if the dialog hasn 't been yet inserted in the database*/
 	LM_DBG("trying to remove dialog [%.*s], update_flag is %i\n",
@@ -441,17 +583,83 @@ int remove_dialog_from_db(struct dlg_cell * cell)
 		return -1;
 	}
 
+	if (use_dialog_vars_table()!=0)
+		return -1;
+
+	if(dialog_dbf.delete(dialog_db_handle, vars_match_keys, 0, values, 2) < 0) {
+		LM_ERR("failed to delete database information\n");
+		return -1;
+	}
+
 	LM_DBG("callid was %.*s\n", cell->callid.len, cell->callid.s );
 
 	return 0;
 }
 
 
+int update_dialog_vars_dbinfo(struct dlg_cell * cell, struct dlg_var * var)
+{
+	db_val_t values[DIALOG_VARS_TABLE_COL_NO];
 
-int update_dialog_dbinfo(struct dlg_cell * cell)
+	db_key_t insert_keys[DIALOG_VARS_TABLE_COL_NO] = { &vars_h_entry_column,
+			&vars_h_id_column,	&vars_key_column,	&vars_value_column };
+
+	if(use_dialog_vars_table()!=0)
+		return -1;
+
+	VAL_TYPE(values) = VAL_TYPE(values+1) = DB1_INT;
+	VAL_TYPE(values+2) = VAL_TYPE(values+3) = DB1_STR;
+	VAL_NULL(values) = VAL_NULL(values+1) = VAL_NULL(values+2) = VAL_NULL(values+3) = 0;
+	SET_STR_VALUE(values+2, var->key);
+
+	VAL_INT(values)			= cell->h_entry;
+	VAL_INT(values+1)		= cell->h_id;
+	
+	if((var->vflags & DLG_FLAG_DEL) != 0) {
+		/* delete the current variable */
+		db_key_t vars_match_keys[3] = { &vars_h_entry_column, &vars_h_id_column, &vars_key_column};
+
+		if (use_dialog_vars_table()!=0)
+			return -1;
+
+		if(dialog_dbf.delete(dialog_db_handle, vars_match_keys, 0, values, 3) < 0) {
+			LM_ERR("failed to delete database information\n");
+			return -1;
+		}
+	} else if((var->vflags & DLG_FLAG_NEW) != 0) {
+		/* save all the current dialogs information*/
+		SET_STR_VALUE(values+3, var->value);
+
+		if((dialog_dbf.insert(dialog_db_handle, insert_keys, values, 
+								DIALOG_VARS_TABLE_COL_NO)) !=0){
+			LM_ERR("could not add another dialog-var to db\n");
+			goto error;
+		}
+		var->vflags &= ~(DLG_FLAG_NEW|DLG_FLAG_CHANGED);
+	} else if((var->vflags & DLG_FLAG_CHANGED) != 0) {
+		/* save only dialog's state and timeout */
+		SET_STR_VALUE(values+3, var->value);
+
+		if((dialog_dbf.update(dialog_db_handle, insert_keys, 0, 
+						values, (insert_keys+3), (values+3), 3, 1)) !=0){
+			LM_ERR("could not update database info\n");
+			goto error;
+		}
+		var->vflags &= ~DLG_FLAG_CHANGED;
+	} else {
+		return 0;
+	}
+	return 0;
+error:
+	return -1;
+}
+
+
+int update_dialog_dbinfo_unsafe(struct dlg_cell * cell)
 {
 	int i;
-	struct dlg_entry entry;
+	struct dlg_var *var;
+
 	db_val_t values[DIALOG_TABLE_COL_NO];
 
 	db_key_t insert_keys[DIALOG_TABLE_COL_NO] = { &h_entry_column,
@@ -463,6 +671,17 @@ int update_dialog_dbinfo(struct dlg_cell * cell)
 			&to_route_column,    &from_contact_column,&to_contact_column,
 			&sflags_column,      &toroute_name_column,     &req_uri_column };
 
+	if( (cell->dflags & DLG_FLAG_NEW) != 0 
+	|| (cell->dflags & DLG_FLAG_CHANGED_VARS) != 0) {
+		/* iterate the list */
+		for(var=cell->vars ; var ; var=var->next) {
+			if (update_dialog_vars_dbinfo(cell, var) != 0)
+				return -1;
+		}
+		/* Remove the flag */
+		cell->dflags &= ~DLG_FLAG_CHANGED_VARS;
+	}
+
 	if(use_dialog_table()!=0)
 		return -1;
 	
@@ -481,10 +700,6 @@ int update_dialog_dbinfo(struct dlg_cell * cell)
 		VAL_TYPE(values+18) = DB1_INT;
 		VAL_TYPE(values+19) = DB1_STR;
 
-		/* lock the entry */
-		entry = (d_table->entries)[cell->h_entry];
-		dlg_lock( d_table, &entry);
-
 		VAL_INT(values)			= cell->h_entry;
 		VAL_INT(values+1)		= cell->h_id;
 		VAL_INT(values+9)		= cell->start_ts;
@@ -540,10 +755,6 @@ int update_dialog_dbinfo(struct dlg_cell * cell)
 
 		VAL_TYPE(values+12) = VAL_TYPE(values+13) =DB1_STR;
 
-		/* lock the entry */
-		entry = (d_table->entries)[cell->h_entry];
-		dlg_lock( d_table, &entry);
-
 		VAL_INT(values)			= cell->h_entry;
 		VAL_INT(values+1)		= cell->h_id;
 		VAL_INT(values+10)		= cell->state;
@@ -568,139 +779,43 @@ int update_dialog_dbinfo(struct dlg_cell * cell)
 		return 0;
 	}
 
-	dlg_unlock( d_table, &entry);
 	return 0;
-
 error:
-	dlg_unlock( d_table, &entry);
 	return -1;
 }
 
-
+int update_dialog_dbinfo(struct dlg_cell * cell)
+{
+	struct dlg_entry entry;
+	/* lock the entry */
+	entry = (d_table->entries)[cell->h_entry];
+	dlg_lock( d_table, &entry);
+	if (update_dialog_dbinfo_unsafe(cell) != 0) {
+		dlg_unlock( d_table, &entry);
+		return -1;
+	} 
+	dlg_unlock( d_table, &entry);
+	return 0;
+}
 
 void dialog_update_db(unsigned int ticks, void * param)
 {
-	int index, i;
-	db_val_t values[DIALOG_TABLE_COL_NO];
+	int index;
 	struct dlg_entry entry;
 	struct dlg_cell  * cell; 
-	
-	db_key_t insert_keys[DIALOG_TABLE_COL_NO] = {		&h_entry_column,
-			&h_id_column,		&call_id_column,		&from_uri_column,
-			&from_tag_column,	&to_uri_column,			&to_tag_column,
-			&from_sock_column,	&to_sock_column,
-			&start_time_column,	&state_column,			&timeout_column,
-			&from_cseq_column,	&to_cseq_column,		&from_route_column,
-			&to_route_column, 	&from_contact_column, 	&to_contact_column,
-			&sflags_column,     &toroute_name_column, 	&req_uri_column };
-
-	if(use_dialog_table()!=0)
-		return;
-
-	/*save the current dialogs information*/
-	VAL_TYPE(values) = VAL_TYPE(values+1) = VAL_TYPE(values+9) = 
-	VAL_TYPE(values+10) = VAL_TYPE(values+11) = DB1_INT;
-
-	VAL_TYPE(values+2) = VAL_TYPE(values+3) = VAL_TYPE(values+4) = 
-	VAL_TYPE(values+5) = VAL_TYPE(values+6) = VAL_TYPE(values+7) = 
-	VAL_TYPE(values+8) = VAL_TYPE(values+12) = VAL_TYPE(values+13) = 
-	VAL_TYPE(values+14) = VAL_TYPE(values+15) = VAL_TYPE(values+16) = 
-	VAL_TYPE(values+17) = VAL_TYPE(values+20) = DB1_STR;
-
-	SET_NULL_FLAG(values, i, DIALOG_TABLE_COL_NO-6, 0);
-
-	VAL_TYPE(values+18) = DB1_INT;
-	VAL_TYPE(values+19) = DB1_STR;
 
 	LM_DBG("saving current_info \n");
 	
 	for(index = 0; index< d_table->size; index++){
-
 		/* lock the whole entry */
 		entry = (d_table->entries)[index];
 		dlg_lock( d_table, &entry);
 
 		for(cell = entry.first; cell != NULL; cell = cell->next){
-
-			if( (cell->dflags & DLG_FLAG_NEW) != 0 ) {
-
-				VAL_INT(values)			= cell->h_entry;
-				VAL_INT(values+1)		= cell->h_id;
-
-				VAL_INT(values+9)		= cell->start_ts;
-				VAL_INT(values+10)		= cell->state;
-				VAL_INT(values+11)	= (unsigned int)( (unsigned int)time(0) +
-					 cell->tl.timeout - get_ticks() );
-
-				SET_STR_VALUE(values+2, cell->callid);
-				SET_STR_VALUE(values+3, cell->from_uri);
-				SET_STR_VALUE(values+4, cell->tag[DLG_CALLER_LEG]);
-				SET_STR_VALUE(values+5, cell->to_uri);
-				SET_STR_VALUE(values+6, cell->tag[DLG_CALLEE_LEG]);
-				SET_PROPER_NULL_FLAG(cell->tag[DLG_CALLEE_LEG], values, 6);
-
-				SET_STR_VALUE(values+7,
-					cell->bind_addr[DLG_CALLER_LEG]->sock_str);
-				SET_STR_VALUE(values+8,
-					cell->bind_addr[DLG_CALLEE_LEG]->sock_str);
-				
-				SET_STR_VALUE(values+12, cell->cseq[DLG_CALLER_LEG]);
-				SET_STR_VALUE(values+13, cell->cseq[DLG_CALLEE_LEG]);
-
-				SET_STR_VALUE(values+14, cell->route_set[DLG_CALLER_LEG]);
-				SET_STR_VALUE(values+15, cell->route_set[DLG_CALLEE_LEG]);
-				SET_STR_VALUE(values+16, cell->contact[DLG_CALLER_LEG]);
-				SET_STR_VALUE(values+17, cell->contact[DLG_CALLEE_LEG]);
-			
-				SET_PROPER_NULL_FLAG(cell->route_set[DLG_CALLER_LEG],
-					values, 14);
-				SET_PROPER_NULL_FLAG(cell->route_set[DLG_CALLEE_LEG],
-					values, 15);
-				SET_PROPER_NULL_FLAG(cell->contact[DLG_CALLER_LEG],
-					values, 16);
-				SET_PROPER_NULL_FLAG(cell->contact[DLG_CALLEE_LEG],
-					values, 17);
-				
-				VAL_INT(values+18)		= cell->sflags;
-
-				SET_STR_VALUE(values+19, cell->toroute_name);
-				SET_PROPER_NULL_FLAG(cell->toroute_name,
-					values, 19);
-
-				SET_STR_VALUE(values+20, cell->req_uri);
-				SET_PROPER_NULL_FLAG(cell->req_uri,
-					values, 20);
-
-				if((dialog_dbf.insert(dialog_db_handle, insert_keys, 
-				values, DIALOG_TABLE_COL_NO)) !=0){
-					LM_ERR("could not add another dialog to db\n");
-					goto error;
-				}
-
-				cell->dflags &= ~(DLG_FLAG_NEW |DLG_FLAG_CHANGED);
-
-			} else if( (cell->dflags & DLG_FLAG_CHANGED)!=0 ){
-
-				VAL_INT(values)			= cell->h_entry;
-				VAL_INT(values+1)		= cell->h_id;
-
-				VAL_INT(values+10)		= cell->state;
-				VAL_INT(values+11)	= (unsigned int)( (unsigned int)time(0) +
-					 cell->tl.timeout - get_ticks() );
-				SET_STR_VALUE(values+12, cell->cseq[0]);
-				SET_STR_VALUE(values+13, cell->cseq[DLG_CALLEE_LEG]);
-
-
-				if((dialog_dbf.update(dialog_db_handle, (insert_keys), 0, 
-				(values), (insert_keys+10), (values+10), 2, 4)) !=0) {
-					LM_ERR("could not update database info\n");
-					goto error;
-				}
-
-				cell->dflags &= ~DLG_FLAG_CHANGED;
-
+			if (update_dialog_dbinfo_unsafe(cell) != 0) {
+				dlg_unlock( d_table, &entry);
+				goto error;
 			}
-
 		}
 		dlg_unlock( d_table, &entry);
 

+ 22 - 3
modules_k/dialog/dlg_db_handler.h

@@ -2,6 +2,7 @@
  * $Id$
  *
  * Copyright (C) 2007 Voice System SRL
+ * Copyright (C) 2011 Carsten Bock, [email protected]
  *
  * This file is part of Kamailio, a free SIP server.
  *
@@ -53,9 +54,20 @@
 #define TOROUTE_NAME_COL		"toroute_name"
 #define REQ_URI_COL				"req_uri"
 #define DIALOG_TABLE_NAME		"dialog"
-
 #define DLG_TABLE_VERSION		5
 
+#define DIALOG_TABLE_COL_NO 		21
+
+#define VARS_HASH_ID_COL 		"hash_id"
+#define VARS_HASH_ENTRY_COL		"hash_entry"
+#define VARS_KEY_COL			"dialog_key"
+#define VARS_VALUE_COL			"dialog_value"
+#define DIALOG_VARS_TABLE_NAME		"dialog_vars"
+#define DLG_VARS_TABLE_VERSION		1
+
+#define DIALOG_VARS_TABLE_COL_NO 4
+
+
 /*every minute the dialogs' information will be refreshed*/
 #define DB_DEFAULT_UPDATE_PERIOD	60
 #define DB_MODE_NONE				0
@@ -63,9 +75,8 @@
 #define DB_MODE_DELAYED				2
 #define DB_MODE_SHUTDOWN			3
 
-#define DIALOG_TABLE_COL_NO 		21
-
 
+/* Dialog table */
 extern str call_id_column; 
 extern str from_uri_column;
 extern str from_tag_column;
@@ -89,6 +100,14 @@ extern str toroute_name_column;
 extern str dialog_table_name;
 extern int dlg_db_mode;
 
+/* Dialog-Vars Table */
+extern str vars_h_id_column;
+extern str vars_h_entry_column;
+extern str vars_key_column;
+extern str vars_value_column;
+extern str dialog_vars_table_name;
+
+
 int init_dlg_db(const str *db_url, int dlg_hash_size, int db_update_period, int fetch_num_rows);
 int dlg_connect_db(const str *db_url);
 void destroy_dlg_db(void);

+ 16 - 6
modules_k/dialog/dlg_handlers.c

@@ -82,8 +82,8 @@ static str       rr_param;		/*!< record-route parameter for matching */
 static int       dlg_flag;		/*!< flag for dialog tracking */
 static pv_spec_t *timeout_avp;		/*!< AVP for timeout setting */
 static int       default_timeout;	/*!< default dialog timeout */
+static int       seq_match_mode;	/*!< dlg_match mode */ 
 static int       shutdown_done = 0;	/*!< 1 when destroy_dlg_handlers was called */
-extern int       seq_match_mode;	/*!< dlg_match mode */ 
 extern int       detect_spirals;
 
 extern struct rr_binds d_rrb;		/*!< binding to record-routing module */
@@ -113,9 +113,11 @@ static unsigned int CURR_DLG_ID  = 0xffffffff;	/*!< current dialog id */
  * \param dlg_flag_p dialog flag
  * \param timeout_avp_p AVP for timeout setting
  * \param default_timeout_p default timeout
+ * \param seq_match_mode_p matching mode
  */
 void init_dlg_handlers(char *rr_param_p, int dlg_flag_p,
-		pv_spec_t *timeout_avp_p ,int default_timeout_p)
+		pv_spec_t *timeout_avp_p ,int default_timeout_p,
+		int seq_match_mode_p)
 {
 	rr_param.s = rr_param_p;
 	rr_param.len = strlen(rr_param.s);
@@ -124,6 +126,7 @@ void init_dlg_handlers(char *rr_param_p, int dlg_flag_p,
 
 	timeout_avp = timeout_avp_p;
 	default_timeout = default_timeout_p;
+	seq_match_mode = seq_match_mode_p;
 }
 
 
@@ -676,6 +679,8 @@ int dlg_new_dialog(struct sip_msg *msg, struct cell *t)
 		return -1;
 	}
 
+	
+
 	/* save caller's tag, cseq, contact and record route*/
 	if (populate_leg_info(dlg, msg, t, DLG_CALLER_LEG,
 			&(get_from(msg)->tag_value)) !=0)
@@ -688,6 +693,9 @@ int dlg_new_dialog(struct sip_msg *msg, struct cell *t)
 	set_current_dialog(msg, dlg);
 	_dlg_ctx.dlg = dlg;
 
+	/* Populate initial varlist: */
+	dlg->vars = get_local_varlist_pointer(msg, 1);
+
 	link_dlg(dlg, 2/* extra ref for the callback and current dlg hook */);
 
 	/* first INVITE seen (dialog created, unconfirmed) */
@@ -713,10 +721,12 @@ int dlg_new_dialog(struct sip_msg *msg, struct cell *t)
 	if (_dlg_ctx.to_bye!=0)
 		dlg->dflags |= DLG_FLAG_TOBYE;
 
-	if ( d_tmb.register_tmcb( msg, t, TMCB_MAX,
-				dlg_tmcb_dummy, (void*)dlg, 0)<0 ) {
-		LM_ERR("failed cache in T the shortcut to dlg\n");
-		goto error;
+	if (t) {
+		if ( d_tmb.register_tmcb( msg, t, TMCB_MAX,
+					dlg_tmcb_dummy, (void*)dlg, 0)<0 ) {
+			LM_ERR("failed cache in T the shortcut to dlg\n");
+			goto error;
+		}
 	}
 #if 0
 		t->dialog_ctx = (void*) dlg;

+ 2 - 1
modules_k/dialog/dlg_handlers.h

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

+ 23 - 10
modules_k/dialog/dlg_hash.c

@@ -2,6 +2,7 @@
  * $Id$
  *
  * Copyright (C) 2006 Voice System SRL
+ * Copyright (C) 2011 Carsten Bock, [email protected]
  *
  * This file is part of Kamailio, a free SIP server.
  *
@@ -58,6 +59,7 @@
 #include "../../lib/kcore/hash_func.h"
 #include "../../lib/kmi/mi.h"
 #include "dlg_timer.h"
+#include "dlg_var.h"
 #include "dlg_hash.h"
 #include "dlg_profile.h"
 #include "dlg_req_within.h"
@@ -132,6 +134,7 @@ error0:
 inline void destroy_dlg(struct dlg_cell *dlg)
 {
 	int ret = 0;
+	struct dlg_var *var;
 
 	LM_DBG("destroying dialog %p\n",dlg);
 
@@ -178,6 +181,16 @@ inline void destroy_dlg(struct dlg_cell *dlg)
 	if (dlg->toroute_name.s)
 		shm_free(dlg->toroute_name.s);
 
+	
+	while (dlg->vars) {
+		var = dlg->vars;
+		dlg->vars = dlg->vars->next;
+		shm_free(var->key.s);
+		shm_free(var->value.s);
+		shm_free(var);
+	}
+
+
 	shm_free(dlg);
 	dlg = 0;
 }
@@ -543,10 +556,11 @@ void link_dlg(struct dlg_cell *dlg, int n)
  */
 #define unref_dlg_unsafe(_dlg,_cnt,_d_entry)   \
 	do { \
-		LM_DBG("unref dlg %p with %d, crt ref count: %d\n",\
+		(_dlg)->ref -= (_cnt); \
+		LM_DBG("unref dlg %p with %d -> %d\n",\
 			(_dlg),(_cnt),(_dlg)->ref);\
-		if ((_dlg)->ref<=0) {\
-			LM_CRIT("bogus op: ref %d with cnt %d for dlg %p [%u:%u] "\
+		if ((_dlg)->ref<0) {\
+			LM_CRIT("bogus ref %d with cnt %d for dlg %p [%u:%u] "\
 				"with clid '%.*s' and tags '%.*s' '%.*s'\n",\
 				(_dlg)->ref, _cnt, _dlg,\
 				(_dlg)->h_entry, (_dlg)->h_id,\
@@ -555,13 +569,11 @@ void link_dlg(struct dlg_cell *dlg, int n)
 				(_dlg)->tag[DLG_CALLER_LEG].s,\
 				(_dlg)->tag[DLG_CALLEE_LEG].len,\
 				(_dlg)->tag[DLG_CALLEE_LEG].s); \
-		} else { \
-			(_dlg)->ref -= (_cnt); \
-			if ((_dlg)->ref<=0) { \
-				unlink_unsafe_dlg( _d_entry, _dlg);\
-				LM_DBG("ref <=0 for dialog %p\n",_dlg);\
-				destroy_dlg(_dlg);\
-			}\
+		}\
+		if ((_dlg)->ref<=0) { \
+			unlink_unsafe_dlg( _d_entry, _dlg);\
+			LM_DBG("ref <=0 for dialog %p\n",_dlg);\
+			destroy_dlg(_dlg);\
 		}\
 	}while(0)
 
@@ -1132,3 +1144,4 @@ error:
 	return NULL;
 }
 
+

+ 6 - 1
modules_k/dialog/dlg_hash.h

@@ -2,6 +2,7 @@
  * $Id$
  *
  * Copyright (C) 2006 Voice System SRL
+ * Copyright (C) 2011 Carsten Bock, [email protected]
  *
  * This file is part of Kamailio, a free SIP server.
  *
@@ -75,6 +76,10 @@
 #define DLG_FLAG_CALLERBYE     (1<<4) /*!< bye from caller */
 #define DLG_FLAG_CALLEEBYE     (1<<5) /*!< bye from callee */
 #define DLG_FLAG_LOCALDLG      (1<<6) /*!< local dialog, unused */
+#define DLG_FLAG_CHANGED_VARS  (1<<7) /*!< dialog-variables changed */
+
+/* dialog-variable flags (in addition to dialog-flags) */
+#define DLG_FLAG_DEL           (1<<8) /*!< delete this var */
 
 #define DLG_CALLER_LEG         0 /*!< attribute that belongs to a caller leg */
 #define DLG_CALLEE_LEG         1 /*!< attribute that belongs to a callee leg */
@@ -112,6 +117,7 @@ struct dlg_cell
 	struct socket_info * bind_addr[2];	/*! binded address of caller and callee */
 	struct dlg_head_cbl  cbs;		/*!< dialog callbacks */
 	struct dlg_profile_link *profile_links; /*!< dialog profiles */
+	struct dlg_var       *vars;		/*!< dialog variables */
 };
 
 
@@ -158,7 +164,6 @@ extern struct dlg_cell  *current_dlg_pointer;
 #define dlg_unlock(_table, _entry) \
 		lock_set_release( (_table)->locks, (_entry)->lock_idx);
 
-
 /*!
  * \brief Unlink a dialog from the list without locking
  * \see unref_dlg_unsafe

+ 274 - 1
modules_k/dialog/dlg_var.c

@@ -2,6 +2,7 @@
  * $Id$
  *
  * Copyright (C) 2009 Daniel-Constantin Mierla (asipto.com)
+ * Copyright (C) 2011 Carsten Bock, [email protected]
  *
  * This file is part of kamailio, a free SIP server.
  *
@@ -23,9 +24,17 @@
 #include "../../route.h"
 
 #include "dlg_var.h"
+#include "dlg_hash.h"
+#include "dlg_profile.h"
+#include "dlg_db_handler.h"
 
 dlg_ctx_t _dlg_ctx;
 
+/*! global variable table, in case the dialog does not exist yet */
+struct dlg_var * var_table = 0;
+/*! ID of the current message */
+int msg_id;
+
 int dlg_cfg_cb(struct sip_msg *foo, unsigned int flags, void *bar)
 {
 	memset(&_dlg_ctx, 0, sizeof(dlg_ctx_t));
@@ -33,6 +42,270 @@ int dlg_cfg_cb(struct sip_msg *foo, unsigned int flags, void *bar)
 	return 1;
 }
 
+
+static inline struct dlg_var *new_dlg_var(str *key, str *val)
+{
+	struct dlg_var *var;
+
+	var =(struct dlg_var*)shm_malloc(sizeof(struct dlg_var));
+	if (var==NULL) {
+		LM_ERR("no more shm mem\n");
+		return NULL;
+	}
+	var->next = NULL;
+	var->vflags = DLG_FLAG_NEW;
+	/* set key */
+	var->key.len = key->len;
+	var->key.s = (char*)shm_malloc(var->key.len);
+	if (var->key.s==NULL) {
+		shm_free(var);			
+		LM_ERR("no more shm mem\n");
+		return NULL;
+	}
+	memcpy(var->key.s, key->s, key->len);
+	/* set value */
+	var->value.len = val->len;
+	var->value.s = (char*)shm_malloc(var->value.len);
+	if (var->value.s==NULL) {
+		shm_free(var->key.s);			
+		shm_free(var);			
+		LM_ERR("no more shm mem\n");
+		return NULL;
+	}
+	memcpy(var->value.s, val->s, val->len);
+	return var;
+}
+
+/*! Delete the current var-list */
+void free_local_varlist() {
+	struct dlg_var *var;
+	while (var_table) {
+		var = var_table;
+		var_table = var_table->next;
+		shm_free(var->key.s);
+		shm_free(var->value.s);
+		shm_free(var);
+	}
+}
+
+/*! Retrieve the local var-list pointer */
+struct dlg_var * get_local_varlist_pointer(struct sip_msg *msg, int clear_pointer) {
+	struct dlg_var *var;
+	/* New list, delete the old one */
+	if (msg->id != msg_id) {
+		free_local_varlist();
+		msg_id = msg->id;
+	}
+	var = var_table;
+	if (clear_pointer)
+		var_table = NULL;
+	return var;
+}
+
+/* Adds, updates and deletes dialog variables */
+int set_dlg_variable_unsafe(struct dlg_cell *dlg, str *key, str *val, int new)
+{
+	struct dlg_var * var = NULL;
+	struct dlg_var * it;
+	struct dlg_var * it_prev;
+	struct dlg_var ** var_list;
+	
+	if (dlg) 
+		var_list = &dlg->vars;
+	else 
+		var_list = &var_table;
+
+	if ( val && (var=new_dlg_var(key, val))==NULL) {
+		LM_ERR("failed to create new dialog variable\n");
+		return -1;
+	}
+
+	/* iterate the list */
+	for( it_prev=NULL, it=*var_list ; it ; it_prev=it,it=it->next) {
+		if (key->len==it->key.len && memcmp(key->s,it->key.s,key->len)==0
+			&& (it->vflags & DLG_FLAG_DEL) == 0) {
+			/* found -> replace or delete it */
+			if (val==NULL) {
+				/* delete it */
+				if (it_prev) it_prev->next = it->next;
+				else *var_list = it->next;
+				/* Set the delete-flag for the current var: */
+				it->vflags &= DLG_FLAG_DEL;
+			} else {
+				/* replace the current it with var and free the it */
+				var->next = it->next;
+				/* Take the previous vflags: */
+				var->vflags = it->vflags & DLG_FLAG_CHANGED;
+				if (it_prev) it_prev->next = var;
+				else *var_list = var;				  
+			}
+
+			/* Free this var: */
+			shm_free(it->key.s);
+			shm_free(it->value.s);
+			shm_free(it);
+			return 0;
+		}
+	}
+
+	/* not found -> simply add a new one */
+
+	/* insert at the beginning of the list */
+	var->next = *var_list;
+	*var_list = var;
+
+	return 0;
+}
+
+str * get_dlg_variable_unsafe(struct dlg_cell *dlg, str *key)
+{
+	struct dlg_var *var, *var_list;
+
+	if (dlg) 
+		var_list = dlg->vars;
+	else
+		var_list = var_table;
+
+	/* iterate the list */
+	for(var=var_list ; var ; var=var->next) {
+		if (key->len==var->key.len && memcmp(key->s,var->key.s,key->len)==0
+		&& (var->vflags & DLG_FLAG_DEL) == 0) {
+			return &var->value;
+		}
+	}
+
+	return NULL;
+}
+
+int pv_parse_dialog_var_name(pv_spec_p sp, str *in)
+{
+	if(in==NULL || in->s==NULL || sp==NULL)
+		return -1;
+
+	sp->pvp.pvn.type = PV_NAME_INTSTR;
+	sp->pvp.pvn.u.isname.type = AVP_NAME_STR;
+	sp->pvp.pvn.u.isname.name.s = *in;
+
+	return 0;
+}
+
+/*! Internal debugging function: Prints the list of dialogs */
+void print_lists(struct dlg_cell *dlg) {
+	struct dlg_var *varlist;
+	varlist = var_table;
+	LM_DBG("Internal var-list (%p):\n", varlist);
+	while (varlist) {
+		LM_DBG("%.*s=%.*s (flags %i)\n",
+			varlist->key.len, varlist->key.s,
+			varlist->value.len, varlist->value.s,
+			varlist->vflags);
+		varlist = varlist->next;
+	}
+	if (dlg) {
+		varlist = dlg->vars;
+		LM_DBG("Dialog var-list (%p):\n", varlist);
+		while (varlist) {
+			LM_DBG("%.*s=%.*s (flags %i)\n",
+				varlist->key.len, varlist->key.s,
+				varlist->value.len, varlist->value.s,
+				varlist->vflags);
+			varlist = varlist->next;
+		}
+	}
+}
+
+int pv_get_dlg_variable(struct sip_msg *msg, pv_param_t *param, pv_value_t *res)
+{
+	struct dlg_cell *dlg;
+	str * value;
+
+	if (param==NULL || param->pvn.type!=PV_NAME_INTSTR || param->pvn.u.isname.type!=AVP_NAME_STR || param->pvn.u.isname.name.s.s==NULL) {
+		LM_CRIT("BUG - bad parameters\n");
+		return -1;
+	}
+
+	/* Retrieve the current dialog */
+	dlg=get_current_dlg_pointer();
+
+	if (dlg) {
+		/* Lock the dialog */
+		dlg_lock(d_table, &(d_table->entries[dlg->h_entry]));
+	} else {
+		/* Verify the local list */
+		get_local_varlist_pointer(msg, 0);
+	}
+
+	value = get_dlg_variable_unsafe(dlg, &param->pvn.u.isname.name.s);
+
+	print_lists(dlg);
+
+	/* unlock dialog */
+	if (dlg) dlg_unlock(d_table, &(d_table->entries[dlg->h_entry]));
+
+	if (value)
+		return pv_get_strval(msg, param, res, value);
+
+
+	return 0;
+}
+
+int pv_set_dlg_variable(struct sip_msg* msg, pv_param_t *param, int op, pv_value_t *val)
+{
+	struct dlg_cell *dlg;
+
+	/* Retrieve the current dialog */
+	dlg=get_current_dlg_pointer();
+	
+	if (dlg) {
+		/* Lock the dialog */
+		dlg_lock(d_table, &(d_table->entries[dlg->h_entry]));
+	} else {
+		/* Verify the local list */
+		get_local_varlist_pointer(msg, 0);
+	}
+
+	if (param==NULL || param->pvn.type!=PV_NAME_INTSTR || param->pvn.u.isname.type!=AVP_NAME_STR || param->pvn.u.isname.name.s.s==NULL ) {
+		LM_CRIT("BUG - bad parameters\n");
+		return -1;
+	}
+
+	if (val==NULL || val->flags&(PV_VAL_NONE|PV_VAL_NULL|PV_VAL_EMPTY)) {
+		/* if NULL, remove the value */
+		if (set_dlg_variable_unsafe(dlg, &param->pvn.u.isname.name.s, NULL, 1)!=0) {
+			LM_ERR("failed to delete dialog variable <%.*s>\n", param->pvn.u.isname.name.s.len,param->pvn.u.isname.name.s.s);
+			/* unlock dialog */
+			if (dlg) dlg_unlock(d_table, &(d_table->entries[dlg->h_entry]));
+			return -1;
+		}
+	} else {
+		/* if value, must be string */
+		if ( !(val->flags&PV_VAL_STR)) {
+			LM_ERR("non-string values are not supported\n");
+			/* unlock dialog */
+			if (dlg) dlg_unlock(d_table, &(d_table->entries[dlg->h_entry]));
+			return -1;
+		}
+
+		if (set_dlg_variable_unsafe(dlg, &param->pvn.u.isname.name.s, &val->rs, 1)!=0) {
+			LM_ERR("failed to store dialog values <%.*s>\n",param->pvn.u.isname.name.s.len,param->pvn.u.isname.name.s.s);
+			/* unlock dialog */
+			if (dlg) dlg_unlock(d_table, &(d_table->entries[dlg->h_entry]));
+			return -1;
+		}
+	}
+	/* unlock dialog */
+	if (dlg) {
+		dlg->dflags &= DLG_FLAG_CHANGED_VARS;		
+		dlg_unlock(d_table, &(d_table->entries[dlg->h_entry]));
+		if ( dlg_db_mode==DB_MODE_REALTIME )
+			update_dialog_dbinfo(dlg);
+
+	}
+	print_lists(dlg);
+
+	return 0;
+}
+
 int pv_get_dlg_ctx(struct sip_msg *msg,  pv_param_t *param,
 		pv_value_t *res)
 {
@@ -92,7 +365,7 @@ int pv_set_dlg_ctx(struct sip_msg* msg, pv_param_t *param,
 			_dlg_ctx.to_bye = n;
 		break;
 		case 4:
-			if(val && val->flags&PV_VAL_STR) {
+			if(val->flags&PV_VAL_STR) {
 				if(val->rs.s[val->rs.len]=='\0'
 						&& val->rs.len<DLG_TOROUTE_SIZE) {
 					_dlg_ctx.to_route = route_lookup(&main_rt, val->rs.s);

+ 22 - 0
modules_k/dialog/dlg_var.h

@@ -2,6 +2,7 @@
  * $Id$
  *
  * Copyright (C) 2009 Daniel-Constantin Mierla (asipto.com)
+ * Copyright (C) 2011 Carsten Bock, [email protected]
  *
  * This file is part of kamailio, a free SIP server.
  *
@@ -40,6 +41,27 @@ typedef struct _dlg_ctx {
 	unsigned int dir;
 } dlg_ctx_t;
 
+/* A dialog-variable */
+struct dlg_var {
+	str key;
+	str value;
+	unsigned int vflags;		/*!< internal variable flags */
+	struct dlg_var *next;
+};
+
+
+int pv_parse_dialog_var_name(pv_spec_p sp, str *in);
+
+int pv_get_dlg_variable(struct sip_msg *msg, pv_param_t *param, pv_value_t *res);
+
+int pv_set_dlg_variable(struct sip_msg* msg, pv_param_t *param, int op, pv_value_t *val);
+
+/*! Retrieve the current var-list */
+struct dlg_var * get_local_varlist_pointer(struct sip_msg *msg, int clear_pointer);
+
+/* Adds, updates and deletes dialog variables */
+int set_dlg_variable_unsafe(struct dlg_cell *dlg, str *key, str *val, int new);
+
 extern dlg_ctx_t _dlg_ctx;
 
 int pv_get_dlg_ctx(struct sip_msg *msg,  pv_param_t *param,

+ 19 - 0
modules_k/dialog/doc/dialog.xml

@@ -21,6 +21,14 @@
 			<email>[email protected]</email>
 		</address>
 		</author>
+		<author>
+		<firstname>Carsten</firstname>
+		<surname>Bock</surname>
+		<affiliation><orgname>ng-voice.com</orgname></affiliation>
+		<address>
+			<email>[email protected]</email>
+		</address>
+		</author>
 		<editor>
 		<firstname>Bogdan-Andrei</firstname>
 		<surname>Iancu</surname>
@@ -28,11 +36,22 @@
 			<email>[email protected]</email>
 		</address>
 		</editor>
+		<editor>
+		<firstname>Carsten</firstname>
+		<surname>Bock</surname>
+		<address>
+			<email>[email protected]</email>
+		</address>
+		</editor>
 	</authorgroup>
 	<copyright>
 		<year>2006</year>
 		<holder>&voicesystem;</holder>
 	</copyright>
+	<copyright>
+		<year>2011</year>
+		<holder>Carsten Bock, http://www.ng-voice.com</holder>
+	</copyright>
 	<revhistory>
 		<revision>
 		<revnumber>$Revision$</revnumber>

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

@@ -341,9 +341,9 @@ modparam("dialog", "dlg_match_mode", 1)
 		<example>
 			<title>Set <varname>detect_spirals</varname> parameter</title>
 			<programlisting format="linespecific">
-...
-modparam("dialog", "detect_spirals", 1)
-...
+				...
+				modparam("dialog", "detect_spirals", 1)
+				...
 			</programlisting>
 		</example>
 	</section>
@@ -891,6 +891,109 @@ modparam("dialog", "toroute_column", "timeout_route")
 		</example>
 	</section>
 
+	<section>
+		<title><varname>vars_table_name</varname> (string)</title>
+		<para>
+		If you want to store the variables for a dialog in a
+		database a table name must be specified.
+		</para>
+		<para>
+		<emphasis>
+			Default value is <quote>dialog_vars</quote>.
+		</emphasis>
+		</para>
+		<example>
+		<title>Set <varname>vars_table_name</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+modparam("dialog", "vars_table_name", "my_dialog_vars")
+...
+</programlisting>
+		</example>
+	</section>
+
+	<section>
+		<title><varname>vars_h_id_column</varname> (string)</title>
+		<para>
+			The column name in the database to store the dialogs'
+			hash id information (as a reference to the dialog table).
+		</para>
+		<para>
+		<emphasis>
+			Default value is <quote>hash_id</quote>.
+		</emphasis>
+		</para>
+		<example>
+		<title>Set <varname>vars_h_id_column</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+modparam("dialog", "vars_h_id_column", "vars_h_id_name")
+...
+</programlisting>
+		</example>
+	</section>
+
+	<section>
+		<title><varname>vars_h_entry_column</varname> (string)</title>
+		<para>
+			The column name in the database to store the dialogs'
+			hash entry information (as a reference to the dialog table).
+		</para>
+		<para>
+		<emphasis>
+			Default value is <quote>hash_entry</quote>.
+		</emphasis>
+		</para>
+		<example>
+		<title>Set <varname>vars_h_entry_column</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+modparam("dialog", "vars_h_entry_column", "vars_h_entry_name")
+...
+</programlisting>
+		</example>
+	</section>
+
+	<section>
+		<title><varname>vars_key_column</varname> (string)</title>
+		<para>
+			The column name in the database to store the keys of a variable.
+		</para>
+		<para>
+		<emphasis>
+			Default value is <quote>dialog_key</quote>.
+		</emphasis>
+		</para>
+		<example>
+		<title>Set <varname>vars_key_column</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+modparam("dialog", "vars_key_column", "vars_key_name")
+...
+</programlisting>
+		</example>
+	</section>
+
+	<section>
+		<title><varname>vars_value_column</varname> (string)</title>
+		<para>
+			The column name in the database to store the keys of a variable.
+		</para>
+		<para>
+		<emphasis>
+			Default value is <quote>dialog_value</quote>.
+		</emphasis>
+		</para>
+		<example>
+		<title>Set <varname>vars_value_column</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+modparam("dialog", "vars_value_column", "vars_value_name")
+...
+</programlisting>
+		</example>
+	</section>
+
 	<section>
 		<title><varname>profiles_with_value</varname> (string)</title>
 		<para>
@@ -1947,6 +2050,21 @@ if(!uri == myself) {
 			<para>Access to dialog context attributes.</para>
 		</section>
 
+		<section>
+			<title><varname>$dlg_var(key)</varname></title>
+			<para>
+			This is a read/write variable that can be used to store 
+			custom values assigned with a dialog (e.g. the URI of a
+			billing-server, an assigned emergency-server).
+			This pseudo-variable will be available only for subsequential
+			requests after doing loose_route().
+			</para>
+			<para>
+			Note: You will receive "NULL", if there is no dialog for this
+			request.
+			</para>
+		</section>
+
 	</section>
 
 

+ 2 - 1
modules_k/dialog/doc/dialog_devel.xml

@@ -52,7 +52,8 @@
 			</listitem>
 			<listitem>
 				<para><emphasis>DLGCB_CONFIRMED</emphasis> - called when the 
-				dialog is confirmed (2xx replied) - it's a per dialog type.
+				dialog is confirmed (2xx replied) and the setup-concluding ACK
+				message from the caller has been seen - it's a per dialog type.
 				</para>
 			</listitem>
 			<listitem>

+ 77 - 13
modules_k/dispatcher/README

@@ -14,7 +14,7 @@ Edited by
 
 Carsten Bock
 
-   BASIS AudioNet GmbH
+   ng-voice.com
 
    Copyright © 2004 FhG FOKUS
 
@@ -82,10 +82,16 @@ Carsten Bock
               5.2. ds_list
               5.3. ds_reload
 
-        6. Installation and Running
+        6. Exported RPC Commands
 
-              6.1. Destination List File
-              6.2. Kamailio config file
+              6.1. dispatcher.set_state
+              6.2. dispatcher.list
+              6.3. dispatcher.reload
+
+        7. Installation and Running
+
+              7.1. Destination List File
+              7.2. Kamailio config file
 
    2. Frequently Asked Questions
 
@@ -183,10 +189,16 @@ Chapter 1. Admin Guide
         5.2. ds_list
         5.3. ds_reload
 
-   6. Installation and Running
+   6. Exported RPC Commands
+
+        6.1. dispatcher.set_state
+        6.2. dispatcher.list
+        6.3. dispatcher.reload
 
-        6.1. Destination List File
-        6.2. Kamailio config file
+   7. Installation and Running
+
+        7.1. Destination List File
+        7.2. Kamailio config file
 
 1. Overview
 
@@ -751,7 +763,8 @@ ds_select_dst("1", "$var(a)");
    possible parameters:
      * "i", "I" or "0" - the last destination should be set to inactive
        and will be ignored in future requests.
-     * "a", "A" or "1" - the last destination should be set to active.
+     * "a", "A" or "1" - the last destination should be set to active and
+       the error-counter should set to "0".
      * "p", "P" or "2" - the last destination will be set to probing.
        Note: You will need to call this function "threshhold"-times,
        before it will be actually set to probing.
@@ -872,12 +885,63 @@ onreply_route {
    MI DATAGRAM Command Format:
                 ":ds_reload:\n."
 
-6. Installation and Running
+6. Exported RPC Commands
+
+   6.1. dispatcher.set_state
+   6.2. dispatcher.list
+   6.3. dispatcher.reload
+
+6.1.  dispatcher.set_state
+
+   Sets the state for a destination address (can be use to mark the
+   destination as active or inactive).
+
+   Name: dispatcher.set_state
+
+   Parameters:
+     * _state_ : state of the destination address
+          + “a”: active
+          + “i”: inactive
+          + “d”: disabled
+       The states “a” or “i” can be followed by “p” to set probing mode
+       (e.g. 'ap' or 'ip')
+     * _group_: destination group id
+     * _address_: address of the destination in the _group_
+
+   Example:
+                sercmd dispatcher.set_state _state_ _group_ _address_
+
+6.2.  dispatcher.list
+
+   It lists the groups and included destinations.
+
+   Name: dispatcher.list
+
+   Parameters: none
+
+   Example:
+                sercmd dispatcher.list
+
+6.3.  dispatcher.reload
+
+   It reloads the groups and included destinations. The command is
+   disabled for call load based dispatching (algorithm 10) since removal
+   of destinations may leave the list of active calls with broken
+   references.
+
+   Name: dispatcher.reload
+
+   Parameters: none
+
+   Example
+                sercmd dispatcher.reload
+
+7. Installation and Running
 
-   6.1. Destination List File
-   6.2. Kamailio config file
+   7.1. Destination List File
+   7.2. Kamailio config file
 
-6.1. Destination List File
+7.1. Destination List File
 
    Each destination point must be on one line. First token is the set id
    (an integer value), followed by destination address (s string value in
@@ -926,7 +990,7 @@ r,opt)
 
 ...
 
-6.2. Kamailio config file
+7.2. Kamailio config file
 
    Next picture displays a sample usage of dispatcher.
 

+ 11 - 31
modules_k/dispatcher/dispatch.c

@@ -86,37 +86,6 @@ static int _ds_table_version = DS_TABLE_VERSION;
 
 static ds_ht_t *_dsht_load = NULL;
 
-typedef struct _ds_attrs
-{
-	str body;
-	str duid;
-	int maxload;
-	int weight;
-} ds_attrs_t;
-
-typedef struct _ds_dest
-{
-	str uri;
-	int flags;
-	int priority;
-	int dload;
-	ds_attrs_t attrs;
-	struct ip_addr ip_address; 	/*!< IP-Address of the entry */
-	unsigned short int port; 	/*!< Port of the request URI */
-	int failure_count;
-	struct _ds_dest *next;
-} ds_dest_t;
-
-typedef struct _ds_set
-{
-	int id;				/*!< id of dst set */
-	int nr;				/*!< number of items in dst set */
-	int last;			/*!< last used item in dst set (round robin) */
-	int wlast;			/*!< last used item in dst set (by weight) */
-	ds_dest_t *dlist;
-	unsigned int wlist[100];
-	struct _ds_set *next;
-} ds_set_t;
 
 extern int ds_force_dst;
 
@@ -2449,3 +2418,14 @@ int bind_dispatcher(dispatcher_api_t* api)
 	api->is_from = ds_is_from_list;
 	return 0;
 }
+
+
+ds_set_t *ds_get_list(void)
+{
+	return _ds_list;
+}
+
+int ds_get_list_nr(void)
+{
+	return _ds_list_nr;
+}

+ 34 - 0
modules_k/dispatcher/dispatch.h

@@ -128,5 +128,39 @@ void ds_ht_timer(unsigned int ticks, void *param);
  */
 int ds_ping_check_rplcode(int);
 
+typedef struct _ds_attrs
+{
+	str body;
+	str duid;
+	int maxload;
+	int weight;
+} ds_attrs_t;
+
+typedef struct _ds_dest
+{
+	str uri;
+	int flags;
+	int priority;
+	int dload;
+	ds_attrs_t attrs;
+	struct ip_addr ip_address; 	/*!< IP-Address of the entry */
+	unsigned short int port; 	/*!< Port of the request URI */
+	int failure_count;
+	struct _ds_dest *next;
+} ds_dest_t;
+
+typedef struct _ds_set
+{
+	int id;				/*!< id of dst set */
+	int nr;				/*!< number of items in dst set */
+	int last;			/*!< last used item in dst set (round robin) */
+	int wlast;			/*!< last used item in dst set (by weight) */
+	ds_dest_t *dlist;
+	unsigned int wlist[100];
+	struct _ds_set *next;
+} ds_set_t;
+
+ds_set_t *ds_get_list(void);
+int ds_get_list_nr(void);
 #endif
 

+ 218 - 0
modules_k/dispatcher/dispatcher.c

@@ -62,6 +62,8 @@
 #include "../../route.h"
 #include "../../mem/mem.h"
 #include "../../mod_fix.h"
+#include "../../rpc.h"
+#include "../../rpc_lookup.h"
 
 #include "ds_ht.h"
 #include "dispatch.h"
@@ -138,6 +140,7 @@ static int mod_init(void);
 static int child_init(int);
 
 static int ds_parse_reply_codes();
+static int ds_init_rpc(void);
 
 static int w_ds_select_dst(struct sip_msg*, char*, char*);
 static int w_ds_select_domain(struct sip_msg*, char*, char*);
@@ -256,6 +259,11 @@ static int mod_init(void)
 		LM_ERR("failed to register MI commands\n");
 		return -1;
 	}
+	if(ds_init_rpc()<0)
+	{
+		LM_ERR("failed to register RPC commands\n");
+		return -1;
+	}
 
 	if (dst_avp_param.s)
 		dst_avp_param.len = strlen(dst_avp_param.s);
@@ -878,3 +886,213 @@ int ds_ping_check_rplcode(int code)
 void ds_ping_reply_codes_update(str* gname, str* name){
 	ds_parse_reply_codes();
 }
+
+/*** RPC implementation ***/
+
+static const char* dispatcher_rpc_reload_doc[2] = {
+	"Reload dispatcher destination sets",
+	0
+};
+
+
+/*
+ * RPC command to reload dispatcher destination sets
+ */
+static void dispatcher_rpc_reload(rpc_t* rpc, void* ctx)
+{
+	if(dstid_avp_name.n!=0) {
+		LM_ERR("No reload support when call load dispatching is enabled."
+				" Do not set dstid_avp param if you do not use alg 10.\n");
+		rpc->fault(ctx, 500, "Command disabled");
+		return ;
+	}
+
+	if(!ds_db_url.s) {
+		if (ds_load_list(dslistfile)!=0) {
+			rpc->fault(ctx, 500, "Reload Failed");
+			return;
+		}
+	} else {
+		if(ds_load_db()<0) {
+			rpc->fault(ctx, 500, "Reload Failed");
+			return;
+		}
+	}
+	return;
+}
+
+
+
+static const char* dispatcher_rpc_list_doc[2] = {
+	"Return the content of dispatcher sets",
+	0
+};
+
+
+/*
+ * RPC command to print dispatcher destination sets
+ */
+static void dispatcher_rpc_list(rpc_t* rpc, void* ctx)
+{
+	void* th;
+	void* ih;
+	void* vh;
+	int j;
+	char c[3];
+	str data = {"", 0};
+	ds_set_t *ds_list;
+	int ds_list_nr;
+	ds_set_t *list;
+
+	ds_list = ds_get_list();
+	ds_list_nr = ds_get_list_nr();
+
+	if(ds_list==NULL || ds_list_nr<=0)
+	{
+		LM_ERR("no destination sets\n");
+		rpc->fault(ctx, 500, "No Destination Sets");
+		return;
+	}
+
+	/* add entry node */
+	if (rpc->add(ctx, "{", &th) < 0)
+	{
+		rpc->fault(c, 500, "Internal error root reply");
+		return;
+	}
+	if(rpc->struct_add(th, "d{",
+				"SET_NO", ds_list_nr,
+				"SET",  &ih)<0)
+	{
+		rpc->fault(c, 500, "Internal error set structure");
+		return;
+	}
+
+
+	for(list = ds_list; list!= NULL; list= list->next)
+	{
+		if(rpc->struct_add(ih, "d",
+				"SET_ID", list->id)<0)
+		{
+			rpc->fault(c, 500, "Internal error creating set id");
+			return;
+		}
+
+		for(j=0; j<list->nr; j++)
+		{
+			if(rpc->struct_add(ih, "{",
+				"DEST", &vh)<0)
+			{
+				rpc->fault(c, 500, "Internal error creating dest");
+				return;
+			}
+
+			memset(&c, 0, sizeof(c));
+			if (list->dlist[j].flags & DS_INACTIVE_DST)
+				c[0] = 'I';
+			else if (list->dlist[j].flags & DS_DISABLED_DST)
+				c[0] = 'D';
+			else
+				c[0] = 'A';
+
+			if (list->dlist[j].flags & DS_PROBING_DST)
+				c[1] = 'P';
+			else
+				c[1] = 'X';
+
+			if(rpc->struct_add(vh, "SsdS",
+				"URI", &list->dlist[j].uri,
+				"FLAGS", c,
+				"PRIORITY", list->dlist[j].priority,
+				"ATTRS", (list->dlist[j].attrs.body.s)?
+							&(list->dlist[j].attrs.body):&data)<0)
+			{
+				rpc->fault(c, 500, "Internal error creating dest struct");
+				return;
+			}
+		}
+	}
+
+	return;
+}
+
+
+static const char* dispatcher_rpc_set_state_doc[2] = {
+	"Set the state of a destination address",
+	0
+};
+
+
+/*
+ * RPC command to set the state of a destination address
+ */
+static void dispatcher_rpc_set_state(rpc_t* rpc, void* ctx)
+{
+	int group;
+	str dest;
+	str state;
+	int stval;
+
+	if(rpc->scan(ctx, ".SdS", &state, &group, &dest)<3)
+	{
+		rpc->fault(ctx, 500, "Invalid Parameters");
+		return;
+	}
+	if(state.len<=0 || state.s==NULL)
+	{
+		LM_ERR("bad state value\n");
+		rpc->fault(ctx, 500, "Invalid State Parameter");
+		return;
+	}
+
+	stval = 0;
+	if(state.s[0]=='0' || state.s[0]=='I' || state.s[0]=='i') {
+		/* set inactive */
+		stval |= DS_INACTIVE_DST;
+		if((state.len>1) && (state.s[1]=='P' || state.s[1]=='p'))
+			stval |= DS_PROBING_DST;
+	} else if(state.s[0]=='1' || state.s[0]=='A' || state.s[0]=='a') {
+		/* set active */
+		if((state.len>1) && (state.s[1]=='P' || state.s[1]=='p'))
+			stval |= DS_PROBING_DST;
+	} else if(state.s[0]=='2' || state.s[0]=='D' || state.s[0]=='d') {
+		/* set disabled */
+		stval |= DS_DISABLED_DST;
+	} else {
+		LM_ERR("unknow state value\n");
+		rpc->fault(ctx, 500, "Unknown State Value");
+		return;
+	}
+
+	if(ds_reinit_state(group, &dest, stval)<0)
+	{
+		rpc->fault(ctx, 500, "State Update Failed");
+		return;
+	}
+
+	return;
+}
+
+
+rpc_export_t dispatcher_rpc_cmds[] = {
+	{"dispatcher.reload", dispatcher_rpc_reload,
+		dispatcher_rpc_reload_doc, 0},
+	{"dispatcher.list",   dispatcher_rpc_list,
+		dispatcher_rpc_list_doc,   0},
+	{"dispatcher.set_state",   dispatcher_rpc_set_state,
+		dispatcher_rpc_set_state_doc,   0},
+	{0, 0, 0, 0}
+};
+
+/**
+ * register RPC commands
+ */
+static int ds_init_rpc(void)
+{
+	if (rpc_register_array(dispatcher_rpc_cmds)!=0)
+	{
+		LM_ERR("failed to register RPC commands\n");
+		return -1;
+	}
+	return 0;
+}

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

@@ -1091,7 +1091,86 @@ onreply_route {
     </section>
 
     </section>
-	
+
+	<section>
+	<title>Exported RPC Commands</title>
+	<section>
+		<title>
+		<function moreinfo="none">dispatcher.set_state</function>
+		</title>
+		<para>
+		Sets the state for a destination address (can be use to mark the destination
+		as active or inactive).
+		</para>
+		<para>
+		Name: <emphasis>dispatcher.set_state</emphasis>
+		</para>
+		<para>Parameters:</para>
+		<itemizedlist>
+			<listitem><para>_state_ : state of the destination address</para>
+			      <itemizedlist>
+	                 <listitem><para> <quote>a</quote>: active</para></listitem>
+			         <listitem><para> <quote>i</quote>: inactive</para></listitem>
+			         <listitem><para> <quote>d</quote>: disabled</para></listitem>
+				  </itemizedlist>
+				  <para>The states <quote>a</quote> or <quote>i</quote> can be
+					  followed by <quote>p</quote> to set probing mode (e.g. 'ap'
+					  or 'ip')</para>
+			</listitem>
+
+			<listitem><para>_group_: destination group id</para></listitem>
+
+			<listitem><para>_address_: address of the destination in the _group_</para></listitem>
+		</itemizedlist>
+		<para>
+		Example:
+		</para>
+        <programlisting  format="linespecific">
+		sercmd dispatcher.set_state _state_ _group_ _address_
+		</programlisting>
+    </section>
+	<section>
+		<title>
+		<function moreinfo="none">dispatcher.list</function>
+		</title>
+		<para>
+		It lists the groups and included destinations.
+		</para>
+		<para>
+		Name: <emphasis>dispatcher.list</emphasis>
+		</para>
+		<para>Parameters: <emphasis>none</emphasis></para>
+		<para>
+		Example:
+		</para>
+        <programlisting  format="linespecific">
+		sercmd dispatcher.list
+		</programlisting>
+    </section>
+	<section>
+		<title>
+		<function moreinfo="none">dispatcher.reload</function>
+		</title>
+		<para>
+		It reloads the groups and included destinations. The command is
+		disabled for call load based dispatching (algorithm 10) since
+		removal of destinations may leave the list of active
+		calls with broken references.
+		</para>
+		<para>
+		Name: <emphasis>dispatcher.reload</emphasis>
+		</para>
+		<para>Parameters: <emphasis>none</emphasis></para>
+		<para>
+		Example
+		</para>
+        <programlisting  format="linespecific">
+		sercmd dispatcher.reload
+		</programlisting>
+    </section>
+
+   </section>
+
 	<section>
 	<title>Installation and Running</title>
 	<section>

+ 1 - 0
modules_k/dispatcher/ds_ht.c

@@ -20,6 +20,7 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
+#include <stddef.h>
 #include <regex.h>
 
 #include "../../mem/shm_mem.h"

+ 49 - 11
modules_k/domain/README

@@ -10,7 +10,7 @@ Juha Heinanen
 
    <[email protected]>
 
-   Copyright © 2002-2008 Juha Heinanen
+   Copyright © 2002-2008 Juha Heinanen
    Revision History
    Revision $Revision$ $Date$
      __________________________________________________________________
@@ -40,7 +40,12 @@ Juha Heinanen
               5.1. domain_reload
               5.2. domain_dump
 
-        6. Known Limitations
+        6. Exported RPC Commands
+
+              6.1. domain.reload
+              6.2. domain.dump
+
+        7. Known Limitations
 
    2. Developer Guide
 
@@ -84,12 +89,17 @@ Chapter 1. Admin Guide
         5.1. domain_reload
         5.2. domain_dump
 
-   6. Known Limitations
+   6. Exported RPC Commands
+
+        6.1. domain.reload
+        6.2. domain.dump
+
+   7. Known Limitations
 
 1. Overview
 
    Domain module implements checks that based on domain table determine if
-   a host part of an URI is "local" or not. A "local" domain is one that
+   a host part of an URI is “local� or not. A “local� domain is one that
    the proxy is responsible for.
 
    Domain module operates in caching or non-caching mode depending on
@@ -97,13 +107,13 @@ Chapter 1. Admin Guide
    the contents of domain table into cache memory when the module is
    loaded. After that domain table is re-read only when module is given
    domain_reload fifo command. Any changes in domain table must thus be
-   followed by "domain_reload" command in order to reflect them in module
+   followed by “domain_reload� command in order to reflect them in module
    behavior. In non-caching mode domain module always queries domain table
    in the database.
 
    Caching is implemented using a hash table. The size of the hash table
-   is given by HASH_SIZE constant defined in domain_mod.h. Its "factory
-   default" value is 128.
+   is given by HASH_SIZE constant defined in domain_mod.h. Its “factory
+   default� value is 128.
 
 2. Dependencies
 
@@ -123,7 +133,7 @@ Chapter 1. Admin Guide
 
    This is URL of the database to be used.
 
-   Default value is "mysql://openserro:openserro@localhost/openser"
+   Default value is “mysql://openserro:openserro@localhost/openser�
 
    Example 1.1. Setting db_url parameter
 modparam("domain", "db_url", "mysql://ser:pass@db_host/ser")
@@ -143,7 +153,7 @@ modparam("domain", "db_mode", 1)   # Use caching
    responsible for. Local users must have in their sip uri a host part
    that is equal to one of these domains.
 
-   Default value is "domain".
+   Default value is “domain�.
 
    Example 1.3. Setting domain_table parameter
 modparam("domain", "domain_table", "new_name")
@@ -152,7 +162,7 @@ modparam("domain", "domain_table", "new_name")
 
    Name of column containing domains in domain table.
 
-   Default value is "domain".
+   Default value is “domain�.
 
    Example 1.4. Setting domain_col parameter
 modparam("domain", "domain_col", "domain_name")
@@ -270,7 +280,35 @@ if (is_domain_local("$avp(s:some_avp)")) {
                 :domain_dump:_reply_fifo_file_
                 _empty_line_
 
-6. Known Limitations
+6. Exported RPC Commands
+
+   6.1. domain.reload
+   6.2. domain.dump
+
+6.1. domain.reload
+
+   Causes domain module to re-read the contents of domain table into cache
+   memory.
+
+   Name: domain.reload
+
+   Parameters: none
+
+   Example:
+                sercmd domain.reload
+
+6.2. domain.dump
+
+   Causes domain module to dump domain names in its cache memory.
+
+   Name: domain.dump
+
+   Parameters: none
+
+   Example:
+                sercmd domain.dump
+
+7. Known Limitations
 
    There is an unlikely race condition on domain list update. If a process
    uses a table, which is reloaded at the same time twice through FIFO,

+ 37 - 0
modules_k/domain/doc/domain_admin.xml

@@ -275,6 +275,43 @@ if (is_domain_local("$avp(s:some_avp)")) {
 	</section>
 	</section>
 	<section>
+	<title>Exported RPC Commands</title>
+	<section>
+		<title><function moreinfo="none">domain.reload</function></title>
+		<para>
+		Causes domain module to re-read the contents of domain table
+		into cache memory.
+		</para>
+		<para>
+		Name: <emphasis>domain.reload</emphasis>
+		</para>
+		<para>Parameters: <emphasis>none</emphasis></para>
+		<para>
+		Example:
+		</para>
+        <programlisting  format="linespecific">
+		sercmd domain.reload
+		</programlisting>
+	</section>
+	<section>
+		<title><function moreinfo="none">domain.dump</function></title>
+		<para>
+		Causes domain module to dump domain names in
+		its cache memory.
+		</para>
+		<para>
+		Name: <emphasis>domain.dump</emphasis>
+		</para>
+		<para>Parameters: <emphasis>none</emphasis></para>
+		<para>
+		Example:
+		</para>
+        <programlisting  format="linespecific">
+		sercmd domain.dump
+		</programlisting>
+	</section>
+	</section>
+	<section>
 	<title>Known Limitations</title>
 	<para>
 		There is an unlikely race condition on domain list update.  If a 

+ 88 - 0
modules_k/domain/domain_mod.c

@@ -42,6 +42,8 @@
 #include "../../pvar.h"
 #include "../../forward.h"
 #include "../../mod_fix.h"
+#include "../../rpc.h"
+#include "../../rpc_lookup.h"
 #include "domain.h"
 #include "mi.h"
 #include "hash.h"
@@ -70,6 +72,8 @@ MODULE_VERSION
 #define DOMAIN_COL "domain"
 #define DOMAIN_COL_LEN (sizeof(DOMAIN_COL) - 1)
 
+static int domain_init_rpc(void);
+
 /*
  * Module parameter variables
  */
@@ -156,6 +160,12 @@ static int mod_init(void)
 		LM_ERR("failed to register MI commands\n");
 		return -1;
 	}
+	if(domain_init_rpc()!=0)
+	{
+		LM_ERR("failed to register RPC commands\n");
+		return -1;
+	}
+
 	if(domain_reg_myself!=0)
 	{
 		if(register_check_self_func(domain_check_self)<0)
@@ -260,3 +270,81 @@ static void destroy(void)
 		hash_table_2 = 0;
 	}
 }
+
+
+static const char* domain_rpc_reload_doc[2] = {
+	"Reload domain table from database",
+	0
+};
+
+
+/*
+ * RPC command to reload domain table
+ */
+static void domain_rpc_reload(rpc_t* rpc, void* ctx)
+{
+	if (!db_mode) {
+		rpc->fault(ctx, 500, "Server Domain Cache Disabled");
+		return;
+	}
+
+	if (reload_domain_table() < 0) {
+		rpc->fault(ctx, 400, "Domain Table Reload Failed");
+	}
+}
+
+
+
+static const char* domain_rpc_dump_doc[2] = {
+	"Return the contents of domain table",
+	0
+};
+
+
+/*
+ * Fifo function to print domains from current hash table
+ */
+static void domain_rpc_dump(rpc_t* rpc, void* ctx)
+{
+	int i;
+	struct domain_list *np;
+	struct domain_list **ht;
+
+	if (!db_mode) {
+		rpc->fault(ctx, 400, "Server Domain Cache Disabled");
+		return;
+	}
+
+	if(hash_table==0 || *hash_table==0) {
+		rpc->fault(ctx, 404, "Server Domain Cache Empty");
+		return;
+	}
+	ht = *hash_table;
+	for (i = 0; i < DOM_HASH_SIZE; i++) {
+		np = ht[i];
+		while (np) {
+			if (rpc->add(ctx, "S", &np->domain) < 0)
+				return;
+
+			np = np->next;
+		}
+	}
+	return;
+}
+
+
+rpc_export_t domain_rpc_list[] = {
+	{"domain.reload", domain_rpc_reload, domain_rpc_reload_doc, 0},
+	{"domain.dump",   domain_rpc_dump,   domain_rpc_dump_doc,   0},
+	{0, 0, 0, 0}
+};
+
+static int domain_init_rpc(void)
+{
+	if (rpc_register_array(domain_rpc_list)!=0)
+	{
+		LM_ERR("failed to register RPC commands\n");
+		return -1;
+	}
+	return 0;
+}

+ 10 - 3
modules_k/htable/README

@@ -11,7 +11,7 @@ Elena-Ramona Modroiu
 
    <[email protected]>
 
-   Copyright © 2008-2011 http://www.asipto.com
+   Copyright © 2008-2011 http://www.asipto.com
      __________________________________________________________________
 
    Table of Contents
@@ -130,7 +130,7 @@ Chapter 1. Admin Guide
    You can read more about hash tables at:
    http://en.wikipedia.org/wiki/Hash_table.
 
-   The “name� can be a static string or can include pseudo- variables that
+   The "name" can be a static string or can include pseudo- variables that
    will be replaced at runtime.
 
    Example 1.1. Accessing $sht(htname=>key)
@@ -153,7 +153,7 @@ $sht(a=>$ci::srcip) = $si;
    the failed authentications per user and one for storing the time of
    last authentication attempt. To ensure unique name per user, the hash
    table uses a combination of authentication username and text
-   “::auth_count� and “::last_auth�.
+   "::auth_count" and "::last_auth".
 
    Example 1.2. Dictionary attack limitation
 ...
@@ -268,6 +268,8 @@ if(is_present_hf("Authorization"))
        database table when the SIP server is stopped (i.e., ensure
        persistency over restarts). Default value is 0 (no write back to db
        table).
+     * initval - the integer value to be returned insted of $null when a
+       requested key is not set.
 
    Default value is NULL.
 
@@ -275,6 +277,7 @@ if(is_present_hf("Authorization"))
 ...
 modparam("htable", "htable", "a=>size=4;autoexpire=7200;dbtable=htable_a;")
 modparam("htable", "htable", "b=>size=5;")
+modparam("htable", "htable", "c=>size=4;autoexpire=7200;initval=1;")
 ...
 
 3.2. db_url (str)
@@ -427,6 +430,10 @@ sht_rm_value_re("ha=>.*");
 
      * $sht(htable=>key)
      * $shtex(htable=>key)
+     * $shtcn(htable=>key)
+     * $shtcv(htable=>key)
+     * $shtinc(htable=>key)
+     * $shtval(htable=>key)
 
    Exported pseudo-variables are documented at
    http://www.kamailio.org/dokuwiki/.

+ 19 - 0
modules_k/htable/doc/htable_admin.xml

@@ -261,6 +261,12 @@ if(is_present_hf("Authorization"))
 			write back to db table).
 		</para>
 		</listitem>
+		<listitem>
+		<para>
+			<emphasis>initval</emphasis> - the integer value to be returned
+			insted of $null when a requested key is not set.
+		</para>
+		</listitem>
 		</itemizedlist>
 		<para>
 		<emphasis>
@@ -273,6 +279,7 @@ if(is_present_hf("Authorization"))
 ...
 modparam("htable", "htable", "a=&gt;size=4;autoexpire=7200;dbtable=htable_a;")
 modparam("htable", "htable", "b=&gt;size=5;")
+modparam("htable", "htable", "c=&gt;size=4;autoexpire=7200;initval=1;")
 ...
 </programlisting>
 		</example>
@@ -528,6 +535,18 @@ sht_rm_value_re("ha=>.*");
 			<listitem><para>
 				<emphasis>$shtex(htable=>key)</emphasis>
 			</para></listitem>
+			<listitem><para>
+				<emphasis>$shtcn(htable=>key)</emphasis>
+			</para></listitem>
+			<listitem><para>
+				<emphasis>$shtcv(htable=>key)</emphasis>
+			</para></listitem>
+			<listitem><para>
+				<emphasis>$shtinc(htable=>key)</emphasis>
+			</para></listitem>
+			<listitem><para>
+				<emphasis>$shtval(htable=>key)</emphasis>
+			</para></listitem>
 		</itemizedlist>
 		<para>
 		Exported pseudo-variables are documented at &kamwikilink;.

+ 276 - 137
modules_k/htable/ht_api.c

@@ -20,11 +20,14 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
+#include <stddef.h>
 #include <regex.h>
 
 #include "../../mem/shm_mem.h"
 #include "../../mem/mem.h"
+#include "../../shm_init.h"
 #include "../../dprint.h"
+#include "../../parser/parse_param.h"
 #include "../../lib/kcore/hash_func.h"
 #include "../../ut.h"
 #include "../../re.h"
@@ -38,8 +41,104 @@
 
 
 ht_t *_ht_root = NULL;
-ht_t *_ht_pkg_root = NULL;
 
+typedef struct _keyvalue {
+	str key;
+	str value;
+	int type;
+	union {
+		param_t *params;
+	} u;
+} keyvalue_t;
+
+
+#define KEYVALUE_TYPE_NONE		0
+#define KEYVALUE_TYPE_PARAMS	1
+
+/**
+ * parse a string like: 'key=>value'
+ *   - the value can be parameter list: 'name1=value1;...;nameX=valueX'
+ */
+int keyvalue_parse_str(str *data, int type, keyvalue_t *res)
+{
+	char *p;
+	str s;
+	str in;
+	param_hooks_t phooks;
+
+	if(data==NULL || data->s==NULL || data->len<=0 || res==NULL)
+	{
+		LM_ERR("invalid parameters\n");
+		return -1;
+	}
+
+	memset(res, 0, sizeof(keyvalue_t));
+
+	in.s = data->s;
+	in.len = data->len;
+
+	p = in.s;
+	while(p<in.s+in.len && (*p==' ' || *p=='\t' || *p=='\n' || *p=='\r'))
+		p++;
+	if(p>in.s+in.len || *p=='\0')
+		goto error;
+	res->key.s = p;
+	while(p < in.s + in.len)
+	{
+		if(*p=='=' || *p==' ' || *p=='\t' || *p=='\n' || *p=='\r')
+			break;
+		p++;
+	}
+	if(p>in.s+in.len || *p=='\0')
+		goto error;
+	res->key.len = (int)(p - res->key.s);
+	if(*p!='=')
+	{
+		while(p<in.s+in.len && (*p==' ' || *p=='\t' || *p=='\n' || *p=='\r'))
+			p++;
+		if(p>in.s+in.len || *p=='\0' || *p!='=')
+			goto error;
+	}
+	p++;
+	if(*p!='>')
+		goto error;
+	p++;
+	while(p<in.s+in.len && (*p==' ' || *p=='\t' || *p=='\n' || *p=='\r'))
+		p++;
+
+	s.s = p;
+	s.len = in.s + in.len - p;
+	res->value.s = s.s;
+	res->value.len = s.len;
+	res->type = type;
+	if(type==KEYVALUE_TYPE_PARAMS)
+	{
+		if(s.s[s.len-1]==';')
+			s.len--;
+		if (parse_params(&s, CLASS_ANY, &phooks, &res->u.params)<0)
+		{
+			LM_ERR("failed parsing params value\n");
+			goto error;
+		}
+	}
+	return 0;
+error:
+	LM_ERR("invalid input parameter [%.*s] at [%d]\n", in.len, in.s,
+			(int)(p-in.s));
+	return -1;
+}
+
+void keyvalue_destroy(keyvalue_t *res)
+{
+	if(res==NULL)
+		return;
+	if(res->type==KEYVALUE_TYPE_PARAMS)
+	{
+		if(res->u.params!=NULL)
+			free_params(res->u.params);
+	}
+	memset(res, 0, sizeof(keyvalue_t));
+}
 
 ht_cell_t* ht_cell_new(str *name, int type, int_str *val, unsigned int cellid)
 {
@@ -86,7 +185,6 @@ int ht_cell_free(ht_cell_t *cell)
 	return 0;
 }
 
-
 int ht_cell_pkg_free(ht_cell_t *cell)
 {
 	if(cell==NULL)
@@ -95,6 +193,7 @@ int ht_cell_pkg_free(ht_cell_t *cell)
 	return 0;
 }
 
+
 ht_t* ht_get_table(str *name)
 {
 	unsigned int htid;
@@ -117,7 +216,8 @@ ht_t* ht_get_table(str *name)
 	return NULL;
 }
 
-int ht_pkg_init(str *name, int autoexp, str *dbtable, int size, int dbmode, int usedmq)
+int ht_add_table(str *name, int autoexp, str *dbtable, int size, int dbmode, int dmq,
+		int itype, int_str *ival)
 {
 	unsigned int htid;
 	ht_t *ht;
@@ -125,7 +225,7 @@ int ht_pkg_init(str *name, int autoexp, str *dbtable, int size, int dbmode, int
 	htid = ht_compute_hash(name);
 
 	/* does it exist */
-	ht = _ht_pkg_root;
+	ht = _ht_root;
 	while(ht!=NULL)
 	{
 		if(htid == ht->htid && name->len==ht->name.len 
@@ -137,10 +237,10 @@ int ht_pkg_init(str *name, int autoexp, str *dbtable, int size, int dbmode, int
 		ht = ht->next;
 	}
 
-	ht = (ht_t*)pkg_malloc(sizeof(ht_t));
+	ht = (ht_t*)shm_malloc(sizeof(ht_t));
 	if(ht==NULL)
 	{
-		LM_ERR("no more pkg\n");
+		LM_ERR("no more shared memory\n");
 		return -1;
 	}
 	memset(ht, 0, sizeof(ht_t));
@@ -156,36 +256,29 @@ int ht_pkg_init(str *name, int autoexp, str *dbtable, int size, int dbmode, int
 	if(dbtable!=NULL && dbtable->len>0)
 		ht->dbtable = *dbtable;
 	ht->dbmode = dbmode;
-	ht->usedmq = usedmq;
-	ht->next = _ht_pkg_root;
-	_ht_pkg_root = ht;
+	ht->dmq = dmq;
+	ht->flags = itype;
+	if(ival!=NULL)
+		ht->initval = *ival;
+
+	ht->next = _ht_root;
+	_ht_root = ht;
 	return 0;
 }
 
-int ht_shm_init(void)
+int ht_init_tables(void)
 {
-	ht_t *htp;
-	ht_t *htp0;
 	ht_t *ht;
 	int i;
 
-	htp = _ht_pkg_root;
+	ht = _ht_root;
 
-	while(htp)
+	while(ht)
 	{
-		htp0 = htp->next;
-		ht = (ht_t*)shm_malloc(sizeof(ht_t));
-		if(ht==NULL)
-		{
-			LM_ERR("no more shm\n");
-			return -1;
-		}
-		memcpy(ht, htp, sizeof(ht_t));
-
 		ht->entries = (ht_entry_t*)shm_malloc(ht->htsize*sizeof(ht_entry_t));
 		if(ht->entries==NULL)
 		{
-			LM_ERR("no more shm.\n");
+			LM_ERR("no more shm for [%.*s]\n", ht->name.len, ht->name.s);
 			shm_free(ht);
 			return -1;
 		}
@@ -195,7 +288,8 @@ int ht_shm_init(void)
 		{
 			if(lock_init(&ht->entries[i].lock)==0)
 			{
-				LM_ERR("cannot initalize lock[%d]\n", i);
+				LM_ERR("cannot initalize lock[%d] in [%.*s]\n", i,
+						ht->name.len, ht->name.s);
 				i--;
 				while(i>=0)
 				{
@@ -208,12 +302,8 @@ int ht_shm_init(void)
 
 			}
 		}
-		ht->next = _ht_root;
-		_ht_root = ht;
-		pkg_free(htp);
-		htp = htp0;
+		ht = ht->next;
 	}
-	_ht_pkg_root = NULL;
 
 	return 0;
 }
@@ -232,20 +322,23 @@ int ht_destroy(void)
 	while(ht)
 	{
 		ht0 = ht->next;
-		for(i=0; i<ht->htsize; i++)
+		if(ht->entries!=NULL)
 		{
-			/* free entries */
-			it = ht->entries[i].first;
-			while(it)
+			for(i=0; i<ht->htsize; i++)
 			{
-				it0 = it;
-				it = it->next;
-				ht_cell_free(it0);
+				/* free entries */
+				it = ht->entries[i].first;
+				while(it)
+				{
+					it0 = it;
+					it = it->next;
+					ht_cell_free(it0);
+				}
+				/* free locks */
+				lock_destroy(&ht->entries[i].lock);
 			}
-			/* free locks */
-			lock_destroy(&ht->entries[i].lock);
+			shm_free(ht->entries);
 		}
-		shm_free(ht->entries);
 		shm_free(ht);
 		ht = ht0;
 	}
@@ -428,6 +521,113 @@ int ht_del_cell(ht_t *ht, str *name)
 	return 0;
 }
 
+ht_cell_t* ht_cell_value_add(ht_t *ht, str *name, int val, int mode,
+		ht_cell_t *old)
+{
+	unsigned int idx;
+	unsigned int hid;
+	ht_cell_t *it, *prev, *cell;
+	time_t now;
+	int_str isval;
+
+	if(ht==NULL || ht->entries==NULL)
+		return NULL;
+
+	hid = ht_compute_hash(name);
+
+	idx = ht_get_entry(hid, ht->htsize);
+
+	now = 0;
+	if(ht->htexpire>0)
+		now = time(NULL);
+	prev = NULL;
+	if(mode) lock_get(&ht->entries[idx].lock);
+	it = ht->entries[idx].first;
+	while(it!=NULL && it->cellid < hid)
+	{
+		prev = it;
+		it = it->next;
+	}
+	while(it!=NULL && it->cellid == hid)
+	{
+		if(name->len==it->name.len
+				&& strncmp(name->s, it->name.s, name->len)==0)
+		{
+			/* update value */
+			if(it->flags&AVP_VAL_STR)
+			{
+				/* string value cannot be incremented */
+				if(mode) lock_release(&ht->entries[idx].lock);
+				return NULL;
+			} else {
+				it->value.n += val;
+				it->expire = now + ht->htexpire;
+				if(old!=NULL)
+				{
+					if(old->msize>=it->msize)
+					{
+						memcpy(old, it, it->msize);
+						lock_release(&ht->entries[idx].lock);
+						return old;
+					}
+				}
+				cell = (ht_cell_t*)pkg_malloc(it->msize);
+				if(cell!=NULL)
+					memcpy(cell, it, it->msize);
+
+				if(mode) lock_release(&ht->entries[idx].lock);
+				return cell;
+			}
+		}
+		prev = it;
+		it = it->next;
+	}
+	/* add val if htable has an integer init value */
+	if(ht->flags!=PV_VAL_INT)
+		return NULL;
+	isval.n = ht->initval.n + val;
+	it = ht_cell_new(name, 0, &isval, hid);
+	if(it == NULL)
+	{
+		LM_ERR("cannot create new cell.\n");
+		if(mode) lock_release(&ht->entries[idx].lock);
+		return NULL;
+	}
+	it->expire = now + ht->htexpire;
+	if(prev==NULL)
+	{
+		if(ht->entries[idx].first!=NULL)
+		{
+			it->next = ht->entries[idx].first;
+			ht->entries[idx].first->prev = it;
+		}
+		ht->entries[idx].first = it;
+	} else {
+		it->next = prev->next;
+		it->prev = prev;
+		if(prev->next)
+			prev->next->prev = it;
+		prev->next = it;
+	}
+	ht->entries[idx].esize++;
+	if(old!=NULL)
+	{
+		if(old->msize>=it->msize)
+		{
+			memcpy(old, it, it->msize);
+			lock_release(&ht->entries[idx].lock);
+			return old;
+		}
+	}
+	cell = (ht_cell_t*)pkg_malloc(it->msize);
+	if(cell!=NULL)
+		memcpy(cell, it, it->msize);
+
+	if(mode) lock_release(&ht->entries[idx].lock);
+	return cell;
+}
+
+
 ht_cell_t* ht_cell_pkg_copy(ht_t *ht, str *name, ht_cell_t *old)
 {
 	unsigned int idx;
@@ -512,138 +712,77 @@ int ht_dbg(void)
 
 int ht_table_spec(char *spec)
 {
+	keyvalue_t kval;
 	str name;
 	str dbtable = {0, 0};
 	unsigned int autoexpire = 0;
-	unsigned int usedmq = 0;
 	unsigned int size = 4;
-	int type = 0;
 	unsigned int dbmode = 0;
+	unsigne int dmq = 0;
 	str in;
 	str tok;
-	char *p;
+	param_t *pit=NULL;
+	int_str ival;
+	int itype;
 
+	if(!shm_initialized())
+	{
+		LM_ERR("shared memory was not initialized\n");
+		return -1;
+	}
 	/* parse: name=>dbtable=abc;autoexpire=123;size=123*/
 	in.s = spec;
 	in.len = strlen(in.s);
-
-	p = in.s;
-	while(p<in.s+in.len && (*p==' ' || *p=='\t' || *p=='\n' || *p=='\r'))
-		p++;
-	if(p>in.s+in.len || *p=='\0')
-		goto error;
-	name.s = p;
-	while(p < in.s + in.len)
+	if(keyvalue_parse_str(&in, KEYVALUE_TYPE_PARAMS, &kval)<0)
 	{
-		if(*p=='=' || *p==' ' || *p=='\t' || *p=='\n' || *p=='\r')
-			break;
-		p++;
-	}
-	if(p>in.s+in.len || *p=='\0')
-		goto error;
-	name.len = p - name.s;
-	if(*p!='=')
-	{
-		while(p<in.s+in.len && (*p==' ' || *p=='\t' || *p=='\n' || *p=='\r'))
-			p++;
-		if(p>in.s+in.len || *p=='\0' || *p!='=')
-			goto error;
-	}
-	p++;
-	if(*p!='>')
-		goto error;
-	p++;
-	while(p<in.s+in.len && (*p==' ' || *p=='\t' || *p=='\n' || *p=='\r'))
-		p++;
-
-next_token:
-	tok.s = p;
-	while(p < in.s + in.len)
-	{
-		if(*p=='=' || *p==' ' || *p=='\t' || *p=='\n' || *p=='\r')
-			break;
-		p++;
+		LM_ERR("failed parsing: %.*s\n", in.len, in.s);
+		return -1;
 	}
-	if(p>in.s+in.len || *p=='\0')
-		goto error;
-	tok.len = p - tok.s;
-	if(tok.len==7 && strncmp(tok.s, "dbtable", 7)==0)
-		type = 1;
-	else if(tok.len==10 && strncmp(tok.s, "autoexpire", 10)==0)
-		type = 2;
-	else if(tok.len==4 && strncmp(tok.s, "size", 4)==0)
-		type = 3;
-	else if(tok.len==6 && strncmp(tok.s, "dbmode", 6)==0)
-		type = 4;
-	else if(tok.len==3 && strncmp(tok.s, "dmq", 3)==0)
-		type = 5;
-	else goto error;
+	name = kval.key;
+	itype = PV_VAL_NONE;
+	memset(&ival, 0, sizeof(int_str));
 
-	if(*p!='=')
+	for (pit = kval.u.params; pit; pit=pit->next)
 	{
-		while(p<in.s+in.len && (*p==' ' || *p=='\t' || *p=='\n' || *p=='\r'))
-			p++;
-		if(p>in.s+in.len || *p=='\0' || *p!='=')
-			goto error;
-	}
-	p++;
-	while(p<in.s+in.len && (*p==' ' || *p=='\t' || *p=='\n' || *p=='\r'))
-		p++;
-	if(p>in.s+in.len || *p=='\0')
-		goto error;
-	tok.s = p;
-	while(p < in.s + in.len)
-	{
-		if(*p==';' || *p==' ' || *p=='\t' || *p=='\n' || *p=='\r')
-			break;
-		p++;
-	}
-	if(p>in.s+in.len || *p=='\0')
-		goto error;
-	tok.len = p - tok.s;
-	switch(type)
-	{
-		case 1:
+		tok = pit->body;
+		if(pit->name.len==7 && strncmp(pit->name.s, "dbtable", 7)==0) {
 			dbtable = tok;
 			LM_DBG("htable [%.*s] - dbtable [%.*s]\n", name.len, name.s,
 					dbtable.len, dbtable.s);
-			break;
-		case 2:
+		} else if(pit->name.len==10 && strncmp(pit->name.s, "autoexpire", 10)==0) {
 			if(str2int(&tok, &autoexpire)!=0)
 				goto error;
 			LM_DBG("htable [%.*s] - expire [%u]\n", name.len, name.s,
 					autoexpire);
-			break;
-		case 3:
+		} else if(pit->name.len==4 && strncmp(pit->name.s, "size", 4)==0) {
 			if(str2int(&tok, &size)!=0)
 				goto error;
 			LM_DBG("htable [%.*s] - size [%u]\n", name.len, name.s,
 					size);
-			break;
-		case 4:
+		} else if(pit->name.len==6 && strncmp(pit->name.s, "dbmode", 6)==0) {
 			if(str2int(&tok, &dbmode)!=0)
 				goto error;
 			LM_DBG("htable [%.*s] - dbmode [%u]\n", name.len, name.s,
 					dbmode);
-			break;
-		case 5:
-			if(str2int(&tok, &usedmq)!=0)
+		} else if(pit->name.len==7 && strncmp(pit->name.s, "initval", 7)==0) {
+			if(str2sint(&tok, &ival.n)!=0)
 				goto error;
-			LM_DBG("htable [%.*s] - usedmq [%u]\n", name.len, name.s,
-					usedmq);
-			break;
+			itype = PV_VAL_INT;
+			LM_DBG("htable [%.*s] - initval [%d]\n", name.len, name.s,
+					ival.n);
+		} else if(tok.len==3 && strncmp(tok.s, "dmq", 3)==0) {
+			if(str2sint(&tok, &dmq)!=0)
+				goto error;
+			LM_DBG("htable [%.*s] - dmq [%d]\n", name.len, name.s,
+					dmq);
+		} else { goto error; }
 	}
-	while(p<in.s+in.len && (*p==';' || *p==' ' || *p=='\t'
-				|| *p=='\n' || *p=='\r'))
-		p++;
-	if(p<in.s+in.len)
-		goto next_token;
 
-	return ht_pkg_init(&name, autoexpire, &dbtable, size, dbmode, usedmq);
+	return ht_add_table(&name, autoexpire, &dbtable, size, dbmode, dmq,
+			itype, &ival);
 
 error:
-	LM_ERR("invalid htable parameter [%.*s] at [%d]\n", in.len, in.s,
-			(int)(p-in.s));
+	LM_ERR("invalid htable parameter [%.*s]\n", in.len, in.s);
 	return -1;
 }
 

+ 8 - 3
modules_k/htable/ht_api.h

@@ -55,7 +55,9 @@ typedef struct _ht
 	unsigned int htexpire;
 	str dbtable;
 	int dbmode;
-	int usedmq;
+	int dmq;
+	int flags;
+	int_str initval;
 	unsigned int htsize;
 	ht_entry_t *entries;
 	struct _ht *next;
@@ -67,11 +69,14 @@ typedef struct _ht_pv {
 	pv_elem_t *pve;
 } ht_pv_t, *ht_pv_p;
 
-int ht_pkg_init(str *name, int autoexp, str *dbtable, int size, int dbmode, int usedmq);
-int ht_shm_init(void);
+int ht_add_table(str *name, int autoexp, str *dbtable, int size, int dbmode, int dmq,
+		int itype, int_str *ival);
+int ht_init_tables(void);
 int ht_destroy(void);
 int ht_set_cell(ht_t *ht, str *name, int type, int_str *val, int mode);
 int ht_del_cell(ht_t *ht, str *name);
+ht_cell_t* ht_cell_value_add(ht_t *ht, str *name, int val, int mode,
+		ht_cell_t *old);
 
 int ht_dbg(void);
 ht_cell_t* ht_cell_pkg_copy(ht_t *ht, str *name, ht_cell_t *old);

+ 33 - 43
modules_k/htable/ht_db.c

@@ -124,7 +124,7 @@ int ht_db_load_table(ht_t *ht, str *dbtable, int mode)
 {
 	db_key_t db_cols[4] = {&ht_db_name_column, &ht_db_ktype_column,
 		&ht_db_vtype_column, &ht_db_value_column};
-	db_key_t db_ord = &ht_db_ktype_column;
+	db_key_t db_ord = &ht_db_name_column;
 	db1_res_t* db_res = NULL;
 	str kname;
 	str pname;
@@ -199,64 +199,54 @@ int ht_db_load_table(ht_t *ht, str *dbtable, int mode)
 			cnt++;
 			/* not NULL values enforced in table definition ?!?! */
 			kname.s = (char*)(RES_ROWS(db_res)[i].values[0].val.string_val);
+			if(kname.s==NULL) {
+				LM_ERR("null key in row %d\n", i);
+				goto error;
+			}
 			kname.len = strlen(kname.s);
 			ktype = RES_ROWS(db_res)[i].values[1].val.int_val;
-			if(ktype==0 && last_ktype==1)
+			if(last_ktype==1)
 			{
-				snprintf(ht_name_buf, HT_NAME_BUF_SIZE, "%.*s%.*s",
-					pname.len, pname.s, ht_array_size_suffix.len,
-					ht_array_size_suffix.s);
-				hname.s = ht_name_buf;
-				hname.len = strlen(ht_name_buf);
-				val.n = n+1;
-
-				if(ht_set_cell(ht, &hname, 0, &val, mode))
+				if(pname.len>0
+						&& (pname.len!=kname.len
+							|| strncmp(pname.s, kname.s, pname.len)!=0))
 				{
-					LM_ERR("error adding array size to hash table.\n");
-					goto error;
+					/* new key name, last was an array => add its size */
+					snprintf(ht_name_buf, HT_NAME_BUF_SIZE, "%.*s%.*s",
+						pname.len, pname.s, ht_array_size_suffix.len,
+						ht_array_size_suffix.s);
+					hname.s = ht_name_buf;
+					hname.len = strlen(ht_name_buf);
+					val.n = n;
+
+					if(ht_set_cell(ht, &hname, 0, &val, mode))
+					{
+						LM_ERR("error adding array size to hash table.\n");
+						goto error;
+					}
+					pname.len = 0;
+					pname.s = "";
+					n = 0;
 				}
-				pname.len = 0;
-				pname.s = "";
-				n = 0;
 			}
+			last_ktype = ktype;
+			pname = kname;
 			if(ktype==1)
 			{
-				if(pname.len!=kname.len 
-						|| strncmp(pname.s, kname.s, pname.len)) 
-				{
-					/* add count */
-					if(pname.len > 0)
-					{
-						/* perhaps some opt can be done here */
-						snprintf(ht_name_buf, HT_NAME_BUF_SIZE, "%.*s%.*s",
-							pname.len, pname.s, ht_array_size_suffix.len,
-							ht_array_size_suffix.s);
-						hname.s = ht_name_buf;
-						hname.len = strlen(ht_name_buf);
-						val.n = n+1;
-
-						if(ht_set_cell(ht, &hname, 0, &val, mode))
-						{
-							LM_ERR("error adding array size to hash table\n");
-							goto error;
-						}
-					}
-					/* reset */
-					pname = kname;
-					n=0;
-				} else {
-					n++;
-				}
 				snprintf(ht_name_buf, HT_NAME_BUF_SIZE, "%.*s[%d]",
 						kname.len, kname.s, n);
 				hname.s = ht_name_buf;
 				hname.len = strlen(ht_name_buf);
+				n++;
 			} else {
 				hname = kname;
 			}
-			last_ktype = ktype;
 			vtype = RES_ROWS(db_res)[i].values[2].val.int_val;
 			kvalue.s = (char*)(RES_ROWS(db_res)[i].values[3].val.string_val);
+			if(kvalue.s==NULL) {
+				LM_ERR("null value in row %d\n", i);
+				goto error;
+			}
 			kvalue.len = strlen(kvalue.s);
 
 			/* add to hash */
@@ -288,7 +278,7 @@ int ht_db_load_table(ht_t *ht, str *dbtable, int mode)
 			ht_array_size_suffix.s);
 		hname.s = ht_name_buf;
 		hname.len = strlen(ht_name_buf);
-		val.n = n+1;
+		val.n = n;
 		if(ht_set_cell(ht, &hname, 0, &val, mode))
 		{
 			LM_ERR("error adding array size to hash table.\n");

+ 54 - 2
modules_k/htable/ht_var.c

@@ -49,7 +49,11 @@ int pv_get_ht_cell(struct sip_msg *msg,  pv_param_t *param,
 	}
 	htc = ht_cell_pkg_copy(hpv->ht, &htname, _htc_local);
 	if(htc==NULL)
+	{
+		if(hpv->ht->flags==PV_VAL_INT)
+			return pv_get_sintval(msg, param, res, hpv->ht->initval.n);
 		return pv_get_null(msg, param, res);
+	}
 	if(_htc_local!=htc)
 	{
 		ht_cell_pkg_free(_htc_local);
@@ -218,7 +222,6 @@ int pv_get_ht_cell_expire(struct sip_msg *msg,  pv_param_t *param,
 		pv_value_t *res)
 {
 	str htname;
-	ht_cell_t *htc=NULL;
 	ht_pv_t *hpv;
 	unsigned int now;
 
@@ -237,7 +240,7 @@ int pv_get_ht_cell_expire(struct sip_msg *msg,  pv_param_t *param,
 	if(ht_get_cell_expire(hpv->ht, &htname, &now)!=0)
 		return pv_get_null(msg, param, res);
 	/* integer */
-	return pv_get_uintval(msg, param, res, htc->value.n);
+	return pv_get_uintval(msg, param, res, now);
 }
 
 int pv_set_ht_cell_expire(struct sip_msg* msg, pv_param_t *param,
@@ -330,3 +333,52 @@ int pv_get_ht_cv(struct sip_msg *msg,  pv_param_t *param,
 	return pv_get_sintval(msg, param, res, cnt);
 }
 
+int pv_get_ht_add(struct sip_msg *msg,  pv_param_t *param,
+		pv_value_t *res, int val)
+{
+	str htname;
+	ht_cell_t *htc=NULL;
+	ht_pv_t *hpv;
+
+	hpv = (ht_pv_t*)param->pvn.u.dname;
+
+	if(hpv->ht==NULL)
+	{
+		hpv->ht = ht_get_table(&hpv->htname);
+		if(hpv->ht==NULL)
+			return pv_get_null(msg, param, res);
+	}
+	if(pv_printf_s(msg, hpv->pve, &htname)!=0)
+	{
+		LM_ERR("cannot get $ht name\n");
+		return -1;
+	}
+	htc = ht_cell_value_add(hpv->ht, &htname, val, 1, _htc_local);
+	if(htc==NULL)
+	{
+		return pv_get_null(msg, param, res);
+	}
+	if(_htc_local!=htc)
+	{
+		ht_cell_pkg_free(_htc_local);
+		_htc_local=htc;
+	}
+
+	if(htc->flags&AVP_VAL_STR)
+		return pv_get_null(msg, param, res);
+
+	/* integer */
+	return pv_get_sintval(msg, param, res, htc->value.n);
+}
+
+int pv_get_ht_inc(struct sip_msg *msg,  pv_param_t *param,
+		pv_value_t *res)
+{
+	return pv_get_ht_add(msg, param, res, 1);
+}
+
+int pv_get_ht_dec(struct sip_msg *msg,  pv_param_t *param,
+		pv_value_t *res)
+{
+	return pv_get_ht_add(msg, param, res, -1);
+}

Algúns arquivos non se mostraron porque demasiados arquivos cambiaron neste cambio