فهرست منبع

Merge branch 'master' into outbound

* master:
  pkg/kamailio/(centos|fedora): Updated ver and rel in .spec
  sl: fix compilation warnings in sl_forward_reply()
  dialog: fixed ka_timer linking
  core: command line option -v replaced with -K
  msrp: new parameter use_path_addr
  msrp: added rpc command to list active connections
  msrp: added internal map table to track msrp connections
  pipelimit: implemented support for RPC commands
  Makefile.defs: major version base updated to 4.0.0
  sl: new function sl_forward_reply(...)
  core: added function to remove an exiting lump structure from internal list
  dialog2: generate and add missing README for dialog2 module
  Do not bind with libser_cmd, this is not required.
  Added Debian-Packaging for IMS modules
  - Add group for IMS modules - Added convenience rule to build packages for current debian-stable
  ims modules: don't link with -lrt on macosx
  auth_ims: don't link with -lrt on darwin os
  kamailio.cfg: xhttp left only in kamailio-oob.cfg
  modules/rtpproxy: rtpproxy_manage can now add ice relay candidates
  parser/sdp: fixed freeing of ice attributes
Peter Dunkley 12 سال پیش
والد
کامیت
0b108c83ba
50فایلهای تغییر یافته به همراه3292 افزوده شده و 214 حذف شده
  1. 16 0
      Makefile
  2. 3 3
      Makefile.defs
  3. 29 0
      data_lump.c
  4. 2 0
      data_lump.h
  5. 0 57
      etc/kamailio.cfg
  6. 2 2
      lib/ims/Makefile
  7. 6 4
      main.c
  8. 5 1
      modules/auth_ims/Makefile
  9. 1061 0
      modules/dialog2/README
  10. 5 1
      modules/icscf/Makefile
  11. 8 1
      modules/icscf/scscf_list.h
  12. 5 1
      modules/isc/Makefile
  13. 3 0
      modules/msrp/Makefile
  14. 173 30
      modules/msrp/README
  15. 173 1
      modules/msrp/doc/msrp_admin.xml
  16. 511 0
      modules/msrp/msrp_cmap.c
  17. 74 0
      modules/msrp/msrp_cmap.h
  18. 1 0
      modules/msrp/msrp_env.h
  19. 102 10
      modules/msrp/msrp_mod.c
  20. 92 0
      modules/msrp/msrp_parser.c
  21. 4 0
      modules/msrp/msrp_parser.h
  22. 121 12
      modules/pipelimit/README
  23. 9 0
      modules/pipelimit/doc/pipelimit.xml
  24. 149 5
      modules/pipelimit/doc/pipelimit_admin.xml
  25. 88 0
      modules/pipelimit/pipelimit.c
  26. 98 0
      modules/pipelimit/pl_ht.c
  27. 5 1
      modules/registrar_pcscf/Makefile
  28. 5 1
      modules/registrar_scscf/Makefile
  29. 85 64
      modules/rtpproxy/README
  30. 28 0
      modules/rtpproxy/doc/rtpproxy_admin.xml
  31. 137 2
      modules/rtpproxy/rtpproxy.c
  32. 24 3
      modules/sl/README
  33. 36 0
      modules/sl/doc/sl_functions.xml
  34. 145 2
      modules/sl/sl.c
  35. 2 2
      modules_k/dialog/dlg_hash.c
  36. 1 1
      parser/sdp/sdp.c
  37. 12 0
      pkg/kamailio/deb/debian/control
  38. 1 1
      pkg/kamailio/deb/debian/rules
  39. 12 0
      pkg/kamailio/deb/lenny/control
  40. 1 1
      pkg/kamailio/deb/lenny/rules
  41. 12 0
      pkg/kamailio/deb/lucid/control
  42. 1 1
      pkg/kamailio/deb/lucid/rules
  43. 12 0
      pkg/kamailio/deb/precise/control
  44. 1 1
      pkg/kamailio/deb/precise/rules
  45. 12 0
      pkg/kamailio/deb/squeeze/control
  46. 1 1
      pkg/kamailio/deb/squeeze/rules
  47. 12 0
      pkg/kamailio/deb/wheezy/control
  48. 1 1
      pkg/kamailio/deb/wheezy/rules
  49. 5 3
      pkg/kamailio/fedora/16/kamailio.spec
  50. 1 1
      sip-router.8

+ 16 - 0
Makefile

@@ -297,6 +297,11 @@ module_group_kredis=ndb_redis
 # K mono module
 # K mono module
 module_group_kmono=app_mono
 module_group_kmono=app_mono
 
 
+# For IMS
+# kamailio modules
+module_group_kims=auth_ims cdp cdp_avp dialog2 ims_qos isc icscf ipsec\
+                        registrar_pcscf registrar_scscf usrloc_pcscf usrloc_scscf
+
 # if not set on the cmd. line, env or in the modules.lst (cfg_group_include)
 # if not set on the cmd. line, env or in the modules.lst (cfg_group_include)
 # exclude the below modules.
 # exclude the below modules.
 ifneq ($(group_include)$(cfg_group_include),)
 ifneq ($(group_include)$(cfg_group_include),)
@@ -871,6 +876,17 @@ deb:
 		rm debian; \
 		rm debian; \
 	fi
 	fi
 
 
+.PHONY: deb-stable
+deb-stable:
+	-@if [ -d debian ]; then \
+		dpkg-buildpackage -rfakeroot -tc; \
+		rm debian; \
+	else \
+		ln -s pkg/$(MAIN_NAME)/deb/squeeze debian; \
+		dpkg-buildpackage -rfakeroot -tc; \
+		rm debian; \
+	fi
+
 .PHONY: sunpkg
 .PHONY: sunpkg
 sunpkg:
 sunpkg:
 	mkdir -p tmp/$(MAIN_NAME)
 	mkdir -p tmp/$(MAIN_NAME)

+ 3 - 3
Makefile.defs

@@ -159,10 +159,10 @@ endif
 INSTALL_FLAVOUR=$(FLAVOUR)
 INSTALL_FLAVOUR=$(FLAVOUR)
 
 
 #version number
 #version number
-VERSION = 3
-PATCHLEVEL = 4
+VERSION = 4
+PATCHLEVEL = 0
 SUBLEVEL =  0
 SUBLEVEL =  0
-EXTRAVERSION = -dev7
+EXTRAVERSION = -dev8
 
 
 # memory manager switcher
 # memory manager switcher
 # 0 - f_malloc (fast malloc)
 # 0 - f_malloc (fast malloc)

+ 29 - 0
data_lump.c

@@ -712,3 +712,32 @@ unsigned int count_applied_lumps(struct lump *ll, int type)
 	return n;
 	return n;
 }
 }
 
 
+int remove_lump(sip_msg_t *msg, struct lump *l)
+{
+	struct lump *t = NULL;
+	struct lump *prev = NULL;
+	struct lump **list = NULL;
+
+	list=&msg->add_rm;	
+	for (t=*list; t; prev=t, t=t->next) {
+		if(t==l)
+			break;
+	}
+	if(t==NULL) {
+		list=&msg->body_lumps;
+		for (t=*list; t; prev=t, t=t->next) {
+			if(t==l)
+				break;
+		}
+	}
+	if(t!=NULL) {
+		if(prev==NULL) {
+			*list = t->next;
+		} else {
+			prev->next = t->next;
+		}
+		free_lump(t);
+		return 1;
+	}
+	return 0;
+}

+ 2 - 0
data_lump.h

@@ -95,4 +95,6 @@ void free_duped_lump_list(struct lump* l);
 /*! \brief remove all non-SHMEM lumps from the list */
 /*! \brief remove all non-SHMEM lumps from the list */
 void del_nonshm_lump( struct lump** lump_list );
 void del_nonshm_lump( struct lump** lump_list );
 
 
+/*! \brief remove the lump from the internal lists */
+int remove_lump(sip_msg_t *msg, struct lump *l);
 #endif
 #endif

+ 0 - 57
etc/kamailio.cfg

@@ -67,18 +67,6 @@
 #     - define WITH_XMLRPC
 #     - define WITH_XMLRPC
 #     - adjust route[XMLRPC] for access policy
 #     - adjust route[XMLRPC] for access policy
 #
 #
-# *** To enable the embedded http server:
-#     - define WITH_XHTTP
-#
-# *** To enable the RPC web interface execute:
-#     - enable xhttp
-#     - define WITH_XHTTP_RPC
-#
-# *** To enable the provisioning web interface execute:
-#     - enable mysql
-#     - enable xhttp
-#     - define WITH_XHTTP_PI
-#
 # *** To enable anti-flood detection execute:
 # *** To enable anti-flood detection execute:
 #     - adjust pike and htable=>ipban settings as needed (default is
 #     - adjust pike and htable=>ipban settings as needed (default is
 #       block if more than 16 requests in 2 seconds and ban for 300 seconds)
 #       block if more than 16 requests in 2 seconds and ban for 300 seconds)
@@ -186,10 +174,6 @@ enable_tls=yes
 # - a bit higher than registration expires to cope with UA behind NAT
 # - a bit higher than registration expires to cope with UA behind NAT
 tcp_connection_lifetime=3605
 tcp_connection_lifetime=3605
 
 
-#!ifdef WITH_XHTTP
-tcp_accept_no_cl=yes
-#!endif
-
 ####### Custom Parameters #########
 ####### Custom Parameters #########
 
 
 # These parameters can be modified runtime via RPC interface
 # These parameters can be modified runtime via RPC interface
@@ -298,18 +282,6 @@ loadmodule "xmlrpc.so"
 loadmodule "debugger.so"
 loadmodule "debugger.so"
 #!endif
 #!endif
 
 
-#!ifdef WITH_XHTTP
-loadmodule "xhttp.so"
-#!endif
-
-#!ifdef WITH_XHTTP_RPC
-loadmodule "xhttp_rpc.so"
-#!endif
-
-#!ifdef WITH_XHTTP_PI
-loadmodule "xhttp_pi.so"
-#!endif
-
 # ----------------- setting module-specific parameters ---------------
 # ----------------- setting module-specific parameters ---------------
 
 
 
 
@@ -473,15 +445,6 @@ modparam("xmlrpc", "url_match", "^/RPC")
 modparam("debugger", "cfgtrace", 1)
 modparam("debugger", "cfgtrace", 1)
 #!endif
 #!endif
 
 
-#!ifdef WITH_XHTTP_RPC
-modparam("xhttp_rpc", "xhttp_rpc_root", "http_rpc")
-#!endif
-
-#!ifdef WITH_XHTTP_PI
-modparam("xhttp_pi", "xhttp_pi_root", "http_pi")
-modparam("xhttp_pi", "framework", "/usr/local/etc/kamailio/pi_framework.xml")
-#!endif
-
 ####### Routing Logic ########
 ####### Routing Logic ########
 
 
 
 
@@ -958,23 +921,3 @@ failure_route[MANAGE_FAILURE] {
 	}
 	}
 #!endif
 #!endif
 }
 }
-
-#!ifdef WITH_XHTTP
-event_route[xhttp:request] {
-#!ifdef WITH_XHTTP_RPC
-	$var(xhttp_rpc_root) = $(hu{s.substr,0,9});
-	if ($var(xhttp_rpc_root) == "/http_rpc") {
-		dispatch_xhttp_rpc();
-	}
-#!endif
-#!ifdef WITH_XHTTP_PI
-	$var(xhttp_rpc_root) = $(hu{s.substr,0,8});
-	if ($var(xhttp_rpc_root) == "/http_pi") {
-		dispatch_xhttp_pi();
-	}
-#!endif
-	xhttp_reply("200", "OK", "text/html",
-		"<html><body>Wrong URL $hu</body></html>");
-}
-#!endif
-

+ 2 - 2
lib/ims/Makefile

@@ -14,8 +14,8 @@ libxml2_includes=-I/usr/include/libxml2 -I$(LOCALBASE)/include/libxml2 \
 libxml2_libs=-L$(LOCALBASE)/lib -lxml2
 libxml2_libs=-L$(LOCALBASE)/lib -lxml2
 INCLUDES= -I$(CURDIR)/.. -I$(CURDIR)/../.. $(libxml2_includes) 
 INCLUDES= -I$(CURDIR)/.. -I$(CURDIR)/../.. $(libxml2_includes) 
 LIBS=$(libxml2_libs)
 LIBS=$(libxml2_libs)
-SERLIBPATH=..
-SER_LIBS=$(SERLIBPATH)/cds/ser_cds
+#SERLIBPATH=..
+#SER_LIBS=$(SERLIBPATH)/cds/ser_cds
 
 
 include ../../Makefile.libs
 include ../../Makefile.libs
 
 

+ 6 - 4
main.c

@@ -225,7 +225,7 @@ Options:\n\
                   field to a via\n\
                   field to a via\n\
     -R           Same as `-r` but use reverse dns;\n\
     -R           Same as `-r` but use reverse dns;\n\
                   (to use both use `-rR`)\n\
                   (to use both use `-rR`)\n\
-    -v           Turn on \"via:\" host checking when forwarding replies\n\
+    -K           Turn on \"via:\" host checking when forwarding replies\n\
     -d           Debugging mode (multiple -d increase the level)\n\
     -d           Debugging mode (multiple -d increase the level)\n\
     -D no        1..do not fork (almost) anyway, 2..do not daemonize creator\n\
     -D no        1..do not fork (almost) anyway, 2..do not daemonize creator\n\
                   3..daemonize (default)\n\
                   3..daemonize (default)\n\
@@ -1860,7 +1860,7 @@ int main(int argc, char** argv)
 	dprint_init_colors();
 	dprint_init_colors();
 
 
 	/* command line options */
 	/* command line options */
-	options=  ":f:cm:M:dVIhEeb:l:L:n:vrRDTN:W:w:t:u:g:P:G:SQ:O:a:A:"
+	options=  ":f:cm:M:dVIhEeb:l:L:n:vKrRDTN:W:w:t:u:g:P:G:SQ:O:a:A:"
 #ifdef STATS
 #ifdef STATS
 		"s:"
 		"s:"
 #endif
 #endif
@@ -1957,6 +1957,7 @@ int main(int argc, char** argv)
 			case 'd':
 			case 'd':
 					/* ignore it, was parsed immediately after startup */
 					/* ignore it, was parsed immediately after startup */
 					break;
 					break;
+			case 'v':
 			case 'V':
 			case 'V':
 					printf("version: %s\n", full_version);
 					printf("version: %s\n", full_version);
 					printf("flags: %s\n", ver_flags );
 					printf("flags: %s\n", ver_flags );
@@ -2019,7 +2020,7 @@ int main(int argc, char** argv)
 			case 'b':
 			case 'b':
 			case 'l':
 			case 'l':
 			case 'n':
 			case 'n':
-			case 'v':
+			case 'K':
 			case 'r':
 			case 'r':
 			case 'R':
 			case 'R':
 			case 'D':
 			case 'D':
@@ -2129,6 +2130,7 @@ try_again:
 			case 'm':
 			case 'm':
 			case 'M':
 			case 'M':
 			case 'd':
 			case 'd':
+			case 'v':
 			case 'V':
 			case 'V':
 			case 'I':
 			case 'I':
 			case 'h':
 			case 'h':
@@ -2175,7 +2177,7 @@ try_again:
 						goto error;
 						goto error;
 					}
 					}
 					break;
 					break;
-			case 'v':
+			case 'K':
 					check_via=1;
 					check_via=1;
 					break;
 					break;
 			case 'r':
 			case 'r':

+ 5 - 1
modules/auth_ims/Makefile

@@ -13,7 +13,11 @@ LIBS=
 DEFS+=-DOPENSER_MOD_INTERFACE
 DEFS+=-DOPENSER_MOD_INTERFACE
 
 
 DEFS += -I/usr/include/libxml2
 DEFS += -I/usr/include/libxml2
-LIBS += -L$(LOCALBASE)/lib -lxml2 -lrt
+LIBS += -L$(LOCALBASE)/lib -lxml2
+
+ifneq ($(OS),darwin)
+	LIBS += -lrt
+endif
 
 
 SERLIBPATH=../../lib
 SERLIBPATH=../../lib
 SER_LIBS+=$(SERLIBPATH)/kcore/kcore
 SER_LIBS+=$(SERLIBPATH)/kcore/kcore

+ 1061 - 0
modules/dialog2/README

@@ -0,0 +1,1061 @@
+dialog2 Module
+
+Bogdan-Andrei Iancu
+
+   Voice Sistem SRL
+
+Carsten Bock
+
+   ng-voice.com
+
+Jason Penton
+
+   Smile Communications
+
+Richard Good
+
+   Smile Communications
+
+Edited by
+
+Bogdan-Andrei Iancu
+
+Edited by
+
+Carsten Bock
+
+Edited by
+
+Jason Penton
+
+Edited by
+
+Richard Good
+
+   Copyright © 2006 Voice Sistem SRL
+
+   Copyright © 2011 Carsten Bock, http://www.ng-voice.com
+     __________________________________________________________________
+
+   Table of Contents
+
+   1. Admin Guide
+
+        1. Overview
+        2. How it works
+        3. Dialog profiling
+        4. Dependencies
+
+              4.1. Kamailio Modules
+              4.2. External Libraries or Applications
+
+        5. Parameters
+
+              5.1. enable_stats (integer)
+              5.2. hash_size (integer)
+              5.3. rr_param (string)
+              5.4. dlg_flag (integer)
+              5.5. timeout_avp (string)
+              5.6. default_timeout (integer)
+              5.7. dlg_extra_hdrs (string)
+              5.8. dlg_match_mode (integer)
+              5.9. detect_spirals (integer)
+              5.10. db_url (string)
+              5.11. db_mode (integer)
+              5.12. db_update_period (integer)
+              5.13. db_fetch_rows (integer)
+              5.14. table_name (string)
+              5.15. profiles_with_value (string)
+              5.16. profiles_no_value (string)
+              5.17. bridge_controller (string)
+              5.18. initial_cbs_inscript (string)
+
+        6. Functions
+
+              6.1. set_dlg_profile(profile,[value])
+              6.2. unset_dlg_profile(profile,[value])
+              6.3. is_in_profile(profile,[value])
+              6.4. get_profile_size(profile,[value],size)
+              6.5. dlg_isflagset(flag)
+              6.6. dlg_setflag(flag)
+              6.7. dlg_resetflag(flag)
+              6.8. dlg_terminate
+              6.9. dlg_refer(side, address)
+              6.10. dlg_manage()
+              6.11. dlg_bridge(from, to, op)
+              6.12. dlg_get(callid, ftag, ttag)
+              6.13. is_known_dlg()
+
+        7. Exported statistics
+
+              7.1. active_dialogs
+              7.2. early_dialogs
+              7.3. processed_dialogs
+              7.4. expired_dialogs
+              7.5. failed_dialogs
+
+        8. MI Commands
+
+              8.1. dlg_list
+              8.2. dlg_list_ctx
+              8.3. dlg_end_dlg
+              8.4. dlg_terminate_dlg
+              8.5. profile_get_size
+              8.6. profile_list_dlgs
+              8.7. dlg_bridge
+
+        9. Exported RPC Functions
+
+              9.1. dlg.list
+              9.2. dlg.list_ctx
+              9.3. dlg.dlg_list
+              9.4. dlg.dlg_list_ctx
+              9.5. dlg.end_dlg
+              9.6. dlg.profile_get_size
+              9.7. dlg.profile_list
+              9.8. dlg.bridge_dlg
+
+        10. Exported pseudo-variables
+
+              10.1. $DLG_count
+              10.2. $DLG_status
+              10.3. $DLG_lifetime
+              10.4. $dlg(...)
+              10.5. $dlg_ctx(...)
+              10.6. $dlg_var(key)
+
+   2. Developer Guide
+
+        1. Available Functions
+
+              1.1. register_dlgcb (dialog, type, cb, param, free_param_cb)
+
+              1.2. terminate_dlg (str callid, str ftag, str ttag, hdrs)
+              1.3. set_dlg_var (dlg, key, val)
+              1.4. get_dlg_var (dlg, key)
+              1.5. get_current_dialog ()
+
+   3. Frequently Asked Questions
+
+   List of Examples
+
+   1.1. Set hash_size parameter
+   1.2. Set rr_param parameter
+   1.3. Set dlg_flag parameter
+   1.4. Set timeout_avp parameter
+   1.5. Set default_timeout parameter
+   1.6. Set dlf_extra_hdrs parameter
+   1.7. Set detect_spirals parameter
+   1.8. Set profiles_with_value parameter
+   1.9. Set profiles_no_value parameter
+   1.10. Set bridge_controller parameter
+   1.11. set_dlg_profile usage
+   1.12. unset_dlg_profile usage
+   1.13. is_in_profile usage
+   1.14. get_profile_size usage
+   1.15. dlg_isflagset usage
+   1.16. dlg_setflag usage
+   1.17. dlg_resetflag usage
+   1.18. dlg_terminate usage
+
+Chapter 1. Admin Guide
+
+   Table of Contents
+
+   1. Overview
+   2. How it works
+   3. Dialog profiling
+   4. Dependencies
+
+        4.1. Kamailio Modules
+        4.2. External Libraries or Applications
+
+   5. Parameters
+
+        5.1. enable_stats (integer)
+        5.2. hash_size (integer)
+        5.3. rr_param (string)
+        5.4. dlg_flag (integer)
+        5.5. timeout_avp (string)
+        5.6. default_timeout (integer)
+        5.7. dlg_extra_hdrs (string)
+        5.8. dlg_match_mode (integer)
+        5.9. detect_spirals (integer)
+        5.10. db_url (string)
+        5.11. db_mode (integer)
+        5.12. db_update_period (integer)
+        5.13. db_fetch_rows (integer)
+        5.14. table_name (string)
+        5.15. profiles_with_value (string)
+        5.16. profiles_no_value (string)
+        5.17. bridge_controller (string)
+        5.18. initial_cbs_inscript (string)
+
+   6. Functions
+
+        6.1. set_dlg_profile(profile,[value])
+        6.2. unset_dlg_profile(profile,[value])
+        6.3. is_in_profile(profile,[value])
+        6.4. get_profile_size(profile,[value],size)
+        6.5. dlg_isflagset(flag)
+        6.6. dlg_setflag(flag)
+        6.7. dlg_resetflag(flag)
+        6.8. dlg_terminate
+        6.9. dlg_refer(side, address)
+        6.10. dlg_manage()
+        6.11. dlg_bridge(from, to, op)
+        6.12. dlg_get(callid, ftag, ttag)
+        6.13. is_known_dlg()
+
+   7. Exported statistics
+
+        7.1. active_dialogs
+        7.2. early_dialogs
+        7.3. processed_dialogs
+        7.4. expired_dialogs
+        7.5. failed_dialogs
+
+   8. MI Commands
+
+        8.1. dlg_list
+        8.2. dlg_list_ctx
+        8.3. dlg_end_dlg
+        8.4. dlg_terminate_dlg
+        8.5. profile_get_size
+        8.6. profile_list_dlgs
+        8.7. dlg_bridge
+
+   9. Exported RPC Functions
+
+        9.1. dlg.list
+        9.2. dlg.list_ctx
+        9.3. dlg.dlg_list
+        9.4. dlg.dlg_list_ctx
+        9.5. dlg.end_dlg
+        9.6. dlg.profile_get_size
+        9.7. dlg.profile_list
+        9.8. dlg.bridge_dlg
+
+   10. Exported pseudo-variables
+
+        10.1. $DLG_count
+        10.2. $DLG_status
+        10.3. $DLG_lifetime
+        10.4. $dlg(...)
+        10.5. $dlg_ctx(...)
+        10.6. $dlg_var(key)
+
+1. Overview
+
+   The dialog2 module provides dialog awareness to the Kamailio proxy. Its
+   functionality is to keep track of the current dialogs, to offer
+   information about them (like how many dialogs are active) or to manage
+   them. The module exports several functions that could be used directly
+   from scripts. The dialog2 module extends the original dialog module by
+   providing support for forked calling and early dialog termination. It
+   is the intention that the dialog2 module will eventually replace the
+   dialog module.
+
+   The module, via an internal API, also provide the foundation to build
+   on top of it more complex dialog-based functionalities via other
+   Kamailio modules.
+
+2. How it works
+
+   To create the dialog associated to an initial request, the flag
+   “dlg_flag” ( Section 5.4, “ dlg_flag (integer) ”) must be set before
+   creating the corresponding transaction.
+
+   The dialog is automatically destroyed when a “BYE” is received. In case
+   of no “BYE”, the dialog lifetime is controlled via the default timeout
+   (see “default_timeout” - Section 5.6, “ default_timeout (integer) ”)
+   and custom timeout (see “timeout_avp” - Section 5.5, “ timeout_avp
+   (string) ”). The dialog timeout is reset each time a sequential request
+   passes.
+
+3. Dialog profiling
+
+   Dialog profiling is a mechanism that helps in classifying, sorting and
+   keeping trace of certain types of dialogs, using whatever properties of
+   the dialog (like caller, destination, type of calls, etc). Dialogs can
+   be dynamically added in different (and several) profile tables -
+   logically, each profile table can have a special meaning (like dialogs
+   outside the domain, dialogs terminated to PSTN, etc).
+
+   There are two types of profiles:
+     * with no value - a dialog simply belongs to a profile. (like
+       outbound calls profile). There is no other additional information
+       to describe the dialog's belonging to the profile;
+     * with value - a dialog belongs to a profile having a certain value
+       (like in caller profile, where the value is the caller ID). The
+       belonging of the dialog to the profile is strictly related to the
+       value.
+
+   A dialog can be added to multiple profiles in the same time.
+
+   Profiles are visible (at the moment) in the request route (for initial
+   and sequential requests) and in the branch, failure and reply routes of
+   the original request.
+
+4. Dependencies
+
+   4.1. Kamailio Modules
+   4.2. External Libraries or Applications
+
+4.1. Kamailio Modules
+
+   The following modules must be loaded before this module:
+     * TM - Transaction module
+     * RR - Record-Route module
+
+4.2. External Libraries or Applications
+
+   The following libraries or applications must be installed before
+   running Kamailio with this module loaded:
+     * None.
+
+5. Parameters
+
+   5.1. enable_stats (integer)
+   5.2. hash_size (integer)
+   5.3. rr_param (string)
+   5.4. dlg_flag (integer)
+   5.5. timeout_avp (string)
+   5.6. default_timeout (integer)
+   5.7. dlg_extra_hdrs (string)
+   5.8. dlg_match_mode (integer)
+   5.9. detect_spirals (integer)
+   5.10. db_url (string)
+   5.11. db_mode (integer)
+   5.12. db_update_period (integer)
+   5.13. db_fetch_rows (integer)
+   5.14. table_name (string)
+   5.15. profiles_with_value (string)
+   5.16. profiles_no_value (string)
+   5.17. bridge_controller (string)
+   5.18. initial_cbs_inscript (string)
+
+5.1.  enable_stats (integer)
+
+   This function is currently not supported by the dialog2 module. To be
+   incorporated in the future.
+
+5.2.  hash_size (integer)
+
+   The size of the hash table internally used to keep the dialogs. A
+   larger table is much faster but consumes more memory. The hash size
+   must be a power of two number.
+
+   IMPORTANT: If dialogs' information should be stored in a database, a
+   constant hash_size should be used, otherwise the restoring process will
+   not take place. If you really want to modify the hash_size you must
+   delete all table's rows before restarting the server.
+
+   Default value is “4096”.
+
+   Example 1.1. Set hash_size parameter
+...
+modparam("dialog2", "hash_size", 1024)
+...
+
+5.3.  rr_param (string)
+
+   Name of the Record-Route parameter to be added with the dialog cookie.
+   It is used for the fast dialog matching of sequential requests.
+
+   Default value is “did”.
+
+   Example 1.2. Set rr_param parameter
+...
+modparam("dialog2", "rr_param", "xyz")
+...
+
+5.4.  dlg_flag (integer)
+
+   Flag to be used for marking if a dialog should be constructed for the
+   current request (this make sense only for initial requests).
+
+   Default value is “none”.
+
+   Example 1.3. Set dlg_flag parameter
+...
+modparam("dialog2", "dlg_flag", 4)
+...
+
+5.5.  timeout_avp (string)
+
+   The specification of an AVP that contain a custom timeout (in seconds)
+   for the dialog. It may be used only in a request (initial or
+   sequential) context
+
+   Default value is “none”.
+
+   Example 1.4. Set timeout_avp parameter
+...
+modparam("dialog2", "timeout_avp", "$avp(i:10)")
+...
+
+5.6.  default_timeout (integer)
+
+   The default dialog timeout (in seconds) if no custom one is set.
+
+   Default value is “43200 (12 hours)”.
+
+   Example 1.5. Set default_timeout parameter
+...
+modparam("dialog2", "default_timeout", 21600)
+...
+
+5.7.  dlg_extra_hdrs (string)
+
+   A string containing the extra headers (full format, with EOH) to be
+   added in the requests generated by the module (like BYEs).
+
+   Default value is “NULL”.
+
+   Example 1.6. Set dlf_extra_hdrs parameter
+...
+modparam("dialog2", "dlg_extra_hdrs", "Hint: credit expired\r\n")
+...
+
+5.8.  dlg_match_mode (integer)
+
+   Deprecated - in the new dialog module we always match using DID ONLY
+
+5.9.  detect_spirals (integer)
+
+   Whether spirals (i.e., messages routed through the proxy multiple
+   times) should be detected or not.
+
+   If set to 0, spirals will not be detected and result in the generation
+   of a new, possibly dangling dialog structure per occurring spiral. If
+   set to 1, spirals are detected and internally mapped to existing dialog
+   structures.
+
+   Default value is 1.
+
+   Example 1.7. Set detect_spirals parameter
+...
+modparam("dialog2", "detect_spirals", 1)
+...
+
+5.10.  db_url (string)
+
+   Db storage not yet supported by dialog2 - this to be done in future.
+
+5.11.  db_mode (integer)
+
+   Db storage not yet supported by dialog2 - this to be done in future.
+
+5.12.  db_update_period (integer)
+
+   Db storage not yet supported by dialog2 - this to be done in future.
+
+5.13.  db_fetch_rows (integer)
+
+   Db storage not yet supported by dialog2 - this to be done in future.
+
+5.14.  table_name (string)
+
+   Db storage not yet supported by dialog2 - this to be done in future.
+
+5.15.  profiles_with_value (string)
+
+   List of names for profiles with values.
+
+   Default value is “empty”.
+
+   Example 1.8. Set profiles_with_value parameter
+...
+modparam("dialog", "profiles_with_value", "caller ; my_profile")
+...
+
+5.16.  profiles_no_value (string)
+
+   List of names for profiles without values.
+
+   Default value is “empty”.
+
+   Example 1.9. Set profiles_no_value parameter
+...
+modparam("dialog", "profiles_no_value", "inbound ; outbound")
+...
+
+5.17.  bridge_controller (string)
+
+   SIP address to be used in From header when initiating a call bridge.
+
+   Default value is “sip:[email protected]”.
+
+   Example 1.10. Set bridge_controller parameter
+...
+modparam("dialog", "bridge_controller", "sip:[email protected]")
+...
+
+5.18.  initial_cbs_inscript (string)
+
+   This has been deprecated since dlg_manage has been removed.
+
+6. Functions
+
+   6.1. set_dlg_profile(profile,[value])
+   6.2. unset_dlg_profile(profile,[value])
+   6.3. is_in_profile(profile,[value])
+   6.4. get_profile_size(profile,[value],size)
+   6.5. dlg_isflagset(flag)
+   6.6. dlg_setflag(flag)
+   6.7. dlg_resetflag(flag)
+   6.8. dlg_terminate
+   6.9. dlg_refer(side, address)
+   6.10. dlg_manage()
+   6.11. dlg_bridge(from, to, op)
+   6.12. dlg_get(callid, ftag, ttag)
+   6.13. is_known_dlg()
+
+6.1.  set_dlg_profile(profile,[value])
+
+   Inserts the current dialog into a profile. Note that if the profile
+   does not supports values, this will be silently discarded. Also, there
+   is no check for inserting the same dialog in the same profile for
+   multiple times.
+
+   Meaning of the parameters is as follows:
+     * profile - name of the profile to be added to;
+     * value (optional) - string value to define the belonging of the
+       dialog to the profile - note that the profile must support values.
+       Pseudo-variables are supported.
+
+   This function can be used from REQUEST_ROUTE, BRANCH_ROUTE, REPLY_ROUTE
+   and FAILURE_ROUTE.
+
+   Example 1.11.  set_dlg_profile usage
+...
+set_dlg_profile("inbound_call");
+set_dlg_profile("caller","$fu");
+...
+
+6.2.  unset_dlg_profile(profile,[value])
+
+   Removes the current dialog from a profile.
+
+   Meaning of the parameters is as follows:
+     * profile - name of the profile to be removed from;
+     * value (optional) - string value to define the belonging of the
+       dialog to the profile - note that the profile must support values.
+       Pseudo-variables are supported.
+
+   This function can be used from BRANCH_ROUTE, REPLY_ROUTE and
+   FAILURE_ROUTE.
+
+   Example 1.12.  unset_dlg_profile usage
+...
+unset_dlg_profile("inbound_call");
+unset_dlg_profile("caller","$fu");
+...
+
+6.3.  is_in_profile(profile,[value])
+
+   Checks if the current dialog belongs to a profile. If the profile
+   supports values, the check can be reinforced to take into account a
+   specific value - if the dialog was inserted into the profile for a
+   specific value. If no value is passed, only the simply belonging of the
+   dialog to the profile is checked. Note that if the profile does not
+   supports values, this will be silently discarded.
+
+   Meaning of the parameters is as follows:
+     * profile - name of the profile to be checked against;
+     * value (optional) - string value to further restrict the check.
+       Pseudo-variables are supported.
+
+   This function can be used from REQUEST_ROUTE, BRANCH_ROUTE, REPLY_ROUTE
+   and FAILURE_ROUTE.
+
+   Example 1.13.  is_in_profile usage
+...
+if (is_in_profile("inbound_call")) {
+        log("this request belongs to a inbound call\n");
+}
+...
+if (is_in_profile("caller","XX")) {
+        log("this request belongs to a call of user XX\n");
+}
+...
+
+6.4.  get_profile_size(profile,[value],size)
+
+   Returns the number of dialogs belonging to a profile. If the profile
+   supports values, the check can be reinforced to take into account a
+   specific value - how many dialogs were inserted into the profile with a
+   specific value. If no value is passed, only simply belonging of the
+   dialog to the profile is checked. Note that if the profile does not
+   supports values, this will be silently discarded.
+
+   Meaning of the parameters is as follows:
+     * profile - name of the profile to get the size for;
+     * value (optional) - string value to further restrict the check.
+       Pseudo-variables are supported;
+     * size - an AVP or script variable to return the profile size in.
+
+   This function can be used from REQUEST_ROUTE, BRANCH_ROUTE, REPLY_ROUTE
+   and FAILURE_ROUTE.
+
+   Example 1.14.  get_profile_size usage
+...
+if(get_profile_size("inbound_call","$avp(size)"))
+    xlog("currently there are $avp(size) inbound calls\n");
+...
+if(get_profile_size("caller","$fu","$avp(size)"))
+    xlog("currently, the user $fu has $avp(size) active outgoing calls\n");
+...
+
+6.5.  dlg_isflagset(flag)
+
+   Check if the dialog flag is set or not.
+
+   Meaning of the parameters is as follows:
+     * flag - index of the flag - can be pseudo-variable.
+
+   This function can be used from BRANCH_ROUTE, REQUEST_ROUTE,
+   ONREPLY_ROUTE and FAILURE_ROUTE.
+
+   Example 1.15.  dlg_isflagset usage
+...
+if(dlg_isflagset("1"))
+{
+    ...
+}
+...
+
+6.6.  dlg_setflag(flag)
+
+   Set the dialog flag.
+
+   Meaning of the parameters is as follows:
+     * flag - index of the flag - can be pseudo-variable.
+
+   This function can be used from BRANCH_ROUTE, REQUEST_ROUTE,
+   ONREPLY_ROUTE and FAILURE_ROUTE.
+
+   Example 1.16.  dlg_setflag usage
+...
+dlg_setflag("1");
+...
+
+6.7.  dlg_resetflag(flag)
+
+   Reset the dialog flag.
+
+   Meaning of the parameters is as follows:
+     * flag - index of the flag - can be pseudo-variable.
+
+   This function can be used from BRANCH_ROUTE, REQUEST_ROUTE,
+   ONREPLY_ROUTE and FAILURE_ROUTE.
+
+   Example 1.17.  dlg_resetflag usage
+...
+redlg_setflag("1");
+...
+
+6.8.  dlg_terminate
+
+   Terminates a dialog. In dialog2 module this function now includes
+   support for early as well as confirmed dialogs.
+
+   Meaning of the parameters is as follows:
+     * side - which side to terminate. It can be: caller, callee or both
+       of them.
+     * reason - reason for termination.
+
+   This function can be used from BRANCH_ROUTE, REQUEST_ROUTE,
+   ONREPLY_ROUTE and FAILURE_ROUTE.
+
+   Example 1.18.  dlg_terminate usage
+...
+dlg_terminate("all", "Insufficient QoS");
+...
+
+6.9.  dlg_refer(side, address)
+
+   This function is currently not supported by the dialog2 module. To be
+   incorporated in the future.
+
+6.10.  dlg_manage()
+
+   This has been deprecated in dialog2. Instead set dialog flag for
+   initial INVITE and Route-parameter-callback execution for within-dialog
+   requests.
+
+6.11.  dlg_bridge(from, to, op)
+
+   This function is currently not supported by the dialog2 module. To be
+   incorporated in the future.
+
+6.12.  dlg_get(callid, ftag, ttag)
+
+   This function is currently not supported by the dialog2 module. To be
+   incorporated in the future.
+
+6.13.  is_known_dlg()
+
+   This function is currently not supported by the dialog2 module. To be
+   incorporated in the future.
+
+7. Exported statistics
+
+   7.1. active_dialogs
+   7.2. early_dialogs
+   7.3. processed_dialogs
+   7.4. expired_dialogs
+   7.5. failed_dialogs
+
+7.1.  active_dialogs
+
+   This function is currently not supported by the dialog2 module. To be
+   incorporated in the future.
+
+7.2.  early_dialogs
+
+   This function is currently not supported by the dialog2 module. To be
+   incorporated in the future.
+
+7.3.  processed_dialogs
+
+   This function is currently not supported by the dialog2 module. To be
+   incorporated in the future.
+
+7.4.  expired_dialogs
+
+   This function is currently not supported by the dialog2 module. To be
+   incorporated in the future.
+
+7.5.  failed_dialogs
+
+   This function is currently not supported by the dialog2 module. To be
+   incorporated in the future.
+
+8. MI Commands
+
+   8.1. dlg_list
+   8.2. dlg_list_ctx
+   8.3. dlg_end_dlg
+   8.4. dlg_terminate_dlg
+   8.5. profile_get_size
+   8.6. profile_list_dlgs
+   8.7. dlg_bridge
+
+8.1.  dlg_list
+
+   Lists the description of a dialog or of all dialogs (calls). If only
+   one dialogs is to be listed, the dialog identifiers are to be passed as
+   parameter (callid and fromtag). In dialog2 module this also now also
+   lists all dlg_out entries for early dialogs.
+
+   Name: dlg_list
+
+   Parameters:
+     * callid (optional) - callid if a single dialog to be listed.
+     * from_tag (optional, but cannot be present without the callid
+       parameter) - from tag (as per initial request) of the dialog to be
+       listed. Note that if the from_tag is not specified, only dialogs
+       created by a request without a from tag are matched, which will
+       only occur with broken clients and is thus a very rare situation.
+
+   MI FIFO Command Format:
+                :dlg_list:_reply_fifo_file_
+                _empty_line_
+                :dlg_list:_reply_fifo_file_
+                [email protected]
+                AAdfeEFF33
+
+8.2.  dlg_list_ctx
+
+   This function is currently not supported by the dialog2 module. To be
+   incorporated in the future.
+
+8.3.  dlg_end_dlg
+
+   This function is currently not supported by the dialog2 module. To be
+   incorporated in the future.
+
+8.4.  dlg_terminate_dlg
+
+   Terminates a singe dialog, identified by the call_id, ftag, ttag. In
+   dialog2 module this dialog can be terminated in the early or confirmed
+   states.
+
+   Name: dlg_terminate_dlg
+
+   Parameters:
+     * callid - callid of the dialog to be terminated.
+     * ftag fromtag of dialog to be terminated.
+     * ttag totag of dialog to be terminated.
+
+   Note: Works for confirmed and early dialogs.
+
+   MI FIFO Command Format:
+                :dlg_terminate_dlg:_reply_fifo_file_
+                [email protected]
+                AAdfeEFF33 ftag-1234 t-tag1234
+
+8.5.  profile_get_size
+
+   This function is currently not supported by the dialog2 module. To be
+   incorporated in the future.
+
+8.6.  profile_list_dlgs
+
+   This function is currently not supported by the dialog2 module. To be
+   incorporated in the future.
+
+8.7.  dlg_bridge
+
+   This function is currently not supported by the dialog2 module. To be
+   incorporated in the future.
+
+9. Exported RPC Functions
+
+   9.1. dlg.list
+   9.2. dlg.list_ctx
+   9.3. dlg.dlg_list
+   9.4. dlg.dlg_list_ctx
+   9.5. dlg.end_dlg
+   9.6. dlg.profile_get_size
+   9.7. dlg.profile_list
+   9.8. dlg.bridge_dlg
+
+9.1.  dlg.list
+
+   This function is currently not supported by the dialog2 module. To be
+   incorporated in the future.
+
+9.2.  dlg.list_ctx
+
+   This function is currently not supported by the dialog2 module. To be
+   incorporated in the future.
+
+9.3.  dlg.dlg_list
+
+   This function is currently not supported by the dialog2 module. To be
+   incorporated in the future.
+
+9.4.  dlg.dlg_list_ctx
+
+   This function is currently not supported by the dialog2 module. To be
+   incorporated in the future.
+
+9.5.  dlg.end_dlg
+
+   This function is currently not supported by the dialog2 module. To be
+   incorporated in the future.
+
+9.6.  dlg.profile_get_size
+
+   This function is currently not supported by the dialog2 module. To be
+   incorporated in the future.
+
+9.7.  dlg.profile_list
+
+   This function is currently not supported by the dialog2 module. To be
+   incorporated in the future.
+
+9.8.  dlg.bridge_dlg
+
+   This function is currently not supported by the dialog2 module. To be
+   incorporated in the future.
+
+10. Exported pseudo-variables
+
+   10.1. $DLG_count
+   10.2. $DLG_status
+   10.3. $DLG_lifetime
+   10.4. $dlg(...)
+   10.5. $dlg_ctx(...)
+   10.6. $dlg_var(key)
+
+10.1.  $DLG_count
+
+   This function is currently not supported by the dialog2 module. To be
+   incorporated in the future.
+
+10.2.  $DLG_status
+
+   This function is currently not supported by the dialog2 module. To be
+   incorporated in the future.
+
+10.3.  $DLG_lifetime
+
+   This function is currently not supported by the dialog2 module. To be
+   incorporated in the future.
+
+10.4.  $dlg(...)
+
+   This function is currently not supported by the dialog2 module. To be
+   incorporated in the future.
+
+10.5.  $dlg_ctx(...)
+
+   This function is currently not supported by the dialog2 module. To be
+   incorporated in the future.
+
+10.6.  $dlg_var(key)
+
+   This function is currently not supported by the dialog2 module. To be
+   incorporated in the future.
+
+Chapter 2. Developer Guide
+
+   Table of Contents
+
+   1. Available Functions
+
+        1.1. register_dlgcb (dialog, type, cb, param, free_param_cb)
+        1.2. terminate_dlg (str callid, str ftag, str ttag, hdrs)
+        1.3. set_dlg_var (dlg, key, val)
+        1.4. get_dlg_var (dlg, key)
+        1.5. get_current_dialog ()
+
+1. Available Functions
+
+   1.1. register_dlgcb (dialog, type, cb, param, free_param_cb)
+   1.2. terminate_dlg (str callid, str ftag, str ttag, hdrs)
+   1.3. set_dlg_var (dlg, key, val)
+   1.4. get_dlg_var (dlg, key)
+   1.5. get_current_dialog ()
+
+1.1.  register_dlgcb (dialog, type, cb, param, free_param_cb)
+
+   Register a new callback to the dialog.
+
+   Meaning of the parameters is as follows:
+     * struct dlg_cell* dlg - dialog to register callback to. If maybe
+       NULL only for DLGCB_CREATED callback type, which is not a per
+       dialog type.
+     * int type - types of callbacks; more types may be register for the
+       same callback function; only DLGCB_CREATED must be register alone.
+       Possible types:
+          + DLGCB_LOADED
+          + DLGCB_CREATED - called when a new dialog is created - it's a
+            global type (not associated to any dialog)
+          + DLGCB_FAILED - called when the dialog was negatively replied
+            (non-2xx) - it's a per dialog type.
+          + DLGCB_CONFIRMED_NA - called when the dialog is confirmed (2xx
+            replied) but the setup-concluding ACK message from the caller
+            is yet pending - it's a per dialog type.
+          + DLGCB_CONFIRMED - called when the dialog is confirmed (2xx
+            replied) and the setup-concluding ACK message from the caller
+            has been seen - it's a per dialog type.
+          + DLGCB_REQ_WITHIN - called when the dialog matches a sequential
+            request (excluding setup-concluding ACK messages which are
+            handled in DLGCB_CONFIRMED) - it's a per dialog type.
+          + DLGCB_TERMINATED - called when the dialog is terminated via
+            BYE - it's a per dialog type.
+          + DLGCB_TERMINATED_CONFIRMED - called when response to a BYE
+            request is received - it's a per dialog type.
+          + DLGCB_EXPIRED - called when the dialog expires without
+            receiving a BYE - it's a per dialog type.
+          + DLGCB_EARLY - called when the dialog is created in an early
+            state (18x replied) - it's a per dialog type.
+          + DLGCB_RESPONSE_FWDED - called when the dialog matches a reply
+            to the initial INVITE request - it's a per dialog type.
+          + DLGCB_RESPONSE_WITHIN - called when the dialog matches a reply
+            to a subsequent in dialog request - it's a per dialog type.
+          + DLGCB_MI_CONTEXT - called when the mi dlg_list_ctx command is
+            invoked - it's a per dialog type.
+          + DLGCB_SPIRALED - called when the dialog matches a spiraling
+            request - it's a per dialog type.
+          + DLGCB_DESTROY
+     * dialog_cb cb - callback function to be called. Prototype is: “void
+       (dialog_cb) (struct dlg_cell* dlg, int type, struct dlg_cb_params *
+       params); ”
+     * void *param - parameter to be passed to the callback function.
+     * param_free callback_param_free - callback function to be called to
+       free the param. Prototype is: “void (param_free_cb) (void *param);”
+
+1.2.  terminate_dlg (str callid, str ftag, str ttag, hdrs)
+
+   Terminate a Dialog identified by callid, ftag and ttag in early or
+   confirmed state.
+
+   Meaning of parameters is as follows:
+     * str* callid - callid of dialog to terminate.
+     * str* ftag - from_tag of dialog to terminate.
+     * str* ttag - to tag of dialog to terminate.
+     * str* hdrs - string containg extra headers (full format) to be added
+       to the BYE requests of the dialog.
+
+1.3.  set_dlg_var (dlg, key, val)
+
+   Add a variable to the dialog structure
+
+   Meaning of parameters is as follows:
+     * struct dlg_cell* dlg - dialog to add to.
+     * str* key - Name of the variable.
+     * str* val - Value of the variable.
+
+1.4.  get_dlg_var (dlg, key)
+
+   Retrieves a variable attached to the dialog structure
+
+   Meaning of parameters is as follows:
+     * struct dlg_cell* dlg - dialog to get the variable from.
+     * str* key - Name of the variable.
+
+1.5.  get_current_dialog ()
+
+   Get the current dialog for a message, if exists
+
+Chapter 3. Frequently Asked Questions
+
+   3.1. What happend with “use_tight_match” parameter?
+   3.2. Why is there a dialog2 module and a dialog module?
+   3.3. Where can I find more about Kamailio?
+   3.4. Where can I post a question about this module?
+   3.5. How can I report a bug?
+
+   3.1.
+
+       What happend with “use_tight_match” parameter?
+
+       The parameter was removed with version 1.3 as the option of tight
+       matching became mandatory and not configurable. Now, the tight matching
+       is done all the time (when using DID matching).
+
+   3.2.
+
+       Why is there a dialog2 module and a dialog module?
+
+       The dialog2 module addresses shortcomings in the intial dialog module
+       design. It makes some large changes to the API and therefore must be
+       introduced slowly. It is currently in the early development stages.
+       Eventually the dialog2 module should replace the dialog module.
+
+   3.3.
+
+       Where can I find more about Kamailio?
+
+       Take a look at http://www.kamailio.org/.
+
+   3.4.
+
+       Where can I post a question about this module?
+
+       First at all check if your question was already answered on one of our
+       mailing lists:
+         * User Mailing List -
+           http://lists.sip-router.org/cgi-bin/mailman/listinfo/sr-users
+         * Developer Mailing List -
+           http://lists.sip-router.org/cgi-bin/mailman/listinfo/sr-dev
+
+       E-mails regarding any stable Kamailio release should be sent to
+       <[email protected]> and e-mails regarding development
+       versions should be sent to <[email protected]>.
+
+       If you want to keep the mail private, send it to
+       <[email protected]>.
+
+   3.5.
+
+       How can I report a bug?
+
+       Please follow the guidelines provided at:
+       http://sip-router.org/tracker.

+ 5 - 1
modules/icscf/Makefile

@@ -13,7 +13,11 @@ LIBS=
 DEFS += -DOPENSER_MOD_INTERFACE
 DEFS += -DOPENSER_MOD_INTERFACE
 
 
 DEFS += -I/usr/include/libxml2
 DEFS += -I/usr/include/libxml2
-LIBS += -L$(LOCALBASE)/lib -lxml2 -lrt
+LIBS += -L$(LOCALBASE)/lib -lxml2
+
+ifneq ($(OS),darwin)
+	LIBS += -lrt
+endif
 
 
 
 
 SERLIBPATH=../../lib
 SERLIBPATH=../../lib

+ 8 - 1
modules/icscf/scscf_list.h

@@ -49,14 +49,21 @@
 #include "../../sr_module.h"
 #include "../../sr_module.h"
 #include "../../modules/tm/tm_load.h"
 #include "../../modules/tm/tm_load.h"
 #include "mod.h"
 #include "mod.h"
+#ifndef __OS_darwin
 #include <values.h>
 #include <values.h>
-
+#endif
 #include "../../mem/shm_mem.h"
 #include "../../mem/shm_mem.h"
 
 
 #include "../../dset.h"
 #include "../../dset.h"
 
 
 #include "../../timer.h"
 #include "../../timer.h"
 
 
+#ifdef __OS_darwin
+#ifndef MAXINT
+#define MAXINT INT_MAX
+#endif
+#endif
+
 
 
 /** S-CSCF list element */ 
 /** S-CSCF list element */ 
 typedef struct _scscf_entry {
 typedef struct _scscf_entry {

+ 5 - 1
modules/isc/Makefile

@@ -12,7 +12,11 @@ LIBS=
 DEFS += -DOPENSER_MOD_INTERFACE
 DEFS += -DOPENSER_MOD_INTERFACE
 
 
 DEFS += -I/usr/include/libxml2
 DEFS += -I/usr/include/libxml2
-LIBS += -L$(LOCALBASE)/lib -lxml2 -lrt
+LIBS += -L$(LOCALBASE)/lib -lxml2
+
+ifneq ($(OS),darwin)
+	LIBS += -lrt
+endif
 
 
 SERLIBPATH=../../lib
 SERLIBPATH=../../lib
 SER_LIBS+=$(SERLIBPATH)/ims/kamailio_ims
 SER_LIBS+=$(SERLIBPATH)/ims/kamailio_ims

+ 3 - 0
modules/msrp/Makefile

@@ -9,4 +9,7 @@ LIBS=
 
 
 DEFS+=-DKAMAILIO_MOD_INTERFACE
 DEFS+=-DKAMAILIO_MOD_INTERFACE
 
 
+SERLIBPATH=../../lib
+SER_LIBS+=$(SERLIBPATH)/srutils/srutils
+
 include ../../Makefile.modules
 include ../../Makefile.modules

+ 173 - 30
modules/msrp/README

@@ -16,7 +16,7 @@ Alex Balashov
 
 
    <[email protected]>
    <[email protected]>
 
 
-   Copyright © 2012 asipto.com
+   Copyright © 2012 asipto.com
      __________________________________________________________________
      __________________________________________________________________
 
 
    Table of Contents
    Table of Contents
@@ -32,6 +32,11 @@ Alex Balashov
         3. Parameters
         3. Parameters
 
 
               3.1. sipmsg (int)
               3.1. sipmsg (int)
+              3.2. cmap_size (int)
+              3.3. timer_interval (int)
+              3.4. auth_min_expires (int)
+              3.5. auth_max_expires (int)
+              3.6. use_path_addr (str)
 
 
         4. Functions
         4. Functions
 
 
@@ -42,22 +47,35 @@ Alex Balashov
               4.5. msrp_set_dst(addr, sock)
               4.5. msrp_set_dst(addr, sock)
               4.6. msrp_relay_flags(flags)
               4.6. msrp_relay_flags(flags)
               4.7. msrp_reply_flags(flags)
               4.7. msrp_reply_flags(flags)
+              4.8. msrp_cmap_save()
+              4.9. msrp_cmap_lookup()
 
 
         5. Pseudo Variables
         5. Pseudo Variables
-        6. Event Routes
-        7. Usage
+        6. RPC Commands
+
+              6.1. msrp.cmaplist
+
+        7. Event Routes
+        8. Usage
 
 
    List of Examples
    List of Examples
 
 
    1.1. Set sipmsg parameter
    1.1. Set sipmsg parameter
-   1.2. msrp usage
-   1.3. msrp_reply usage
-   1.4. msrp_is_request usage
-   1.5. msrp_is_reply usage
-   1.6. msrp_set_dst usage
-   1.7. msrp_relay_flags usage
-   1.8. msrp_reply_flags usage
-   1.9. Event Route
+   1.2. Set cmap_size parameter
+   1.3. Set timer_interval parameter
+   1.4. Set auth_min_expires parameter
+   1.5. Set auth_max_expires parameter
+   1.6. Set use_path_addr parameter
+   1.7. msrp_relay usage
+   1.8. msrp_reply usage
+   1.9. msrp_is_request usage
+   1.10. msrp_is_reply usage
+   1.11. msrp_set_dst usage
+   1.12. msrp_relay_flags usage
+   1.13. msrp_reply_flags usage
+   1.14. msrp_cmap_save usage
+   1.15. msrp_cmap_lookup usage
+   1.16. Event Route
 
 
 Chapter 1. Admin Guide
 Chapter 1. Admin Guide
 
 
@@ -72,6 +90,11 @@ Chapter 1. Admin Guide
    3. Parameters
    3. Parameters
 
 
         3.1. sipmsg (int)
         3.1. sipmsg (int)
+        3.2. cmap_size (int)
+        3.3. timer_interval (int)
+        3.4. auth_min_expires (int)
+        3.5. auth_max_expires (int)
+        3.6. use_path_addr (str)
 
 
    4. Functions
    4. Functions
 
 
@@ -82,10 +105,16 @@ Chapter 1. Admin Guide
         4.5. msrp_set_dst(addr, sock)
         4.5. msrp_set_dst(addr, sock)
         4.6. msrp_relay_flags(flags)
         4.6. msrp_relay_flags(flags)
         4.7. msrp_reply_flags(flags)
         4.7. msrp_reply_flags(flags)
+        4.8. msrp_cmap_save()
+        4.9. msrp_cmap_lookup()
 
 
    5. Pseudo Variables
    5. Pseudo Variables
-   6. Event Routes
-   7. Usage
+   6. RPC Commands
+
+        6.1. msrp.cmaplist
+
+   7. Event Routes
+   8. Usage
 
 
 1. Overview
 1. Overview
 
 
@@ -137,6 +166,11 @@ Chapter 1. Admin Guide
 3. Parameters
 3. Parameters
 
 
    3.1. sipmsg (int)
    3.1. sipmsg (int)
+   3.2. cmap_size (int)
+   3.3. timer_interval (int)
+   3.4. auth_min_expires (int)
+   3.5. auth_max_expires (int)
+   3.6. use_path_addr (str)
 
 
 3.1. sipmsg (int)
 3.1. sipmsg (int)
 
 
@@ -152,6 +186,63 @@ Chapter 1. Admin Guide
 modparam("msrp", "sipmsg", 1)
 modparam("msrp", "sipmsg", 1)
 ...
 ...
 
 
+3.2. cmap_size (int)
+
+   The size of connection map table, to be computed as power of 2 (e.g.,
+   if the value is 4, then the number of slots in map table is 2^4 = 16).
+
+   Default value is '0' (no internal map table to be used).
+
+   Example 1.2. Set cmap_size parameter
+...
+modparam("msrp", "cmap_size", 8)
+...
+
+3.3. timer_interval (int)
+
+   The timer interval in seconds to run the procedure for cleaning expired
+   connections.
+
+   Default value is '60'.
+
+   Example 1.3. Set timer_interval parameter
+...
+modparam("msrp", "timer_interval", 90)
+...
+
+3.4. auth_min_expires (int)
+
+   The minimum value accepted for Expires header in AUTH requests.
+
+   Default value is '60'.
+
+   Example 1.4. Set auth_min_expires parameter
+...
+modparam("msrp", "auth_min_expiresl", 90)
+...
+
+3.5. auth_max_expires (int)
+
+   The maximum value accepted for Expires header in AUTH requests.
+
+   Default value is '3600'.
+
+   Example 1.5. Set auth_max_expires parameter
+...
+modparam("msrp", "auth_max_expiresl", 1800)
+...
+
+3.6. use_path_addr (str)
+
+   The hostname:port to be used when building Use-Path header.
+
+   Default value is NULL (server IP and port are used).
+
+   Example 1.6. Set use_path_addr parameter
+...
+modparam("msrp", "use_path_addr", "msrp.kamailio.org:5061")
+...
+
 4. Functions
 4. Functions
 
 
    4.1. msrp_relay()
    4.1. msrp_relay()
@@ -161,8 +252,10 @@ modparam("msrp", "sipmsg", 1)
    4.5. msrp_set_dst(addr, sock)
    4.5. msrp_set_dst(addr, sock)
    4.6. msrp_relay_flags(flags)
    4.6. msrp_relay_flags(flags)
    4.7. msrp_reply_flags(flags)
    4.7. msrp_reply_flags(flags)
+   4.8. msrp_cmap_save()
+   4.9. msrp_cmap_lookup()
 
 
-4.1.  msrp_relay()
+4.1. msrp_relay()
 
 
    Relay MSRP frame according to the To-Path. This function has to be
    Relay MSRP frame according to the To-Path. This function has to be
    executed for each MSRP request or reply that has to be forwarded. Note
    executed for each MSRP request or reply that has to be forwarded. Note
@@ -171,14 +264,14 @@ modparam("msrp", "sipmsg", 1)
 
 
    This function can be used in ANY_ROUTE.
    This function can be used in ANY_ROUTE.
 
 
-   Example 1.2. msrp usage
+   Example 1.7. msrp_relay usage
 ...
 ...
 event_route[msrp:frame-in] {
 event_route[msrp:frame-in] {
     msrp_relay();
     msrp_relay();
 }
 }
 ...
 ...
 
 
-4.2.  msrp_reply(code, text [, hdrs])
+4.2. msrp_reply(code, text [, hdrs])
 
 
    Send a reply for the current MSRP request, adding optional headers.
    Send a reply for the current MSRP request, adding optional headers.
 
 
@@ -186,20 +279,20 @@ event_route[msrp:frame-in] {
 
 
    This function can be used in ANY_ROUTE.
    This function can be used in ANY_ROUTE.
 
 
-   Example 1.3. msrp_reply usage
+   Example 1.8. msrp_reply usage
 ...
 ...
 event_route[msrp:frame-in] {
 event_route[msrp:frame-in] {
     msrp_reply("403", "Not allowed");
     msrp_reply("403", "Not allowed");
 }
 }
 ...
 ...
 
 
-4.3.  msrp_is_request()
+4.3. msrp_is_request()
 
 
    Return true if the MSRP frame is a request.
    Return true if the MSRP frame is a request.
 
 
    This function can be used in ANY_ROUTE.
    This function can be used in ANY_ROUTE.
 
 
-   Example 1.4. msrp_is_request usage
+   Example 1.9. msrp_is_request usage
 ...
 ...
 event_route[msrp:frame-in] {
 event_route[msrp:frame-in] {
     if(msrp_is_request())
     if(msrp_is_request())
@@ -210,13 +303,13 @@ event_route[msrp:frame-in] {
 }
 }
 ...
 ...
 
 
-4.4.  msrp_is_reply()
+4.4. msrp_is_reply()
 
 
    Return true if the MSRP frame is a reply.
    Return true if the MSRP frame is a reply.
 
 
    This function can be used in ANY_ROUTE.
    This function can be used in ANY_ROUTE.
 
 
-   Example 1.5. msrp_is_reply usage
+   Example 1.10. msrp_is_reply usage
 ...
 ...
 event_route[msrp:frame-in] {
 event_route[msrp:frame-in] {
     if(msrp_is_reply())
     if(msrp_is_reply())
@@ -227,7 +320,7 @@ event_route[msrp:frame-in] {
 }
 }
 ...
 ...
 
 
-4.5.  msrp_set_dst(addr, sock)
+4.5. msrp_set_dst(addr, sock)
 
 
    Set destination attributes: addr - target address as MSRP URI; sock -
    Set destination attributes: addr - target address as MSRP URI; sock -
    local socket to be used (format 'proto:ip:port').
    local socket to be used (format 'proto:ip:port').
@@ -236,7 +329,7 @@ event_route[msrp:frame-in] {
 
 
    This function can be used in ANY_ROUTE.
    This function can be used in ANY_ROUTE.
 
 
-   Example 1.6. msrp_set_dst usage
+   Example 1.11. msrp_set_dst usage
 ...
 ...
 event_route[msrp:frame-in] {
 event_route[msrp:frame-in] {
     ...
     ...
@@ -245,7 +338,7 @@ event_route[msrp:frame-in] {
 }
 }
 ...
 ...
 
 
-4.6.  msrp_relay_flags(flags)
+4.6. msrp_relay_flags(flags)
 
 
    Set transport layer sending flags for forwarding current MSRP frame;
    Set transport layer sending flags for forwarding current MSRP frame;
    flags - a bitmask of flags - 1 (don't create a new connection), 2
    flags - a bitmask of flags - 1 (don't create a new connection), 2
@@ -255,7 +348,7 @@ event_route[msrp:frame-in] {
 
 
    This function can be used in ANY_ROUTE.
    This function can be used in ANY_ROUTE.
 
 
-   Example 1.7. msrp_relay_flags usage
+   Example 1.12. msrp_relay_flags usage
 ...
 ...
 event_route[msrp:frame-in] {
 event_route[msrp:frame-in] {
     ...
     ...
@@ -264,7 +357,7 @@ event_route[msrp:frame-in] {
 }
 }
 ...
 ...
 
 
-4.7.  msrp_reply_flags(flags)
+4.7. msrp_reply_flags(flags)
 
 
    Set transport layer sending flags for replies to the current MSRP
    Set transport layer sending flags for replies to the current MSRP
    frame; flags - a bitmask of flags - 1 (don't create a new connection),
    frame; flags - a bitmask of flags - 1 (don't create a new connection),
@@ -274,7 +367,7 @@ event_route[msrp:frame-in] {
 
 
    This function can be used in ANY_ROUTE.
    This function can be used in ANY_ROUTE.
 
 
-   Example 1.8. msrp_reply_flags usage
+   Example 1.13. msrp_reply_flags usage
 ...
 ...
 event_route[msrp:frame-in] {
 event_route[msrp:frame-in] {
     ...
     ...
@@ -283,6 +376,43 @@ event_route[msrp:frame-in] {
 }
 }
 ...
 ...
 
 
+4.8. msrp_cmap_save()
+
+   Save details of a MSRP connection upon AUTH request inside the internal
+   map table, indexed by session id.
+
+   This function can be used in ANY_ROUTE.
+
+   Example 1.14. msrp_cmap_save usage
+...
+event_route[msrp:frame-in] {
+    ...
+        if(metod=="AUTH") { msrp_cmap_save(); exit; }
+    ...
+}
+...
+
+4.9. msrp_cmap_lookup()
+
+   Lookup MSRP connection details for current session id.
+
+   This function can be used in ANY_ROUTE.
+
+   Example 1.15. msrp_cmap_lookup usage
+...
+event_route[msrp:frame-in] {
+    ...
+        if(metod=="SEND" and $msrp(nexthops)==1) {
+                if(msrp_cmap_lookup()) {
+                        msrp_relay();
+                } else {
+                        msrp_reply("481", "Session not found");
+                }
+        }
+    ...
+}
+...
+
 5. Pseudo Variables
 5. Pseudo Variables
 
 
    The module exports a pseudo-variable class, $msrp(key), to access the
    The module exports a pseudo-variable class, $msrp(key), to access the
@@ -294,12 +424,25 @@ event_route[msrp:frame-in] {
    These are documented in the appropriate Wiki pages hosted on the
    These are documented in the appropriate Wiki pages hosted on the
    project web site.
    project web site.
 
 
-6. Event Routes
+6. RPC Commands
+
+   6.1. msrp.cmaplist
+
+6.1. msrp.cmaplist
+
+   List active MSRP connections.
+
+   Example:
+...
+kamcmd msrp.cmaplist
+...
+
+7. Event Routes
 
 
    For each MSRP frame received from the network, the module executes
    For each MSRP frame received from the network, the module executes
    event_route[msrp:frame-in] block in the config file.
    event_route[msrp:frame-in] block in the config file.
 
 
-7. Usage
+8. Usage
 
 
    When 'sipmsg' parameter is set to 1 (which is default), the module
    When 'sipmsg' parameter is set to 1 (which is default), the module
    internally builds a SIP request from the MSRP frame and exposes it to
    internally builds a SIP request from the MSRP frame and exposes it to
@@ -362,7 +505,7 @@ Content-Type: text/plain
    Next is an example of configuration file with the routing block for
    Next is an example of configuration file with the routing block for
    MSRP frames. In this config, the SIP traffic is rejected.
    MSRP frames. In this config, the SIP traffic is rejected.
 
 
-   Example 1.9. Event Route
+   Example 1.16. Event Route
 ...
 ...
 
 
 #!KAMAILIO
 #!KAMAILIO

+ 173 - 1
modules/msrp/doc/msrp_admin.xml

@@ -102,6 +102,103 @@
 ...
 ...
 modparam("msrp", "sipmsg", 1)
 modparam("msrp", "sipmsg", 1)
 ...
 ...
+</programlisting>
+		</example>
+	</section>
+	<section>
+		<title><varname>cmap_size</varname> (int)</title>
+		<para>
+		The size of connection map table, to be computed as power of 2 (e.g.,
+		if the value is 4, then the number of slots in map table is 2^4 = 16).
+		</para>
+		<para>
+		<emphasis>
+			Default value is '0' (no internal map table to be used).
+		</emphasis>
+		</para>
+		<example>
+		<title>Set <varname>cmap_size</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+modparam("msrp", "cmap_size", 8)
+...
+</programlisting>
+		</example>
+	</section>
+	<section>
+		<title><varname>timer_interval</varname> (int)</title>
+		<para>
+		The timer interval in seconds to run the procedure for cleaning
+		expired connections.
+		</para>
+		<para>
+		<emphasis>
+			Default value is '60'.
+		</emphasis>
+		</para>
+		<example>
+		<title>Set <varname>timer_interval</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+modparam("msrp", "timer_interval", 90)
+...
+</programlisting>
+		</example>
+	</section>
+	<section>
+		<title><varname>auth_min_expires</varname> (int)</title>
+		<para>
+		The minimum value accepted for Expires header in AUTH requests.
+		</para>
+		<para>
+		<emphasis>
+			Default value is '60'.
+		</emphasis>
+		</para>
+		<example>
+		<title>Set <varname>auth_min_expires</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+modparam("msrp", "auth_min_expiresl", 90)
+...
+</programlisting>
+		</example>
+	</section>
+	<section>
+		<title><varname>auth_max_expires</varname> (int)</title>
+		<para>
+		The maximum value accepted for Expires header in AUTH requests.
+		</para>
+		<para>
+		<emphasis>
+			Default value is '3600'.
+		</emphasis>
+		</para>
+		<example>
+		<title>Set <varname>auth_max_expires</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+modparam("msrp", "auth_max_expiresl", 1800)
+...
+</programlisting>
+		</example>
+	</section>
+	<section>
+		<title><varname>use_path_addr</varname> (str)</title>
+		<para>
+		The hostname:port to be used when building Use-Path header.
+		</para>
+		<para>
+		<emphasis>
+			Default value is NULL (server IP and port are used).
+		</emphasis>
+		</para>
+		<example>
+		<title>Set <varname>use_path_addr</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+modparam("msrp", "use_path_addr", "msrp.kamailio.org:5061")
+...
 </programlisting>
 </programlisting>
 		</example>
 		</example>
 	</section>
 	</section>
@@ -124,7 +221,7 @@ modparam("msrp", "sipmsg", 1)
 		This function can be used in ANY_ROUTE.
 		This function can be used in ANY_ROUTE.
 		</para>
 		</para>
 		<example>
 		<example>
-		<title><function>msrp</function> usage</title>
+		<title><function>msrp_relay</function> usage</title>
 		<programlisting format="linespecific">
 		<programlisting format="linespecific">
 ...
 ...
 event_route[msrp:frame-in] {
 event_route[msrp:frame-in] {
@@ -299,6 +396,61 @@ event_route[msrp:frame-in] {
 	    </example>
 	    </example>
 	</section>
 	</section>
 
 
+	<section>
+	    <title>
+		<function moreinfo="none">msrp_cmap_save()</function>
+	    </title>
+	    <para>
+		Save details of a MSRP connection upon AUTH request inside
+		the internal map table, indexed by session id.
+		</para>
+		<para>
+		This function can be used in ANY_ROUTE.
+		</para>
+		<example>
+		<title><function>msrp_cmap_save</function> usage</title>
+		<programlisting format="linespecific">
+...
+event_route[msrp:frame-in] {
+    ...
+	if(metod=="AUTH") { msrp_cmap_save(); exit; }
+    ...
+}
+...
+</programlisting>
+	    </example>
+	</section>
+
+	<section>
+	    <title>
+		<function moreinfo="none">msrp_cmap_lookup()</function>
+	    </title>
+	    <para>
+		Lookup MSRP connection details for current session id.
+		</para>
+		<para>
+		This function can be used in ANY_ROUTE.
+		</para>
+		<example>
+		<title><function>msrp_cmap_lookup</function> usage</title>
+		<programlisting format="linespecific">
+...
+event_route[msrp:frame-in] {
+    ...
+	if(metod=="SEND" and $msrp(nexthops)==1) {
+		if(msrp_cmap_lookup()) {
+			msrp_relay();
+		} else {
+			msrp_reply("481", "Session not found");
+		}
+	}
+    ...
+}
+...
+</programlisting>
+	    </example>
+	</section>
+
 	</section>
 	</section>
 
 
 	<section>
 	<section>
@@ -318,6 +470,26 @@ event_route[msrp:frame-in] {
 		</para>
 		</para>
 	</section>
 	</section>
 
 
+	<section>
+	<title>RPC Commands</title>
+	<section>
+		<title>
+		<function moreinfo="none">msrp.cmaplist</function>
+		</title>
+		<para>
+		List active MSRP connections.
+		</para>
+		<para>
+		Example:
+		</para>
+<programlisting  format="linespecific">
+...
+&sercmd; msrp.cmaplist
+...
+</programlisting>
+    </section>
+    </section>
+
 	<section>
 	<section>
 		<title>Event Routes</title>
 		<title>Event Routes</title>
 		<para>
 		<para>

+ 511 - 0
modules/msrp/msrp_cmap.c

@@ -0,0 +1,511 @@
+/**
+ * $Id$
+ *
+ * Copyright (C) 2013 Daniel-Constantin Mierla (asipto.com)
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * This file 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
+ *
+ *
+ * This file 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/shm_mem.h"
+#include "../../mem/mem.h"
+#include "../../dprint.h"
+#include "../../hashes.h"
+#include "../../ut.h"
+
+#include "../../lib/srutils/sruid.h"
+#include "../../rpc.h"
+#include "../../rpc_lookup.h"
+
+#include "msrp_netio.h"
+#include "msrp_env.h"
+#include "msrp_cmap.h"
+
+static msrp_cmap_t *_msrp_cmap_head = NULL;
+
+static sruid_t _msrp_sruid;
+
+extern int msrp_auth_min_expires;
+extern int msrp_auth_max_expires;
+extern str msrp_use_path_addr;
+
+/**
+ *
+ */
+int msrp_sruid_init(void)
+{
+	return sruid_init(&_msrp_sruid, '-', "msrp", SRUID_INC);
+}
+
+/**
+ *
+ */
+int msrp_citem_free(msrp_citem_t *it)
+{
+	if(it==NULL)
+		return -1;
+	shm_free(it);
+	return 0;
+}
+
+/**
+ *
+ */
+int msrp_cmap_init(int msize)
+{
+	int i;
+
+	_msrp_cmap_head = (msrp_cmap_t*)shm_malloc(sizeof(msrp_cmap_t));
+	if(_msrp_cmap_head==NULL)
+	{
+		LM_ERR("no more shm\n");
+		return -1;
+	}
+	memset(_msrp_cmap_head, 0, sizeof(msrp_cmap_t));
+	_msrp_cmap_head->mapsize = msize;
+
+	_msrp_cmap_head->cslots = (msrp_centry_t*)shm_malloc(
+							_msrp_cmap_head->mapsize*sizeof(msrp_centry_t) );
+	if(_msrp_cmap_head->cslots==NULL)
+	{
+		LM_ERR("no more shm.\n");
+		shm_free(_msrp_cmap_head);
+		_msrp_cmap_head = NULL;
+		return -1;
+	}
+	memset(_msrp_cmap_head->cslots, 0,
+						_msrp_cmap_head->mapsize*sizeof(msrp_centry_t));
+
+	for(i=0; i<_msrp_cmap_head->mapsize; i++)
+	{
+		if(lock_init(&_msrp_cmap_head->cslots[i].lock)==0)
+		{
+			LM_ERR("cannot initalize lock[%d]\n", i);
+			i--;
+			while(i>=0)
+			{
+				lock_destroy(&_msrp_cmap_head->cslots[i].lock);
+				i--;
+			}
+			shm_free(_msrp_cmap_head->cslots);
+			shm_free(_msrp_cmap_head);
+			_msrp_cmap_head = NULL;
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+/**
+ *
+ */
+int msrp_cmap_destroy(void)
+{
+	int i;
+	msrp_citem_t *ita, *itb;
+
+	if(_msrp_cmap_head==NULL)
+		return -1;
+
+	for(i=0; i<_msrp_cmap_head->mapsize; i++)
+	{
+		/* free entries */
+		ita = _msrp_cmap_head->cslots[i].first;
+		while(ita)
+		{
+			itb = ita;
+			ita = ita->next;
+			msrp_citem_free(itb);
+		}
+		/* free locks */
+		lock_destroy(&_msrp_cmap_head->cslots[i].lock);
+	}
+	shm_free(_msrp_cmap_head->cslots);
+	shm_free(_msrp_cmap_head);
+	_msrp_cmap_head = NULL;
+	return 0;
+}
+
+#define msrp_get_hashid(_s)        core_case_hash(_s,0,0)
+#define msrp_get_slot(_h, _size)    (_h)&((_size)-1)
+
+
+static str msrp_reply_200_code = {"200", 3};
+static str msrp_reply_200_text = {"OK", 2};
+static str msrp_reply_423_code = {"423", 3};
+static str msrp_reply_423_text = {"Interval Out Of Bounds", 22};
+
+/**
+ *
+ */
+int msrp_cmap_save(msrp_frame_t *mf)
+{
+	unsigned int idx;
+	unsigned int hid;
+	str fpeer;
+#define MSRP_SBUF_SIZE	256
+	char sbuf[MSRP_SBUF_SIZE];
+	str srcaddr;
+	str srcsock;
+	int msize;
+	int expires;
+	msrp_citem_t *it;
+	msrp_citem_t *itb;
+
+	if(_msrp_cmap_head==NULL || mf==NULL)
+		return -1;
+	if(mf->fline.rtypeid!=MSRP_REQ_AUTH)
+	{
+		LM_DBG("save can be used only for AUTH\n");
+		return -2;
+	}
+
+	if(msrp_frame_get_expires(mf, &expires)<0)
+		expires = msrp_auth_max_expires;
+	if(expires<msrp_auth_min_expires)
+	{
+		LM_DBG("expires is lower than min value\n");
+		srcaddr.len = snprintf(sbuf, MSRP_SBUF_SIZE, "Min-Expires: %d\r\n",
+				msrp_auth_min_expires);
+		msrp_reply(mf, &msrp_reply_423_code, &msrp_reply_423_text,
+				&srcaddr);
+		return -3;
+	}
+	if(expires>msrp_auth_max_expires)
+	{
+		LM_DBG("expires is greater than max value\n");
+		srcaddr.len = snprintf(sbuf, MSRP_SBUF_SIZE, "Max-Expires: %d\r\n",
+				msrp_auth_max_expires);
+		msrp_reply(mf, &msrp_reply_423_code, &msrp_reply_423_text,
+				&srcaddr);
+		return -4;
+	}
+	if(msrp_frame_get_first_from_path(mf, &fpeer)<0)
+	{
+		LM_ERR("cannot get first path uri\n");
+		return -1;
+	}
+
+	if(sruid_next(&_msrp_sruid)<0)
+	{
+		LM_ERR("cannot get next msrp uid\n");
+		return -1;
+	}
+	hid = msrp_get_hashid(&_msrp_sruid.uid);	
+	idx = msrp_get_slot(hid, _msrp_cmap_head->mapsize);
+
+	srcaddr.s = sbuf;;
+	if(mf->tcpinfo->rcv->proto==PROTO_TLS)
+	{
+		memcpy(srcaddr.s, "msrps://", 8);
+		srcaddr.s+=8;
+	} else {
+		memcpy(srcaddr.s, "msrp://", 7);
+		srcaddr.s+=7;
+	}
+	strcpy(srcaddr.s, ip_addr2a(&mf->tcpinfo->rcv->src_ip));
+	strcat(srcaddr.s, ":");
+	strcat(srcaddr.s, int2str(mf->tcpinfo->rcv->src_port, NULL));
+	srcaddr.s = sbuf;
+	srcaddr.len = strlen(srcaddr.s);
+	srcsock = mf->tcpinfo->rcv->bind_address->sock_str;
+	LM_DBG("saving connection info for [%.*s] [%.*s] (%u/%u)\n",
+			fpeer.len, fpeer.s, _msrp_sruid.uid.len, _msrp_sruid.uid.s,
+			idx, hid);
+	LM_DBG("frame received from [%.*s] via [%.*s]\n",
+			srcaddr.len, srcaddr.s, srcsock.len, srcsock.s);
+
+	msize = sizeof(msrp_citem_t) + (_msrp_sruid.uid.len
+			+ fpeer.len + srcaddr.len + srcsock.len + 4)*sizeof(char);
+
+	/* build the item */
+	it = (msrp_citem_t*)shm_malloc(msize);
+	if(it==NULL)
+	{
+		LM_ERR("no more shm\n");
+		return -1;
+	}
+	memset(it, 0, msize);
+	it->citemid = hid;
+
+	it->sessionid.s = (char*)it +  + sizeof(msrp_citem_t);
+	it->sessionid.len = _msrp_sruid.uid.len;
+	memcpy(it->sessionid.s, _msrp_sruid.uid.s, _msrp_sruid.uid.len);
+	it->sessionid.s[it->sessionid.len] = '\0';
+
+	it->peer.s = it->sessionid.s + it->sessionid.len + 1;
+	it->peer.len = fpeer.len;
+	memcpy(it->peer.s, fpeer.s, fpeer.len);
+	it->peer.s[it->peer.len] = '\0';
+
+	it->addr.s = it->peer.s + it->peer.len + 1;
+	it->addr.len = srcaddr.len;
+	memcpy(it->addr.s, srcaddr.s, srcaddr.len);
+	it->addr.s[it->addr.len] = '\0';
+
+	it->sock.s = it->addr.s + it->addr.len + 1;
+	it->sock.len = srcsock.len;
+	memcpy(it->sock.s, srcsock.s, srcsock.len);
+	it->sock.s[it->sock.len] = '\0';
+
+	it->expires = time(NULL) + expires;
+	it->conid = mf->tcpinfo->con->id;
+
+	/* insert item in cmap */
+	lock_get(&_msrp_cmap_head->cslots[idx].lock);
+	if(_msrp_cmap_head->cslots[idx].first==NULL) {
+		_msrp_cmap_head->cslots[idx].first = it;
+	} else {
+		for(itb=_msrp_cmap_head->cslots[idx].first; itb; itb=itb->next)
+		{
+			if(itb->citemid>it->citemid || itb->next==NULL) {
+				if(itb->next==NULL) {
+					itb->next=it;
+					it->prev = itb;
+				} else {
+					it->next = itb;
+					if(itb->prev==NULL) {
+						_msrp_cmap_head->cslots[idx].first = it;
+					} else {
+						itb->prev->next = it;
+					}
+					it->prev = itb->prev;
+					itb->prev = it;
+				}
+				break;
+			}
+		}
+	}
+	_msrp_cmap_head->cslots[idx].lsize++;
+	lock_release(&_msrp_cmap_head->cslots[idx].lock);
+
+	if(mf->tcpinfo->rcv->proto==PROTO_TLS)
+	{
+		srcaddr.len = snprintf(sbuf, MSRP_SBUF_SIZE,
+				"Use-Path: msrps://%.*s/%.*s;tcp\r\nExpires: %d\r\n",
+				(msrp_use_path_addr.s)?msrp_use_path_addr.len:(srcsock.len-4),
+				(msrp_use_path_addr.s)?msrp_use_path_addr.s:(srcsock.s+4),
+				_msrp_sruid.uid.len, _msrp_sruid.uid.s,
+				expires);
+	} else {
+		srcaddr.len = snprintf(sbuf, MSRP_SBUF_SIZE,
+				"Use-Path: msrp://%.*s/%.*s;tcp\r\nExpires: %d\r\n",
+				(msrp_use_path_addr.s)?msrp_use_path_addr.len:(srcsock.len-4),
+				(msrp_use_path_addr.s)?msrp_use_path_addr.s:(srcsock.s+4),
+				_msrp_sruid.uid.len, _msrp_sruid.uid.s,
+				expires);
+	}
+	srcaddr.s = sbuf;
+
+	if(msrp_reply(mf, &msrp_reply_200_code, &msrp_reply_200_text,
+				&srcaddr)<0)
+		return -5;
+	return 0;
+}
+
+/**
+ *
+ */
+int msrp_cmap_lookup(msrp_frame_t *mf)
+{
+	unsigned int idx;
+	unsigned int hid;
+	str sesid;
+	msrp_citem_t *itb;
+	int ret;
+
+	if(_msrp_cmap_head==NULL || mf==NULL)
+		return -1;
+	if(mf->fline.rtypeid==MSRP_REQ_AUTH)
+	{
+		LM_DBG("save cannot be used for AUTH\n");
+		return -2;
+	}
+	if(msrp_frame_get_sessionid(mf, &sesid)<0)
+	{
+		LM_ERR("cannot get session id\n");
+		return -3;
+	}
+
+	LM_DBG("searching for session [%.*s]\n", sesid.len, sesid.s);
+
+	hid = msrp_get_hashid(&sesid);	
+	idx = msrp_get_slot(hid, _msrp_cmap_head->mapsize);
+
+	ret = 0;
+	lock_get(&_msrp_cmap_head->cslots[idx].lock);
+	for(itb=_msrp_cmap_head->cslots[idx].first; itb; itb=itb->next)
+	{
+		if(itb->citemid>hid) {
+			break;
+		}
+		if(itb->citemid>hid) {
+			if(itb->sessionid.len == sesid.len
+					&& memcmp(itb->sessionid.s, sesid.s, sesid.len)==0) {
+				LM_DBG("found session [%.*s]\n", sesid.len, sesid.s);
+				ret = msrp_env_set_dstinfo(mf, &itb->addr, &itb->sock, 0);
+				break;
+			}
+		}
+	}
+	lock_release(&_msrp_cmap_head->cslots[idx].lock);
+	if(itb==NULL)
+		return -4;
+	return (ret<0)?-5:0;
+}
+
+/**
+ *
+ */
+int msrp_cmap_clean(void)
+{
+	time_t tnow;
+	msrp_citem_t *ita;
+	msrp_citem_t *itb;
+	int i;
+
+	if(_msrp_cmap_head==NULL)
+		return -1;
+	tnow = time(NULL);
+	for(i=0; i<_msrp_cmap_head->mapsize; i++)
+	{
+		lock_get(&_msrp_cmap_head->cslots[i].lock);
+		ita = _msrp_cmap_head->cslots[i].first;
+		while(ita)
+		{
+			itb = ita;
+			ita = ita->next;
+			if(itb->expires<tnow) {
+				if(itb->prev==NULL) {
+					_msrp_cmap_head->cslots[i].first = itb->next;
+				} else {
+					itb->prev->next = ita;
+				}
+				if(ita!=NULL)
+					ita->prev = itb->prev;
+				msrp_citem_free(itb);
+				_msrp_cmap_head->cslots[i].lsize--;
+			}
+		}
+		lock_release(&_msrp_cmap_head->cslots[i].lock);
+	}
+
+	return 0;
+}
+
+static const char* msrp_cmap_rpc_list_doc[2] = {
+	"Return the content of dispatcher sets",
+	0
+};
+
+
+/*
+ * RPC command to print connections map table
+ */
+static void msrp_cmap_rpc_list(rpc_t* rpc, void* ctx)
+{
+	void* th;
+	void* ih;
+	void* vh;
+	msrp_citem_t *it;
+	int i;
+	int n;
+	str edate;
+
+	if(_msrp_cmap_head==NULL)
+	{
+		LM_ERR("no connections map table\n");
+		rpc->fault(ctx, 500, "No Connections Map Table");
+		return;
+	}
+
+	/* add entry node */
+	if (rpc->add(ctx, "{", &th) < 0)
+	{
+		rpc->fault(ctx, 500, "Internal error root reply");
+		return;
+	}
+
+	if(rpc->struct_add(th, "d{",
+				"MAP_SIZE", _msrp_cmap_head->mapsize,
+				"CONLIST",  &ih)<0)
+	{
+		rpc->fault(ctx, 500, "Internal error set structure");
+		return;
+	}
+	n = 0;
+	for(i=0; i<_msrp_cmap_head->mapsize; i++)
+	{
+		lock_get(&_msrp_cmap_head->cslots[i].lock);
+		for(it=_msrp_cmap_head->cslots[i].first; it; it=it->next)
+		{
+			if(rpc->struct_add(ih, "{",
+						"CONDATA", &vh)<0)
+			{
+				rpc->fault(ctx, 500, "Internal error creating connection");
+				lock_release(&_msrp_cmap_head->cslots[i].lock);
+				return;
+			}
+			edate.s = ctime(&it->expires);
+			edate.len = 24;
+			if(rpc->struct_add(vh, "dSSSSSdd",
+						"CITEMID", it->citemid,
+						"SESSIONID", &it->sessionid,
+						"PEER", &it->peer,
+						"ADDR", &it->addr,
+						"SOCK", &it->sock,
+						"EXPIRES", &edate,
+						"CONID", it->conid,
+						"FLAGS", it->cflags)<0)
+			{
+				rpc->fault(ctx, 500, "Internal error creating dest struct");
+				lock_release(&_msrp_cmap_head->cslots[i].lock);
+				return;
+			}
+			n++;
+		}
+		lock_release(&_msrp_cmap_head->cslots[i].lock);
+	}
+	if(rpc->struct_add(th, "d", "CONCOUNT", n)<0)
+	{
+		rpc->fault(ctx, 500, "Internal error connection counter");
+		return;
+	}
+	return;
+}
+
+rpc_export_t msrp_cmap_rpc_cmds[] = {
+	{"msrp.cmaplist",   msrp_cmap_rpc_list,
+		msrp_cmap_rpc_list_doc,   0},
+	{0, 0, 0, 0}
+};
+
+/**
+ *
+ */
+int msrp_cmap_init_rpc(void)
+{
+	if (rpc_register_array(msrp_cmap_rpc_cmds)!=0)
+	{
+		LM_ERR("failed to register RPC commands\n");
+		return -1;
+	}
+
+	return 0;
+}

+ 74 - 0
modules/msrp/msrp_cmap.h

@@ -0,0 +1,74 @@
+/**
+ * $Id$
+ *
+ * Copyright (C) 2013 Daniel-Constantin Mierla (asipto.com)
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * This file 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
+ *
+ *
+ * This file 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 _MSRP_CMAP_H_
+#define _MSRP_CMAP_H_
+
+#include <time.h>
+
+#include "../../str.h"
+#include "../../locking.h"
+
+#include "msrp_parser.h"
+
+typedef struct _msrp_citem
+{
+    unsigned int citemid;
+	str sessionid;
+	str peer;
+	str addr;
+	str sock;
+	int conid;
+	int cflags;
+	time_t  expires;
+    struct _msrp_citem *prev;
+    struct _msrp_citem *next;
+} msrp_citem_t;
+
+typedef struct _msrp_centry
+{
+	unsigned int lsize;
+	msrp_citem_t *first;
+	gen_lock_t lock;	
+} msrp_centry_t;
+
+typedef struct _msrp_cmap
+{
+	unsigned int mapexpire;
+	unsigned int mapsize;
+	msrp_centry_t *cslots;
+	struct _msrp_cmap *next;
+} msrp_cmap_t;
+
+int msrp_cmap_init(int msize);
+int msrp_cmap_destroy(void);
+int msrp_cmap_clean(void);
+
+int msrp_cmap_save(msrp_frame_t *mf);
+int msrp_cmap_lookup(msrp_frame_t *mf);
+
+int msrp_sruid_init(void);
+
+int msrp_cmap_init_rpc(void);
+#endif

+ 1 - 0
modules/msrp/msrp_env.h

@@ -25,6 +25,7 @@
 #ifndef _MSRP_ENV_H_
 #ifndef _MSRP_ENV_H_
 #define _MSRP_ENV_H_
 #define _MSRP_ENV_H_
 
 
+#include "../../parser/msg_parser.h"
 #include "msrp_parser.h"
 #include "msrp_parser.h"
 
 
 #define MSRP_ENV_SRCINFO	(1<<0)
 #define MSRP_ENV_SRCINFO	(1<<0)

+ 102 - 10
modules/msrp/msrp_mod.c

@@ -36,11 +36,13 @@
 #include "../../events.h"
 #include "../../events.h"
 #include "../../tcp_conn.h"
 #include "../../tcp_conn.h"
 #include "../../pvar.h"
 #include "../../pvar.h"
+#include "../../timer_proc.h" /* register_sync_timer */
 
 
 #include "msrp_parser.h"
 #include "msrp_parser.h"
 #include "msrp_netio.h"
 #include "msrp_netio.h"
 #include "msrp_vars.h"
 #include "msrp_vars.h"
 #include "msrp_env.h"
 #include "msrp_env.h"
+#include "msrp_cmap.h"
 
 
 MODULE_VERSION
 MODULE_VERSION
 
 
@@ -56,8 +58,17 @@ static int w_msrp_is_reply(sip_msg_t* msg, char* str1, char* str2);
 static int w_msrp_set_dst(sip_msg_t* msg, char* taddr, char* fsock);
 static int w_msrp_set_dst(sip_msg_t* msg, char* taddr, char* fsock);
 static int w_msrp_relay_flags(sip_msg_t* msg, char *tflags, char* str2);
 static int w_msrp_relay_flags(sip_msg_t* msg, char *tflags, char* str2);
 static int w_msrp_reply_flags(sip_msg_t* msg, char *tflags, char* str2);
 static int w_msrp_reply_flags(sip_msg_t* msg, char *tflags, char* str2);
+static int w_msrp_cmap_save(sip_msg_t* msg, char* str1, char* str2);
+static int w_msrp_cmap_lookup(sip_msg_t* msg, char* str1, char* str2);
+
+static void msrp_local_timer(unsigned int ticks, void* param); /*!< Local timer handler */
 
 
 int msrp_param_sipmsg = 1;
 int msrp_param_sipmsg = 1;
+int msrp_cmap_size = 0;
+int msrp_auth_min_expires = 60;
+int msrp_auth_max_expires = 3600;
+int msrp_timer_interval = 60;
+str msrp_use_path_addr = { 0 };
 
 
 static int msrp_frame_received(void *data);
 static int msrp_frame_received(void *data);
 sip_msg_t *msrp_fake_sipmsg(msrp_frame_t *mf);
 sip_msg_t *msrp_fake_sipmsg(msrp_frame_t *mf);
@@ -83,21 +94,30 @@ static cmd_export_t cmds[]={
 		0, ANY_ROUTE},
 		0, ANY_ROUTE},
 	{"msrp_reply", (cmd_function)w_msrp_reply3, 3, fixup_spve_all,
 	{"msrp_reply", (cmd_function)w_msrp_reply3, 3, fixup_spve_all,
 		0, ANY_ROUTE},
 		0, ANY_ROUTE},
-	{"msrp_is_request", (cmd_function)w_msrp_is_request, 0, 0,
+	{"msrp_is_request",  (cmd_function)w_msrp_is_request, 0, 0,
 		0, ANY_ROUTE},
 		0, ANY_ROUTE},
-	{"msrp_is_reply", (cmd_function)w_msrp_is_reply, 0, 0,
+	{"msrp_is_reply",    (cmd_function)w_msrp_is_reply, 0, 0,
 		0, ANY_ROUTE},
 		0, ANY_ROUTE},
-	{"msrp_set_dst", (cmd_function)w_msrp_set_dst, 2, fixup_spve_all,
+	{"msrp_set_dst",     (cmd_function)w_msrp_set_dst, 2, fixup_spve_all,
 		0, ANY_ROUTE},
 		0, ANY_ROUTE},
 	{"msrp_relay_flags", (cmd_function)w_msrp_relay_flags, 1, fixup_igp_null,
 	{"msrp_relay_flags", (cmd_function)w_msrp_relay_flags, 1, fixup_igp_null,
 		0, ANY_ROUTE},
 		0, ANY_ROUTE},
 	{"msrp_reply_flags", (cmd_function)w_msrp_reply_flags, 1, fixup_igp_null,
 	{"msrp_reply_flags", (cmd_function)w_msrp_reply_flags, 1, fixup_igp_null,
 		0, ANY_ROUTE},
 		0, ANY_ROUTE},
+	{"msrp_cmap_save",   (cmd_function)w_msrp_cmap_save, 0, 0,
+		0, ANY_ROUTE},
+	{"msrp_cmap_lookup", (cmd_function)w_msrp_cmap_lookup, 0, 0,
+		0, ANY_ROUTE},
 	{0, 0, 0, 0, 0, 0}
 	{0, 0, 0, 0, 0, 0}
 };
 };
 
 
 static param_export_t params[]={
 static param_export_t params[]={
-	{"sipmsg",     INT_PARAM,   &msrp_param_sipmsg},
+	{"sipmsg",            PARAM_INT,   &msrp_param_sipmsg},
+	{"cmap_size",         PARAM_INT,   &msrp_cmap_size},
+	{"auth_min_expires",  PARAM_INT,   &msrp_auth_min_expires},
+	{"auth_max_expires",  PARAM_INT,   &msrp_auth_max_expires},
+	{"timer_interval",    PARAM_INT,   &msrp_timer_interval},
+	{"use_path_addr",     PARAM_STR,   &msrp_use_path_addr},
 	{0, 0, 0}
 	{0, 0, 0}
 };
 };
 
 
@@ -123,6 +143,28 @@ struct module_exports exports = {
  */
  */
 static int mod_init(void)
 static int mod_init(void)
 {
 {
+	if(msrp_sruid_init()<0) {
+		LM_ERR("cannot init msrp uid\n");
+		return -1;
+	}
+
+	if(msrp_cmap_init_rpc()<0)
+	{
+		LM_ERR("failed to register cmap RPC commands\n");
+		return -1;
+	}
+
+	if(msrp_cmap_size>0) {
+		if(msrp_cmap_size>16)
+			msrp_cmap_size = 16;
+		if(msrp_cmap_init(1<<msrp_cmap_size)<0) {
+			LM_ERR("Cannot init internal cmap\n");
+			return -1;
+		}
+		if(msrp_timer_interval<=0)
+			msrp_timer_interval = 60;
+		register_sync_timers(1);
+	}
 	sr_event_register_cb(SREV_TCP_MSRP_FRAME, msrp_frame_received);
 	sr_event_register_cb(SREV_TCP_MSRP_FRAME, msrp_frame_received);
 	return 0;
 	return 0;
 }
 }
@@ -132,8 +174,20 @@ static int mod_init(void)
  */
  */
 static int child_init(int rank)
 static int child_init(int rank)
 {
 {
+	if(msrp_sruid_init()<0) {
+		LM_ERR("cannot init msrp uid\n");
+		return -1;
+	}
+
 	if (rank!=PROC_MAIN)
 	if (rank!=PROC_MAIN)
 		return 0;
 		return 0;
+	if(msrp_cmap_size>0) {
+		if(fork_sync_timer(PROC_TIMER, "MSRP Timer", 1 /*socks flag*/,
+				msrp_local_timer, NULL, msrp_timer_interval /*sec*/)<0) {
+			LM_ERR("failed to start timer routine as process\n");
+			return -1; /* error */
+		}
+	}
 
 
 	return 0;
 	return 0;
 }
 }
@@ -333,6 +387,42 @@ static int w_msrp_reply_flags(sip_msg_t* msg, char *tflags, char* str2)
 	return ret;
 	return ret;
 }
 }
 
 
+
+/**
+ *
+ */
+static int w_msrp_cmap_save(sip_msg_t* msg, char* str1, char* str2)
+{
+	msrp_frame_t *mf;
+	int ret;
+
+	mf = msrp_get_current_frame();
+	if(mf==NULL)
+		return -1;
+
+	ret = msrp_cmap_save(mf);
+	if(ret==0) ret = 1;
+	return ret;
+}
+
+
+/**
+ *
+ */
+static int w_msrp_cmap_lookup(sip_msg_t* msg, char* str1, char* str2)
+{
+	msrp_frame_t *mf;
+	int ret;
+
+	mf = msrp_get_current_frame();
+	if(mf==NULL)
+		return -1;
+
+	ret = msrp_cmap_lookup(mf);
+	if(ret==0) ret = 1;
+	return ret;
+}
+
 /**
 /**
  *
  *
  */
  */
@@ -340,7 +430,6 @@ static int msrp_frame_received(void *data)
 {
 {
 	tcp_event_info_t *tev;
 	tcp_event_info_t *tev;
 	static msrp_frame_t mf;
 	static msrp_frame_t mf;
-	msrp_uri_t uri;
 	sip_msg_t *fmsg;
 	sip_msg_t *fmsg;
 	struct run_act_ctx ctx;
 	struct run_act_ctx ctx;
 	int rtb, rt;
 	int rtb, rt;
@@ -385,10 +474,13 @@ static int msrp_frame_received(void *data)
 	}
 	}
 	msrp_reset_env();
 	msrp_reset_env();
 	msrp_destroy_frame(&mf);
 	msrp_destroy_frame(&mf);
-	msrp_parse_uri("msrps://alice.example.com:9892/98cjs;tcp",
-			sizeof("msrps://alice.example.com:9892/98cjs;tcp")-1, &uri);
-	msrp_parse_uri("msrps://[email protected]:9892/98cjs;tcp;a=123",
-			sizeof("msrps://[email protected]:9892/98cjs;tcp;a=123")-1, &uri);
-
 	return 0;
 	return 0;
 }
 }
+
+/**
+ *
+ */
+static void msrp_local_timer(unsigned int ticks, void* param)
+{
+	msrp_cmap_clean();
+}

+ 92 - 0
modules/msrp/msrp_parser.c

@@ -60,6 +60,7 @@ static msrp_str_id_t _msrp_htypes[] = {
 	{ str_init("Authorization"),        MSRP_HDR_AUTH },
 	{ str_init("Authorization"),        MSRP_HDR_AUTH },
 	{ str_init("WWW-Authenticate"),     MSRP_HDR_WWWAUTH },
 	{ str_init("WWW-Authenticate"),     MSRP_HDR_WWWAUTH },
 	{ str_init("Authentication-Info"),  MSRP_HDR_AUTHINFO },
 	{ str_init("Authentication-Info"),  MSRP_HDR_AUTHINFO },
+	{ str_init("Expires"),              MSRP_HDR_EXPIRES },
 	{ {0, 0}, 0}
 	{ {0, 0}, 0}
 };
 };
 
 
@@ -698,3 +699,94 @@ int msrp_parse_hdr_to_path(msrp_frame_t *mf)
 	return msrp_parse_hdr_uri_list(hdr);
 	return msrp_parse_hdr_uri_list(hdr);
 }
 }
 
 
+/**
+ *
+ */
+int msrp_parse_hdr_expires(msrp_frame_t *mf)
+{
+	msrp_hdr_t *hdr;
+	str hbody;
+	int expires;
+
+	hdr = msrp_get_hdr_by_id(mf, MSRP_HDR_EXPIRES);
+	if(hdr==NULL)
+		return -1;
+	if(hdr->parsed.flags&MSRP_DATA_SET)
+		return 0;
+	hbody = hdr->body;
+	trim(&hbody);
+	if(str2sint(&hbody, &expires)<0) {
+		LM_ERR("invalid expires value\n");
+		return -1;
+	}
+	hdr->parsed.flags |= MSRP_DATA_SET;
+	hdr->parsed.free_fn = NULL;
+	hdr->parsed.data = (void*)(long)expires;
+
+	return 0;
+}
+
+/**
+ *
+ */
+int msrp_frame_get_first_from_path(msrp_frame_t *mf, str *sres)
+{
+	str s = {0};
+	msrp_hdr_t *hdr;
+	str_array_t *sar;
+
+	if(msrp_parse_hdr_from_path(mf)<0)
+		return -1;
+	hdr = msrp_get_hdr_by_id(mf, MSRP_HDR_FROM_PATH);
+	if(hdr==NULL)
+		return -1;
+	sar = (str_array_t*)hdr->parsed.data;
+	s = sar->list[sar->size-1];
+	trim(&s);
+	*sres = s;
+	return 0;
+}
+
+/**
+ *
+ */
+int msrp_frame_get_expires(msrp_frame_t *mf, int *expires)
+{
+	msrp_hdr_t *hdr;
+
+	if(msrp_parse_hdr_expires(mf)<0)
+		return -1;
+	hdr = msrp_get_hdr_by_id(mf, MSRP_HDR_AUTH);
+	if(hdr==NULL)
+		return -1;
+	*expires = (int)(long)hdr->parsed.data;
+	return 0;
+}
+
+/**
+ *
+ */
+int msrp_frame_get_sessionid(msrp_frame_t *mf, str *sres)
+{
+	str s = {0};
+	msrp_hdr_t *hdr;
+	str_array_t *sar;
+	msrp_uri_t uri;
+
+	if(msrp_parse_hdr_to_path(mf)<0)
+		return -1;
+	hdr = msrp_get_hdr_by_id(mf, MSRP_HDR_TO_PATH);
+	if(hdr==NULL)
+		return -1;
+	sar = (str_array_t*)hdr->parsed.data;
+	s = sar->list[0];
+	trim(&s);
+	if(msrp_parse_uri(s.s, s.len, &uri)<0 || uri.session.len<=0)
+		return -1;
+	s = uri.session;
+	trim(&s);
+	*sres = s;
+
+	return 0;
+}
+

+ 4 - 0
modules/msrp/msrp_parser.h

@@ -89,6 +89,7 @@ int msrp_parse_uri(char *start, int len, msrp_uri_t *uri);
 #define MSRP_HDR_AUTH			9
 #define MSRP_HDR_AUTH			9
 #define MSRP_HDR_WWWAUTH		10
 #define MSRP_HDR_WWWAUTH		10
 #define MSRP_HDR_AUTHINFO		11
 #define MSRP_HDR_AUTHINFO		11
+#define MSRP_HDR_EXPIRES		12
 
 
 #define MSRP_DATA_SET	1
 #define MSRP_DATA_SET	1
 
 
@@ -136,4 +137,7 @@ typedef struct str_array {
 	str *list;
 	str *list;
 } str_array_t;
 } str_array_t;
 
 
+int msrp_frame_get_sessionid(msrp_frame_t *mf, str *sres);
+int msrp_frame_get_first_from_path(msrp_frame_t *mf, str *sres);
+int msrp_frame_get_expires(msrp_frame_t *mf, int *expires);
 #endif
 #endif

+ 121 - 12
modules/pipelimit/README

@@ -6,11 +6,17 @@ Hendrik Scholz
 
 
 Edited by
 Edited by
 
 
+Ovidiu Sas
+
+Edited by
+
 Daniel-Constantin Mierla
 Daniel-Constantin Mierla
 
 
-   Copyright © 2010 Asipto.com
+   Copyright © 2013 VoIPEmbedded Inc.
+
+   Copyright © 2010 Asipto.com
 
 
-   Copyright © 2006 Freenet Cityline GmbH
+   Copyright © 2006 Freenet Cityline GmbH
      __________________________________________________________________
      __________________________________________________________________
 
 
    Table of Contents
    Table of Contents
@@ -48,6 +54,15 @@ Daniel-Constantin Mierla
               5.5. pl_get_pid
               5.5. pl_get_pid
               5.6. pl_push_load
               5.6. pl_push_load
 
 
+        6. RPC Commands
+
+              6.1. pl.stats
+              6.2. pl.set_pipe
+              6.3. pl.get_pipes
+              6.4. pl.set_pid
+              6.5. pl.get_pid
+              6.6. pl.push_load
+
    List of Examples
    List of Examples
 
 
    1.1. Set db_url parameter
    1.1. Set db_url parameter
@@ -98,6 +113,15 @@ Chapter 1. Admin Guide
         5.5. pl_get_pid
         5.5. pl_get_pid
         5.6. pl_push_load
         5.6. pl_push_load
 
 
+   6. RPC Commands
+
+        6.1. pl.stats
+        6.2. pl.set_pipe
+        6.3. pl.get_pipes
+        6.4. pl.set_pid
+        6.5. pl.get_pid
+        6.6. pl.push_load
+
 1. Overview
 1. Overview
 
 
    This module implements traffic limiting for SIP requests.
    This module implements traffic limiting for SIP requests.
@@ -145,7 +169,7 @@ Chapter 1. Admin Guide
 
 
    URL of the database server to be used.
    URL of the database server to be used.
 
 
-   Default value is "mysql://kamailio:kamailiorw@localhost/kamailio".
+   Default value is “mysql://kamailio:kamailiorw@localhost/kamailio�.
 
 
    Example 1.1. Set db_url parameter
    Example 1.1. Set db_url parameter
 ...
 ...
@@ -156,7 +180,7 @@ modparam("pipelimit", "db_url", "dbdriver://username:password@dbhost/dbname")
 
 
    Name of DB table where data definition for pipes is stores.
    Name of DB table where data definition for pipes is stores.
 
 
-   Default value is "pl_pipes".
+   Default value is “pl_pipes�.
 
 
    Example 1.2. Set plp_table_name parameter
    Example 1.2. Set plp_table_name parameter
 ...
 ...
@@ -167,7 +191,7 @@ modparam("pipelimit", "plp_table_name", "mypipes")
 
 
    Name of 'pipeid' column.
    Name of 'pipeid' column.
 
 
-   Default value is "pipeid".
+   Default value is “pipeid�.
 
 
    Example 1.3. Set plp_pipeid_column parameter
    Example 1.3. Set plp_pipeid_column parameter
 ...
 ...
@@ -178,7 +202,7 @@ modparam("pipelimit", "plp_pipeid_column", "name")
 
 
    Name of 'limit' column.
    Name of 'limit' column.
 
 
-   Default value is "limit".
+   Default value is “limit�.
 
 
    Example 1.4. Set plp_limit_column parameter
    Example 1.4. Set plp_limit_column parameter
 ...
 ...
@@ -189,7 +213,7 @@ modparam("pipelimit", "plp_limit_column", "name")
 
 
    Name of 'algorithm' column.
    Name of 'algorithm' column.
 
 
-   Default value is "algorithm".
+   Default value is “algorithm�.
 
 
    Example 1.5. Set plp_algorithm_column parameter
    Example 1.5. Set plp_algorithm_column parameter
 ...
 ...
@@ -209,7 +233,7 @@ modparam("pipelimit", "plp_algorithm_column", "name")
 
 
    Example 1.6. Set timer_interval parameter
    Example 1.6. Set timer_interval parameter
 ...
 ...
-modparam("ratelimit", "timer_interval", 5)
+modparam("pipelimit", "timer_interval", 5)
 ...
 ...
 
 
 3.7. reply_code (integer)
 3.7. reply_code (integer)
@@ -220,13 +244,13 @@ modparam("ratelimit", "timer_interval", 5)
 
 
    Example 1.7. Set reply_code parameter
    Example 1.7. Set reply_code parameter
 ...
 ...
-modparam("ratelimit", "reply_code", 505)
+modparam("pipelimit", "reply_code", 505)
 ...
 ...
 
 
    This value can be modified at runtime using kamcmd
    This value can be modified at runtime using kamcmd
 
 
    Example 1.8.  Set reply_code parameter at runtime
    Example 1.8.  Set reply_code parameter at runtime
-kamcmd cfg.set_now_int ratelimit reply_code 505
+kamcmd cfg.set_now_int pipelimit reply_code 505
 
 
 3.8. reply_reason (string)
 3.8. reply_reason (string)
 
 
@@ -236,13 +260,13 @@ kamcmd cfg.set_now_int ratelimit reply_code 505
 
 
    Example 1.9. Set reply_reason parameter
    Example 1.9. Set reply_reason parameter
 ...
 ...
-modparam("ratelimit", "reply_reason", "Limiting")
+modparam("pipelimit", "reply_reason", "Limiting")
 ...
 ...
 
 
    This value can be modified at runtime using kamcmd
    This value can be modified at runtime using kamcmd
 
 
    Example 1.10.  Set reply_reason parameter at runtime
    Example 1.10.  Set reply_reason parameter at runtime
-kamcmd cfg.set_now_string ratelimit reply_reason "Limiting"
+kamcmd cfg.set_now_string pipelimit reply_reason "Limiting"
 
 
 4. Functions
 4. Functions
 
 
@@ -400,3 +424,88 @@ kamcmd cfg.set_now_string ratelimit reply_reason "Limiting"
                 :pl_push_load:_reply_fifo_file_
                 :pl_push_load:_reply_fifo_file_
                 0.85
                 0.85
                 _empty_line_
                 _empty_line_
+
+6. RPC Commands
+
+   6.1. pl.stats
+   6.2. pl.set_pipe
+   6.3. pl.get_pipes
+   6.4. pl.set_pid
+   6.5. pl.get_pid
+   6.6. pl.push_load
+
+6.1.  pl.stats
+
+   Lists the parameters and variabiles in the pipelimit module: pipe id,
+   pipe load and pipe couter.
+
+   Name: pl.stats
+
+   Parameters: none
+
+   RPC Command Format:
+        kamcmd pl.stats
+
+6.2.  pl.set_pipe
+
+   Sets the pipe parameters for the given pipe id.
+
+   Name: pl.set_pipe
+
+   Parameters:
+     * pipe_id - pipe id.
+     * pipe_algorithm - the algorithm assigned to the given pipe id.
+     * pipe_limit - the limit assigned to the given pipe id.
+
+   RPC Command Format:
+        kamcmd pl.set_pipe 2 RED 10
+
+6.3.  pl.get_pipes
+
+   Gets the list of in use pipes.
+
+   Name: pl.get_pipes
+
+   Parameters: none
+
+   RPC Command Format:
+        kamcmd pl.get_pipes
+
+6.4.  pl.set_pid
+
+   Sets the PID Controller parameters for the Feedback Algorithm.
+
+   Name: pl.set_pid
+
+   Parameters:
+     * ki - the integral parameter.
+     * kp - the proportional parameter.
+     * kd - the derivative parameter.
+
+   RPC Command Format:
+        kamcmd pl.set_pid 0.5 0.5 0.5
+
+6.5.  pl.get_pid
+
+   Gets the list of in use PID Controller parameters.
+
+   Name: pl.get_pid
+
+   Parameters: none
+
+   RPC Command Format:
+        kamcmd pl.get_pid
+
+6.6.  pl.push_load
+
+   Force the value of the load parameter. This command is useful for
+   testing the Feedback algorithm.
+
+   Name: pl.push_load
+
+   Parameters:
+     * load - the forced value of load (it must be greater then 0.0 and
+       smaller then 1.0).
+
+   RPC Command Format:
+        kamcmd pl.push_load 0.85

+ 9 - 0
modules/pipelimit/doc/pipelimit.xml

@@ -28,6 +28,11 @@
 		</address>
 		</address>
 		</author>
 		</author>
 		<editor>
 		<editor>
+		<firstname>Ovidiu</firstname>
+		<surname>Sas</surname>
+		<address><email>[email protected]</email></address>
+		</editor>
+		<editor>
 		<firstname>Daniel-Constantin</firstname>
 		<firstname>Daniel-Constantin</firstname>
 		<surname>Mierla</surname>
 		<surname>Mierla</surname>
 		<address>
 		<address>
@@ -35,6 +40,10 @@
 		</address>
 		</address>
 		</editor>
 		</editor>
 	</authorgroup>
 	</authorgroup>
+	<copyright>
+		<year>2013</year>
+		<holder><ulink url='http://www.voipembedded.com'>VoIPEmbedded Inc.</ulink></holder>
+	</copyright>
 	<copyright>
 	<copyright>
 		<year>2010</year>
 		<year>2010</year>
 		<holder>Asipto.com</holder>
 		<holder>Asipto.com</holder>

+ 149 - 5
modules/pipelimit/doc/pipelimit_admin.xml

@@ -185,7 +185,7 @@ modparam("pipelimit", "plp_algorithm_column", "name")
 		<title>Set <varname>timer_interval</varname> parameter</title>
 		<title>Set <varname>timer_interval</varname> parameter</title>
 		<programlisting format="linespecific">
 		<programlisting format="linespecific">
 ...
 ...
-modparam("ratelimit", "timer_interval", 5)
+modparam("pipelimit", "timer_interval", 5)
 ...
 ...
 </programlisting>
 </programlisting>
 		</example>
 		</example>
@@ -205,7 +205,7 @@ modparam("ratelimit", "timer_interval", 5)
 		<title>Set <varname>reply_code</varname> parameter</title>
 		<title>Set <varname>reply_code</varname> parameter</title>
 		<programlisting format="linespecific">
 		<programlisting format="linespecific">
 ...
 ...
-modparam("ratelimit", "reply_code", 505)
+modparam("pipelimit", "reply_code", 505)
 ...
 ...
 </programlisting>
 </programlisting>
 		</example>
 		</example>
@@ -216,7 +216,7 @@ modparam("ratelimit", "reply_code", 505)
 		<title> Set <varname>reply_code</varname> parameter at runtime </title>
 		<title> Set <varname>reply_code</varname> parameter at runtime </title>
 		<programlisting format="linespecific">
 		<programlisting format="linespecific">
 
 
-&sercmd; cfg.set_now_int ratelimit reply_code 505
+&sercmd; cfg.set_now_int pipelimit reply_code 505
 
 
 		</programlisting>
 		</programlisting>
 		</example>
 		</example>
@@ -235,7 +235,7 @@ modparam("ratelimit", "reply_code", 505)
 		<title>Set <varname>reply_reason</varname> parameter</title>
 		<title>Set <varname>reply_reason</varname> parameter</title>
 		<programlisting format="linespecific">
 		<programlisting format="linespecific">
 ...
 ...
-modparam("ratelimit", "reply_reason", "Limiting")
+modparam("pipelimit", "reply_reason", "Limiting")
 ...
 ...
 </programlisting>
 </programlisting>
 		</example>
 		</example>
@@ -246,7 +246,7 @@ modparam("ratelimit", "reply_reason", "Limiting")
 		<title> Set <varname>reply_reason</varname> parameter at runtime </title>
 		<title> Set <varname>reply_reason</varname> parameter at runtime </title>
 		<programlisting format="linespecific">
 		<programlisting format="linespecific">
 
 
-&sercmd; cfg.set_now_string ratelimit reply_reason "Limiting"
+&sercmd; cfg.set_now_string pipelimit reply_reason "Limiting"
 
 
 		</programlisting>
 		</programlisting>
 		</example>
 		</example>
@@ -495,4 +495,148 @@ modparam("ratelimit", "reply_reason", "Limiting")
 	</section>
 	</section>
 	</section>
 	</section>
 	
 	
+	<section>
+	<title>RPC Commands</title>
+	<section>
+		<title>
+		<function moreinfo="none">pl.stats</function>
+		</title>
+		<para>
+		Lists the parameters and variabiles in the pipelimit module:
+		pipe id, pipe load and pipe couter.
+		</para>
+		<para>
+		Name: <emphasis>pl.stats</emphasis>
+		</para>
+		<para>Parameters: <emphasis>none</emphasis></para>
+ 		<para>
+		RPC Command Format:
+		</para>
+		<programlisting  format="linespecific">
+	kamcmd pl.stats
+		</programlisting>
+	</section>
+	<section>
+		<title>
+		<function moreinfo="none">pl.set_pipe</function>
+		</title>
+		<para>
+		Sets the pipe parameters for the given pipe id.
+		</para>
+		<para>
+		Name: <emphasis>pl.set_pipe</emphasis>
+		</para>
+		<para>Parameters:</para>
+		<itemizedlist>
+			<listitem><para>
+			<emphasis>pipe_id</emphasis> - pipe id.
+			</para></listitem>
+			<listitem><para>
+			<emphasis>pipe_algorithm</emphasis> - the
+			algorithm assigned to the given pipe id.
+			</para></listitem>
+			<listitem><para>
+			<emphasis>pipe_limit</emphasis> - the limit
+			assigned to the given pipe id.
+			</para></listitem>
+		</itemizedlist>
+		<para>
+		RPC Command Format:
+		</para>
+		<programlisting  format="linespecific">
+	kamcmd pl.set_pipe 2 RED 10
+		</programlisting>
+	</section>
+	<section>
+		<title>
+		<function moreinfo="none">pl.get_pipes</function>
+		</title>
+		<para>
+		Gets the list of in use pipes.
+		</para>
+		<para>
+		Name: <emphasis>pl.get_pipes</emphasis>
+		</para>
+		<para>Parameters: <emphasis>none</emphasis></para>
+		<para>
+		RPC Command Format:
+		</para>
+		<programlisting  format="linespecific">
+	kamcmd pl.get_pipes
+		</programlisting>
+	</section>
+	<section>
+		<title>
+		<function moreinfo="none">pl.set_pid</function>
+		</title>
+		<para>
+		Sets the PID Controller parameters for the Feedback Algorithm.
+		</para>
+		<para>
+		Name: <emphasis>pl.set_pid</emphasis>
+		</para>
+		<para>Parameters:</para>
+		<itemizedlist>
+			<listitem><para>
+			<emphasis>ki</emphasis> - the integral parameter.
+			</para></listitem>
+			<listitem><para>
+			<emphasis>kp</emphasis> - the proportional parameter.
+			</para></listitem>
+			<listitem><para>
+			<emphasis>kd</emphasis> - the derivative parameter.
+			</para></listitem>
+		</itemizedlist>
+		<para>
+		RPC Command Format:
+		</para>
+		<programlisting  format="linespecific">
+	kamcmd pl.set_pid 0.5 0.5 0.5
+		</programlisting>
+	</section>
+	<section>
+		<title>
+		<function moreinfo="none">pl.get_pid</function>
+		</title>
+		<para>
+		Gets the list of in use PID Controller parameters.
+		</para>
+		<para>
+		Name: <emphasis>pl.get_pid</emphasis>
+		</para>
+		<para>Parameters: <emphasis>none</emphasis></para>
+		<para>
+		RPC Command Format:
+		</para>
+		<programlisting  format="linespecific">
+	kamcmd pl.get_pid
+		</programlisting>
+	</section>
+	<section>
+		<title>
+		<function moreinfo="none">pl.push_load</function>
+		</title>
+		<para>
+		Force the value of the load parameter.  This command is useful
+		for testing the Feedback algorithm.
+		</para>
+		<para>
+		Name: <emphasis>pl.push_load</emphasis>
+		</para>
+		<para>Parameters:</para>
+		<itemizedlist>
+			<listitem><para>
+			<emphasis>load</emphasis> - the forced value of load
+			(it must be greater then 0.0 and smaller then 1.0).
+			</para></listitem>
+		</itemizedlist>
+		<para>
+		RPC Command Format:
+		</para>
+		<programlisting  format="linespecific">
+	kamcmd pl.push_load 0.85
+		</programlisting>
+	</section>
+	</section>
+	
 </chapter>
 </chapter>

+ 88 - 0
modules/pipelimit/pipelimit.c

@@ -50,6 +50,7 @@
 #include "../../lib/kcore/statistics.h"
 #include "../../lib/kcore/statistics.h"
 #include "../../modules/sl/sl.h"
 #include "../../modules/sl/sl.h"
 #include "../../lib/kmi/mi.h"
 #include "../../lib/kmi/mi.h"
+#include "../../rpc_lookup.h"
 
 
 #include "pl_ht.h"
 #include "pl_ht.h"
 #include "pl_db.h"
 #include "pl_db.h"
@@ -156,6 +157,8 @@ static mi_export_t mi_cmds [] = {
 	{0,0,0,0,0}
 	{0,0,0,0,0}
 };
 };
 
 
+static rpc_export_t rpc_methods[];
+
 /** module exports */
 /** module exports */
 struct module_exports exports= {
 struct module_exports exports= {
 	"pipelimit",
 	"pipelimit",
@@ -279,6 +282,11 @@ static void update_cpu_load(void)
 /* initialize ratelimit module */
 /* initialize ratelimit module */
 static int mod_init(void)
 static int mod_init(void)
 {
 {
+	if(rpc_register_array(rpc_methods)!=0)
+	{
+		LM_ERR("failed to register RPC commands\n");
+		return -1;
+	}
 	if(register_mi_mod(exports.name, mi_cmds)!=0)
 	if(register_mi_mod(exports.name, mi_cmds)!=0)
 	{
 	{
 		LM_ERR("failed to register MI commands\n");
 		LM_ERR("failed to register MI commands\n");
@@ -700,3 +708,83 @@ bad_syntax:
 	return init_mi_tree( 400, MI_BAD_PARM_S, MI_BAD_PARM_LEN);
 	return init_mi_tree( 400, MI_BAD_PARM_S, MI_BAD_PARM_LEN);
 }
 }
 
 
+/* rpc function documentation */
+const char *rpc_pl_stats_doc[2] = {
+	"Print pipelimit statistics: \
+<id> <load> <counter>", 0
+};
+
+const char *rpc_pl_get_pipes_doc[2] = {
+	"Print pipes info: \
+<id> <algorithm> <limit> <counter>", 0
+};
+
+const char *rpc_pl_set_pipe_doc[2] = {
+	"Sets a pipe params: <pipe_id> <pipe_algorithm> <pipe_limit>", 0
+};
+
+const char *rpc_pl_get_pid_doc[2] = {
+	"Print PID Controller parameters for the FEEDBACK algorithm: \
+<ki> <kp> <kd>", 0
+};
+
+const char *rpc_pl_set_pid_doc[2] = {
+	"Sets the PID Controller parameters for the FEEDBACK algorithm: \
+<ki> <kp> <kd>", 0
+};
+
+const char *rpc_pl_push_load_doc[2] = {
+	"Force the value of the load parameter for FEEDBACK algorithm: \
+<load>", 0
+};
+
+/* rpc function implementations */
+void rpc_pl_stats(rpc_t *rpc, void *c);
+void rpc_pl_get_pipes(rpc_t *rpc, void *c);
+void rpc_pl_set_pipe(rpc_t *rpc, void *c);
+
+void rpc_pl_get_pid(rpc_t *rpc, void *c) {
+	rpl_pipe_lock(0);
+	rpc->printf(c, "ki[%f] kp[%f] kd[%f] ", *pid_ki, *pid_kp, *pid_kd);
+	rpl_pipe_release(0);
+}
+
+void rpc_pl_set_pid(rpc_t *rpc, void *c) {
+	double ki, kp, kd;
+
+	if (rpc->scan(c, "fff", &ki, &kp, &kd) < 3) return;
+
+	rpl_pipe_lock(0);
+	*pid_ki = ki;
+	*pid_kp = kp;
+	*pid_kd = kd;
+	rpl_pipe_release(0);
+}
+
+void rpc_pl_push_load(rpc_t *rpc, void *c) {
+	double value;
+
+	if (rpc->scan(c, "f", &value) < 1) return;
+
+	if (value < 0.0 || value > 1.0) {
+		LM_ERR("value out of range: %0.3f in not in [0.0,1.0]\n", value);
+		rpc->fault(c, 400, "Value out of range");
+		return;
+	}
+	rpl_pipe_lock(0);
+	*load_value = value;
+	rpl_pipe_release(0);
+
+	do_update_load();
+}
+
+static rpc_export_t rpc_methods[] = {
+	{"pl.stats",      rpc_pl_stats,     rpc_pl_stats_doc,     0},
+	{"pl.get_pipes",  rpc_pl_get_pipes, rpc_pl_get_pipes_doc, 0},
+	{"pl.set_pipe",   rpc_pl_set_pipe,  rpc_pl_set_pipe_doc,  0},
+	{"pl.get_pid",    rpc_pl_get_pid,   rpc_pl_get_pid_doc,   0},
+	{"pl.set_pid",    rpc_pl_set_pid,   rpc_pl_set_pid_doc,   0},
+	{"pl.push_load",  rpc_pl_push_load, rpc_pl_push_load_doc, 0},
+	{0, 0, 0, 0}
+};
+

+ 98 - 0
modules/pipelimit/pl_ht.c

@@ -39,6 +39,7 @@
 #include "../../hashes.h"
 #include "../../hashes.h"
 #include "../../mem/shm_mem.h"
 #include "../../mem/shm_mem.h"
 #include "../../lib/kmi/mi.h"
 #include "../../lib/kmi/mi.h"
+#include "../../rpc_lookup.h"
 
 
 #include "pl_ht.h"
 #include "pl_ht.h"
 
 
@@ -591,3 +592,100 @@ void rpl_pipe_release(int slot)
 }
 }
 
 
 
 
+/* rpc function implementations */
+void rpc_pl_stats(rpc_t *rpc, void *c)
+{
+	int i;
+	pl_pipe_t *it;
+
+	for(i=0; i<_pl_pipes_ht->htsize; i++)
+	{
+		lock_get(&_pl_pipes_ht->slots[i].lock);
+		it = _pl_pipes_ht->slots[i].first;
+		while(it)
+		{
+			if (it->algo != PIPE_ALGO_NOP) {
+				if (rpc->printf(c, "PIPE: id=%.*s load=%d counter=%d",
+					it->name.len, it->name.s,
+					it->load, it->last_counter) < 0)
+				{
+					lock_release(&_pl_pipes_ht->slots[i].lock);
+					return;
+				}
+			}
+			it = it->next;
+		}
+		lock_release(&_pl_pipes_ht->slots[i].lock);
+	}
+}
+
+void rpc_pl_get_pipes(rpc_t *rpc, void *c)
+{
+	int i;
+	str algo;
+	pl_pipe_t *it;
+
+	for(i=0; i<_pl_pipes_ht->htsize; i++)
+	{
+		lock_get(&_pl_pipes_ht->slots[i].lock);
+		it = _pl_pipes_ht->slots[i].first;
+		while(it)
+		{
+			if (it->algo != PIPE_ALGO_NOP) {
+				if (str_map_int(algo_names, it->algo, &algo))
+				{
+					lock_release(&_pl_pipes_ht->slots[i].lock);
+					return;
+				}
+				if (rpc->printf(c, "PIPE: id=%.*s algorithm=%.*s limit=%d counter=%d",
+					it->name.len, it->name.s, algo.len, algo.s,
+					it->limit, it->counter) < 0)
+				{
+					lock_release(&_pl_pipes_ht->slots[i].lock);
+					return;
+				}
+			}
+			it = it->next;
+		}
+		lock_release(&_pl_pipes_ht->slots[i].lock);
+	}
+}
+
+void rpc_pl_set_pipe(rpc_t *rpc, void *c)
+{
+	unsigned int algo_id, limit = 0;
+	pl_pipe_t *it;
+	str pipeid, algo_str;
+
+	if (rpc->scan(c, "SSd", &pipeid, &algo_str, &limit) < 3) return;
+
+	if (str_map_str(algo_names, &algo_str, (int*)&algo_id)) {
+		LM_ERR("unknown algorithm: '%.*s'\n", algo_str.len, algo_str.s);
+		rpc->fault(c, 400, "Unknown algorithm");
+		return;
+	}
+
+	LM_DBG("set_pipe: %.*s:%d:%d\n", pipeid.len, pipeid.s, algo_id, limit);
+
+	it = pl_pipe_get(&pipeid, 1);
+	if (it==NULL) {
+		LM_ERR("no pipe: %.*s\n", pipeid.len, pipeid.s);
+		rpc->fault(c, 400, "Unknown pipe id %.*s", pipeid.len, pipeid.s);
+		return;
+	}
+
+	it->algo = algo_id;
+	it->limit = limit;
+
+	if (check_feedback_setpoints(0)) {
+		pl_pipe_release(&pipeid);
+		LM_ERR("feedback limits don't match\n");
+		rpc->fault(c, 400, "Feedback limits don't match");
+		return;
+	} else {
+		*_pl_pid_setpoint = 0.01 * (double)_pl_cfg_setpoint;
+	}
+
+	pl_pipe_release(&pipeid);
+}
+

+ 5 - 1
modules/registrar_pcscf/Makefile

@@ -12,7 +12,11 @@ LIBS=
 
 
 DEFS+=-DOPENSER_MOD_INTERFACE -I/usr/include/libxml2 -I$(LOCALBASE)/include/libxml2
 DEFS+=-DOPENSER_MOD_INTERFACE -I/usr/include/libxml2 -I$(LOCALBASE)/include/libxml2
 
 
-LIBS += -L$(LOCALBASE)/lib -lrt
+LIBS += -L$(LOCALBASE)/lib
+
+ifneq ($(OS),darwin)
+	LIBS += -lrt
+endif
 
 
 SERLIBPATH=../../lib
 SERLIBPATH=../../lib
 SER_LIBS+=$(SERLIBPATH)/kcore/kcore
 SER_LIBS+=$(SERLIBPATH)/kcore/kcore

+ 5 - 1
modules/registrar_scscf/Makefile

@@ -12,7 +12,11 @@ LIBS=
 
 
 DEFS+=-DOPENSER_MOD_INTERFACE
 DEFS+=-DOPENSER_MOD_INTERFACE
 DEFS += -I/usr/include/libxml2 
 DEFS += -I/usr/include/libxml2 
-LIBS += -L$(LOCALBASE)/lib -lxml2 -lrt
+LIBS += -L$(LOCALBASE)/lib -lxml2
+
+ifneq ($(OS),darwin)
+	LIBS += -lrt
+endif
 
 
 SERLIBPATH=../../lib
 SERLIBPATH=../../lib
 SER_LIBS+=$(SERLIBPATH)/kcore/kcore
 SER_LIBS+=$(SERLIBPATH)/kcore/kcore

+ 85 - 64
modules/rtpproxy/README

@@ -30,13 +30,13 @@ Carsten Bock
 
 
    ng-voice GmbH
    ng-voice GmbH
 
 
-   Copyright © 2003-2008 Sippy Software, Inc.
+   Copyright © 2003-2008 Sippy Software, Inc.
 
 
-   Copyright © 2005 Voice Sistem SRL
+   Copyright © 2005 Voice Sistem SRL
 
 
-   Copyright © 2009-2012 TuTPro Inc.
+   Copyright © 2009-2012 TuTPro Inc.
 
 
-   Copyright © 2010 VoIPEmbedded Inc.
+   Copyright © 2010 VoIPEmbedded Inc.
      __________________________________________________________________
      __________________________________________________________________
 
 
    Table of Contents
    Table of Contents
@@ -58,6 +58,7 @@ Carsten Bock
               4.4. rtpproxy_retr (integer)
               4.4. rtpproxy_retr (integer)
               4.5. nortpproxy_str (string)
               4.5. nortpproxy_str (string)
               4.6. timeout_socket (string)
               4.6. timeout_socket (string)
+              4.7. ice_candidate_priority_avp (string)
 
 
         5. Functions
         5. Functions
 
 
@@ -92,16 +93,17 @@ Carsten Bock
    1.4. Set rtpproxy_retr parameter
    1.4. Set rtpproxy_retr parameter
    1.5. Set nortpproxy_str parameter
    1.5. Set nortpproxy_str parameter
    1.6. Set timeout_socket parameter
    1.6. Set timeout_socket parameter
-   1.7. set_rtp_proxy_set usage
-   1.8. rtpproxy_offer usage
-   1.9. rtpproxy_answer usage
-   1.10. rtpproxy_destroy usage
-   1.11. rtpproxy_manage usage
-   1.12. rtpproxy_stream2xxx usage
-   1.13. start_recording usage
-   1.14. $rtpstat-Usage
-   1.15. nh_enable_rtpp usage
-   1.16. nh_show_rtpp usage
+   1.7. Set ice_candidate_priority_avp parameter
+   1.8. set_rtp_proxy_set 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
+   1.16. nh_enable_rtpp usage
+   1.17. nh_show_rtpp usage
 
 
 Chapter 1. Admin Guide
 Chapter 1. Admin Guide
 
 
@@ -122,6 +124,7 @@ Chapter 1. Admin Guide
         4.4. rtpproxy_retr (integer)
         4.4. rtpproxy_retr (integer)
         4.5. nortpproxy_str (string)
         4.5. nortpproxy_str (string)
         4.6. timeout_socket (string)
         4.6. timeout_socket (string)
+        4.7. ice_candidate_priority_avp (string)
 
 
    5. Functions
    5. Functions
 
 
@@ -163,7 +166,7 @@ Chapter 1. Admin Guide
    The module allows definition of several sets of rtpproxies.
    The module allows definition of several sets of rtpproxies.
    Load-balancing will be performed over a set and the admin has the
    Load-balancing will be performed over a set and the admin has the
    ability to choose what set should be used. The set is selected via its
    ability to choose what set should be used. The set is selected via its
-   id - the id being defined with the set. Refer to the "rtpproxy_sock"
+   id - the id being defined with the set. Refer to the “rtpproxy_sock�
    module parameter definition for syntax description.
    module parameter definition for syntax description.
 
 
    The balancing inside a set is done automatically by the module based on
    The balancing inside a set is done automatically by the module based on
@@ -205,13 +208,14 @@ Chapter 1. Admin Guide
    4.4. rtpproxy_retr (integer)
    4.4. rtpproxy_retr (integer)
    4.5. nortpproxy_str (string)
    4.5. nortpproxy_str (string)
    4.6. timeout_socket (string)
    4.6. timeout_socket (string)
+   4.7. ice_candidate_priority_avp (string)
 
 
 4.1. rtpproxy_sock (string)
 4.1. rtpproxy_sock (string)
 
 
    Definition of socket(s) used to connect to (a set) RTPProxy. It may
    Definition of socket(s) used to connect to (a set) RTPProxy. It may
    specify a UNIX socket or an IPv4/IPv6 UDP socket.
    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
    Example 1.1. Set rtpproxy_sock parameter
 ...
 ...
@@ -233,7 +237,7 @@ modparam("rtpproxy", "rtpproxy_sock",
    rtpproxy module will not attempt to establish communication to RTPProxy
    rtpproxy module will not attempt to establish communication to RTPProxy
    for rtpproxy_disable_tout seconds.
    for rtpproxy_disable_tout seconds.
 
 
-   Default value is "60".
+   Default value is “60�.
 
 
    Example 1.2. Set rtpproxy_disable_tout parameter
    Example 1.2. Set rtpproxy_disable_tout parameter
 ...
 ...
@@ -244,7 +248,7 @@ modparam("rtpproxy", "rtpproxy_disable_tout", 20)
 
 
    Timeout value in waiting for reply from RTPProxy.
    Timeout value in waiting for reply from RTPProxy.
 
 
-   Default value is "1".
+   Default value is “1�.
 
 
    Example 1.3. Set rtpproxy_tout parameter
    Example 1.3. Set rtpproxy_tout parameter
 ...
 ...
@@ -256,7 +260,7 @@ modparam("rtpproxy", "rtpproxy_tout", 2)
    How many times the module should retry to send and receive after
    How many times the module should retry to send and receive after
    timeout was generated.
    timeout was generated.
 
 
-   Default value is "5".
+   Default value is “5�.
 
 
    Example 1.4. Set rtpproxy_retr parameter
    Example 1.4. Set rtpproxy_retr parameter
 ...
 ...
@@ -275,7 +279,7 @@ Note
 
 
    The string must be a complete SDP line, including the EOH (\r\n).
    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.5. Set nortpproxy_str parameter
    Example 1.5. Set nortpproxy_str parameter
 ...
 ...
@@ -291,13 +295,30 @@ modparam("rtpproxy", "nortpproxy_str", "a=sdpmangled:yes\r\n")
    If it is an empty string, no timeout socket will be transmitted to the
    If it is an empty string, no timeout socket will be transmitted to the
    RTP-Proxy.
    RTP-Proxy.
 
 
-   Default value is "" (nothing).
+   Default value is “� (nothing).
 
 
    Example 1.6. Set timeout_socket parameter
    Example 1.6. Set timeout_socket parameter
 ...
 ...
 modparam("nathelper", "timeout_socket", "xmlrpc:http://127.0.0.1:8000/RPC2")
 modparam("nathelper", "timeout_socket", "xmlrpc:http://127.0.0.1:8000/RPC2")
 ...
 ...
 
 
+4.7. ice_candidate_priority_avp (string)
+
+   If specified and if value of the avp value is not 0, rtpproxy_manage
+   function adds ICE relay candidate attributes to sdp stream(s)
+   containing ICE candidate attributes.
+
+   If value of the avp is 1, added candidates have high priority. If value
+   of the avp is 2 (default), added candidates have low priority.
+
+   There is no default value meaning that no ICE relay candidates are
+   added in any circumstance.
+
+   Example 1.7. Set ice_candidate_priority_avp parameter
+...
+modparam("rtpproxy", "ice_candidate_priority_avp", "$avp(ice_priority)")
+...
+
 5. Functions
 5. Functions
 
 
    5.1. set_rtp_proxy_set(setid)
    5.1. set_rtp_proxy_set(setid)
@@ -322,7 +343,7 @@ modparam("nathelper", "timeout_socket", "xmlrpc:http://127.0.0.1:8000/RPC2")
    This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
    This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
    BRANCH_ROUTE.
    BRANCH_ROUTE.
 
 
-   Example 1.7. set_rtp_proxy_set usage
+   Example 1.8. set_rtp_proxy_set usage
 ...
 ...
 set_rtp_proxy_set("2");
 set_rtp_proxy_set("2");
 rtpproxy_offer();
 rtpproxy_offer();
@@ -338,16 +359,16 @@ rtpproxy_offer();
      * flags - flags to turn on some features.
      * flags - flags to turn on some features.
           + 1 - append first Via branch to Call-ID when sending command to
           + 1 - append first Via branch to Call-ID when sending command to
             rtpproxy. This can be used to create one media session per
             rtpproxy. This can be used to create one media session per
-            branch on the rtpproxy. When sending a subsequent "delete"
+            branch on the rtpproxy. When sending a subsequent “delete�
             command to the rtpproxy, you can then stop just the session
             command to the rtpproxy, you can then stop just the session
             for a specific branch when passing the flag '1' or '2' in the
             for a specific branch when passing the flag '1' or '2' in the
-            "unforce_rtpproxy", or stop all sessions for a call when not
+            “unforce_rtpproxy�, or stop all sessions for a call when not
             passing one of those two flags there. This is especially
             passing one of those two flags there. This is especially
             useful if you have serially forked call scenarios where
             useful if you have serially forked call scenarios where
-            rtpproxy gets an "update" command for a new branch, and then a
-            "delete" command for the previous branch, which would
+            rtpproxy gets an “update� command for a new branch, and then a
+            “delete� command for the previous branch, which would
             otherwise delete the full call, breaking the subsequent
             otherwise delete the full call, breaking the subsequent
-            "lookup" for the new branch. This flag is only supported by
+            “lookup� for the new branch. This flag is only supported by
             the ngcp-mediaproxy-ng rtpproxy at the moment!
             the ngcp-mediaproxy-ng rtpproxy at the moment!
           + 2 - append second Via branch to Call-ID when sending command
           + 2 - append second Via branch to Call-ID when sending command
             to rtpproxy. See flag '1' for its meaning.
             to rtpproxy. See flag '1' for its meaning.
@@ -355,7 +376,7 @@ rtpproxy_offer();
             set for a reply.
             set for a reply.
           + a - flags that UA from which message is received doesn't
           + a - flags that UA from which message is received doesn't
             support symmetric RTP. (automatically sets the 'r' flag)
             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 already exists in the RTP proxy. By
             corresponding session already exists in the RTP proxy. By
             default is on when the session is to be completed.
             default is on when the session is to be completed.
           + i, e - these flags specify the direction of the SIP message.
           + i, e - these flags specify the direction of the SIP message.
@@ -416,7 +437,7 @@ rtpproxy_offer();
 
 
    This function can be used from ANY_ROUTE.
    This function can be used from ANY_ROUTE.
 
 
-   Example 1.8. rtpproxy_offer usage
+   Example 1.9. rtpproxy_offer usage
 route {
 route {
 ...
 ...
     if (is_method("INVITE")) {
     if (is_method("INVITE")) {
@@ -460,7 +481,7 @@ onreply_route[2]
    This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
    This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
    FAILURE_ROUTE, BRANCH_ROUTE.
    FAILURE_ROUTE, BRANCH_ROUTE.
 
 
-   Example 1.9. rtpproxy_answer usage
+   Example 1.10. rtpproxy_answer usage
 
 
    See rtpproxy_offer() function example above for example.
    See rtpproxy_offer() function example above for example.
 
 
@@ -474,25 +495,25 @@ onreply_route[2]
      * flags - flags to turn on some features.
      * flags - flags to turn on some features.
           + 1 - append first Via branch to Call-ID when sending command to
           + 1 - append first Via branch to Call-ID when sending command to
             rtpproxy. This can be used to create one media session per
             rtpproxy. This can be used to create one media session per
-            branch on the rtpproxy. When sending a subsequent "delete"
+            branch on the rtpproxy. When sending a subsequent “delete�
             command to the rtpproxy, you can then stop just the session
             command to the rtpproxy, you can then stop just the session
             for a specific branch when passing the flag '1' or '2' in the
             for a specific branch when passing the flag '1' or '2' in the
-            "unforce_rtpproxy", or stop all sessions for a call when not
+            “unforce_rtpproxy�, or stop all sessions for a call when not
             passing one of those two flags there. This is especially
             passing one of those two flags there. This is especially
             useful if you have serially forked call scenarios where
             useful if you have serially forked call scenarios where
-            rtpproxy gets an "update" command for a new branch, and then a
-            "delete" command for the previous branch, which would
+            rtpproxy gets an “update� command for a new branch, and then a
+            “delete� command for the previous branch, which would
             otherwise delete the full call, breaking the subsequent
             otherwise delete the full call, breaking the subsequent
-            "lookup" for the new branch. This flag is only supported by
+            “lookup� for the new branch. This flag is only supported by
             the ngcp-mediaproxy-ng rtpproxy at the moment!
             the ngcp-mediaproxy-ng rtpproxy at the moment!
           + 2 - append second Via branch to Call-ID when sending command
           + 2 - append second Via branch to Call-ID when sending command
             to rtpproxy. See flag '1' for its meaning.
             to rtpproxy. See flag '1' for its meaning.
-          + t - do not include To tag to "delete" command to rtpproxy thus
+          + t - do not include To tag to “delete� command to rtpproxy thus
             causing full call to be deleted. Useful for deleting unused
             causing full call to be deleted. Useful for deleting unused
             rtpproxy call when 200 OK is received on a branch, where
             rtpproxy call when 200 OK is received on a branch, where
             rtpproxy is not needed.
             rtpproxy is not needed.
 
 
-   Example 1.10. rtpproxy_destroy usage
+   Example 1.11. rtpproxy_destroy usage
 ...
 ...
 rtpproxy_destroy();
 rtpproxy_destroy();
 ...
 ...
@@ -524,7 +545,7 @@ rtpproxy_destroy();
 
 
    This function can be used from ANY_ROUTE.
    This function can be used from ANY_ROUTE.
 
 
-   Example 1.11. rtpproxy_manage usage
+   Example 1.12. rtpproxy_manage usage
 ...
 ...
 rtpproxy_manage();
 rtpproxy_manage();
 ...
 ...
@@ -560,7 +581,7 @@ rtpproxy_manage();
        -1 means that it will be streaming in a loop indefinitely, until
        -1 means that it will be streaming in a loop indefinitely, until
        the appropriate rtpproxy_stop_stream2xxx is issued.
        the appropriate rtpproxy_stop_stream2xxx is issued.
 
 
-   Example 1.12. rtpproxy_stream2xxx usage
+   Example 1.13. rtpproxy_stream2xxx usage
 ...
 ...
     if (is_method("INVITE")) {
     if (is_method("INVITE")) {
         rtpproxy_offer();
         rtpproxy_offer();
@@ -593,7 +614,7 @@ rtpproxy_manage();
 
 
    This function can be used from REQUEST_ROUTE and ONREPLY_ROUTE.
    This function can be used from REQUEST_ROUTE and ONREPLY_ROUTE.
 
 
-   Example 1.13. start_recording usage
+   Example 1.14. start_recording usage
 ...
 ...
 start_recording();
 start_recording();
 ...
 ...
@@ -613,7 +634,7 @@ start_recording();
    packet-counters. The statistics must be retrieved before the session is
    packet-counters. The statistics must be retrieved before the session is
    deleted (before unforce_rtpproxy()).
    deleted (before unforce_rtpproxy()).
 
 
-   Example 1.14. $rtpstat-Usage
+   Example 1.15. $rtpstat-Usage
 ...
 ...
     append_hf("X-RTP-Statistics: $rtpstat\r\n");
     append_hf("X-RTP-Statistics: $rtpstat\r\n");
 ...
 ...
@@ -636,7 +657,7 @@ start_recording();
    NOTE: if a rtpproxy is defined multiple times (in the same or diferente
    NOTE: if a rtpproxy is defined multiple times (in the same or diferente
    sete), all of its instances will be enables/disabled.
    sete), all of its instances will be enables/disabled.
 
 
-   Example 1.15.  nh_enable_rtpp usage
+   Example 1.16.  nh_enable_rtpp usage
 ...
 ...
 $ kamctl fifo nh_enable_rtpp udp:192.168.2.133:8081 0
 $ kamctl fifo nh_enable_rtpp udp:192.168.2.133:8081 0
 ...
 ...
@@ -648,52 +669,52 @@ $ kamctl fifo nh_enable_rtpp udp:192.168.2.133:8081 0
 
 
    No parameter.
    No parameter.
 
 
-   Example 1.16.  nh_show_rtpp usage
+   Example 1.17.  nh_show_rtpp usage
 ...
 ...
 $ kamctl fifo nh_show_rtpp
 $ kamctl fifo nh_show_rtpp
 ...
 ...
 
 
 Chapter 2. Frequently Asked Questions
 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.2. Where can I find more about Kamailio?
    2.3. Where can I post a question about this module?
    2.3. Where can I post a question about this module?
    2.4. How can I report a bug?
    2.4. How can I report a bug?
 
 
    2.1.
    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
-   empty value to disable the rtpproxy functionality.
+       It was removed as it became obsolete - now “rtpproxy_sock� can take
+       empty value to disable the rtpproxy functionality.
 
 
    2.2.
    2.2.
 
 
-   Where can I find more about Kamailio?
+       Where can I find more about Kamailio?
 
 
-   Take a look at http://www.kamailio.org/.
+       Take a look at http://www.kamailio.org/.
 
 
    2.3.
    2.3.
 
 
-   Where can I post a question about this module?
+       Where can I post a question about this module?
 
 
-   First at all check if your question was already answered on one of our
-   mailing lists:
-     * User Mailing List -
-       http://lists.sip-router.org/cgi-bin/mailman/listinfo/sr-users
-     * Developer Mailing List -
-       http://lists.sip-router.org/cgi-bin/mailman/listinfo/sr-dev
+       First at all check if your question was already answered on one of our
+       mailing lists:
+         * User Mailing List -
+           http://lists.sip-router.org/cgi-bin/mailman/listinfo/sr-users
+         * Developer Mailing List -
+           http://lists.sip-router.org/cgi-bin/mailman/listinfo/sr-dev
 
 
-   E-mails regarding any stable Kamailio release should be sent to
-   <[email protected]> and e-mails regarding development
-   versions should be sent to <[email protected]>.
+       E-mails regarding any stable Kamailio release should be sent to
+       <[email protected]> and e-mails regarding development
+       versions should be sent to <[email protected]>.
 
 
-   If you want to keep the mail private, send it to
-   <[email protected]>.
+       If you want to keep the mail private, send it to
+       <[email protected]>.
 
 
    2.4.
    2.4.
 
 
-   How can I report a bug?
+       How can I report a bug?
 
 
-   Please follow the guidelines provided at:
-   http://sip-router.org/tracker.
+       Please follow the guidelines provided at:
+       http://sip-router.org/tracker.

+ 28 - 0
modules/rtpproxy/doc/rtpproxy_admin.xml

@@ -232,6 +232,34 @@ modparam("rtpproxy", "nortpproxy_str", "a=sdpmangled:yes\r\n")
 ...
 ...
 modparam("nathelper", "timeout_socket", "xmlrpc:http://127.0.0.1:8000/RPC2")
 modparam("nathelper", "timeout_socket", "xmlrpc:http://127.0.0.1:8000/RPC2")
 ...
 ...
+</programlisting>
+		</example>
+	</section>
+	<section>
+		<title><varname>ice_candidate_priority_avp</varname> (string)</title>
+		<para>
+		If specified and if value of the avp value is not 0,
+		<function>rtpproxy_manage</function> function adds
+		ICE relay candidate attributes
+		to sdp stream(s) containing ICE candidate attributes.
+		</para>
+		<para>
+		If value of the avp is 1, added candidates
+		have high priority.  If value of the avp is 2 (default),
+		added candidates have low priority.
+		</para>
+		<para>
+		<emphasis>
+		There is no default value meaning that no ICE relay
+		candidates are added in any circumstance.
+		</emphasis>
+		</para>
+		<example>
+		<title>Set <varname>ice_candidate_priority_avp</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+modparam("rtpproxy", "ice_candidate_priority_avp", "$avp(ice_priority)")
+...
 </programlisting>
 </programlisting>
 		</example>
 		</example>
 	</section>
 	</section>

+ 137 - 2
modules/rtpproxy/rtpproxy.c

@@ -331,6 +331,9 @@ static unsigned int current_msg_id = (unsigned int)-1;
 struct rtpp_set_head * rtpp_set_list =0;
 struct rtpp_set_head * rtpp_set_list =0;
 struct rtpp_set * selected_rtpp_set =0;
 struct rtpp_set * selected_rtpp_set =0;
 struct rtpp_set * default_rtpp_set=0;
 struct rtpp_set * default_rtpp_set=0;
+static char *ice_candidate_priority_avp_param = NULL;
+static int ice_candidate_priority_avp_type;
+static int_str ice_candidate_priority_avp;
 
 
 /* array with the sockets used by rtpporxy (per process)*/
 /* array with the sockets used by rtpporxy (per process)*/
 static unsigned int rtpp_no = 0;
 static unsigned int rtpp_no = 0;
@@ -425,6 +428,8 @@ static param_export_t params[] = {
 	{"rtpproxy_retr",         INT_PARAM, &rtpproxy_retr         },
 	{"rtpproxy_retr",         INT_PARAM, &rtpproxy_retr         },
 	{"rtpproxy_tout",         INT_PARAM, &rtpproxy_tout         },
 	{"rtpproxy_tout",         INT_PARAM, &rtpproxy_tout         },
 	{"timeout_socket",    	  STR_PARAM, &timeout_socket_str.s  },
 	{"timeout_socket",    	  STR_PARAM, &timeout_socket_str.s  },
+	{"ice_candidate_priority_avp", STR_PARAM,
+	 &ice_candidate_priority_avp_param},
 	{0, 0, 0}
 	{0, 0, 0}
 };
 };
 
 
@@ -868,6 +873,9 @@ static int
 mod_init(void)
 mod_init(void)
 {
 {
 	int i;
 	int i;
+	pv_spec_t avp_spec;
+	str s;
+	unsigned short avp_flags;
 
 
 	if(register_mi_mod(exports.name, mi_cmds)!=0)
 	if(register_mi_mod(exports.name, mi_cmds)!=0)
 	{
 	{
@@ -910,6 +918,19 @@ mod_init(void)
 		timeout_socket_str.len = strlen(timeout_socket_str.s);
 		timeout_socket_str.len = strlen(timeout_socket_str.s);
 	}
 	}
 
 
+	if (ice_candidate_priority_avp_param) {
+	    s.s = ice_candidate_priority_avp_param; s.len = strlen(s.s);
+	    if (pv_parse_spec(&s, &avp_spec) == 0 || avp_spec.type != PVT_AVP) {
+		LM_ERR("malformed or non AVP definition <%s>\n", ice_candidate_priority_avp_param);
+		return -1;
+	    }
+	    if (pv_get_avp_name(0, &(avp_spec.pvp), &ice_candidate_priority_avp, &avp_flags) != 0) {
+		LM_ERR("invalid AVP definition <%s>\n", ice_candidate_priority_avp_param);
+		return -1;
+	    }
+	    ice_candidate_priority_avp_type = avp_flags;
+	}
+
 	if (rtpp_strings)
 	if (rtpp_strings)
 		pkg_free(rtpp_strings);
 		pkg_free(rtpp_strings);
 
 
@@ -1379,6 +1400,88 @@ alter_rtcp(struct sip_msg *msg, str *body, str *oldport, str *newport)
 	return 0;
 	return 0;
 }
 }
 
 
+
+static char *
+append_filtered_ip(char *at, str *ip)
+{
+    int i;
+    for (i = 0; i < ip->len; i++) {
+	if (isdigit(ip->s[i])) {
+	    append_chr(at, ip->s[i]);
+	}
+    }
+    return at;
+}
+
+		
+static int
+insert_candidates(struct sip_msg *msg, char *where, str *ip, unsigned int port,
+		  str *rtcp_port, int priority)
+{
+    char *buf, *at;
+    struct lump* anchor;
+    str rtp_port;
+
+    if (rtcp_port->len) {
+	buf = pkg_malloc(24 + 78 + 14 + 24 + 2*ip->len + 2 + 2*rtcp_port->len +
+			 24);
+    } else {
+	buf = pkg_malloc(12 + 39 + 12 + 12 + ip->len + 1 + rtcp_port->len + 12);
+    }	
+    if (buf == NULL) {
+	LM_ERR("insert_candidates: out of memory\n");
+	return -1;
+    }
+
+    at = buf;
+
+    if (rtcp_port->len) {
+	append_str(at, "a=candidate:", 12);
+	at = append_filtered_ip(at, ip);
+	append_str(at, " 2 UDP ", 7);
+	if (priority == 2) {
+	    append_str(at, "16777214 ", 9);
+	} else {
+	    append_str(at, "2197815294 ", 11);
+	}
+	append_str(at, ip->s, ip->len);
+	append_chr(at, ' ');
+	append_str(at, rtcp_port->s, rtcp_port->len);
+	append_str(at, " typ relay\r\n", 12);
+    }
+
+    rtp_port.s = int2str(port, &rtp_port.len);
+    append_str(at, "a=candidate:", 12);
+    at = append_filtered_ip(at, ip);
+    append_str(at, " 1 UDP ", 7);
+    if (priority == 2) {
+	append_str(at, "16777215 ", 9);
+    } else {
+	append_str(at, "2197815295 ", 11);
+    }
+    append_str(at, ip->s, ip->len);
+    append_chr(at, ' ');
+    append_str(at, rtp_port.s, rtp_port.len);
+    append_str(at, " typ relay\r\n", 12);
+
+    LM_DBG("inserting '%.*s'\n", at - buf, buf);
+
+    anchor = anchor_lump(msg, where - msg->buf, 0, 0);
+    if (anchor == 0) {
+	LOG(L_ERR, "insert_candidates: can't get anchor\n");
+	pkg_free(buf);
+	return -1;
+    }
+    if (insert_new_lump_before(anchor, buf, at - buf, 0) == 0) {
+	LM_ERR("insert_candidates: insert_new_lump_before failed\n");
+	pkg_free(buf);
+	return -1;
+    }
+
+    return 0;
+}
+    
+
 static char * gencookie(void)
 static char * gencookie(void)
 {
 {
 	static char cook[34];
 	static char cook[34];
@@ -2002,7 +2105,8 @@ force_rtp_proxy(struct sip_msg* msg, char* str1, char* str2, int offer, int forc
 {
 {
 	str body, body1, oldport, oldip, newport, newip;
 	str body, body1, oldport, oldip, newport, newip;
 	str callid, from_tag, to_tag, tmp, payload_types;
 	str callid, from_tag, to_tag, tmp, payload_types;
-	str newrtcp, viabranch;
+	str newrtcp = {0, 0};
+	str viabranch;
 	int create, port, len, flookup, argc, proxied, real, via, ret;
 	int create, port, len, flookup, argc, proxied, real, via, ret;
 	int orgip, commip;
 	int orgip, commip;
 	int pf, pf1, force;
 	int pf, pf1, force;
@@ -2049,6 +2153,8 @@ force_rtp_proxy(struct sip_msg* msg, char* str1, char* str2, int offer, int forc
 	sdp_session_cell_t* sdp_session;
 	sdp_session_cell_t* sdp_session;
 	sdp_stream_cell_t* sdp_stream;
 	sdp_stream_cell_t* sdp_stream;
 
 
+	int_str ice_candidate_priority_val;
+
 	memset(&opts, '\0', sizeof(opts));
 	memset(&opts, '\0', sizeof(opts));
 	memset(&rep_opts, '\0', sizeof(rep_opts));
 	memset(&rep_opts, '\0', sizeof(rep_opts));
 	memset(&pt_opts, '\0', sizeof(pt_opts));
 	memset(&pt_opts, '\0', sizeof(pt_opts));
@@ -2268,6 +2374,22 @@ force_rtp_proxy(struct sip_msg* msg, char* str1, char* str2, int offer, int forc
 	STR2IOVEC(from_tag, v[13]);
 	STR2IOVEC(from_tag, v[13]);
 	STR2IOVEC(to_tag, v[17]);
 	STR2IOVEC(to_tag, v[17]);
 
 
+	if (ice_candidate_priority_avp_param) {
+	    if (search_first_avp(ice_candidate_priority_avp_type,
+				 ice_candidate_priority_avp,
+				 &ice_candidate_priority_val, 0)
+		== NULL) {
+		ice_candidate_priority_val.n = 2;
+	    } else if ((ice_candidate_priority_val.n < 1) ||
+		       (ice_candidate_priority_val.n > 2)) {
+		LM_ERR("invalid ice candidate priority value %d\n",
+		       ice_candidate_priority_val.n);
+		FORCE_RTP_PROXY_RET (-1);
+	    }
+	} else {
+	    ice_candidate_priority_val.n = 0;
+	}
+
 	/* check if this is a single or a multi stream SDP offer/answer */
 	/* check if this is a single or a multi stream SDP offer/answer */
 	sdp_stream_num = get_sdp_stream_num(msg);
 	sdp_stream_num = get_sdp_stream_num(msg);
 	switch (sdp_stream_num) {
 	switch (sdp_stream_num) {
@@ -2294,7 +2416,8 @@ force_rtp_proxy(struct sip_msg* msg, char* str1, char* str2, int offer, int forc
 		o1p = sdp_session->o_ip_addr.s;
 		o1p = sdp_session->o_ip_addr.s;
 		for(;;) {
 		for(;;) {
 			sdp_stream = get_sdp_stream(msg, sdp_session_num, sdp_stream_num);
 			sdp_stream = get_sdp_stream(msg, sdp_session_num, sdp_stream_num);
-			if(!sdp_stream) break;
+			if (!sdp_stream ||
+			    (ice_candidate_priority_val.n && sdp_stream->remote_candidates.len)) break;
 
 
 			if (sdp_stream->ip_addr.s && sdp_stream->ip_addr.len>0) {
 			if (sdp_stream->ip_addr.s && sdp_stream->ip_addr.len>0) {
 				oldip = sdp_stream->ip_addr;
 				oldip = sdp_stream->ip_addr;
@@ -2509,6 +2632,7 @@ force_rtp_proxy(struct sip_msg* msg, char* str1, char* str2, int offer, int forc
 			 * See RFC 3605 for definition of RTCP attribute.
 			 * See RFC 3605 for definition of RTCP attribute.
 			 * ported from ser
 			 * ported from ser
 			 */
 			 */
+
 			if (sdp_stream->rtcp_port.s && sdp_stream->rtcp_port.len) {
 			if (sdp_stream->rtcp_port.s && sdp_stream->rtcp_port.len) {
 				newrtcp.s = int2str(port+1, &newrtcp.len); /* beware static buffer */
 				newrtcp.s = int2str(port+1, &newrtcp.len); /* beware static buffer */
 				/* Alter port. */
 				/* Alter port. */
@@ -2522,6 +2646,17 @@ force_rtp_proxy(struct sip_msg* msg, char* str1, char* str2, int offer, int forc
 				}
 				}
 			}
 			}
 
 
+			/* Add ice relay candidates */
+			if (ice_candidate_priority_val.n && sdp_stream->ice_attrs_num > 0) {
+			    body1.s = sdp_stream->ice_attr->foundation.s - 12;
+			    body1.len = bodylimit - body1.s;
+			    if (insert_candidates(msg, sdp_stream->ice_attr->foundation.s - 12,
+						  &newip, port, &newrtcp,
+						  ice_candidate_priority_val.n) == -1) {
+				FORCE_RTP_PROXY_RET (-1);
+			    }
+			}
+
 			c1p = sdp_session->ip_addr.s;
 			c1p = sdp_session->ip_addr.s;
 			c2p = sdp_stream->ip_addr.s;
 			c2p = sdp_stream->ip_addr.s;
 			/*
 			/*

+ 24 - 3
modules/sl/README

@@ -19,6 +19,7 @@ Daniel-Constantin Mierla
    4. sl_send_reply usage
    4. sl_send_reply usage
    5. send_reply usage
    5. send_reply usage
    6. sl_reply_error usage
    6. sl_reply_error usage
+   7. send_reply usage
 
 
 1. Overview
 1. Overview
 
 
@@ -92,8 +93,9 @@ modparam("sl", "bind_tm", 0)  # feature disabled
    3.1. sl_send_reply(code, reason)
    3.1. sl_send_reply(code, reason)
    3.2. send_reply(code, reason)
    3.2. send_reply(code, reason)
    3.3. sl_reply_error()
    3.3. sl_reply_error()
+   3.4. sl_forward _reply([ code, [ reason ] ])
 
 
-3.1.  sl_send_reply(code, reason)
+3.1. sl_send_reply(code, reason)
 
 
    For the current request, a reply is sent back having the given code and
    For the current request, a reply is sent back having the given code and
    text reason. The reply is sent stateless, totally independent of the
    text reason. The reply is sent stateless, totally independent of the
@@ -108,7 +110,7 @@ modparam("sl", "bind_tm", 0)  # feature disabled
 sl_send_reply("404", "Not found");
 sl_send_reply("404", "Not found");
 ...
 ...
 
 
-3.2.  send_reply(code, reason)
+3.2. send_reply(code, reason)
 
 
    For the current request, a reply is sent back having the given code and
    For the current request, a reply is sent back having the given code and
    text reason. The reply is sent stateful or stateless, depending of the
    text reason. The reply is sent stateful or stateless, depending of the
@@ -129,7 +131,7 @@ send_reply("404", "Not found");
 send_reply("403", "Invalid user - $fU");
 send_reply("403", "Invalid user - $fU");
 ...
 ...
 
 
-3.3.  sl_reply_error()
+3.3. sl_reply_error()
 
 
    Sends back an error reply describing the nature of the last internal
    Sends back an error reply describing the nature of the last internal
    error. Usually this function should be used after a script function
    error. Usually this function should be used after a script function
@@ -140,6 +142,25 @@ send_reply("403", "Invalid user - $fU");
 sl_reply_error();
 sl_reply_error();
 ...
 ...
 
 
+3.4. sl_forward _reply([ code, [ reason ] ])
+
+   Forward statelessy the current received SIP reply, with the option to
+   change the status code and reason text. The new code has to be in the
+   same class. The received reply is forwarded as well by core when the
+   config execution ended, unless it is dropped from config.
+
+   Meaning of the parameters is as follows:
+     * code - Status code.
+     * reason - Reason phrase.
+
+   This function can be used from ONREPLY_ROUTE.
+
+   Example 7. send_reply usage
+...
+if(status=="408")
+    sl_forward_reply("404", "Not found");
+...
+
 4. Statistics
 4. Statistics
 
 
    4.1. 1xx_replies
    4.1. 1xx_replies

+ 36 - 0
modules/sl/doc/sl_functions.xml

@@ -92,4 +92,40 @@ sl_reply_error();
 	    </programlisting>
 	    </programlisting>
 	</example>
 	</example>
     </section>
     </section>
+
+	<section id="sl_forward_reply">
+		<title>
+		<function moreinfo="none">sl_forward _reply([ code, [ reason ] ])</function>
+		</title>
+		<para>
+		Forward statelessy the current received SIP reply, with the option to
+		change the status code and reason text. The new code has to be in the same
+		class. The received reply is forwarded as well by core when the config
+		execution ended, unless it is dropped from config.
+		</para>
+		<para>Meaning of the parameters is as follows:</para>
+		<itemizedlist>
+		<listitem>
+			<para><emphasis>code</emphasis> - Status code.
+			</para>
+		</listitem>
+		<listitem>
+			<para><emphasis>reason</emphasis> - Reason phrase.
+			</para>
+		</listitem>
+		</itemizedlist>
+		<para>
+			This function can be used from ONREPLY_ROUTE.
+		</para>
+		<example>
+		<title><function>send_reply</function> usage</title>
+		<programlisting format="linespecific">
+...
+if(status=="408")
+    sl_forward_reply("404", "Not found");
+...
+</programlisting>
+		</example>
+	</section>
+
 </section>
 </section>

+ 145 - 2
modules/sl/sl.c

@@ -62,6 +62,8 @@
 #include "../../dprint.h"
 #include "../../dprint.h"
 #include "../../error.h"
 #include "../../error.h"
 #include "../../ut.h"
 #include "../../ut.h"
+#include "../../data_lump.h"
+#include "../../mod_fix.h"
 #include "../../script_cb.h"
 #include "../../script_cb.h"
 #include "../../mem/mem.h"
 #include "../../mem/mem.h"
 
 
@@ -81,9 +83,12 @@ int _sl_filtered_ack_route = -1; /* default disabled */
 static int sl_bind_tm = 1;
 static int sl_bind_tm = 1;
 static struct tm_binds tmb;
 static struct tm_binds tmb;
 
 
-static int w_sl_send_reply(struct sip_msg* msg, char* str, char* str2);
+static int w_sl_send_reply(struct sip_msg* msg, char* str1, char* str2);
 static int w_send_reply(struct sip_msg* msg, char* str1, char* str2);
 static int w_send_reply(struct sip_msg* msg, char* str1, char* str2);
-static int w_sl_reply_error(struct sip_msg* msg, char* str, char* str2);
+static int w_sl_reply_error(struct sip_msg* msg, char* str1, char* str2);
+static int w_sl_forward_reply0(sip_msg_t* msg, char* str1, char* str2);
+static int w_sl_forward_reply1(sip_msg_t* msg, char* str1, char* str2);
+static int w_sl_forward_reply2(sip_msg_t* msg, char* str1, char* str2);
 static int bind_sl(sl_api_t* api);
 static int bind_sl(sl_api_t* api);
 static int mod_init(void);
 static int mod_init(void);
 static int child_init(int rank);
 static int child_init(int rank);
@@ -99,6 +104,12 @@ static cmd_export_t cmds[]={
 		REQUEST_ROUTE|BRANCH_ROUTE|FAILURE_ROUTE},
 		REQUEST_ROUTE|BRANCH_ROUTE|FAILURE_ROUTE},
 	{"sl_reply_error", w_sl_reply_error,            0, 0,
 	{"sl_reply_error", w_sl_reply_error,            0, 0,
 		REQUEST_ROUTE},
 		REQUEST_ROUTE},
+	{"sl_forward_reply",  w_sl_forward_reply0,      0, 0,
+		ONREPLY_ROUTE},
+	{"sl_forward_reply",  w_sl_forward_reply1,      1, fixup_spve_all,
+		ONREPLY_ROUTE},
+	{"sl_forward_reply",  w_sl_forward_reply2,      2, fixup_spve_all,
+		ONREPLY_ROUTE},
 	{"bind_sl",        (cmd_function)bind_sl,       0, 0,              0},
 	{"bind_sl",        (cmd_function)bind_sl,       0, 0,              0},
 	{0,0,0,0,0}
 	{0,0,0,0,0}
 };
 };
@@ -347,6 +358,138 @@ static int fixup_sl_reply(void** param, int param_no)
 	return 0;
 	return 0;
 }
 }
 
 
+/**
+ * @brief forward SIP reply statelessy with different code and reason text
+ */
+static int w_sl_forward_reply(sip_msg_t* msg, str* code, str* reason)
+{
+	char oldscode[3];
+	int oldncode;
+	int ret;
+	struct lump	*ldel = NULL;
+	struct lump	*ladd = NULL;
+	char *rbuf;
+
+	if(msg->first_line.type!=SIP_REPLY) {
+		LM_ERR("invalid SIP message type\n");
+		return -1;
+	}
+	if(code!=NULL) {
+		if(code->len!=3) {
+			LM_ERR("invalid reply code value %.*s\n", code->len, code->s);
+			return -1;
+		}
+		if(msg->first_line.u.reply.status.s[0]!=code->s[0]) {
+			LM_ERR("reply code class cannot be changed\n");
+			return -1;
+		}
+		if(code->s[1]<'0' || code->s[1]>'9'
+				|| code->s[2]<'0' || code->s[2]>'9') {
+			LM_ERR("invalid reply code value %.*s!\n", code->len, code->s);
+			return -1;
+		}
+	}
+	if(reason!=NULL && reason->len<=0) {
+		LM_ERR("invalid reply reason value\n");
+		return -1;
+	}
+	/* backup old values */
+	oldscode[0] = msg->first_line.u.reply.status.s[0];
+	oldscode[1] = msg->first_line.u.reply.status.s[1];
+	oldscode[2] = msg->first_line.u.reply.status.s[2];
+	oldncode = msg->first_line.u.reply.statuscode;
+	if(code!=NULL) {
+		/* update status code directly in msg buffer */
+		msg->first_line.u.reply.statuscode = (code->s[0]-'0')*100
+			+ (code->s[1]-'0')*10 + code->s[2]-'0';
+		msg->first_line.u.reply.status.s[0] = code->s[0];
+		msg->first_line.u.reply.status.s[1] = code->s[1];
+		msg->first_line.u.reply.status.s[2] = code->s[2];
+
+	}
+	if(reason!=NULL) {
+		ldel = del_lump(msg,
+					msg->first_line.u.reply.reason.s - msg->buf,
+					msg->first_line.u.reply.reason.len,
+					0);
+		if (ldel==NULL) {
+			LM_ERR("failed to add del lump\n");
+			ret = -1;
+			goto restore;
+		}
+		rbuf = (char *)pkg_malloc(reason->len);
+		if (rbuf==NULL) {
+			LM_ERR("not enough memory\n");
+			ret = -1;
+			goto restore;
+		}
+		memcpy(rbuf, reason->s, reason->len);
+		ladd = insert_new_lump_after(ldel, rbuf, reason->len, 0);
+		if (ladd==0) {
+			LOG(L_ERR, "failed to add reason lump: %.*s\n",
+				reason->len, reason->s);
+			pkg_free(rbuf);
+			ret = -1;
+			goto restore;
+		}
+	}
+	ret = forward_reply(msg);
+restore:
+	if(reason!=NULL) {
+		if(ldel!=NULL) {
+			remove_lump(msg, ldel);
+		}
+		if(ladd!=NULL) {
+			remove_lump(msg, ladd);
+		}
+	}
+	if(code!=NULL) {
+		msg->first_line.u.reply.statuscode = oldncode;
+		msg->first_line.u.reply.status.s[0] = oldscode[0];
+		msg->first_line.u.reply.status.s[1] = oldscode[1];
+		msg->first_line.u.reply.status.s[2] = oldscode[2];
+	}
+	return ret;
+}
+
+/**
+ * @brief forward SIP reply statelessy
+ */
+static int w_sl_forward_reply0(sip_msg_t* msg, char* str1, char* str2)
+{
+	return w_sl_forward_reply(msg, NULL, NULL);
+}
+
+/**
+ * @brief forward SIP reply statelessy with a new code
+ */
+static int w_sl_forward_reply1(sip_msg_t* msg, char* str1, char* str2)
+{
+	str code;
+	if(fixup_get_svalue(msg, (gparam_t*)str1, &code)<0) {
+		LM_ERR("cannot get the reply code parameter value\n");
+		return -1;
+	}
+	return w_sl_forward_reply(msg, &code, NULL);
+}
+
+/**
+ * @brief forward SIP reply statelessy with new code and reason text
+ */
+static int w_sl_forward_reply2(sip_msg_t* msg, char* str1, char* str2)
+{
+	str code;
+	str reason;
+	if(fixup_get_svalue(msg, (gparam_t*)str1, &code)<0) {
+		LM_ERR("cannot get the reply code parameter value\n");
+		return -1;
+	}
+	if(fixup_get_svalue(msg, (gparam_t*)str2, &reason)<0) {
+		LM_ERR("cannot get the reply reason parameter value\n");
+		return -1;
+	}
+	return w_sl_forward_reply(msg, &code, &reason);
+}
 
 
 /**
 /**
  * @brief bind functions to SL API structure
  * @brief bind functions to SL API structure

+ 2 - 2
modules_k/dialog/dlg_hash.c

@@ -189,7 +189,7 @@ int dlg_ka_run(ticks_t ti)
 		}
 		}
 		if(*dlg_ka_list_head == *dlg_ka_list_tail) {
 		if(*dlg_ka_list_head == *dlg_ka_list_tail) {
 			*dlg_ka_list_head = NULL;
 			*dlg_ka_list_head = NULL;
-			*dlg_ka_list_head = NULL;
+			*dlg_ka_list_tail = NULL;
 		}
 		}
 		*dlg_ka_list_head = dka->next;
 		*dlg_ka_list_head = dka->next;
 		lock_release(dlg_ka_list_lock);
 		lock_release(dlg_ka_list_lock);
@@ -213,7 +213,7 @@ int dlg_ka_run(ticks_t ti)
 			if(*dlg_ka_list_tail!=NULL)
 			if(*dlg_ka_list_tail!=NULL)
 				(*dlg_ka_list_tail)->next = dka;
 				(*dlg_ka_list_tail)->next = dka;
 			if(*dlg_ka_list_head==NULL)
 			if(*dlg_ka_list_head==NULL)
-				*dlg_ka_list_tail = dka;
+				*dlg_ka_list_head = dka;
 			*dlg_ka_list_tail = dka;
 			*dlg_ka_list_tail = dka;
 			lock_release(dlg_ka_list_lock);
 			lock_release(dlg_ka_list_lock);
 		}
 		}

+ 1 - 1
parser/sdp/sdp.c

@@ -810,7 +810,7 @@ void free_sdp(sdp_info_t** _sdp)
 			while (l_stream->ice_attr) {
 			while (l_stream->ice_attr) {
 			    tmp = l_stream->ice_attr->next;
 			    tmp = l_stream->ice_attr->next;
 			    pkg_free(l_stream->ice_attr);
 			    pkg_free(l_stream->ice_attr);
-			    l_stream->ice_attr->next = tmp;
+			    l_stream->ice_attr = tmp;
 			}
 			}
 			pkg_free(l_stream);
 			pkg_free(l_stream);
 		}
 		}

+ 12 - 0
pkg/kamailio/deb/debian/control

@@ -429,3 +429,15 @@ Depends: binutils,
 Description: Kamailio - package for "nice to have" installation
 Description: Kamailio - package for "nice to have" installation
  This is a meta-package for easy installation various useful tools that may be
  This is a meta-package for easy installation various useful tools that may be
  handy on server with Kamailio installed.
  handy on server with Kamailio installed.
+
+Package: kamailio-ims-modules
+Architecture: any
+Depends: ${shlibs:Depends}, kamailio (= ${binary:Version})
+Description: Kamailio - IMS Modules
+ Kamailio is a very fast and flexible SIP (RFC3261)
+ proxy server. Written entirely in C, Kamailio can handle thousands calls
+ per second even on low-budget hardware.
+ .
+ This package contains various Diameter interfaces and modules for Kamailio
+ to run as an IMS core.
+

+ 1 - 1
pkg/kamailio/deb/debian/rules

@@ -42,7 +42,7 @@ MODULES_SP=
 PACKAGE_GROUPS=mysql postgres berkeley unixodbc radius presence \
 PACKAGE_GROUPS=mysql postgres berkeley unixodbc radius presence \
 			   ldap xml perl utils purple memcached tls \
 			   ldap xml perl utils purple memcached tls \
 			   snmpstats carrierroute xmpp cpl lua python geoip\
 			   snmpstats carrierroute xmpp cpl lua python geoip\
-			   redis sqlite json mono
+			   redis sqlite json mono ims
 
 
 # name of libdir in the path for libraries (e.g., lib for 32b, lib64 for 64b)
 # name of libdir in the path for libraries (e.g., lib for 32b, lib64 for 64b)
 LIBDIR ?= lib
 LIBDIR ?= lib

+ 12 - 0
pkg/kamailio/deb/lenny/control

@@ -373,3 +373,15 @@ Depends: binutils,
 Description: Kamailio - package for "nice to have" installation
 Description: Kamailio - package for "nice to have" installation
  This is a meta-package for easy installation various useful tools that may be
  This is a meta-package for easy installation various useful tools that may be
  handy on server with Kamailio installed.
  handy on server with Kamailio installed.
+
+Package: kamailio-ims-modules
+Architecture: any
+Depends: ${shlibs:Depends}, kamailio (= ${binary:Version})
+Description: Kamailio - IMS Modules
+ Kamailio is a very fast and flexible SIP (RFC3261)
+ proxy server. Written entirely in C, Kamailio can handle thousands calls
+ per second even on low-budget hardware.
+ .
+ This package contains various Diameter interfaces and modules for Kamailio
+ to run as an IMS core.
+

+ 1 - 1
pkg/kamailio/deb/lenny/rules

@@ -42,7 +42,7 @@ MODULES_SP=
 PACKAGE_GROUPS=mysql postgres berkeley unixodbc radius presence \
 PACKAGE_GROUPS=mysql postgres berkeley unixodbc radius presence \
 			   ldap xml perl utils purple memcached tls \
 			   ldap xml perl utils purple memcached tls \
 			   snmpstats carrierroute xmpp cpl lua python \
 			   snmpstats carrierroute xmpp cpl lua python \
-			   sqlite
+			   sqlite ims
 
 
 # name of libdir in the path for libraries (e.g., lib for 32b, lib64 for 64b)
 # name of libdir in the path for libraries (e.g., lib for 32b, lib64 for 64b)
 LIBDIR ?= lib
 LIBDIR ?= lib

+ 12 - 0
pkg/kamailio/deb/lucid/control

@@ -386,3 +386,15 @@ Depends: binutils,
 Description: Kamailio - package for "nice to have" installation
 Description: Kamailio - package for "nice to have" installation
  This is a meta-package for easy installation various useful tools that may be
  This is a meta-package for easy installation various useful tools that may be
  handy on server with Kamailio installed.
  handy on server with Kamailio installed.
+
+Package: kamailio-ims-modules
+Architecture: any
+Depends: ${shlibs:Depends}, kamailio (= ${binary:Version})
+Description: Kamailio - IMS Modules
+ Kamailio is a very fast and flexible SIP (RFC3261)
+ proxy server. Written entirely in C, Kamailio can handle thousands calls
+ per second even on low-budget hardware.
+ .
+ This package contains various Diameter interfaces and modules for Kamailio
+ to run as an IMS core.
+

+ 1 - 1
pkg/kamailio/deb/lucid/rules

@@ -42,7 +42,7 @@ MODULES_SP=
 PACKAGE_GROUPS=mysql postgres berkeley unixodbc radius presence \
 PACKAGE_GROUPS=mysql postgres berkeley unixodbc radius presence \
 			   ldap xml perl utils purple memcached tls \
 			   ldap xml perl utils purple memcached tls \
 			   snmpstats carrierroute xmpp cpl lua python geoip \
 			   snmpstats carrierroute xmpp cpl lua python geoip \
-			   sqlite
+			   sqlite ims
 
 
 # name of libdir in the path for libraries (e.g., lib for 32b, lib64 for 64b)
 # name of libdir in the path for libraries (e.g., lib for 32b, lib64 for 64b)
 LIBDIR ?= lib
 LIBDIR ?= lib

+ 12 - 0
pkg/kamailio/deb/precise/control

@@ -423,3 +423,15 @@ Depends: binutils,
 Description: Kamailio - package for "nice to have" installation
 Description: Kamailio - package for "nice to have" installation
  This is a meta-package for easy installation various useful tools that may be
  This is a meta-package for easy installation various useful tools that may be
  handy on server with Kamailio installed.
  handy on server with Kamailio installed.
+
+Package: kamailio-ims-modules
+Architecture: any
+Depends: ${shlibs:Depends}, kamailio (= ${binary:Version})
+Description: Kamailio - IMS Modules
+ Kamailio is a very fast and flexible SIP (RFC3261)
+ proxy server. Written entirely in C, Kamailio can handle thousands calls
+ per second even on low-budget hardware.
+ .
+ This package contains various Diameter interfaces and modules for Kamailio
+ to run as an IMS core.
+

+ 1 - 1
pkg/kamailio/deb/precise/rules

@@ -42,7 +42,7 @@ MODULES_SP=
 PACKAGE_GROUPS=mysql postgres berkeley unixodbc radius presence \
 PACKAGE_GROUPS=mysql postgres berkeley unixodbc radius presence \
 			   ldap xml perl utils purple memcached tls \
 			   ldap xml perl utils purple memcached tls \
 			   snmpstats carrierroute xmpp cpl lua python geoip\
 			   snmpstats carrierroute xmpp cpl lua python geoip\
-			   redis sqlite json mono
+			   redis sqlite json mono ims
 
 
 # name of libdir in the path for libraries (e.g., lib for 32b, lib64 for 64b)
 # name of libdir in the path for libraries (e.g., lib for 32b, lib64 for 64b)
 LIBDIR ?= lib
 LIBDIR ?= lib

+ 12 - 0
pkg/kamailio/deb/squeeze/control

@@ -388,3 +388,15 @@ Depends: binutils,
 Description: Kamailio - package for "nice to have" installation
 Description: Kamailio - package for "nice to have" installation
  This is a meta-package for easy installation various useful tools that may be
  This is a meta-package for easy installation various useful tools that may be
  handy on server with Kamailio installed.
  handy on server with Kamailio installed.
+
+Package: kamailio-ims-modules
+Architecture: any
+Depends: ${shlibs:Depends}, kamailio (= ${binary:Version})
+Description: Kamailio - IMS Modules
+ Kamailio is a very fast and flexible SIP (RFC3261)
+ proxy server. Written entirely in C, Kamailio can handle thousands calls
+ per second even on low-budget hardware.
+ .
+ This package contains various Diameter interfaces and modules for Kamailio
+ to run as an IMS core.
+

+ 1 - 1
pkg/kamailio/deb/squeeze/rules

@@ -42,7 +42,7 @@ MODULES_SP=
 PACKAGE_GROUPS=mysql postgres berkeley unixodbc radius presence \
 PACKAGE_GROUPS=mysql postgres berkeley unixodbc radius presence \
 			   ldap xml perl utils geoip memcached tls \
 			   ldap xml perl utils geoip memcached tls \
 			   snmpstats carrierroute xmpp cpl lua python \
 			   snmpstats carrierroute xmpp cpl lua python \
-			   sqlite json
+			   sqlite json ims
 
 
 # name of libdir in the path for libraries (e.g., lib for 32b, lib64 for 64b)
 # name of libdir in the path for libraries (e.g., lib for 32b, lib64 for 64b)
 LIBDIR ?= lib
 LIBDIR ?= lib

+ 12 - 0
pkg/kamailio/deb/wheezy/control

@@ -415,3 +415,15 @@ Depends: binutils,
 Description: Kamailio - package for "nice to have" installation
 Description: Kamailio - package for "nice to have" installation
  This is a meta-package for easy installation various useful tools that may be
  This is a meta-package for easy installation various useful tools that may be
  handy on server with Kamailio installed.
  handy on server with Kamailio installed.
+
+Package: kamailio-ims-modules
+Architecture: any
+Depends: ${shlibs:Depends}, kamailio (= ${binary:Version})
+Description: Kamailio - IMS Modules
+ Kamailio is a very fast and flexible SIP (RFC3261)
+ proxy server. Written entirely in C, Kamailio can handle thousands calls
+ per second even on low-budget hardware.
+ .
+ This package contains various Diameter interfaces and modules for Kamailio
+ to run as an IMS core.
+

+ 1 - 1
pkg/kamailio/deb/wheezy/rules

@@ -42,7 +42,7 @@ MODULES_SP=
 PACKAGE_GROUPS=mysql postgres berkeley unixodbc radius presence \
 PACKAGE_GROUPS=mysql postgres berkeley unixodbc radius presence \
 			   ldap xml perl utils lua memcached tls \
 			   ldap xml perl utils lua memcached tls \
 			   snmpstats carrierroute xmpp cpl redis python geoip\
 			   snmpstats carrierroute xmpp cpl redis python geoip\
-			   sqlite json mono
+			   sqlite json mono ims
 
 
 # name of libdir in the path for libraries (e.g., lib for 32b, lib64 for 64b)
 # name of libdir in the path for libraries (e.g., lib for 32b, lib64 for 64b)
 LIBDIR ?= lib
 LIBDIR ?= lib

+ 5 - 3
pkg/kamailio/fedora/16/kamailio.spec

@@ -1,6 +1,6 @@
 %define name    kamailio
 %define name    kamailio
-%define ver     3.4.0
-%define rel     dev7%{dist}
+%define ver     4.0.0
+%define rel     dev8%{dist}
 
 
 
 
 
 
@@ -507,7 +507,7 @@ fi
 %doc %{_docdir}/kamailio/modules/README.db_flatstore
 %doc %{_docdir}/kamailio/modules/README.db_flatstore
 %doc %{_docdir}/kamailio/modules/README.db2_ops
 %doc %{_docdir}/kamailio/modules/README.db2_ops
 %doc %{_docdir}/kamailio/modules/README.debugger
 %doc %{_docdir}/kamailio/modules/README.debugger
-#%doc %{_docdir}/kamailio/modules/README.dialog2
+%doc %{_docdir}/kamailio/modules/README.dialog2
 %doc %{_docdir}/kamailio/modules/README.enum
 %doc %{_docdir}/kamailio/modules/README.enum
 %doc %{_docdir}/kamailio/modules/README.ipops
 %doc %{_docdir}/kamailio/modules/README.ipops
 %doc %{_docdir}/kamailio/modules/README.malloc_test
 %doc %{_docdir}/kamailio/modules/README.malloc_test
@@ -1074,6 +1074,8 @@ fi
 
 
 
 
 %changelog
 %changelog
+* Sun Jan 6 2013 Peter Dunkley <[email protected]>
+  - Updated ver to 4.0.0 and rel to dev8
 * Mon Dec 31 2012 Peter Dunkley <[email protected]>
 * Mon Dec 31 2012 Peter Dunkley <[email protected]>
   - Added dialog2 and IMS modules to the build
   - Added dialog2 and IMS modules to the build
 * Fri Dec 21 2012 Peter Dunkley <[email protected]>
 * Fri Dec 21 2012 Peter Dunkley <[email protected]>

+ 1 - 1
sip-router.8

@@ -66,7 +66,7 @@ Same as
 .B \-r
 .B \-r
 but uses reverse dns.
 but uses reverse dns.
 .TP
 .TP
-.BI \-v
+.BI \-K
 Turns on via host checking when forwarding replies.
 Turns on via host checking when forwarding replies.
 .TP
 .TP
 .BI \-d
 .BI \-d