Browse Source

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 years ago
parent
commit
0b108c83ba
50 changed files with 3292 additions and 214 deletions
  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
 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)
 # exclude the below modules.
 ifneq ($(group_include)$(cfg_group_include),)
@@ -871,6 +876,17 @@ deb:
 		rm debian; \
 	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
 sunpkg:
 	mkdir -p tmp/$(MAIN_NAME)

+ 3 - 3
Makefile.defs

@@ -159,10 +159,10 @@ endif
 INSTALL_FLAVOUR=$(FLAVOUR)
 
 #version number
-VERSION = 3
-PATCHLEVEL = 4
+VERSION = 4
+PATCHLEVEL = 0
 SUBLEVEL =  0
-EXTRAVERSION = -dev7
+EXTRAVERSION = -dev8
 
 # memory manager switcher
 # 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;
 }
 
+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 */
 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

+ 0 - 57
etc/kamailio.cfg

@@ -67,18 +67,6 @@
 #     - define WITH_XMLRPC
 #     - 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:
 #     - adjust pike and htable=>ipban settings as needed (default is
 #       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
 tcp_connection_lifetime=3605
 
-#!ifdef WITH_XHTTP
-tcp_accept_no_cl=yes
-#!endif
-
 ####### Custom Parameters #########
 
 # These parameters can be modified runtime via RPC interface
@@ -298,18 +282,6 @@ loadmodule "xmlrpc.so"
 loadmodule "debugger.so"
 #!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 ---------------
 
 
@@ -473,15 +445,6 @@ modparam("xmlrpc", "url_match", "^/RPC")
 modparam("debugger", "cfgtrace", 1)
 #!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 ########
 
 
@@ -958,23 +921,3 @@ failure_route[MANAGE_FAILURE] {
 	}
 #!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
 INCLUDES= -I$(CURDIR)/.. -I$(CURDIR)/../.. $(libxml2_includes) 
 LIBS=$(libxml2_libs)
-SERLIBPATH=..
-SER_LIBS=$(SERLIBPATH)/cds/ser_cds
+#SERLIBPATH=..
+#SER_LIBS=$(SERLIBPATH)/cds/ser_cds
 
 include ../../Makefile.libs
 

+ 6 - 4
main.c

@@ -225,7 +225,7 @@ Options:\n\
                   field to a via\n\
     -R           Same as `-r` but use reverse dns;\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 no        1..do not fork (almost) anyway, 2..do not daemonize creator\n\
                   3..daemonize (default)\n\
@@ -1860,7 +1860,7 @@ int main(int argc, char** argv)
 	dprint_init_colors();
 
 	/* 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
 		"s:"
 #endif
@@ -1957,6 +1957,7 @@ int main(int argc, char** argv)
 			case 'd':
 					/* ignore it, was parsed immediately after startup */
 					break;
+			case 'v':
 			case 'V':
 					printf("version: %s\n", full_version);
 					printf("flags: %s\n", ver_flags );
@@ -2019,7 +2020,7 @@ int main(int argc, char** argv)
 			case 'b':
 			case 'l':
 			case 'n':
-			case 'v':
+			case 'K':
 			case 'r':
 			case 'R':
 			case 'D':
@@ -2129,6 +2130,7 @@ try_again:
 			case 'm':
 			case 'M':
 			case 'd':
+			case 'v':
 			case 'V':
 			case 'I':
 			case 'h':
@@ -2175,7 +2177,7 @@ try_again:
 						goto error;
 					}
 					break;
-			case 'v':
+			case 'K':
 					check_via=1;
 					break;
 			case 'r':

+ 5 - 1
modules/auth_ims/Makefile

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

+ 8 - 1
modules/icscf/scscf_list.h

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

+ 5 - 1
modules/isc/Makefile

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

+ 3 - 0
modules/msrp/Makefile

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

+ 173 - 30
modules/msrp/README

@@ -16,7 +16,7 @@ Alex Balashov
 
    <[email protected]>
 
-   Copyright © 2012 asipto.com
+   Copyright © 2012 asipto.com
      __________________________________________________________________
 
    Table of Contents
@@ -32,6 +32,11 @@ Alex Balashov
         3. Parameters
 
               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
 
@@ -42,22 +47,35 @@ Alex Balashov
               4.5. msrp_set_dst(addr, sock)
               4.6. msrp_relay_flags(flags)
               4.7. msrp_reply_flags(flags)
+              4.8. msrp_cmap_save()
+              4.9. msrp_cmap_lookup()
 
         5. Pseudo Variables
-        6. Event Routes
-        7. Usage
+        6. RPC Commands
+
+              6.1. msrp.cmaplist
+
+        7. Event Routes
+        8. Usage
 
    List of Examples
 
    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
 
@@ -72,6 +90,11 @@ Chapter 1. Admin Guide
    3. Parameters
 
         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
 
@@ -82,10 +105,16 @@ Chapter 1. Admin Guide
         4.5. msrp_set_dst(addr, sock)
         4.6. msrp_relay_flags(flags)
         4.7. msrp_reply_flags(flags)
+        4.8. msrp_cmap_save()
+        4.9. msrp_cmap_lookup()
 
    5. Pseudo Variables
-   6. Event Routes
-   7. Usage
+   6. RPC Commands
+
+        6.1. msrp.cmaplist
+
+   7. Event Routes
+   8. Usage
 
 1. Overview
 
@@ -137,6 +166,11 @@ Chapter 1. Admin Guide
 3. Parameters
 
    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)
 
@@ -152,6 +186,63 @@ Chapter 1. Admin Guide
 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.1. msrp_relay()
@@ -161,8 +252,10 @@ modparam("msrp", "sipmsg", 1)
    4.5. msrp_set_dst(addr, sock)
    4.6. msrp_relay_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
    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.
 
-   Example 1.2. msrp usage
+   Example 1.7. msrp_relay usage
 ...
 event_route[msrp:frame-in] {
     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.
 
@@ -186,20 +279,20 @@ event_route[msrp:frame-in] {
 
    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] {
     msrp_reply("403", "Not allowed");
 }
 ...
 
-4.3.  msrp_is_request()
+4.3. msrp_is_request()
 
    Return true if the MSRP frame is a request.
 
    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] {
     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.
 
    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] {
     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 -
    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.
 
-   Example 1.6. msrp_set_dst usage
+   Example 1.11. msrp_set_dst usage
 ...
 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;
    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.
 
-   Example 1.7. msrp_relay_flags usage
+   Example 1.12. msrp_relay_flags usage
 ...
 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
    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.
 
-   Example 1.8. msrp_reply_flags usage
+   Example 1.13. msrp_reply_flags usage
 ...
 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
 
    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
    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
    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
    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
    MSRP frames. In this config, the SIP traffic is rejected.
 
-   Example 1.9. Event Route
+   Example 1.16. Event Route
 ...
 
 #!KAMAILIO

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

@@ -102,6 +102,103 @@
 ...
 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>
 		</example>
 	</section>
@@ -124,7 +221,7 @@ modparam("msrp", "sipmsg", 1)
 		This function can be used in ANY_ROUTE.
 		</para>
 		<example>
-		<title><function>msrp</function> usage</title>
+		<title><function>msrp_relay</function> usage</title>
 		<programlisting format="linespecific">
 ...
 event_route[msrp:frame-in] {
@@ -299,6 +396,61 @@ event_route[msrp:frame-in] {
 	    </example>
 	</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>
@@ -318,6 +470,26 @@ event_route[msrp:frame-in] {
 		</para>
 	</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>
 		<title>Event Routes</title>
 		<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_
 #define _MSRP_ENV_H_
 
+#include "../../parser/msg_parser.h"
 #include "msrp_parser.h"
 
 #define MSRP_ENV_SRCINFO	(1<<0)

+ 102 - 10
modules/msrp/msrp_mod.c

@@ -36,11 +36,13 @@
 #include "../../events.h"
 #include "../../tcp_conn.h"
 #include "../../pvar.h"
+#include "../../timer_proc.h" /* register_sync_timer */
 
 #include "msrp_parser.h"
 #include "msrp_netio.h"
 #include "msrp_vars.h"
 #include "msrp_env.h"
+#include "msrp_cmap.h"
 
 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_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_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_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);
 sip_msg_t *msrp_fake_sipmsg(msrp_frame_t *mf);
@@ -83,21 +94,30 @@ static cmd_export_t cmds[]={
 		0, ANY_ROUTE},
 	{"msrp_reply", (cmd_function)w_msrp_reply3, 3, fixup_spve_all,
 		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},
-	{"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},
-	{"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},
 	{"msrp_relay_flags", (cmd_function)w_msrp_relay_flags, 1, fixup_igp_null,
 		0, ANY_ROUTE},
 	{"msrp_reply_flags", (cmd_function)w_msrp_reply_flags, 1, fixup_igp_null,
 		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}
 };
 
 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}
 };
 
@@ -123,6 +143,28 @@ struct module_exports exports = {
  */
 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);
 	return 0;
 }
@@ -132,8 +174,20 @@ static int mod_init(void)
  */
 static int child_init(int rank)
 {
+	if(msrp_sruid_init()<0) {
+		LM_ERR("cannot init msrp uid\n");
+		return -1;
+	}
+
 	if (rank!=PROC_MAIN)
 		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;
 }
@@ -333,6 +387,42 @@ static int w_msrp_reply_flags(sip_msg_t* msg, char *tflags, char* str2)
 	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;
 	static msrp_frame_t mf;
-	msrp_uri_t uri;
 	sip_msg_t *fmsg;
 	struct run_act_ctx ctx;
 	int rtb, rt;
@@ -385,10 +474,13 @@ static int msrp_frame_received(void *data)
 	}
 	msrp_reset_env();
 	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;
 }
+
+/**
+ *
+ */
+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("WWW-Authenticate"),     MSRP_HDR_WWWAUTH },
 	{ str_init("Authentication-Info"),  MSRP_HDR_AUTHINFO },
+	{ str_init("Expires"),              MSRP_HDR_EXPIRES },
 	{ {0, 0}, 0}
 };
 
@@ -698,3 +699,94 @@ int msrp_parse_hdr_to_path(msrp_frame_t *mf)
 	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_WWWAUTH		10
 #define MSRP_HDR_AUTHINFO		11
+#define MSRP_HDR_EXPIRES		12
 
 #define MSRP_DATA_SET	1
 
@@ -136,4 +137,7 @@ typedef struct str_array {
 	str *list;
 } 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

+ 121 - 12
modules/pipelimit/README

@@ -6,11 +6,17 @@ Hendrik Scholz
 
 Edited by
 
+Ovidiu Sas
+
+Edited by
+
 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
@@ -48,6 +54,15 @@ Daniel-Constantin Mierla
               5.5. pl_get_pid
               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
 
    1.1. Set db_url parameter
@@ -98,6 +113,15 @@ Chapter 1. Admin Guide
         5.5. pl_get_pid
         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
 
    This module implements traffic limiting for SIP requests.
@@ -145,7 +169,7 @@ Chapter 1. Admin Guide
 
    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
 ...
@@ -156,7 +180,7 @@ modparam("pipelimit", "db_url", "dbdriver://username:password@dbhost/dbname")
 
    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
 ...
@@ -167,7 +191,7 @@ modparam("pipelimit", "plp_table_name", "mypipes")
 
    Name of 'pipeid' column.
 
-   Default value is "pipeid".
+   Default value is “pipeid�.
 
    Example 1.3. Set plp_pipeid_column parameter
 ...
@@ -178,7 +202,7 @@ modparam("pipelimit", "plp_pipeid_column", "name")
 
    Name of 'limit' column.
 
-   Default value is "limit".
+   Default value is “limit�.
 
    Example 1.4. Set plp_limit_column parameter
 ...
@@ -189,7 +213,7 @@ modparam("pipelimit", "plp_limit_column", "name")
 
    Name of 'algorithm' column.
 
-   Default value is "algorithm".
+   Default value is “algorithm�.
 
    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
 ...
-modparam("ratelimit", "timer_interval", 5)
+modparam("pipelimit", "timer_interval", 5)
 ...
 
 3.7. reply_code (integer)
@@ -220,13 +244,13 @@ modparam("ratelimit", "timer_interval", 5)
 
    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
 
    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)
 
@@ -236,13 +260,13 @@ kamcmd cfg.set_now_int ratelimit reply_code 505
 
    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
 
    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
 
@@ -400,3 +424,88 @@ kamcmd cfg.set_now_string ratelimit reply_reason "Limiting"
                 :pl_push_load:_reply_fifo_file_
                 0.85
                 _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>
 		</author>
 		<editor>
+		<firstname>Ovidiu</firstname>
+		<surname>Sas</surname>
+		<address><email>[email protected]</email></address>
+		</editor>
+		<editor>
 		<firstname>Daniel-Constantin</firstname>
 		<surname>Mierla</surname>
 		<address>
@@ -35,6 +40,10 @@
 		</address>
 		</editor>
 	</authorgroup>
+	<copyright>
+		<year>2013</year>
+		<holder><ulink url='http://www.voipembedded.com'>VoIPEmbedded Inc.</ulink></holder>
+	</copyright>
 	<copyright>
 		<year>2010</year>
 		<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>
 		<programlisting format="linespecific">
 ...
-modparam("ratelimit", "timer_interval", 5)
+modparam("pipelimit", "timer_interval", 5)
 ...
 </programlisting>
 		</example>
@@ -205,7 +205,7 @@ modparam("ratelimit", "timer_interval", 5)
 		<title>Set <varname>reply_code</varname> parameter</title>
 		<programlisting format="linespecific">
 ...
-modparam("ratelimit", "reply_code", 505)
+modparam("pipelimit", "reply_code", 505)
 ...
 </programlisting>
 		</example>
@@ -216,7 +216,7 @@ modparam("ratelimit", "reply_code", 505)
 		<title> Set <varname>reply_code</varname> parameter at runtime </title>
 		<programlisting format="linespecific">
 
-&sercmd; cfg.set_now_int ratelimit reply_code 505
+&sercmd; cfg.set_now_int pipelimit reply_code 505
 
 		</programlisting>
 		</example>
@@ -235,7 +235,7 @@ modparam("ratelimit", "reply_code", 505)
 		<title>Set <varname>reply_reason</varname> parameter</title>
 		<programlisting format="linespecific">
 ...
-modparam("ratelimit", "reply_reason", "Limiting")
+modparam("pipelimit", "reply_reason", "Limiting")
 ...
 </programlisting>
 		</example>
@@ -246,7 +246,7 @@ modparam("ratelimit", "reply_reason", "Limiting")
 		<title> Set <varname>reply_reason</varname> parameter at runtime </title>
 		<programlisting format="linespecific">
 
-&sercmd; cfg.set_now_string ratelimit reply_reason "Limiting"
+&sercmd; cfg.set_now_string pipelimit reply_reason "Limiting"
 
 		</programlisting>
 		</example>
@@ -495,4 +495,148 @@ modparam("ratelimit", "reply_reason", "Limiting")
 	</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>

+ 88 - 0
modules/pipelimit/pipelimit.c

@@ -50,6 +50,7 @@
 #include "../../lib/kcore/statistics.h"
 #include "../../modules/sl/sl.h"
 #include "../../lib/kmi/mi.h"
+#include "../../rpc_lookup.h"
 
 #include "pl_ht.h"
 #include "pl_db.h"
@@ -156,6 +157,8 @@ static mi_export_t mi_cmds [] = {
 	{0,0,0,0,0}
 };
 
+static rpc_export_t rpc_methods[];
+
 /** module exports */
 struct module_exports exports= {
 	"pipelimit",
@@ -279,6 +282,11 @@ static void update_cpu_load(void)
 /* initialize ratelimit module */
 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)
 	{
 		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);
 }
 
+/* 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 "../../mem/shm_mem.h"
 #include "../../lib/kmi/mi.h"
+#include "../../rpc_lookup.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
 
-LIBS += -L$(LOCALBASE)/lib -lrt
+LIBS += -L$(LOCALBASE)/lib
+
+ifneq ($(OS),darwin)
+	LIBS += -lrt
+endif
 
 SERLIBPATH=../../lib
 SER_LIBS+=$(SERLIBPATH)/kcore/kcore

+ 5 - 1
modules/registrar_scscf/Makefile

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

+ 85 - 64
modules/rtpproxy/README

@@ -30,13 +30,13 @@ Carsten Bock
 
    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
@@ -58,6 +58,7 @@ Carsten Bock
               4.4. rtpproxy_retr (integer)
               4.5. nortpproxy_str (string)
               4.6. timeout_socket (string)
+              4.7. ice_candidate_priority_avp (string)
 
         5. Functions
 
@@ -92,16 +93,17 @@ Carsten Bock
    1.4. Set rtpproxy_retr parameter
    1.5. Set nortpproxy_str 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
 
@@ -122,6 +124,7 @@ Chapter 1. Admin Guide
         4.4. rtpproxy_retr (integer)
         4.5. nortpproxy_str (string)
         4.6. timeout_socket (string)
+        4.7. ice_candidate_priority_avp (string)
 
    5. Functions
 
@@ -163,7 +166,7 @@ Chapter 1. Admin Guide
    The module allows definition of several sets of rtpproxies.
    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
-   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.
 
    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.5. nortpproxy_str (string)
    4.6. timeout_socket (string)
+   4.7. ice_candidate_priority_avp (string)
 
 4.1. rtpproxy_sock (string)
 
    Definition of socket(s) used to connect to (a set) RTPProxy. It may
    specify a UNIX socket or an IPv4/IPv6 UDP socket.
 
-   Default value is "NONE" (disabled).
+   Default value is “NONE� (disabled).
 
    Example 1.1. Set rtpproxy_sock parameter
 ...
@@ -233,7 +237,7 @@ modparam("rtpproxy", "rtpproxy_sock",
    rtpproxy module will not attempt to establish communication to RTPProxy
    for rtpproxy_disable_tout seconds.
 
-   Default value is "60".
+   Default value is “60�.
 
    Example 1.2. Set rtpproxy_disable_tout parameter
 ...
@@ -244,7 +248,7 @@ modparam("rtpproxy", "rtpproxy_disable_tout", 20)
 
    Timeout value in waiting for reply from RTPProxy.
 
-   Default value is "1".
+   Default value is “1�.
 
    Example 1.3. Set rtpproxy_tout parameter
 ...
@@ -256,7 +260,7 @@ modparam("rtpproxy", "rtpproxy_tout", 2)
    How many times the module should retry to send and receive after
    timeout was generated.
 
-   Default value is "5".
+   Default value is “5�.
 
    Example 1.4. Set rtpproxy_retr parameter
 ...
@@ -275,7 +279,7 @@ Note
 
    The string must be a complete SDP line, including the EOH (\r\n).
 
-   Default value is "a=nortpproxy:yes\r\n".
+   Default value is “a=nortpproxy:yes\r\n�.
 
    Example 1.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
    RTP-Proxy.
 
-   Default value is "" (nothing).
+   Default value is “� (nothing).
 
    Example 1.6. Set timeout_socket parameter
 ...
 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.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,
    BRANCH_ROUTE.
 
-   Example 1.7. set_rtp_proxy_set usage
+   Example 1.8. set_rtp_proxy_set usage
 ...
 set_rtp_proxy_set("2");
 rtpproxy_offer();
@@ -338,16 +359,16 @@ rtpproxy_offer();
      * flags - flags to turn on some features.
           + 1 - append first Via branch to Call-ID when sending command to
             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
             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
             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
-            "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!
           + 2 - append second Via branch to Call-ID when sending command
             to rtpproxy. See flag '1' for its meaning.
@@ -355,7 +376,7 @@ rtpproxy_offer();
             set for a reply.
           + a - flags that UA from which message is received doesn't
             support symmetric RTP. (automatically sets the 'r' flag)
-          + l - force "lookup", that is, only rewrite SDP when
+          + l - force “lookup�, that is, only rewrite SDP when
             corresponding session already exists in the RTP proxy. By
             default is on when the session is to be completed.
           + i, e - these flags specify the direction of the SIP message.
@@ -416,7 +437,7 @@ rtpproxy_offer();
 
    This function can be used from ANY_ROUTE.
 
-   Example 1.8. rtpproxy_offer usage
+   Example 1.9. rtpproxy_offer usage
 route {
 ...
     if (is_method("INVITE")) {
@@ -460,7 +481,7 @@ onreply_route[2]
    This function can be used from REQUEST_ROUTE, ONREPLY_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.
 
@@ -474,25 +495,25 @@ onreply_route[2]
      * flags - flags to turn on some features.
           + 1 - append first Via branch to Call-ID when sending command to
             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
             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
             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
-            "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!
           + 2 - append second Via branch to Call-ID when sending command
             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
             rtpproxy call when 200 OK is received on a branch, where
             rtpproxy is not needed.
 
-   Example 1.10. rtpproxy_destroy usage
+   Example 1.11. rtpproxy_destroy usage
 ...
 rtpproxy_destroy();
 ...
@@ -524,7 +545,7 @@ rtpproxy_destroy();
 
    This function can be used from ANY_ROUTE.
 
-   Example 1.11. rtpproxy_manage usage
+   Example 1.12. rtpproxy_manage usage
 ...
 rtpproxy_manage();
 ...
@@ -560,7 +581,7 @@ rtpproxy_manage();
        -1 means that it will be streaming in a loop indefinitely, until
        the appropriate rtpproxy_stop_stream2xxx is issued.
 
-   Example 1.12. rtpproxy_stream2xxx usage
+   Example 1.13. rtpproxy_stream2xxx usage
 ...
     if (is_method("INVITE")) {
         rtpproxy_offer();
@@ -593,7 +614,7 @@ rtpproxy_manage();
 
    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();
 ...
@@ -613,7 +634,7 @@ start_recording();
    packet-counters. The statistics must be retrieved before the session is
    deleted (before unforce_rtpproxy()).
 
-   Example 1.14. $rtpstat-Usage
+   Example 1.15. $rtpstat-Usage
 ...
     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
    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
 ...
@@ -648,52 +669,52 @@ $ kamctl fifo nh_enable_rtpp udp:192.168.2.133:8081 0
 
    No parameter.
 
-   Example 1.16.  nh_show_rtpp usage
+   Example 1.17.  nh_show_rtpp usage
 ...
 $ kamctl fifo nh_show_rtpp
 ...
 
 Chapter 2. Frequently Asked Questions
 
-   2.1. What happend with "rtpproxy_disable" parameter?
+   2.1. What happend with “rtpproxy_disable� parameter?
    2.2. Where can I find more about Kamailio?
    2.3. Where can I post a question about this module?
    2.4. How can I report a bug?
 
    2.1.
 
-   What happend with "rtpproxy_disable" parameter?
+       What happend with “rtpproxy_disable� parameter?
 
-   It was removed as it became obsolete - now "rtpproxy_sock" can take
-   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.
 
-   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.
 
-   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.
 
-   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")
 ...
+</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>
 		</example>
 	</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 * selected_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)*/
 static unsigned int rtpp_no = 0;
@@ -425,6 +428,8 @@ static param_export_t params[] = {
 	{"rtpproxy_retr",         INT_PARAM, &rtpproxy_retr         },
 	{"rtpproxy_tout",         INT_PARAM, &rtpproxy_tout         },
 	{"timeout_socket",    	  STR_PARAM, &timeout_socket_str.s  },
+	{"ice_candidate_priority_avp", STR_PARAM,
+	 &ice_candidate_priority_avp_param},
 	{0, 0, 0}
 };
 
@@ -868,6 +873,9 @@ static int
 mod_init(void)
 {
 	int i;
+	pv_spec_t avp_spec;
+	str s;
+	unsigned short avp_flags;
 
 	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);
 	}
 
+	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)
 		pkg_free(rtpp_strings);
 
@@ -1379,6 +1400,88 @@ alter_rtcp(struct sip_msg *msg, str *body, str *oldport, str *newport)
 	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 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 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 orgip, commip;
 	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_stream_cell_t* sdp_stream;
 
+	int_str ice_candidate_priority_val;
+
 	memset(&opts, '\0', sizeof(opts));
 	memset(&rep_opts, '\0', sizeof(rep_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(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 */
 	sdp_stream_num = get_sdp_stream_num(msg);
 	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;
 		for(;;) {
 			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) {
 				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.
 			 * ported from ser
 			 */
+
 			if (sdp_stream->rtcp_port.s && sdp_stream->rtcp_port.len) {
 				newrtcp.s = int2str(port+1, &newrtcp.len); /* beware static buffer */
 				/* 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;
 			c2p = sdp_stream->ip_addr.s;
 			/*

+ 24 - 3
modules/sl/README

@@ -19,6 +19,7 @@ Daniel-Constantin Mierla
    4. sl_send_reply usage
    5. send_reply usage
    6. sl_reply_error usage
+   7. send_reply usage
 
 1. Overview
 
@@ -92,8 +93,9 @@ modparam("sl", "bind_tm", 0)  # feature disabled
    3.1. sl_send_reply(code, reason)
    3.2. send_reply(code, reason)
    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
    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");
 ...
 
-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
    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");
 ...
 
-3.3.  sl_reply_error()
+3.3. sl_reply_error()
 
    Sends back an error reply describing the nature of the last internal
    error. Usually this function should be used after a script function
@@ -140,6 +142,25 @@ send_reply("403", "Invalid user - $fU");
 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.1. 1xx_replies

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

@@ -92,4 +92,40 @@ sl_reply_error();
 	    </programlisting>
 	</example>
     </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>

+ 145 - 2
modules/sl/sl.c

@@ -62,6 +62,8 @@
 #include "../../dprint.h"
 #include "../../error.h"
 #include "../../ut.h"
+#include "../../data_lump.h"
+#include "../../mod_fix.h"
 #include "../../script_cb.h"
 #include "../../mem/mem.h"
 
@@ -81,9 +83,12 @@ int _sl_filtered_ack_route = -1; /* default disabled */
 static int sl_bind_tm = 1;
 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_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 mod_init(void);
 static int child_init(int rank);
@@ -99,6 +104,12 @@ static cmd_export_t cmds[]={
 		REQUEST_ROUTE|BRANCH_ROUTE|FAILURE_ROUTE},
 	{"sl_reply_error", w_sl_reply_error,            0, 0,
 		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},
 	{0,0,0,0,0}
 };
@@ -347,6 +358,138 @@ static int fixup_sl_reply(void** param, int param_no)
 	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

+ 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) {
 			*dlg_ka_list_head = NULL;
-			*dlg_ka_list_head = NULL;
+			*dlg_ka_list_tail = NULL;
 		}
 		*dlg_ka_list_head = dka->next;
 		lock_release(dlg_ka_list_lock);
@@ -213,7 +213,7 @@ int dlg_ka_run(ticks_t ti)
 			if(*dlg_ka_list_tail!=NULL)
 				(*dlg_ka_list_tail)->next = dka;
 			if(*dlg_ka_list_head==NULL)
-				*dlg_ka_list_tail = dka;
+				*dlg_ka_list_head = dka;
 			*dlg_ka_list_tail = dka;
 			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) {
 			    tmp = l_stream->ice_attr->next;
 			    pkg_free(l_stream->ice_attr);
-			    l_stream->ice_attr->next = tmp;
+			    l_stream->ice_attr = tmp;
 			}
 			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
  This is a meta-package for easy installation various useful tools that may be
  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 \
 			   ldap xml perl utils purple memcached tls \
 			   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)
 LIBDIR ?= lib

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

@@ -373,3 +373,15 @@ Depends: binutils,
 Description: Kamailio - package for "nice to have" installation
  This is a meta-package for easy installation various useful tools that may be
  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 \
 			   ldap xml perl utils purple memcached tls \
 			   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)
 LIBDIR ?= lib

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

@@ -386,3 +386,15 @@ Depends: binutils,
 Description: Kamailio - package for "nice to have" installation
  This is a meta-package for easy installation various useful tools that may be
  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 \
 			   ldap xml perl utils purple memcached tls \
 			   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)
 LIBDIR ?= lib

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

@@ -423,3 +423,15 @@ Depends: binutils,
 Description: Kamailio - package for "nice to have" installation
  This is a meta-package for easy installation various useful tools that may be
  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 \
 			   ldap xml perl utils purple memcached tls \
 			   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)
 LIBDIR ?= lib

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

@@ -388,3 +388,15 @@ Depends: binutils,
 Description: Kamailio - package for "nice to have" installation
  This is a meta-package for easy installation various useful tools that may be
  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 \
 			   ldap xml perl utils geoip memcached tls \
 			   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)
 LIBDIR ?= lib

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

@@ -415,3 +415,15 @@ Depends: binutils,
 Description: Kamailio - package for "nice to have" installation
  This is a meta-package for easy installation various useful tools that may be
  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 \
 			   ldap xml perl utils lua memcached tls \
 			   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)
 LIBDIR ?= lib

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

@@ -1,6 +1,6 @@
 %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.db2_ops
 %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.ipops
 %doc %{_docdir}/kamailio/modules/README.malloc_test
@@ -1074,6 +1074,8 @@ fi
 
 
 %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]>
   - Added dialog2 and IMS modules to the build
 * Fri Dec 21 2012 Peter Dunkley <[email protected]>

+ 1 - 1
sip-router.8

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