Browse Source

Arrghh. Poor memory. My apologies for this commit.

Merge branch 'master' of ssh://git.sip-router.org/sip-router
Olle E. Johansson 11 years ago
parent
commit
6bc322ee1a
100 changed files with 3055 additions and 939 deletions
  1. 2 0
      INSTALL
  2. 1 0
      README-MODULES
  3. 2 1
      cfg.y
  4. 19 0
      forward.c
  5. 4 0
      forward.h
  6. 12 0
      main.c
  7. 9 0
      modules/app_java/Makefile
  8. 80 74
      modules/app_java/README
  9. 5 5
      modules/app_java/doc/app_java.xml
  10. 74 62
      modules/app_java/doc/app_java_admin.xml
  11. 2 0
      modules/app_java/global.h
  12. 7 7
      modules/app_java/java_iface.c
  13. 4 4
      modules/app_java/java_mod.c
  14. 16 16
      modules/app_java/java_msgobj.c
  15. 28 28
      modules/app_java/java_native_methods.c
  16. 26 26
      modules/app_java/java_sig_parser.c
  17. 8 8
      modules/app_java/java_support.c
  18. 2 2
      modules/app_java/utils.c
  19. 24 8
      modules/app_perl/README
  20. 9 0
      modules/app_perl/app_perl_mod.c
  21. 19 0
      modules/app_perl/doc/app_perl_admin.xml
  22. 19 9
      modules/auth_db/authorize.c
  23. 141 0
      modules/cdp/cdp_rpc.c
  24. 16 0
      modules/cdp/cdp_rpc.h
  25. 1 1
      modules/cdp/config.h
  26. 2 1
      modules/cdp/diameter_comm.c
  27. 21 3
      modules/cdp/doc/cdp_admin.xml
  28. 7 1
      modules/cdp/mod.c
  29. 2 0
      modules/cdp/peer.h
  30. 16 2
      modules/cdp/peermanager.c
  31. 42 4
      modules/cdp/routing.c
  32. 5 0
      modules/cnxcc/cnxcc_mod.c
  33. 1 0
      modules/db_flatstore/km_flat_con.c
  34. 2 2
      modules/db_mysql/km_dbase.c
  35. 4 3
      modules/dialog/dlg_handlers.c
  36. 1 1
      modules/dispatcher/dispatch.c
  37. 50 13
      modules/dispatcher/dispatcher.c
  38. 1 0
      modules/ims_auth/api.h
  39. 1 0
      modules/ims_auth/authims_mod.c
  40. 187 27
      modules/ims_auth/authorize.c
  41. 1 0
      modules/ims_auth/authorize.h
  42. 21 18
      modules/ims_auth/cxdx_mar.c
  43. 1 0
      modules/ims_auth/cxdx_mar.h
  44. 3 2
      modules/ims_charging/ccr.c
  45. 0 1
      modules/ims_charging/config.h
  46. 24 49
      modules/ims_charging/ims_ro.c
  47. 1 4
      modules/ims_charging/mod.c
  48. 53 0
      modules/ims_charging/ro_avp.c
  49. 17 0
      modules/ims_charging/ro_avp.h
  50. 4 0
      modules/ims_registrar_pcscf/notify.c
  51. 2 1
      modules/ims_registrar_scscf/registrar_notify.c
  52. 3 4
      modules/ims_usrloc_pcscf/udomain.c
  53. 6 0
      modules/ims_usrloc_scscf/usrloc_db.c
  54. 1 0
      modules/ipops/ipops_pv.c
  55. 3 1
      modules/kex/core_stats.c
  56. 4 4
      modules/mtree/mtree_mod.c
  57. 4 2
      modules/presence_dialoginfo/notify_body.c
  58. 5 0
      modules/pv/pv_core.c
  59. 5 5
      modules/pv/pv_trans.c
  60. 8 2
      modules/rls/list.h
  61. 1 1
      modules/rls/notify.c
  62. 2 0
      modules/rls/subscribe.c
  63. 1 1
      modules/rls/utils.h
  64. 22 19
      modules/sdpops/README
  65. 4 0
      modules/sdpops/doc/sdpops_admin.xml
  66. 1 1
      modules/siputils/checks.c
  67. 10 5
      modules/siputils/sipops.c
  68. 268 301
      modules/textops/README
  69. 140 0
      modules/textops/doc/textops_admin.xml
  70. 673 94
      modules/textops/textops.c
  71. 1 0
      modules/tls/tls_mod.c
  72. 10 0
      modules/tls/tls_select.c
  73. 3 0
      modules/tls/tls_select.h
  74. 46 0
      modules/tls/tls_server.c
  75. 2 0
      modules/tls/tls_server.h
  76. 1 1
      modules/topoh/th_msg.c
  77. 30 11
      modules/utils/README
  78. 1 1
      modules/utils/doc/utils_admin.xml
  79. 15 7
      modules/utils/functions.c
  80. 161 19
      modules/websocket/ws_conn.c
  81. 8 0
      modules/websocket/ws_conn.h
  82. 122 58
      modules/websocket/ws_frame.c
  83. 3 1
      modules/websocket/ws_handshake.c
  84. 299 3
      msg_translator.c
  85. 3 0
      msg_translator.h
  86. 7 5
      onsend.h
  87. 2 1
      parser/sdp/sdp.c
  88. 1 0
      pkg/kamailio/deb/debian/control
  89. 1 0
      pkg/kamailio/deb/jessie/control
  90. 1 0
      pkg/kamailio/deb/precise/control
  91. 1 0
      pkg/kamailio/deb/squeeze/control
  92. 1 0
      pkg/kamailio/deb/wheezy/control
  93. 1 1
      pkg/kamailio/rpm/kamailio.init
  94. 4 8
      route.c
  95. 1 0
      rvalue.c
  96. 94 0
      sr_module.c
  97. 11 0
      sr_module.h
  98. 45 0
      str.c
  99. 9 0
      str.h
  100. 11 0
      tcp_main.c

+ 2 - 0
INSTALL

@@ -131,6 +131,8 @@ Requirements:
 - libsctp devel headers - if you want to compile the SCTP transport in the core
 - libsctp devel headers - if you want to compile the SCTP transport in the core
 - libssl devel headers (openssl project) - if you want to compule the TLS module
 - libssl devel headers (openssl project) - if you want to compule the TLS module
 - linunistring - for the Websockets module
 - linunistring - for the Websockets module
+- python and devel headers for python module
+- jdk and gcj for java module
 
 
 
 
 OS Notes:
 OS Notes:

+ 1 - 0
README-MODULES

@@ -37,6 +37,7 @@ app_lua			Lang :: Execute embedded LUA scripts
 app_mono		Lang :: Execute embedded MONO scripts (like C#, Java, javascript)
 app_mono		Lang :: Execute embedded MONO scripts (like C#, Java, javascript)
 app_perl		Lang :: Embedded perl script support
 app_perl		Lang :: Embedded perl script support
 app_python		Lang :: Execute embedded Python scripts
 app_python		Lang :: Execute embedded Python scripts
+app_java		Lang :: Execute embedded Java compiled code
 async			Asynchronus SIP request handling functions
 async			Asynchronus SIP request handling functions
 auth			MD5 digest authentication support
 auth			MD5 digest authentication support
 auth_db			Authentication using a database module
 auth_db			Authentication using a database module

+ 2 - 1
cfg.y

@@ -3275,7 +3275,8 @@ cmd:
 					LOG(L_ERR, "misused command %s\n", $1);
 					LOG(L_ERR, "misused command %s\n", $1);
 					yyerror("Command cannot be used in the block\n");
 					yyerror("Command cannot be used in the block\n");
 			} else {
 			} else {
-				LOG(L_ERR, "cfg. parser: failed to find command %s\n", $1);
+				LOG(L_ERR, "cfg. parser: failed to find command %s (params %ld)\n",
+						$1, mod_func_action->val[1].u.number);
 				yyerror("unknown command, missing loadmodule?\n");
 				yyerror("unknown command, missing loadmodule?\n");
 			}
 			}
 			free_mod_func_action(mod_func_action);
 			free_mod_func_action(mod_func_action);

+ 19 - 0
forward.c

@@ -121,6 +121,12 @@
 static int mhomed_sock_cache_disabled = 0;
 static int mhomed_sock_cache_disabled = 0;
 static int sock_inet = -1;
 static int sock_inet = -1;
 static int sock_inet6 = -1;
 static int sock_inet6 = -1;
+static int _forward_set_send_info = 0;
+
+void forward_set_send_info(int v)
+{
+	_forward_set_send_info = v;
+}
 
 
 static void apply_force_send_socket(struct dest_info* dst, struct sip_msg* msg);
 static void apply_force_send_socket(struct dest_info* dst, struct sip_msg* msg);
 
 
@@ -497,6 +503,7 @@ int forward_request(struct sip_msg* msg, str* dst, unsigned short port,
 	int ret;
 	int ret;
 	struct ip_addr ip; /* debugging only */
 	struct ip_addr ip; /* debugging only */
 	char proto;
 	char proto;
+	struct onsend_info onsnd_info = {0};
 #ifdef USE_DNS_FAILOVER
 #ifdef USE_DNS_FAILOVER
 	struct socket_info* prev_send_sock;
 	struct socket_info* prev_send_sock;
 	int err;
 	int err;
@@ -623,7 +630,18 @@ int forward_request(struct sip_msg* msg, str* dst, unsigned short port,
 			}
 			}
 		}
 		}
 #endif
 #endif
+
+		if(unlikely(_forward_set_send_info==1)) {
+			onsnd_info.to=&send_info->to;
+			onsnd_info.send_sock=send_info->send_sock;
+			onsnd_info.buf=buf;
+			onsnd_info.len=len;
+			onsnd_info.msg=msg;
+			p_onsend=&onsnd_info;
+		}
+
 		if (msg_send(send_info, buf, len)<0){
 		if (msg_send(send_info, buf, len)<0){
+			p_onsend=0;
 			ret=ser_error=E_SEND;
 			ret=ser_error=E_SEND;
 #ifdef USE_DST_BLACKLIST
 #ifdef USE_DST_BLACKLIST
 			(void)dst_blacklist_add(BLST_ERR_SEND, send_info, msg);
 			(void)dst_blacklist_add(BLST_ERR_SEND, send_info, msg);
@@ -634,6 +652,7 @@ int forward_request(struct sip_msg* msg, str* dst, unsigned short port,
 			goto error;
 			goto error;
 #endif
 #endif
 		}else{
 		}else{
+			p_onsend=0;
 			ret=ser_error=E_OK;
 			ret=ser_error=E_OK;
 			/* sent requests stats */
 			/* sent requests stats */
 			STATS_TX_REQUEST(  msg->first_line.u.request.method_value );
 			STATS_TX_REQUEST(  msg->first_line.u.request.method_value );

+ 4 - 0
forward.h

@@ -84,6 +84,8 @@ inline static struct socket_info* get_send_socket(struct sip_msg* msg,
 }
 }
 
 
 
 
+#define GET_URI_PORT(uri) ((uri)->port_no?(uri)->port_no:(((uri)->proto==PROTO_TLS)?SIPS_PORT:SIP_PORT))
+
 struct socket_info* get_out_socket(union sockaddr_union* to, int proto);
 struct socket_info* get_out_socket(union sockaddr_union* to, int proto);
 typedef int (*check_self_f)(str* host, unsigned short port,
 typedef int (*check_self_f)(str* host, unsigned short port,
 		unsigned short proto);
 		unsigned short proto);
@@ -107,6 +109,8 @@ int update_sock_struct_from_via( union sockaddr_union* to,
 int forward_reply( struct sip_msg* msg);
 int forward_reply( struct sip_msg* msg);
 int forward_reply_nocb( struct sip_msg* msg);
 int forward_reply_nocb( struct sip_msg* msg);
 
 
+void forward_set_send_info(int v);
+
 int is_check_self_func_list_set(void);
 int is_check_self_func_list_set(void);
 
 
 
 

+ 12 - 0
main.c

@@ -1787,6 +1787,18 @@ static int calc_proc_no(void)
 			 tcp_e_listeners = tcp_cfg_children_no;
 			 tcp_e_listeners = tcp_cfg_children_no;
 	}
 	}
 	tcp_listeners += tcp_e_listeners;
 	tcp_listeners += tcp_e_listeners;
+#ifdef USE_TLS
+	tcp_e_listeners = 0;
+	for (si=tls_listen, tcp_e_listeners=0; si; si=si->next) {
+		if(si->workers>0)
+			tcp_listeners += si->workers;
+		else {
+			if(tcp_listeners==0)
+				tcp_e_listeners = tcp_cfg_children_no;
+		}
+	}
+	tcp_listeners += tcp_e_listeners;
+#endif
 	tcp_children_no = tcp_listeners;
 	tcp_children_no = tcp_listeners;
 #endif
 #endif
 #ifdef USE_SCTP
 #ifdef USE_SCTP

+ 9 - 0
modules/app_java/Makefile

@@ -20,6 +20,15 @@ JAVA_HOME ?= $(shell readlink -f /usr/bin/javac | sed "s:bin/javac::")
 DEFS += $(shell pkg-config libgcj12 --cflags) -I$(JAVA_HOME)/include
 DEFS += $(shell pkg-config libgcj12 --cflags) -I$(JAVA_HOME)/include
 LIBS += $(shell pkg-config libgcj12 --libs) -L$(JAVA_HOME)/lib  -ljvm
 LIBS += $(shell pkg-config libgcj12 --libs) -L$(JAVA_HOME)/lib  -ljvm
 
 
+# On Debian 7.5 there is a bug with JAVA_HOME detection.
+# $(shell readlink -f /usr/bin/javac | sed "s:bin/javac::") points to perl wrapper script (/usr/bin/gcj-wrapper-4.7)
+# whereas the real compiler is at /usr/bin/gcj-4.7. As the result, JAVA_HOME will not be a directory, that is incorrect.
+# At this point I don't see any universal method as explicit setting this variable at the compile phase.
+# -- ez
+ifeq ($(shell [ -d "${JAVA_HOME}" -a -f "$(JAVA_HOME)/include/jni.h" -a -f "$(JAVA_HOME)/lib/libjvm.so" ] && echo 1 || echo 0),0)
+    $(error Can't locate Java Development Kit. You have to specify environment JAVA_HOME to build app_java)
+endif
+
 ifeq ($(OS), freebsd)
 ifeq ($(OS), freebsd)
 LIBS+=-pthread
 LIBS+=-pthread
 endif
 endif

+ 80 - 74
modules/app_java/README

@@ -6,7 +6,7 @@ Edited by
 
 
 Konstantin Mosesov
 Konstantin Mosesov
 
 
-   Copyright © 2013 Konstantin Mosesov
+   Copyright © 2013, 2014 Konstantin Mosesov
      __________________________________________________________________
      __________________________________________________________________
 
 
    Table of Contents
    Table of Contents
@@ -21,7 +21,7 @@ Konstantin Mosesov
 
 
         3. Java runtime
         3. Java runtime
 
 
-              3.1.
+              3.1. JRE or JDK is required to use this module
 
 
         4. Parameters
         4. Parameters
 
 
@@ -84,7 +84,7 @@ Chapter 1. Admin Guide
 
 
    3. Java runtime
    3. Java runtime
 
 
-        3.1.
+        3.1. JRE or JDK is required to use this module
 
 
    4. Parameters
    4. Parameters
 
 
@@ -155,11 +155,12 @@ Chapter 1. Admin Guide
 
 
 3. Java runtime
 3. Java runtime
 
 
-   3.1.
+   3.1. JRE or JDK is required to use this module
 
 
-3.1.
+3.1. JRE or JDK is required to use this module
 
 
-   Java runtime library (JRE or JDK) is required to use this module.
+   Java runtime library (JRE and JDK for building app_java) is required to
+   use this module.
 
 
 4. Parameters
 4. Parameters
 
 
@@ -205,24 +206,25 @@ modparam("app_java", "java_options", "-Djava.compiler=NONE")
    Example 1.4. Set java_options parameter (live configuration)
    Example 1.4. Set java_options parameter (live configuration)
 ...
 ...
 # Assumes "application java folder" is located at /opt/kamailio/java
 # Assumes "application java folder" is located at /opt/kamailio/java
-modparam("app_java", "java_options", "-Djava.compiler=NONE -Djava.class.path=/pa
-th/to/kamailio/modules:/opt/kamailio/java:/opt/kamailio/java/kamailio.jar")
+modparam("app_java", "java_options", "-Djava.compiler=NONE
+    -Djava.class.path=/path/to/kamailio/modules:/opt/kamailio/java:
+    /opt/kamailio/java/kamailio.jar")
 ...
 ...
 
 
    Example 1.5. Set java_options parameter (verbose configuration)
    Example 1.5. Set java_options parameter (verbose configuration)
 ...
 ...
 # Assumes "application java folder" is located at /opt/kamailio/java
 # Assumes "application java folder" is located at /opt/kamailio/java
-modparam("app_java", "java_options", "-verbose:gc,class,jni -Djava.compiler=NONE
- -Djava.class.path=/path/to/kamailio/modules:/opt/kamailio/java:/opt/kamailio/ja
-va/kamailio.jar")
+modparam("app_java", "java_options", "-verbose:gc,class,jni
+    -Djava.compiler=NONE -Djava.class.path=/path/to/kamailio/modules:
+    /opt/kamailio/java:/opt/kamailio/java/kamailio.jar")
 ...
 ...
 
 
    Example 1.6. Set java_options parameter (debug configuration)
    Example 1.6. Set java_options parameter (debug configuration)
 ...
 ...
 # Assumes "application java folder" is located at /opt/kamailio/java
 # Assumes "application java folder" is located at /opt/kamailio/java
-modparam("app_java", "java_options", "-Xdebug -verbose:gc,class,jni -Djava.compi
-ler=NONE -Djava.class.path=/path/to/kamailio/modules:/opt/kamailio/java:/opt/kam
-ailio/java/kamailio.jar")
+modparam("app_java", "java_options", "-Xdebug -verbose:gc,class,jni
+    -Djava.compiler=NONE -Djava.class.path=/path/to/kamailio/modules:
+    /opt/kamailio/java:/opt/kamailio/java/kamailio.jar")
 ...
 ...
 
 
 4.4. force_cmd_exec (int)
 4.4. force_cmd_exec (int)
@@ -269,8 +271,8 @@ modparam("app_java", "force_cmd_exec", 1)
                 object       L
                 object       L
                 short        S
                 short        S
                 void         V
                 void         V
-                Note that to specify an object, the "L" is followed by the objec
-t's class name and ends with a semi-colon, ';' .
+                Note that to specify an object, the "L" is followed by the
+                object's class name and ends with a semi-colon, ';' .
 
 
    app_java supports the following signatures:
    app_java supports the following signatures:
                 Primitives: Z,B,C,D,F,I,J,L,S,V
                 Primitives: Z,B,C,D,F,I,J,L,S,V
@@ -294,7 +296,8 @@ ure.
         Parameters count should be exactly the same as signature count.
         Parameters count should be exactly the same as signature count.
         Note 1: Arrays representation (symbol '[') is not supported yet.
         Note 1: Arrays representation (symbol '[') is not supported yet.
         Note 2: You shall use a correct signature, e.g. the following examples o
         Note 2: You shall use a correct signature, e.g. the following examples o
-f combinations are invalid:
+f
+        combinations are invalid:
         java_method_exec("ExampleMethod", "ZI", "False");
         java_method_exec("ExampleMethod", "ZI", "False");
         java_method_exec("ExampleMethod", "LI", "something", "5");
         java_method_exec("ExampleMethod", "LI", "something", "5");
 
 
@@ -314,8 +317,8 @@ java_method_exec("ExampleMethod", "V");
 # Java
 # Java
 public int ExampleMethod()
 public int ExampleMethod()
 {
 {
-                ... do something;
-                return 1;
+    ... do something;
+    return 1;
 }
 }
      * Example 1.9. Signature: "Ljava/lang/String;I"
      * Example 1.9. Signature: "Ljava/lang/String;I"
        Kamailio prototype
        Kamailio prototype
@@ -331,8 +334,8 @@ java_method_exec("ExampleMethod", "Ljava/lang/String;I", "$mb", "$ml");
 # Java
 # Java
 public int ExampleMethod(String SipMessageBuffer, int SipMessageLenght)
 public int ExampleMethod(String SipMessageBuffer, int SipMessageLenght)
 {
 {
-                ... do something with buffer;
-                return 1;
+    ... do something with buffer;
+    return 1;
 }
 }
      * Example 1.10. Signature: "ZB"
      * Example 1.10. Signature: "ZB"
        Kamailio prototype
        Kamailio prototype
@@ -348,11 +351,12 @@ java_method_exec("ExampleMethod", "ZB", "true", "0x05");
 # Java
 # Java
 public int ExampleMethod(boolean flagSet, byte bFlag);
 public int ExampleMethod(boolean flagSet, byte bFlag);
 {
 {
-                if (flagSet)
-                {
-                        ... do something with flags;
-                }
-                return 1;
+    if (flagSet)
+    {
+        ... do something with flags;
+    }
+
+    return 1;
 }
 }
 
 
 5.3. java_staticmethod_exec(method, method_signature, [param1[, param2[,
 5.3. java_staticmethod_exec(method, method_signature, [param1[, param2[,
@@ -372,8 +376,8 @@ java_staticmethod_exec("ExampleMethod", "V");
 # Java
 # Java
 public static int ExampleMethod()
 public static int ExampleMethod()
 {
 {
-                ... do something;
-                return 1;
+    ... do something;
+    return 1;
 }
 }
      * Example 1.12. Signature: "Ljava/lang/String;I"
      * Example 1.12. Signature: "Ljava/lang/String;I"
        Kamailio prototype
        Kamailio prototype
@@ -390,8 +394,8 @@ java_staticmethod_exec("ExampleMethod", "Ljava/lang/String;I", "$mb", "$ml");
 # Java
 # Java
 public static int ExampleMethod(String SipMessageBuffer, int SipMessageLenght)
 public static int ExampleMethod(String SipMessageBuffer, int SipMessageLenght)
 {
 {
-                ... do something with buffer;
-                return 1;
+    ... do something with buffer;
+    return 1;
 }
 }
      * Example 1.13. Signature: "ZB"
      * Example 1.13. Signature: "ZB"
        Kamailio prototype
        Kamailio prototype
@@ -407,11 +411,12 @@ java_staticmethod_exec("ExampleMethod", "ZB", "true", "0x05");
 # Java
 # Java
 public static int ExampleMethod(boolean flagSet, byte bFlag);
 public static int ExampleMethod(boolean flagSet, byte bFlag);
 {
 {
-                if (flagSet)
-                {
-                        ... do something with flags;
-                }
-                return 1;
+    if (flagSet)
+    {
+        ... do something with flags;
+    }
+
+    return 1;
 }
 }
 
 
 5.4. java_s_method_exec(method, method_signature, [param1[, param2[, ...]]])
 5.4. java_s_method_exec(method, method_signature, [param1[, param2[, ...]]])
@@ -432,8 +437,8 @@ java_s_method_exec("ExampleMethod", "V");
 # Java
 # Java
 public synchronized int ExampleMethod()
 public synchronized int ExampleMethod()
 {
 {
-                ... do something;
-                return 1;
+    ... do something;
+    return 1;
 }
 }
      * Example 1.15. Signature: "Ljava/lang/String;I"
      * Example 1.15. Signature: "Ljava/lang/String;I"
        Kamailio prototype
        Kamailio prototype
@@ -450,8 +455,8 @@ java_s_method_exec("ExampleMethod", "Ljava/lang/String;I", "$mb", "$ml");
 public synchronized int ExampleMethod(String SipMessageBuffer, int SipMessageLen
 public synchronized int ExampleMethod(String SipMessageBuffer, int SipMessageLen
 ght)
 ght)
 {
 {
-                ... do something with buffer;
-                return 1;
+    ... do something with buffer;
+    return 1;
 }
 }
      * Example 1.16. Signature: "ZB"
      * Example 1.16. Signature: "ZB"
        Kamailio prototype
        Kamailio prototype
@@ -467,11 +472,12 @@ java_s_method_exec("ExampleMethod", "ZB", "true", "0x05");
 # Java
 # Java
 public synchronized int ExampleMethod(boolean flagSet, byte bFlag);
 public synchronized int ExampleMethod(boolean flagSet, byte bFlag);
 {
 {
-                if (flagSet)
-                {
-                        ... do something with flags;
-                }
-                return 1;
+    if (flagSet)
+    {
+        ... do something with flags;
+    }
+
+    return 1;
 }
 }
 
 
 5.5. java_s_staticmethod_exec(method, method_signature, [param1[, param2[,
 5.5. java_s_staticmethod_exec(method, method_signature, [param1[, param2[,
@@ -493,8 +499,8 @@ java_s_staticmethod_exec("ExampleMethod", "V");
 # Java
 # Java
 public static synchronized int ExampleMethod()
 public static synchronized int ExampleMethod()
 {
 {
-                ... do something;
-                return 1;
+    ... do something;
+    return 1;
 }
 }
      * Example 1.18. Signature: "Ljava/lang/String;I"
      * Example 1.18. Signature: "Ljava/lang/String;I"
        Kamailio prototype
        Kamailio prototype
@@ -512,8 +518,8 @@ java_s_staticmethod_exec("ExampleMethod", "Ljava/lang/String;I", "$mb", "$ml");
 public static synchronized int ExampleMethod(String SipMessageBuffer, int SipMes
 public static synchronized int ExampleMethod(String SipMessageBuffer, int SipMes
 sageLenght)
 sageLenght)
 {
 {
-                ... do something with buffer;
-                return 1;
+    ... do something with buffer;
+    return 1;
 }
 }
      * Example 1.19. Signature: "ZB"
      * Example 1.19. Signature: "ZB"
        Kamailio prototype
        Kamailio prototype
@@ -529,11 +535,12 @@ java_s_staticmethod_exec("ExampleMethod", "ZB", "true", "0x05");
 # Java
 # Java
 public static synchronized int ExampleMethod(boolean flagSet, byte bFlag);
 public static synchronized int ExampleMethod(boolean flagSet, byte bFlag);
 {
 {
-                if (flagSet)
-                {
-                        ... do something with flags;
-                }
-                return 1;
+    if (flagSet)
+    {
+        ... do something with flags;
+    }
+
+    return 1;
 }
 }
 
 
 6. Java Module API
 6. Java Module API
@@ -549,25 +556,24 @@ import org.siprouter.NativeInterface.*;
 
 
 public class Kamailio extends NativeMethods
 public class Kamailio extends NativeMethods
 {
 {
-                /* Here you should specify a full path to app_java.so */
-                static
-                {
-                                System.load("/opt/kamailio/lib/kamailio/modules/
-app_java.so");
-                }
-
-                /* Constructor. Do not remove !!! */
-                public Kamailio()
-                {
-                }
-
-                /*
-                This method should be executed for each children process, immedi
-ately after forking.
-                Required. Do not remove !!!
-                */
-                public int child_init(int rank)
-                {
-                                return 1;
-                }
+    /* Here you should specify a full path to app_java.so */
+    static
+    {
+        System.load("/opt/kamailio/lib/kamailio/modules/app_java.so");
+    }
+
+    /* Constructor. Do not remove !!! */
+    public Kamailio()
+    {
+    }
+
+    /*
+        This method should be executed for each children process, immediately af
+ter forking.
+        Required. Do not remove !!!
+    */
+    public int child_init(int rank)
+    {
+        return 1;
+    }
 }
 }

+ 5 - 5
modules/app_java/doc/app_java.xml

@@ -6,7 +6,6 @@
 <!-- Include general documentation entities -->
 <!-- Include general documentation entities -->
 <!ENTITY % docentities SYSTEM "../../../docbook/entities.xml">
 <!ENTITY % docentities SYSTEM "../../../docbook/entities.xml">
 %docentities;
 %docentities;
-
 ]>
 ]>
 
 
 <book xmlns:xi="http://www.w3.org/2001/XInclude">
 <book xmlns:xi="http://www.w3.org/2001/XInclude">
@@ -15,8 +14,8 @@
 	<productname class="trade">&kamailioname;</productname>
 	<productname class="trade">&kamailioname;</productname>
 	<authorgroup>
 	<authorgroup>
 	    <author>
 	    <author>
-			<firstname>Konstantin</firstname>
-			<surname>Mosesov</surname>
+		<firstname>Konstantin</firstname>
+		<surname>Mosesov</surname>
 	    </author>
 	    </author>
 	    <editor>
 	    <editor>
 	    	<firstname>Konstantin</firstname>
 	    	<firstname>Konstantin</firstname>
@@ -25,11 +24,12 @@
 	</authorgroup>
 	</authorgroup>
 	<copyright>
 	<copyright>
 	    <year>2013</year>
 	    <year>2013</year>
-		<holder>Konstantin Mosesov</holder>
+	    <year>2014</year>
+	    <holder>Konstantin Mosesov</holder>
 	</copyright>
 	</copyright>
     </bookinfo>
     </bookinfo>
     <toc></toc>
     <toc></toc>
     
     
-	<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="app_java_admin.xml"/>
+    <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="app_java_admin.xml"/>
     
     
 </book>
 </book>

+ 74 - 62
modules/app_java/doc/app_java_admin.xml

@@ -88,8 +88,8 @@
 	<section>
 	<section>
 		<title>Java runtime</title>
 		<title>Java runtime</title>
 		<section>
 		<section>
-			<title/>
-			<para>Java runtime library (JRE or JDK) is required to use this module.</para>
+			<title>JRE or JDK is required to use this module</title>
+			<para>Java runtime library (JRE and JDK for building app_java) is required to use this module.</para>
 		</section>
 		</section>
 	</section>
 	</section>
 	<!-- end of section Java Runtime -->
 	<!-- end of section Java Runtime -->
@@ -166,7 +166,9 @@ modparam("app_java", "java_options", "-Djava.compiler=NONE")
 				<programlisting format="linespecific">
 				<programlisting format="linespecific">
 ...
 ...
 # Assumes "application java folder" is located at /opt/kamailio/java
 # Assumes "application java folder" is located at /opt/kamailio/java
-modparam("app_java", "java_options", "-Djava.compiler=NONE -Djava.class.path=/path/to/kamailio/modules:/opt/kamailio/java:/opt/kamailio/java/kamailio.jar")
+modparam("app_java", "java_options", "-Djava.compiler=NONE 
+    -Djava.class.path=/path/to/kamailio/modules:/opt/kamailio/java:
+    /opt/kamailio/java/kamailio.jar")
 ...
 ...
 </programlisting>
 </programlisting>
 			</example>
 			</example>
@@ -175,7 +177,9 @@ modparam("app_java", "java_options", "-Djava.compiler=NONE -Djava.class.path=/pa
 				<programlisting format="linespecific">
 				<programlisting format="linespecific">
 ...
 ...
 # Assumes "application java folder" is located at /opt/kamailio/java
 # Assumes "application java folder" is located at /opt/kamailio/java
-modparam("app_java", "java_options", "-verbose:gc,class,jni -Djava.compiler=NONE -Djava.class.path=/path/to/kamailio/modules:/opt/kamailio/java:/opt/kamailio/java/kamailio.jar")
+modparam("app_java", "java_options", "-verbose:gc,class,jni 
+    -Djava.compiler=NONE -Djava.class.path=/path/to/kamailio/modules:
+    /opt/kamailio/java:/opt/kamailio/java/kamailio.jar")
 ...
 ...
 </programlisting>
 </programlisting>
 			</example>
 			</example>
@@ -184,7 +188,9 @@ modparam("app_java", "java_options", "-verbose:gc,class,jni -Djava.compiler=NONE
 				<programlisting format="linespecific">
 				<programlisting format="linespecific">
 ...
 ...
 # Assumes "application java folder" is located at /opt/kamailio/java
 # Assumes "application java folder" is located at /opt/kamailio/java
-modparam("app_java", "java_options", "-Xdebug -verbose:gc,class,jni -Djava.compiler=NONE -Djava.class.path=/path/to/kamailio/modules:/opt/kamailio/java:/opt/kamailio/java/kamailio.jar")
+modparam("app_java", "java_options", "-Xdebug -verbose:gc,class,jni 
+    -Djava.compiler=NONE -Djava.class.path=/path/to/kamailio/modules:
+    /opt/kamailio/java:/opt/kamailio/java/kamailio.jar")
 ...
 ...
 </programlisting>
 </programlisting>
 			</example>
 			</example>
@@ -240,7 +246,8 @@ modparam("app_java", "force_cmd_exec", 1)
 		object       L 
 		object       L 
 		short        S 
 		short        S 
 		void         V 
 		void         V 
-		Note that to specify an object, the "L" is followed by the object's class name and ends with a semi-colon, ';' .
+		Note that to specify an object, the "L" is followed by the 
+		object's class name and ends with a semi-colon, ';' .
     			</programlisting>
     			</programlisting>
 			</para>
 			</para>
     		<para> app_java supports the following signatures:
     		<para> app_java supports the following signatures:
@@ -263,7 +270,8 @@ modparam("app_java", "force_cmd_exec", 1)
 	Parameters are optional, ommitting a parameter meant the passed value is NULL.
 	Parameters are optional, ommitting a parameter meant the passed value is NULL.
 	Parameters count should be exactly the same as signature count.
 	Parameters count should be exactly the same as signature count.
 	Note 1: Arrays representation (symbol '[') is not supported yet.
 	Note 1: Arrays representation (symbol '[') is not supported yet.
-	Note 2: You shall use a correct signature, e.g. the following examples of combinations are invalid:    
+	Note 2: You shall use a correct signature, e.g. the following examples of
+	combinations are invalid:
     	java_method_exec("ExampleMethod", "ZI", "False");
     	java_method_exec("ExampleMethod", "ZI", "False");
         java_method_exec("ExampleMethod", "LI", "something", "5");
         java_method_exec("ExampleMethod", "LI", "something", "5");
 </programlisting>
 </programlisting>
@@ -293,8 +301,8 @@ java_method_exec("ExampleMethod", "V");
 # Java
 # Java
 public int ExampleMethod()
 public int ExampleMethod()
 {
 {
-		... do something;
-		return 1;
+    ... do something;
+    return 1;
 }
 }
 </programlisting>
 </programlisting>
 			    	</example>
 			    	</example>
@@ -316,8 +324,8 @@ java_method_exec("ExampleMethod", "Ljava/lang/String;I", "$mb", "$ml");
 # Java
 # Java
 public int ExampleMethod(String SipMessageBuffer, int SipMessageLenght)
 public int ExampleMethod(String SipMessageBuffer, int SipMessageLenght)
 {
 {
-		... do something with buffer;
-		return 1;
+    ... do something with buffer;
+    return 1;
 }
 }
 </programlisting>
 </programlisting>
 	    			</example>
 	    			</example>
@@ -339,11 +347,12 @@ java_method_exec("ExampleMethod", "ZB", "true", "0x05");
 # Java
 # Java
 public int ExampleMethod(boolean flagSet, byte bFlag);
 public int ExampleMethod(boolean flagSet, byte bFlag);
 {
 {
-		if (flagSet)
-		{
-			... do something with flags;
-		}
-		return 1;
+    if (flagSet)
+    {
+        ... do something with flags;
+    }
+
+    return 1;
 }
 }
 </programlisting>
 </programlisting>
     				</example>
     				</example>
@@ -373,8 +382,8 @@ java_staticmethod_exec("ExampleMethod", "V");
 # Java
 # Java
 public static int ExampleMethod()
 public static int ExampleMethod()
 {
 {
-		... do something;
-		return 1;
+    ... do something;
+    return 1;
 }
 }
 </programlisting>
 </programlisting>
     				</example>
     				</example>
@@ -396,8 +405,8 @@ java_staticmethod_exec("ExampleMethod", "Ljava/lang/String;I", "$mb", "$ml");
 # Java
 # Java
 public static int ExampleMethod(String SipMessageBuffer, int SipMessageLenght)
 public static int ExampleMethod(String SipMessageBuffer, int SipMessageLenght)
 {
 {
-		... do something with buffer;
-		return 1;
+    ... do something with buffer;
+    return 1;
 }
 }
 </programlisting>
 </programlisting>
     				</example>
     				</example>
@@ -419,11 +428,12 @@ java_staticmethod_exec("ExampleMethod", "ZB", "true", "0x05");
 # Java
 # Java
 public static int ExampleMethod(boolean flagSet, byte bFlag);
 public static int ExampleMethod(boolean flagSet, byte bFlag);
 {
 {
-		if (flagSet)
-		{
-			... do something with flags;
-		}
-		return 1;
+    if (flagSet)
+    {
+        ... do something with flags;
+    }
+
+    return 1;
 }
 }
 </programlisting>
 </programlisting>
     				</example>
     				</example>
@@ -454,8 +464,8 @@ java_s_method_exec("ExampleMethod", "V");
 # Java
 # Java
 public synchronized int ExampleMethod()
 public synchronized int ExampleMethod()
 {
 {
-		... do something;
-		return 1;
+    ... do something;
+    return 1;
 }
 }
 </programlisting>
 </programlisting>
     				</example>
     				</example>
@@ -477,8 +487,8 @@ java_s_method_exec("ExampleMethod", "Ljava/lang/String;I", "$mb", "$ml");
 # Java
 # Java
 public synchronized int ExampleMethod(String SipMessageBuffer, int SipMessageLenght)
 public synchronized int ExampleMethod(String SipMessageBuffer, int SipMessageLenght)
 {
 {
-		... do something with buffer;
-		return 1;
+    ... do something with buffer;
+    return 1;
 }
 }
 </programlisting>
 </programlisting>
     				</example>
     				</example>
@@ -500,11 +510,12 @@ java_s_method_exec("ExampleMethod", "ZB", "true", "0x05");
 # Java
 # Java
 public synchronized int ExampleMethod(boolean flagSet, byte bFlag);
 public synchronized int ExampleMethod(boolean flagSet, byte bFlag);
 {
 {
-		if (flagSet)
-		{
-			... do something with flags;
-		}
-		return 1;
+    if (flagSet)
+    {
+        ... do something with flags;
+    }
+
+    return 1;
 }
 }
 </programlisting>
 </programlisting>
     				</example>
     				</example>
@@ -535,8 +546,8 @@ java_s_staticmethod_exec("ExampleMethod", "V");
 # Java
 # Java
 public static synchronized int ExampleMethod()
 public static synchronized int ExampleMethod()
 {
 {
-		... do something;
-		return 1;
+    ... do something;
+    return 1;
 }
 }
 </programlisting>
 </programlisting>
     				</example>
     				</example>
@@ -558,8 +569,8 @@ java_s_staticmethod_exec("ExampleMethod", "Ljava/lang/String;I", "$mb", "$ml");
 # Java
 # Java
 public static synchronized int ExampleMethod(String SipMessageBuffer, int SipMessageLenght)
 public static synchronized int ExampleMethod(String SipMessageBuffer, int SipMessageLenght)
 {
 {
-		... do something with buffer;
-		return 1;
+    ... do something with buffer;
+    return 1;
 }
 }
 </programlisting>
 </programlisting>
     				</example>
     				</example>
@@ -581,11 +592,12 @@ java_s_staticmethod_exec("ExampleMethod", "ZB", "true", "0x05");
 # Java
 # Java
 public static synchronized int ExampleMethod(boolean flagSet, byte bFlag);
 public static synchronized int ExampleMethod(boolean flagSet, byte bFlag);
 {
 {
-		if (flagSet)
-		{
-			... do something with flags;
-		}
-		return 1;
+    if (flagSet)
+    {
+        ... do something with flags;
+    }
+
+    return 1;
 }
 }
 </programlisting>
 </programlisting>
     				</example>
     				</example>
@@ -616,25 +628,25 @@ import org.siprouter.NativeInterface.*;
 
 
 public class Kamailio extends NativeMethods
 public class Kamailio extends NativeMethods
 {
 {
-		/* Here you should specify a full path to app_java.so */
-		static
-		{
-				System.load("/opt/kamailio/lib/kamailio/modules/app_java.so");
-		}
-
-		/* Constructor. Do not remove !!! */
-		public Kamailio()
-		{
-		}
-
-		/*
-		This method should be executed for each children process, immediately after forking.
-		Required. Do not remove !!!
-		*/
-		public int child_init(int rank)
-		{
-				return 1;
-		}
+    /* Here you should specify a full path to app_java.so */
+    static
+    {
+        System.load("/opt/kamailio/lib/kamailio/modules/app_java.so");
+    }
+
+    /* Constructor. Do not remove !!! */
+    public Kamailio()
+    {
+    }
+
+    /*
+        This method should be executed for each children process, immediately after forking.
+	Required. Do not remove !!!
+    */
+    public int child_init(int rank)
+    {
+	return 1;
+    }
 }
 }
 </programlisting>
 </programlisting>
     		</example>
     		</example>

+ 2 - 0
modules/app_java/global.h

@@ -35,6 +35,8 @@
 
 
 #include <jni.h>
 #include <jni.h>
 
 
+#define	APP_NAME	"app_java"
+
 JavaVM *jvm;
 JavaVM *jvm;
 JNIEnv *env;
 JNIEnv *env;
 jclass KamailioClass;
 jclass KamailioClass;

+ 7 - 7
modules/app_java/java_iface.c

@@ -120,19 +120,19 @@ int java_exec(struct sip_msg *msgp, int is_static, int is_synchronized, char *me
 
 
     if (signature == NULL || !strcmp(signature, ""))
     if (signature == NULL || !strcmp(signature, ""))
     {
     {
-	LM_ERR("java_method_exec(): signature is empty or invalid.\n");
+	LM_ERR("%s: java_method_exec(): signature is empty or invalid.\n", APP_NAME);
 	return -1;
 	return -1;
     }
     }
 
 
     if (param == NULL && strcmp(signature, "V"))
     if (param == NULL && strcmp(signature, "V"))
     {
     {
-	LM_ERR("java_method_exec(): no parameter (parameter is NULL) but signature '%s' is not equals to 'V'.\n", signature);
+	LM_ERR("%s: java_method_exec(): no parameter (parameter is NULL) but signature '%s' is not equals to 'V'.\n", APP_NAME, signature);
 	return -1;
 	return -1;
     }
     }
 
 
     if (is_sig_allowed(signature) == 0)
     if (is_sig_allowed(signature) == 0)
     {
     {
-	LM_ERR("java_method_exec(): error: signature '%s' isn't supported yet.\n", signature);
+	LM_ERR("%s: java_method_exec(): error: signature '%s' isn't supported yet.\n", APP_NAME, signature);
 	return -1;
 	return -1;
     }
     }
 
 
@@ -147,7 +147,7 @@ int java_exec(struct sip_msg *msgp, int is_static, int is_synchronized, char *me
     cs = (char *)pkg_malloc(cslen * sizeof(char));
     cs = (char *)pkg_malloc(cslen * sizeof(char));
     if (!cs)
     if (!cs)
     {
     {
-	LM_ERR("pkg_malloc() has failed. Can't allocate %lu bytes. Not enough memory!\n", (unsigned long)cslen);
+	LM_ERR("%s: pkg_malloc() has failed. Can't allocate %lu bytes. Not enough memory!\n", APP_NAME, (unsigned long)cslen);
 	return -1;
 	return -1;
     }
     }
     snprintf(cs, cslen, "(%s)%s", signature, retval_sig);
     snprintf(cs, cslen, "(%s)%s", signature, retval_sig);
@@ -208,7 +208,7 @@ int java_exec(struct sip_msg *msgp, int is_static, int is_synchronized, char *me
 	if ((*env)->MonitorEnter(env, invk_method_ref) != JNI_OK)
 	if ((*env)->MonitorEnter(env, invk_method_ref) != JNI_OK)
         {
         {
 	    locked = 0;
 	    locked = 0;
-	    LM_ERR("MonitorEnter() has failed!\n");
+	    LM_ERR("%s: MonitorEnter() has failed! Can't synchronize!\n", APP_NAME);
 	}
 	}
 	else
 	else
 	{
 	{
@@ -240,7 +240,7 @@ int java_exec(struct sip_msg *msgp, int is_static, int is_synchronized, char *me
 
 
     if ((*env)->ExceptionCheck(env))
     if ((*env)->ExceptionCheck(env))
     {
     {
-        LM_ERR("%s(): %s() has failed. See exception below.\n", 
+        LM_ERR("%s: %s(): %s() has failed. See exception below.\n", APP_NAME,
 		(is_static ? 
 		(is_static ? 
 			(is_synchronized ? "java_s_staticmethod_exec" : "java_staticmethod_exec") :
 			(is_synchronized ? "java_s_staticmethod_exec" : "java_staticmethod_exec") :
 			(is_synchronized ? "java_s_method_exec" : "java_method_exec")
 			(is_synchronized ? "java_s_method_exec" : "java_method_exec")
@@ -261,7 +261,7 @@ int java_exec(struct sip_msg *msgp, int is_static, int is_synchronized, char *me
     {
     {
 	if ((*env)->MonitorExit(env, invk_method_ref) != JNI_OK)
 	if ((*env)->MonitorExit(env, invk_method_ref) != JNI_OK)
 	{
 	{
-	    LM_ERR("MonitorExit) has failed!\n");
+	    LM_ERR("%s: MonitorExit() has failed! Can't synchronize!\n", APP_NAME);
 	}
 	}
     }
     }
 
 

+ 4 - 4
modules/app_java/java_mod.c

@@ -78,7 +78,7 @@ static cmd_export_t cmds[] = {
 
 
 /** module exports */
 /** module exports */
 struct module_exports exports = {
 struct module_exports exports = {
-    "app_java",                     /* module name */
+    APP_NAME,                       /* module name */
 //    RTLD_NOW | RTLD_GLOBAL,         /* dlopen flags */
 //    RTLD_NOW | RTLD_GLOBAL,         /* dlopen flags */
     DEFAULT_DLFLAGS,		    /* dlopen flags */
     DEFAULT_DLFLAGS,		    /* dlopen flags */
     cmds,                           /* exported functions */
     cmds,                           /* exported functions */
@@ -109,7 +109,7 @@ static int mod_init(void)
 
 
     if (force_cmd_exec)
     if (force_cmd_exec)
     {
     {
-	LM_NOTICE("app_java: Parameter force_cmd_exec may cause a memory leaks if used from embedded languages\n");
+	LM_NOTICE("%s: Parameter force_cmd_exec may cause a memory leaks if used from embedded languages\n", APP_NAME);
     }
     }
 
 
     options = (JavaVMOption *)pkg_malloc(sizeof(JavaVMOption));
     options = (JavaVMOption *)pkg_malloc(sizeof(JavaVMOption));
@@ -141,7 +141,7 @@ static int mod_init(void)
 	return -1;
 	return -1;
     }
     }
 
 
-    LM_INFO("app_java: Java VM initialization OK\n");
+    LM_INFO("%s: Java VM initialization OK\n", APP_NAME);
 
 
     // attach to current thread
     // attach to current thread
     (*jvm)->AttachCurrentThread(jvm, (void **)&env, NULL);
     (*jvm)->AttachCurrentThread(jvm, (void **)&env, NULL);
@@ -193,7 +193,7 @@ static int mod_init(void)
 	return -1;
 	return -1;
     }
     }
 
 
-    LM_INFO("app_java: module initialization OK\n");
+    LM_INFO("%s: module initialization OK\n", APP_NAME);
 
 
     if (jvm != NULL)
     if (jvm != NULL)
         (*jvm)->DetachCurrentThread(jvm);
         (*jvm)->DetachCurrentThread(jvm);

+ 16 - 16
modules/app_java/java_msgobj.c

@@ -50,7 +50,7 @@ jobject *fill_sipmsg_object(JNIEnv *env, struct sip_msg *msg)
     SipMsgInstance = (jobject *)pkg_malloc(sizeof(jobject));
     SipMsgInstance = (jobject *)pkg_malloc(sizeof(jobject));
     if (!SipMsgInstance)
     if (!SipMsgInstance)
     {
     {
-	LM_ERR("pkg_malloc() has failed. Not enough memory!\n");
+	LM_ERR("%s: pkg_malloc() has failed. Not enough memory!\n", APP_NAME);
 	return NULL;
 	return NULL;
     }
     }
     memset(SipMsgInstance, 0, sizeof(jobject));
     memset(SipMsgInstance, 0, sizeof(jobject));
@@ -83,7 +83,7 @@ jobject *fill_sipmsg_object(JNIEnv *env, struct sip_msg *msg)
     if (!fid)
     if (!fid)
     {
     {
 	(*env)->ExceptionClear(env);
 	(*env)->ExceptionClear(env);
-	LM_ERR("Can't find symbol org.siprouter.SipMsg.id\n");
+	LM_ERR("%s: Can't find symbol org.siprouter.SipMsg.id\n", APP_NAME);
 
 
         return NULL;
         return NULL;
     }
     }
@@ -99,7 +99,7 @@ jobject *fill_sipmsg_object(JNIEnv *env, struct sip_msg *msg)
     if (!fid)
     if (!fid)
     {
     {
 	(*env)->ExceptionClear(env);
 	(*env)->ExceptionClear(env);
-	LM_ERR("Can't find symbol org.siprouter.SipMsg.pid\n");
+	LM_ERR("%s: Can't find symbol org.siprouter.SipMsg.pid\n", APP_NAME);
         return NULL;
         return NULL;
     }
     }
     (*env)->SetIntField(env, SipMsgInstance, fid, msg->pid);
     (*env)->SetIntField(env, SipMsgInstance, fid, msg->pid);
@@ -114,7 +114,7 @@ jobject *fill_sipmsg_object(JNIEnv *env, struct sip_msg *msg)
     if (!fid)
     if (!fid)
     {
     {
 	(*env)->ExceptionClear(env);
 	(*env)->ExceptionClear(env);
-	LM_ERR("Can't find symbol org.siprouter.SipMsg.eoh\n");
+	LM_ERR("%s: Can't find symbol org.siprouter.SipMsg.eoh\n", APP_NAME);
         return NULL;
         return NULL;
     }
     }
     jStrParam = (*env)->NewStringUTF(env, msg->eoh);
     jStrParam = (*env)->NewStringUTF(env, msg->eoh);
@@ -131,7 +131,7 @@ jobject *fill_sipmsg_object(JNIEnv *env, struct sip_msg *msg)
     if (!fid)
     if (!fid)
     {
     {
 	(*env)->ExceptionClear(env);
 	(*env)->ExceptionClear(env);
-	LM_ERR("Can't find symbol org.siprouter.SipMsg.unparsed\n");
+	LM_ERR("%s: Can't find symbol org.siprouter.SipMsg.unparsed\n", APP_NAME);
         return NULL;
         return NULL;
     }
     }
     jStrParam = (*env)->NewStringUTF(env, msg->unparsed);
     jStrParam = (*env)->NewStringUTF(env, msg->unparsed);
@@ -148,7 +148,7 @@ jobject *fill_sipmsg_object(JNIEnv *env, struct sip_msg *msg)
     if (!fid)
     if (!fid)
     {
     {
 	(*env)->ExceptionClear(env);
 	(*env)->ExceptionClear(env);
-        LM_ERR("Can't find symbol org.siprouter.SipMsg.buf\n");
+        LM_ERR("%s: Can't find symbol org.siprouter.SipMsg.buf\n", APP_NAME);
         return NULL;
         return NULL;
     }
     }
     jStrParam = (*env)->NewStringUTF(env, msg->buf);
     jStrParam = (*env)->NewStringUTF(env, msg->buf);
@@ -165,7 +165,7 @@ jobject *fill_sipmsg_object(JNIEnv *env, struct sip_msg *msg)
     if (!fid)
     if (!fid)
     {
     {
 	(*env)->ExceptionClear(env);
 	(*env)->ExceptionClear(env);
-        LM_ERR("Can't find symbol org.siprouter.SipMsg.len\n");
+        LM_ERR("%s: Can't find symbol org.siprouter.SipMsg.len\n", APP_NAME);
         return NULL;
         return NULL;
     }
     }
     (*env)->SetIntField(env, SipMsgInstance, fid, msg->len);
     (*env)->SetIntField(env, SipMsgInstance, fid, msg->len);
@@ -180,7 +180,7 @@ jobject *fill_sipmsg_object(JNIEnv *env, struct sip_msg *msg)
     if (!fid)
     if (!fid)
     {
     {
 	(*env)->ExceptionClear(env);
 	(*env)->ExceptionClear(env);
-        LM_ERR("Can't find symbol org.siprouter.SipMsg.new_uri\n");
+        LM_ERR("%s: Can't find symbol org.siprouter.SipMsg.new_uri\n", APP_NAME);
         return NULL;
         return NULL;
     }
     }
     jStrParam = (*env)->NewStringUTF(env, msg->new_uri.len <= 0 ? "" : msg->new_uri.s);
     jStrParam = (*env)->NewStringUTF(env, msg->new_uri.len <= 0 ? "" : msg->new_uri.s);
@@ -197,7 +197,7 @@ jobject *fill_sipmsg_object(JNIEnv *env, struct sip_msg *msg)
     if (!fid)
     if (!fid)
     {
     {
 	(*env)->ExceptionClear(env);
 	(*env)->ExceptionClear(env);
-        LM_ERR("Can't find symbol org.siprouter.SipMsg.dst_uri\n");
+        LM_ERR("%s: Can't find symbol org.siprouter.SipMsg.dst_uri\n", APP_NAME);
         return NULL;
         return NULL;
     }
     }
     jStrParam = (*env)->NewStringUTF(env, msg->dst_uri.len <= 0 ? "" : msg->dst_uri.s);
     jStrParam = (*env)->NewStringUTF(env, msg->dst_uri.len <= 0 ? "" : msg->dst_uri.s);
@@ -214,7 +214,7 @@ jobject *fill_sipmsg_object(JNIEnv *env, struct sip_msg *msg)
     if (!fid)
     if (!fid)
     {
     {
 	(*env)->ExceptionClear(env);
 	(*env)->ExceptionClear(env);
-        LM_ERR("Can't find symbol org.siprouter.SipMsg.parsed_orig_ruri_ok\n");
+        LM_ERR("%s: Can't find symbol org.siprouter.SipMsg.parsed_orig_ruri_ok\n", APP_NAME);
         return NULL;
         return NULL;
     }
     }
     (*env)->SetIntField(env, SipMsgInstance, fid, msg->parsed_orig_ruri_ok);
     (*env)->SetIntField(env, SipMsgInstance, fid, msg->parsed_orig_ruri_ok);
@@ -229,7 +229,7 @@ jobject *fill_sipmsg_object(JNIEnv *env, struct sip_msg *msg)
     if (!fid)
     if (!fid)
     {
     {
 	(*env)->ExceptionClear(env);
 	(*env)->ExceptionClear(env);
-        LM_ERR("Can't find symbol org.siprouter.SipMsg.add_to_branch_s\n");
+        LM_ERR("%s: Can't find symbol org.siprouter.SipMsg.add_to_branch_s\n", APP_NAME);
         return NULL;
         return NULL;
     }
     }
     jStrParam = (*env)->NewStringUTF(env, (msg->add_to_branch_len <= 0 || msg->add_to_branch_s == NULL) ? "" : strdup(msg->add_to_branch_s));
     jStrParam = (*env)->NewStringUTF(env, (msg->add_to_branch_len <= 0 || msg->add_to_branch_s == NULL) ? "" : strdup(msg->add_to_branch_s));
@@ -246,7 +246,7 @@ jobject *fill_sipmsg_object(JNIEnv *env, struct sip_msg *msg)
     if (!fid)
     if (!fid)
     {
     {
 	(*env)->ExceptionClear(env);
 	(*env)->ExceptionClear(env);
-        LM_ERR("Can't find symbol org.siprouter.SipMsg.add_to_branch_len\n");
+        LM_ERR("%s: Can't find symbol org.siprouter.SipMsg.add_to_branch_len\n", APP_NAME);
         return NULL;
         return NULL;
     }
     }
     (*env)->SetIntField(env, SipMsgInstance, fid, msg->add_to_branch_len);
     (*env)->SetIntField(env, SipMsgInstance, fid, msg->add_to_branch_len);
@@ -261,7 +261,7 @@ jobject *fill_sipmsg_object(JNIEnv *env, struct sip_msg *msg)
     if (!fid)
     if (!fid)
     {
     {
 	(*env)->ExceptionClear(env);
 	(*env)->ExceptionClear(env);
-        LM_ERR("Can't find symbol org.siprouter.SipMsg.hash_index\n");
+        LM_ERR("%s: Can't find symbol org.siprouter.SipMsg.hash_index\n", APP_NAME);
         return NULL;
         return NULL;
     }
     }
     (*env)->SetIntField(env, SipMsgInstance, fid, msg->hash_index);
     (*env)->SetIntField(env, SipMsgInstance, fid, msg->hash_index);
@@ -276,7 +276,7 @@ jobject *fill_sipmsg_object(JNIEnv *env, struct sip_msg *msg)
     if (!fid)
     if (!fid)
     {
     {
 	(*env)->ExceptionClear(env);
 	(*env)->ExceptionClear(env);
-        LM_ERR("Can't find symbol org.siprouter.SipMsg.msg_flags\n");
+        LM_ERR("%s: Can't find symbol org.siprouter.SipMsg.msg_flags\n", APP_NAME);
         return NULL;
         return NULL;
     }
     }
     (*env)->SetIntField(env, SipMsgInstance, fid, msg->msg_flags);
     (*env)->SetIntField(env, SipMsgInstance, fid, msg->msg_flags);
@@ -291,7 +291,7 @@ jobject *fill_sipmsg_object(JNIEnv *env, struct sip_msg *msg)
     if (!fid)
     if (!fid)
     {
     {
 	(*env)->ExceptionClear(env);
 	(*env)->ExceptionClear(env);
-        LM_ERR("Can't find symbol org.siprouter.SipMsg.set_global_address\n");
+        LM_ERR("%s: Can't find symbol org.siprouter.SipMsg.set_global_address\n", APP_NAME);
         return NULL;
         return NULL;
     }
     }
     jStrParam = (*env)->NewStringUTF(env, (msg->set_global_address.len <= 0 || msg->set_global_address.s == NULL) ? "" : msg->set_global_address.s);
     jStrParam = (*env)->NewStringUTF(env, (msg->set_global_address.len <= 0 || msg->set_global_address.s == NULL) ? "" : msg->set_global_address.s);
@@ -308,7 +308,7 @@ jobject *fill_sipmsg_object(JNIEnv *env, struct sip_msg *msg)
     if (!fid)
     if (!fid)
     {
     {
 	(*env)->ExceptionClear(env);
 	(*env)->ExceptionClear(env);
-        LM_ERR("Can't find symbol org.siprouter.SipMsg.set_global_port\n");
+        LM_ERR("%s: Can't find symbol org.siprouter.SipMsg.set_global_port\n", APP_NAME);
         return NULL;
         return NULL;
     }
     }
     jStrParam = (*env)->NewStringUTF(env, (msg->set_global_port.len <= 0 || msg->set_global_port.s == NULL) ? "" : msg->set_global_port.s);
     jStrParam = (*env)->NewStringUTF(env, (msg->set_global_port.len <= 0 || msg->set_global_port.s == NULL) ? "" : msg->set_global_port.s);

+ 28 - 28
modules/app_java/java_native_methods.c

@@ -304,7 +304,7 @@ JNIEXPORT jint JNICALL Java_org_siprouter_NativeMethods_KamExec(JNIEnv *jenv, jo
 
 
     if (jfname == NULL)
     if (jfname == NULL)
     {
     {
-	LM_ERR("app_java: KamExec() required at least 1 argument (function name)\n");
+	LM_ERR("%s: KamExec() required at least 1 argument (function name)\n", APP_NAME);
 	return -1;
 	return -1;
     }
     }
 
 
@@ -369,14 +369,14 @@ int KamExec(JNIEnv *jenv, char *fname, int argc, char **argv)
     fexport = find_export_record(fname, argc, 0, &mod_ver);
     fexport = find_export_record(fname, argc, 0, &mod_ver);
     if (!fexport)
     if (!fexport)
     {
     {
-	LM_ERR("app_java: KamExec(): '%s' - no such function\n", fname);
+	LM_ERR("%s: KamExec(): '%s' - no such function\n", APP_NAME, fname);
         return -1;
         return -1;
     }
     }
 
 
     /* check fixups */
     /* check fixups */
     if (force_cmd_exec == 0 && fexport->fixup != NULL && fexport->free_fixup == NULL)
     if (force_cmd_exec == 0 && fexport->fixup != NULL && fexport->free_fixup == NULL)
     {
     {
-        LM_ERR("app_java: KamExec(): function '%s' has fixup - cannot be used\n", fname);
+        LM_ERR("%s: KamExec(): function '%s' has fixup - cannot be used\n", APP_NAME, fname);
 	return -1;
 	return -1;
     }
     }
 
 
@@ -391,7 +391,7 @@ int KamExec(JNIEnv *jenv, char *fname, int argc, char **argv)
 	case 6:			mod_type = MODULE6_T;	break;
 	case 6:			mod_type = MODULE6_T;	break;
 	case VAR_PARAM_NO:	mod_type = MODULEX_T;	break;
 	case VAR_PARAM_NO:	mod_type = MODULEX_T;	break;
 	default:
 	default:
-		LM_ERR("app_java: KamExec(): unknown/bad definition for function '%s' (%d params)\n", fname, fexport->param_no);
+		LM_ERR("%s: KamExec(): unknown/bad definition for function '%s' (%d params)\n", APP_NAME, fname, fexport->param_no);
 		return -1;
 		return -1;
     }
     }
 
 
@@ -409,7 +409,7 @@ int KamExec(JNIEnv *jenv, char *fname, int argc, char **argv)
 
 
     if (!act)
     if (!act)
     {
     {
-	LM_ERR("app_java: KamExec(): action structure couldn't be created\n");
+	LM_ERR("%s: KamExec(): action structure couldn't be created\n", APP_NAME);
 	return -1;
 	return -1;
     }
     }
 
 
@@ -422,7 +422,7 @@ int KamExec(JNIEnv *jenv, char *fname, int argc, char **argv)
             rval = fexport->fixup(0, 0);
             rval = fexport->fixup(0, 0);
             if (rval < 0)
             if (rval < 0)
 	    {
 	    {
-		LM_ERR("app_java: KamExec(): (no params) Error in fixup (0) for '%s'\n", fname);
+		LM_ERR("%s: KamExec(): (no params) Error in fixup (0) for '%s'\n", APP_NAME, fname);
                 return -1;
                 return -1;
             }
             }
         }
         }
@@ -435,7 +435,7 @@ int KamExec(JNIEnv *jenv, char *fname, int argc, char **argv)
         	    rval = fexport->fixup(&(act->val[i+2].u.data), i+1);
         	    rval = fexport->fixup(&(act->val[i+2].u.data), i+1);
         	    if (rval < 0)
         	    if (rval < 0)
 		    {
 		    {
-			LM_ERR("app_java: KamExec(): (params: %d) Error in fixup (%d) for '%s'\n", argc, i+1, fname);
+			LM_ERR("%s: KamExec(): (params: %d) Error in fixup (%d) for '%s'\n", APP_NAME, argc, i+1, fname);
             		return -1;
             		return -1;
         	    }
         	    }
         	    act->val[i+2].type = MODFIXUP_ST;
         	    act->val[i+2].type = MODFIXUP_ST;
@@ -538,7 +538,7 @@ JNIEXPORT jstring JNICALL Java_org_siprouter_SipMsg_getStatus(JNIEnv *jenv, jobj
 
 
     if ((msg->first_line).type != SIP_REQUEST)
     if ((msg->first_line).type != SIP_REQUEST)
     {
     {
-	LM_ERR("app_java: getStatus(): Unable to fetch status. Error: Not a request message - no method available.\n");
+	LM_ERR("%s: getStatus(): Unable to fetch status. Error: Not a request message - no method available.\n", APP_NAME);
         return NULL;
         return NULL;
     }
     }
 
 
@@ -571,7 +571,7 @@ JNIEXPORT jstring JNICALL Java_org_siprouter_SipMsg_getRURI(JNIEnv *jenv, jobjec
 
 
     if ((msg->first_line).type != SIP_REQUEST)
     if ((msg->first_line).type != SIP_REQUEST)
     {
     {
-	LM_ERR("app_java: getRURI(): Unable to fetch ruri. Error: Not a request message - no method available.\n");
+	LM_ERR("%s: getRURI(): Unable to fetch ruri. Error: Not a request message - no method available.\n", APP_NAME);
         return NULL;
         return NULL;
     }
     }
 
 
@@ -624,7 +624,7 @@ JNIEXPORT jobject JNICALL Java_org_siprouter_SipMsg_getSrcAddress(JNIEnv *jenv,
     ip = ip_addr2a(&msg->rcv.src_ip);
     ip = ip_addr2a(&msg->rcv.src_ip);
     if (!ip)
     if (!ip)
     {
     {
-	LM_ERR("app_java: getSrcAddress(): Unable to fetch src ip address.\n");
+	LM_ERR("%s: getSrcAddress(): Unable to fetch src ip address.\n", APP_NAME);
 	return NULL;
 	return NULL;
     }
     }
     jip = (*jenv)->NewStringUTF(jenv, ip);
     jip = (*jenv)->NewStringUTF(jenv, ip);
@@ -637,7 +637,7 @@ JNIEXPORT jobject JNICALL Java_org_siprouter_SipMsg_getSrcAddress(JNIEnv *jenv,
     port = msg->rcv.src_port;
     port = msg->rcv.src_port;
     if (port == 0x0)
     if (port == 0x0)
     {
     {
-	LM_ERR("app_java: getSrcAddress(): Unable to fetch src port.\n");
+	LM_ERR("%s: getSrcAddress(): Unable to fetch src port.\n", APP_NAME);
 	return NULL;
 	return NULL;
     }
     }
 
 
@@ -689,7 +689,7 @@ JNIEXPORT jobject JNICALL Java_org_siprouter_SipMsg_getDstAddress(JNIEnv *jenv,
     ip = ip_addr2a(&msg->rcv.dst_ip);
     ip = ip_addr2a(&msg->rcv.dst_ip);
     if (!ip)
     if (!ip)
     {
     {
-	LM_ERR("app_java: getDstAddress(): Unable to fetch src ip address.\n");
+	LM_ERR("%s: getDstAddress(): Unable to fetch src ip address.\n", APP_NAME);
 	return NULL;
 	return NULL;
     }
     }
     jip = (*jenv)->NewStringUTF(jenv, ip);
     jip = (*jenv)->NewStringUTF(jenv, ip);
@@ -702,7 +702,7 @@ JNIEXPORT jobject JNICALL Java_org_siprouter_SipMsg_getDstAddress(JNIEnv *jenv,
     port = msg->rcv.dst_port;
     port = msg->rcv.dst_port;
     if (port == 0x0)
     if (port == 0x0)
     {
     {
-	LM_ERR("app_java: getDstAddress(): Unable to fetch src port.\n");
+	LM_ERR("%s: getDstAddress(): Unable to fetch src port.\n", APP_NAME);
 	return NULL;
 	return NULL;
     }
     }
 
 
@@ -733,7 +733,7 @@ JNIEXPORT jstring JNICALL Java_org_siprouter_SipMsg_getBuffer(JNIEnv *jenv, jobj
 
 
     if ((msg->first_line).type != SIP_REQUEST)
     if ((msg->first_line).type != SIP_REQUEST)
     {
     {
-	LM_ERR("app_java: getRURI(): Unable to fetch ruri. Error: Not a request message - no method available.\n");
+	LM_ERR("%s: getRURI(): Unable to fetch ruri. Error: Not a request message - no method available.\n", APP_NAME);
         return NULL;
         return NULL;
     }
     }
 
 
@@ -792,7 +792,7 @@ jint cf_seturi(JNIEnv *jenv, jobject this, jstring juri, char *fname)
 
 
     if (!msg)
     if (!msg)
     {
     {
-	LM_ERR("app_java: %s: Can't process, msg=NULL\n", fname);
+	LM_ERR("%s: %s: Can't process, msg=NULL\n", APP_NAME, fname);
 	return -1;
 	return -1;
     }
     }
 
 
@@ -833,7 +833,7 @@ JNIEXPORT jint JNICALL Java_org_siprouter_CoreMethods_add_1local_1rport(JNIEnv *
 
 
     if (!msg)
     if (!msg)
     {
     {
-	LM_ERR("app_java: add_local_rport: Can't process, msg=NULL\n");
+	LM_ERR("%s: add_local_rport: Can't process, msg=NULL\n", APP_NAME);
 	return -1;
 	return -1;
     }
     }
 
 
@@ -863,7 +863,7 @@ JNIEXPORT jint JNICALL Java_org_siprouter_CoreMethods_append_1branch(JNIEnv *jen
 
 
     if (!msg)
     if (!msg)
     {
     {
-	LM_ERR("app_java: append_branch: Can't process, msg=NULL\n");
+	LM_ERR("%s: append_branch: Can't process, msg=NULL\n", APP_NAME);
 	return -1;
 	return -1;
     }
     }
 
 
@@ -916,7 +916,7 @@ JNIEXPORT jint JNICALL Java_org_siprouter_CoreMethods_drop(JNIEnv *jenv, jobject
 
 
     if (!msg)
     if (!msg)
     {
     {
-	LM_ERR("app_java: drop: Can't process, msg=NULL\n");
+	LM_ERR("%s: drop: Can't process, msg=NULL\n", APP_NAME);
 	return -1;
 	return -1;
     }
     }
 
 
@@ -962,7 +962,7 @@ jint cf_force_rport(JNIEnv *jenv, jobject this, char *fname)
 
 
     if (!msg)
     if (!msg)
     {
     {
-	LM_ERR("app_java: %s: Can't process, msg=NULL\n", fname);
+	LM_ERR("%s: %s: Can't process, msg=NULL\n", APP_NAME, fname);
 	return -1;
 	return -1;
     }
     }
 
 
@@ -992,21 +992,21 @@ JNIEXPORT jint JNICALL Java_org_siprouter_CoreMethods_force_1send_1socket(JNIEnv
 
 
     if (!msg)
     if (!msg)
     {
     {
-	LM_ERR("app_java: force_send_socket: Can't process, msg=NULL\n");
+	LM_ERR("%s: force_send_socket: Can't process, msg=NULL\n", APP_NAME);
 	return -1;
 	return -1;
     }
     }
 
 
     nl = (struct name_lst *)pkg_malloc(sizeof(struct name_lst));
     nl = (struct name_lst *)pkg_malloc(sizeof(struct name_lst));
     if (!nl)
     if (!nl)
     {
     {
-	LM_ERR("app_java: force_send_socket: pkg_malloc() has failed. Not enough memory!\n");
+	LM_ERR("%s: force_send_socket: pkg_malloc() has failed. Not enough memory!\n", APP_NAME);
 	return -1;
 	return -1;
     }
     }
     
     
     si = (struct socket_id *)pkg_malloc(sizeof(struct socket_id));
     si = (struct socket_id *)pkg_malloc(sizeof(struct socket_id));
     if (!si)
     if (!si)
     {
     {
-	LM_ERR("app_java: force_send_socket: pkg_malloc() has failed. Not enough memory!\n");
+	LM_ERR("%s: force_send_socket: pkg_malloc() has failed. Not enough memory!\n", APP_NAME);
 	return -1;
 	return -1;
     }
     }
     
     
@@ -1060,7 +1060,7 @@ JNIEXPORT jint JNICALL Java_org_siprouter_CoreMethods_forward(JNIEnv *jenv, jobj
 
 
     if (!msg)
     if (!msg)
     {
     {
-	LM_ERR("app_java: forward: Can't process, msg=NULL\n");
+	LM_ERR("%s: forward: Can't process, msg=NULL\n", APP_NAME);
 	return -1;
 	return -1;
     }
     }
 
 
@@ -1108,7 +1108,7 @@ JNIEXPORT jboolean JNICALL Java_org_siprouter_CoreMethods_isflagset(JNIEnv *jenv
 {
 {
     if (!msg)
     if (!msg)
     {
     {
-	LM_ERR("app_java: isflagset: Can't process, msg=NULL\n");
+	LM_ERR("%s: isflagset: Can't process, msg=NULL\n", APP_NAME);
 	return -1;
 	return -1;
     }
     }
 
 
@@ -1126,7 +1126,7 @@ JNIEXPORT void JNICALL Java_org_siprouter_CoreMethods_setflag(JNIEnv *jenv, jobj
 {
 {
     if (!msg)
     if (!msg)
     {
     {
-	LM_ERR("app_java: setflag: Can't process, msg=NULL\n");
+	LM_ERR("%s: setflag: Can't process, msg=NULL\n", APP_NAME);
 	return;
 	return;
     }
     }
 
 
@@ -1144,7 +1144,7 @@ JNIEXPORT void JNICALL Java_org_siprouter_CoreMethods_resetflag(JNIEnv *jenv, jo
 {
 {
     if (!msg)
     if (!msg)
     {
     {
-	LM_ERR("app_java: resetflag: Can't process, msg=NULL\n");
+	LM_ERR("%s: resetflag: Can't process, msg=NULL\n", APP_NAME);
 	return;
 	return;
     }
     }
 
 
@@ -1167,7 +1167,7 @@ JNIEXPORT jint JNICALL Java_org_siprouter_CoreMethods_revert_1uri(JNIEnv *jenv,
 
 
     if (!msg)
     if (!msg)
     {
     {
-	LM_ERR("app_java: revert_uri: Can't process, msg=NULL\n");
+	LM_ERR("%s: revert_uri: Can't process, msg=NULL\n", APP_NAME);
 	return -1;
 	return -1;
     }
     }
 
 
@@ -1204,7 +1204,7 @@ JNIEXPORT jint JNICALL Java_org_siprouter_CoreMethods_route(JNIEnv *jenv, jobjec
 
 
     if (retval == -1)	// route index lookup failed.
     if (retval == -1)	// route index lookup failed.
     {
     {
-	LM_ERR("app_java: route: failed to find route name '%s'\n", ctarget);
+	LM_ERR("%s: route: failed to find route name '%s'\n", APP_NAME, ctarget);
 	(*jenv)->ReleaseStringUTFChars(jenv, jtarget, ctarget);
 	(*jenv)->ReleaseStringUTFChars(jenv, jtarget, ctarget);
 	return -1;
 	return -1;
     }
     }

+ 26 - 26
modules/app_java/java_sig_parser.c

@@ -46,7 +46,7 @@ int is_sig_allowed(char *s)
 
 
     if (!strcmp(s, " ") || !strcmp(s, "\n") || !strcmp(s, "\r") || !strcmp(s, "\t"))
     if (!strcmp(s, " ") || !strcmp(s, "\n") || !strcmp(s, "\r") || !strcmp(s, "\t"))
     {
     {
-	LM_ERR("signature error: '%s' contains whitespaces or any unparsable chars.\n", s);
+	LM_ERR("%s: signature error: '%s' contains whitespaces or any unparsable chars.\n", APP_NAME, s);
 	return 0;
 	return 0;
     }
     }
 
 
@@ -56,20 +56,20 @@ int is_sig_allowed(char *s)
     {
     {
 	if (!strcmp(s, "["))		// invalid signature modifier definition
 	if (!strcmp(s, "["))		// invalid signature modifier definition
 	{
 	{
-	    LM_ERR("signature error: '%s': no type of array specified.\n", s);
+	    LM_ERR("%s: signature error: '%s': no type of array specified.\n", APP_NAME, s);
 	    return 0;
 	    return 0;
 	}
 	}
 
 
 	if (!strcmp(s, "L"))		// invalid signature modifier definition
 	if (!strcmp(s, "L"))		// invalid signature modifier definition
 	{
 	{
-	    LM_ERR("signature error '%s': no object specified.\n", s);
+	    LM_ERR("%s: signature error '%s': no object specified.\n", APP_NAME, s);
 	    return 0;
 	    return 0;
 	}
 	}
 
 
 #ifndef JAVA_INV_SUPP_TYPE_VOID
 #ifndef JAVA_INV_SUPP_TYPE_VOID
 	if (!strcmp(s, "V"))
 	if (!strcmp(s, "V"))
 	{
 	{
-	    LM_ERR("signature error '%s': no object specified.\n", s);
+	    LM_ERR("%s: signature error '%s': no object specified.\n", APP_NAME, s);
 	    return 0;
 	    return 0;
 	}
 	}
 #endif
 #endif
@@ -80,7 +80,7 @@ int is_sig_allowed(char *s)
 #ifndef JAVA_INV_SUPP_TYPE_ARRAYS
 #ifndef JAVA_INV_SUPP_TYPE_ARRAYS
 	if (strcmp(s, "[") > 0)
 	if (strcmp(s, "[") > 0)
 	{
 	{
-	    LM_ERR("signature error: '%s' denotes array which isn't supported yet.\n", s);
+	    LM_ERR("%s: signature error: '%s' denotes array which isn't supported yet.\n", APP_NAME, s);
 	    return 0;
 	    return 0;
 	}
 	}
 #endif
 #endif
@@ -89,7 +89,7 @@ int is_sig_allowed(char *s)
 	if (strrchr(&s[0], 'L') > 0)
 	if (strrchr(&s[0], 'L') > 0)
 	{
 	{
 #ifndef JAVA_INV_SUPP_TYPE_OBJECTS
 #ifndef JAVA_INV_SUPP_TYPE_OBJECTS
-	    LM_ERR("signature error: '%s' denotes object which isn't supported yet.\n", s);
+	    LM_ERR("%s: signature error: '%s' denotes object which isn't supported yet.\n", APP_NAME, s);
 	    return 0;
 	    return 0;
 #else
 #else
 	    int f = 0;
 	    int f = 0;
@@ -131,7 +131,7 @@ int is_sig_allowed(char *s)
 #endif
 #endif
 	    if (f == 0)
 	    if (f == 0)
 	    {
 	    {
-		LM_ERR("signature '%s' isn't supported yet.\n", s);
+		LM_ERR("%s: signature '%s' isn't supported yet.\n", APP_NAME, s);
 		return 0;
 		return 0;
 	    }
 	    }
 #endif
 #endif
@@ -184,19 +184,19 @@ jvalue *get_value_by_sig_type(char *sig, char *pval)
     ret = (jvalue *)pkg_malloc(sizeof(jvalue));
     ret = (jvalue *)pkg_malloc(sizeof(jvalue));
     if (!ret)
     if (!ret)
     {
     {
-	LM_ERR("pkg_malloc() has failed. Not enouph memory!\n");
+	LM_ERR("%s: pkg_malloc() has failed. Not enouph memory!\n", APP_NAME);
 	return NULL;
 	return NULL;
     }
     }
 
 
     if (sig == NULL || strlen(sig) <= 0)
     if (sig == NULL || strlen(sig) <= 0)
     {
     {
-	LM_ERR("app_java: Can't process empty or NULL signature.\n");
+	LM_ERR("%s: Can't process empty or NULL signature.\n", APP_NAME);
 	pkg_free(ret);
 	pkg_free(ret);
 	return NULL;
 	return NULL;
     }
     }
     if (pval == NULL || strlen(pval) <= 0)
     if (pval == NULL || strlen(pval) <= 0)
     {
     {
-	LM_ERR("app_java: Can't process empty or NULL parameter value.\n");
+	LM_ERR("%s: Can't process empty or NULL parameter value.\n", APP_NAME);
 	pkg_free(ret);
 	pkg_free(ret);
 	return NULL;
 	return NULL;
     }
     }
@@ -219,7 +219,7 @@ jvalue *get_value_by_sig_type(char *sig, char *pval)
 		(*ret).z = (jboolean)JNI_FALSE;
 		(*ret).z = (jboolean)JNI_FALSE;
 	    else
 	    else
 	    {
 	    {
-    		LM_ERR("app_java: Can't cast '%s' to type '%s'.\n", pval, sig);
+    		LM_ERR("%s: Can't cast '%s' to type '%s'.\n", APP_NAME, pval, sig);
 		pkg_free(ret);
 		pkg_free(ret);
 		return NULL;
 		return NULL;
 	    }
 	    }
@@ -237,13 +237,13 @@ jvalue *get_value_by_sig_type(char *sig, char *pval)
 	    sscanf(pval, "%x", &siptr);
 	    sscanf(pval, "%x", &siptr);
 	    if (siptr == 0 && errno != 0)
 	    if (siptr == 0 && errno != 0)
 	    {
 	    {
-		LM_ERR("app_java: Can't cast '%s' to type '%s'. Error: %s.\n", pval, sig, get_conv_err_str(errno));
+		LM_ERR("%s: Can't cast '%s' to type '%s'. Error: %s.\n", APP_NAME, pval, sig, get_conv_err_str(errno));
 		pkg_free(ret);
 		pkg_free(ret);
                 return NULL;
                 return NULL;
 	    }
 	    }
             if (siptr < SCHAR_MAX || siptr > SCHAR_MAX)
             if (siptr < SCHAR_MAX || siptr > SCHAR_MAX)
 	    {
 	    {
-		LM_ERR("app_java: Can't cast '%s' to type '%s'. Reason: overflow.", pval, sig);
+		LM_ERR("%s: Can't cast '%s' to type '%s'. Reason: overflow.", APP_NAME, pval, sig);
 		pkg_free(ret);
 		pkg_free(ret);
                 return NULL;
                 return NULL;
 	    }
 	    }
@@ -261,13 +261,13 @@ jvalue *get_value_by_sig_type(char *sig, char *pval)
 	    sscanf(pval, "%c", &scptr);
 	    sscanf(pval, "%c", &scptr);
 	    if (scptr == 0 && errno != 0)
 	    if (scptr == 0 && errno != 0)
 	    {
 	    {
-		LM_ERR("app_java: Can't cast '%s' to type '%s'. Error: %s.\n", pval, sig, get_conv_err_str(errno));
+		LM_ERR("%s: Can't cast '%s' to type '%s'. Error: %s.\n", APP_NAME, pval, sig, get_conv_err_str(errno));
 		pkg_free(ret);
 		pkg_free(ret);
                 return NULL;
                 return NULL;
 	    }
 	    }
             if (scptr < CHAR_MIN || scptr > CHAR_MAX)	// overflow
             if (scptr < CHAR_MIN || scptr > CHAR_MAX)	// overflow
 	    {
 	    {
-		LM_ERR("app_java: Can't cast '%s' to type '%s'. Reason: overflow.", pval, sig);
+		LM_ERR("%s: Can't cast '%s' to type '%s'. Reason: overflow.", APP_NAME, pval, sig);
 		pkg_free(ret);
 		pkg_free(ret);
                 return NULL;
                 return NULL;
 	    }
 	    }
@@ -285,13 +285,13 @@ jvalue *get_value_by_sig_type(char *sig, char *pval)
 	    sdptr = (double)strtod(pval, &endptr);
 	    sdptr = (double)strtod(pval, &endptr);
 	    if ((sdptr == 0 && errno != 0) || (pval == endptr))
 	    if ((sdptr == 0 && errno != 0) || (pval == endptr))
 	    {
 	    {
-		LM_ERR("app_java: Can't cast '%s' to type '%s'. Error: %s.\n", pval, sig, get_conv_err_str(errno));
+		LM_ERR("%s: Can't cast '%s' to type '%s'. Error: %s.\n", APP_NAME, pval, sig, get_conv_err_str(errno));
 		pkg_free(ret);
 		pkg_free(ret);
                 return NULL;
                 return NULL;
 	    }
 	    }
             if (sdptr < LLONG_MIN || sdptr > LLONG_MAX)	// overflow
             if (sdptr < LLONG_MIN || sdptr > LLONG_MAX)	// overflow
 	    {
 	    {
-		LM_ERR("app_java: Can't cast '%s' to type '%s'. Reason: overflow.", pval, sig);
+		LM_ERR("%s: Can't cast '%s' to type '%s'. Reason: overflow.", APP_NAME, pval, sig);
 		pkg_free(ret);
 		pkg_free(ret);
                 return NULL;
                 return NULL;
 	    }
 	    }
@@ -309,13 +309,13 @@ jvalue *get_value_by_sig_type(char *sig, char *pval)
 	    sfptr = (float)strtof(pval, &endptr);
 	    sfptr = (float)strtof(pval, &endptr);
 	    if ((sfptr == 0 && errno != 0) || (pval == endptr))
 	    if ((sfptr == 0 && errno != 0) || (pval == endptr))
 	    {
 	    {
-		LM_ERR("app_java: Can't cast '%s' to type '%s'. Error: %s.\n", pval, sig, get_conv_err_str(errno));
+		LM_ERR("%s: Can't cast '%s' to type '%s'. Error: %s.\n", APP_NAME, pval, sig, get_conv_err_str(errno));
 		pkg_free(ret);
 		pkg_free(ret);
                 return NULL;
                 return NULL;
 	    }
 	    }
             if (sfptr < FLT_MIN || sfptr > FLT_MAX)	// overflow
             if (sfptr < FLT_MIN || sfptr > FLT_MAX)	// overflow
 	    {
 	    {
-		LM_ERR("app_java: Can't cast '%s' to type '%s'. Reason: overflow.", pval, sig);
+		LM_ERR("%s: Can't cast '%s' to type '%s'. Reason: overflow.", APP_NAME, pval, sig);
 		pkg_free(ret);
 		pkg_free(ret);
                 return NULL;
                 return NULL;
 	    }
 	    }
@@ -333,13 +333,13 @@ jvalue *get_value_by_sig_type(char *sig, char *pval)
 	    slptr = strtol(pval, &endptr, 10);
 	    slptr = strtol(pval, &endptr, 10);
 	    if ((slptr == 0 && errno != 0) || (pval == endptr))
 	    if ((slptr == 0 && errno != 0) || (pval == endptr))
 	    {
 	    {
-		LM_ERR("app_java: Can't cast '%s' to type '%s'. Error: %s.\n", pval, sig, get_conv_err_str(errno));
+		LM_ERR("%s: Can't cast '%s' to type '%s'. Error: %s.\n", APP_NAME, pval, sig, get_conv_err_str(errno));
 		pkg_free(ret);
 		pkg_free(ret);
                 return NULL;
                 return NULL;
 	    }
 	    }
 	    if (slptr < INT_MIN || slptr > INT_MAX)	// overflow
 	    if (slptr < INT_MIN || slptr > INT_MAX)	// overflow
 	    {
 	    {
-		LM_ERR("app_java: Can't cast '%s' to type '%s'. Reason: overflow.", pval, sig);
+		LM_ERR("%s: Can't cast '%s' to type '%s'. Reason: overflow.", APP_NAME, pval, sig);
 		pkg_free(ret);
 		pkg_free(ret);
                 return NULL;
                 return NULL;
 	    }
 	    }
@@ -357,13 +357,13 @@ jvalue *get_value_by_sig_type(char *sig, char *pval)
 	    slptr = (long)strtol(pval, &endptr, 10);
 	    slptr = (long)strtol(pval, &endptr, 10);
 	    if ((slptr == 0 && errno != 0) || (pval == endptr))
 	    if ((slptr == 0 && errno != 0) || (pval == endptr))
 	    {
 	    {
-		LM_ERR("app_java: Can't cast '%s' to type '%s'. Error: %s.\n", pval, sig, get_conv_err_str(errno));
+		LM_ERR("%s: Can't cast '%s' to type '%s'. Error: %s.\n", APP_NAME, pval, sig, get_conv_err_str(errno));
 		pkg_free(ret);
 		pkg_free(ret);
                 return NULL;
                 return NULL;
 	    }
 	    }
 	    if (slptr < LONG_MIN || slptr > LONG_MAX)	// overflow
 	    if (slptr < LONG_MIN || slptr > LONG_MAX)	// overflow
 	    {
 	    {
-		LM_ERR("app_java: Can't cast '%s' to type '%s'. Reason: overflow.", pval, sig);
+		LM_ERR("%s: Can't cast '%s' to type '%s'. Reason: overflow.", APP_NAME, pval, sig);
 		pkg_free(ret);
 		pkg_free(ret);
                 return NULL;
                 return NULL;
 	    }
 	    }
@@ -381,13 +381,13 @@ jvalue *get_value_by_sig_type(char *sig, char *pval)
 	    ssptr = (short)strtod(pval, &endptr);
 	    ssptr = (short)strtod(pval, &endptr);
 	    if ((ssptr == 0 && errno != 0) || (pval == endptr))
 	    if ((ssptr == 0 && errno != 0) || (pval == endptr))
 	    {
 	    {
-		LM_ERR("app_java: Can't cast '%s' to type '%s'. Error: %s.\n", pval, sig, get_conv_err_str(errno));
+		LM_ERR("%s: Can't cast '%s' to type '%s'. Error: %s.\n", APP_NAME, pval, sig, get_conv_err_str(errno));
 		pkg_free(ret);
 		pkg_free(ret);
                 return NULL;
                 return NULL;
 	    }
 	    }
 	    if (ssptr < SHRT_MIN || ssptr > SHRT_MAX)	// overflow
 	    if (ssptr < SHRT_MIN || ssptr > SHRT_MAX)	// overflow
 	    {
 	    {
-		LM_ERR("app_java: Can't cast '%s' to type '%s'. Reason: overflow.", pval, sig);
+		LM_ERR("%s: Can't cast '%s' to type '%s'. Reason: overflow.", APP_NAME, pval, sig);
 		pkg_free(ret);
 		pkg_free(ret);
                 return NULL;
                 return NULL;
 	    }
 	    }
@@ -429,7 +429,7 @@ jvalue *get_value_by_sig_type(char *sig, char *pval)
     else
     else
     {
     {
 	// unknown sig
 	// unknown sig
-	LM_ERR("app_java: Can't cast '%s' to signature '%s'\n", pval, sig);
+	LM_ERR("%s: Can't cast '%s' to signature '%s'\n", APP_NAME, pval, sig);
 	pkg_free(ret);
 	pkg_free(ret);
 	return NULL;
 	return NULL;
     }
     }

+ 8 - 8
modules/app_java/java_support.c

@@ -171,7 +171,7 @@ void handle_exception(void)
 	(*env)->DeleteLocalRef(env, exception);
 	(*env)->DeleteLocalRef(env, exception);
     }
     }
 
 
-    LM_ERR("Exception:\n%s\n", error_msg == NULL ? "(no info)" : error_msg);
+    LM_ERR("%s: Exception:\n%s\n", APP_NAME, error_msg == NULL ? "(no info)" : error_msg);
 
 
 }
 }
 
 
@@ -194,25 +194,25 @@ void handle_VM_init_failure(int res)
     switch(res)
     switch(res)
     {
     {
 	    case -1:
 	    case -1:
-		LM_ERR("Couldn't initialize Java VM: unknown error\n");
+		LM_ERR("%s: Couldn't initialize Java VM: unknown error\n", APP_NAME);
 		break;
 		break;
 	    case -2:
 	    case -2:
-		LM_ERR("Couldn't initialize Java VM: thread detached from the VM\n");
+		LM_ERR("%s: Couldn't initialize Java VM: thread detached from the VM\n", APP_NAME);
 	        break;
 	        break;
 	    case -3:
 	    case -3:
-		LM_ERR("Couldn't initialize Java VM: JNI version error\n");
+		LM_ERR("%s: Couldn't initialize Java VM: JNI version error\n", APP_NAME);
 		break;
 		break;
 	    case -4:
 	    case -4:
-		LM_ERR("Couldn't initialize Java VM: not enough memory\n");
+		LM_ERR("%s: Couldn't initialize Java VM: not enough memory\n", APP_NAME);
 		break;
 		break;
 	    case -5:
 	    case -5:
-		LM_ERR("Couldn't initialize Java VM: VM already created\n");
+		LM_ERR("%s: Couldn't initialize Java VM: VM already created\n", APP_NAME);
 		break;
 		break;
 	    case -6:
 	    case -6:
-		LM_ERR("Couldn't initialize Java VM: invalid arguments\n");
+		LM_ERR("%s: Couldn't initialize Java VM: invalid arguments\n", APP_NAME);
 		break;
 		break;
 	    default:
 	    default:
-		LM_ERR("Couldn't initialize Java VM. Error code: %d\n", res);
+		LM_ERR("%s: Couldn't initialize Java VM. Error code: %d\n", APP_NAME, res);
 		break;
 		break;
     }
     }
 }
 }

+ 2 - 2
modules/app_java/utils.c

@@ -49,7 +49,7 @@ char **split(char *str, char *sep)
     buf = (char **)pkg_malloc(sizeof(char *));
     buf = (char **)pkg_malloc(sizeof(char *));
     if (!buf)
     if (!buf)
     {
     {
-	LM_ERR("pkg_malloc() has failed. Not enough memory!\n");
+	LM_ERR("%s: pkg_malloc() has failed. Not enough memory!\n", APP_NAME);
 	return NULL;
 	return NULL;
     }
     }
     memset(&buf, 0, sizeof(char *));
     memset(&buf, 0, sizeof(char *));
@@ -75,7 +75,7 @@ char **split(char *str, char *sep)
 	buf = (char **)pkg_realloc(buf, (i+1) * sizeof(char *));
 	buf = (char **)pkg_realloc(buf, (i+1) * sizeof(char *));
 	if (!buf)
 	if (!buf)
 	{
 	{
-	    LM_ERR("pkg_realloc() has failed. Not enough memory!\n");
+	    LM_ERR("%s: pkg_realloc() has failed. Not enough memory!\n", APP_NAME);
 	    return NULL;
 	    return NULL;
 	}
 	}
         buf[i] = strdup(token);
         buf[i] = strdup(token);

+ 24 - 8
modules/app_perl/README

@@ -28,6 +28,7 @@ Bastian Friedrich
               5.1. filename (string)
               5.1. filename (string)
               5.2. modpath (string)
               5.2. modpath (string)
               5.3. reset_cycles (int)
               5.3. reset_cycles (int)
+              5.4. perl_destroy_func (string)
 
 
         6. Functions
         6. Functions
 
 
@@ -194,10 +195,11 @@ Bastian Friedrich
    1.1. Set filename parameter
    1.1. Set filename parameter
    1.2. Set modpath parameter
    1.2. Set modpath parameter
    1.3. Set reset_cycles parameter
    1.3. Set reset_cycles parameter
-   1.4. perl_exec_simple() usage
-   1.5. perl_exec() usage
-   1.6. app_perl.set_reset_cycles usage
-   1.7. app_perl.get_reset_cycles usage
+   1.4. Set perl_destroy_func parameter
+   1.5. perl_exec_simple() usage
+   1.6. perl_exec() usage
+   1.7. app_perl.set_reset_cycles usage
+   1.8. app_perl.get_reset_cycles usage
 
 
 Chapter 1. Admin Guide
 Chapter 1. Admin Guide
 
 
@@ -216,6 +218,7 @@ Chapter 1. Admin Guide
         5.1. filename (string)
         5.1. filename (string)
         5.2. modpath (string)
         5.2. modpath (string)
         5.3. reset_cycles (int)
         5.3. reset_cycles (int)
+        5.4. perl_destroy_func (string)
 
 
    6. Functions
    6. Functions
 
 
@@ -335,6 +338,7 @@ if (perl_exec("ldap_alias")) {
    5.1. filename (string)
    5.1. filename (string)
    5.2. modpath (string)
    5.2. modpath (string)
    5.3. reset_cycles (int)
    5.3. reset_cycles (int)
+   5.4. perl_destroy_func (string)
 
 
 5.1. filename (string)
 5.1. filename (string)
 
 
@@ -383,6 +387,18 @@ modparam("app_perl", "modpath", "/usr/local/lib/kamailio/perl/")
 modparam("app_perl", "reset_cycles", 100000)
 modparam("app_perl", "reset_cycles", 100000)
 ...
 ...
 
 
+5.4. perl_destroy_func (string)
+
+   The name of Perl function to be executed before the interpreter is
+   re-initialized (reset -- see reset_cycles parameter) at runtime. This
+   could be useful to clean global variables or file descriptors from the
+   Perl script.
+
+   Example 1.4. Set perl_destroy_func parameter
+...
+modparam("app_perl", "perl_destroy_func", "my_perl_destroy")
+...
+
 6. Functions
 6. Functions
 
 
    6.1. perl_exec_simple(func, [param])
    6.1. perl_exec_simple(func, [param])
@@ -401,7 +417,7 @@ modparam("app_perl", "reset_cycles", 100000)
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
    ONREPLY_ROUTE and BRANCH_ROUTE.
    ONREPLY_ROUTE and BRANCH_ROUTE.
 
 
-   Example 1.4. perl_exec_simple() usage
+   Example 1.5. perl_exec_simple() usage
 ...
 ...
 if (method=="INVITE") {
 if (method=="INVITE") {
         perl_exec_simple("dosomething", "on invite messages");
         perl_exec_simple("dosomething", "on invite messages");
@@ -420,7 +436,7 @@ if (method=="INVITE") {
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
    ONREPLY_ROUTE and BRANCH_ROUTE.
    ONREPLY_ROUTE and BRANCH_ROUTE.
 
 
-   Example 1.5. perl_exec() usage
+   Example 1.6. perl_exec() usage
 ...
 ...
 if (perl_exec("ldapalias")) {
 if (perl_exec("ldapalias")) {
         ...
         ...
@@ -437,7 +453,7 @@ if (perl_exec("ldapalias")) {
    Set the value of the reset_cycle. The command has one integer
    Set the value of the reset_cycle. The command has one integer
    parameter.
    parameter.
 
 
-   Example 1.6. app_perl.set_reset_cycles usage
+   Example 1.7. app_perl.set_reset_cycles usage
 ...
 ...
 kamcmd app_perl.set_reset_cycles 20000
 kamcmd app_perl.set_reset_cycles 20000
 ...
 ...
@@ -446,7 +462,7 @@ kamcmd app_perl.set_reset_cycles 20000
 
 
    Return the value of the reset_cycle.
    Return the value of the reset_cycle.
 
 
-   Example 1.7. app_perl.get_reset_cycles usage
+   Example 1.8. app_perl.get_reset_cycles usage
 ...
 ...
 kamcmd app_perl.get_reset_cycles
 kamcmd app_perl.get_reset_cycles
 ...
 ...

+ 9 - 0
modules/app_perl/app_perl_mod.c

@@ -62,6 +62,10 @@ char *filename = NULL;
  * installed */
  * installed */
 char *modpath = NULL;
 char *modpath = NULL;
 
 
+/* Function to be called before perl interpreter instance is destroyed
+ * when attempting reinit */
+static char *perl_destroy_func = NULL;
+
 /* Allow unsafe module functions - functions with fixups. This will create
 /* Allow unsafe module functions - functions with fixups. This will create
  * memory leaks, the variable thus is not documented! */
  * memory leaks, the variable thus is not documented! */
 int unsafemodfnc = 0;
 int unsafemodfnc = 0;
@@ -128,6 +132,7 @@ static param_export_t params[] = {
 	{"modpath", STR_PARAM, &modpath},
 	{"modpath", STR_PARAM, &modpath},
 	{"unsafemodfnc", INT_PARAM, &unsafemodfnc},
 	{"unsafemodfnc", INT_PARAM, &unsafemodfnc},
 	{"reset_cycles", INT_PARAM, &_ap_reset_cycles_init},
 	{"reset_cycles", INT_PARAM, &_ap_reset_cycles_init},
+	{"perl_destroy_func",  STR_PARAM, &perl_destroy_func},
 	{ 0, 0, 0 }
 	{ 0, 0, 0 }
 };
 };
 
 
@@ -426,6 +431,7 @@ int app_perl_reset_interpreter(void)
 {
 {
 	struct timeval t1;
 	struct timeval t1;
 	struct timeval t2;
 	struct timeval t2;
+	char *args[] = { NULL };
 
 
 	if(*_ap_reset_cycles==0)
 	if(*_ap_reset_cycles==0)
 		return 0;
 		return 0;
@@ -437,6 +443,9 @@ int app_perl_reset_interpreter(void)
 	if(_ap_exec_cycles<=*_ap_reset_cycles)
 	if(_ap_exec_cycles<=*_ap_reset_cycles)
 		return 0;
 		return 0;
 
 
+	if(perl_destroy_func)
+		call_argv(perl_destroy_func, G_DISCARD | G_NOARGS, args);
+
 	gettimeofday(&t1, NULL);
 	gettimeofday(&t1, NULL);
 	if (perl_reload()<0) {
 	if (perl_reload()<0) {
 		LM_ERR("perl interpreter cannot be reset [%d/%d]\n",
 		LM_ERR("perl interpreter cannot be reset [%d/%d]\n",

+ 19 - 0
modules/app_perl/doc/app_perl_admin.xml

@@ -220,6 +220,25 @@ modparam("app_perl", "reset_cycles", 100000)
 </programlisting>
 </programlisting>
 			</example>
 			</example>
 		</section>
 		</section>
+
+		<section id="app_perl.p.perl_destroy_func">
+			<title><varname>perl_destroy_func</varname> (string)</title>
+			<para>
+			The name of Perl function to be executed before the interpreter is
+			re-initialized (reset -- see reset_cycles parameter) at runtime.
+			This could be useful to clean global variables or file descriptors
+			from the Perl script.
+			</para>
+			<example>
+			<title>Set <varname>perl_destroy_func</varname> parameter</title>
+			<programlisting format="linespecific">
+...
+modparam("app_perl", "perl_destroy_func", "my_perl_destroy")
+...
+</programlisting>
+			</example>
+		</section>
+
 	</section>
 	</section>
 
 
 	<section>
 	<section>

+ 19 - 9
modules/auth_db/authorize.c

@@ -223,10 +223,10 @@ static int generate_avps(struct sip_msg* msg, db1_res_t* db_res)
 
 
 
 
 /*
 /*
- * Authorize digest credentials
+ * Authorize digest credentials and set the pointer to used hdr
  */
  */
-static int digest_authenticate(struct sip_msg* msg, str *realm,
-				str *table, hdr_types_t hftype, str *method)
+static int digest_authenticate_hdr(sip_msg_t* msg, str *realm,
+				str *table, hdr_types_t hftype, str *method, hdr_field_t **ahdr)
 {
 {
 	char ha1[256];
 	char ha1[256];
 	int res;
 	int res;
@@ -277,6 +277,7 @@ static int digest_authenticate(struct sip_msg* msg, str *realm,
 	}
 	}
 
 
 	cred = (auth_body_t*)h->parsed;
 	cred = (auth_body_t*)h->parsed;
+	if(ahdr!=NULL) *ahdr = h;
 
 
 	res = get_ha1(&cred->digest.username, realm, table, ha1, &result);
 	res = get_ha1(&cred->digest.username, realm, table, ha1, &result);
 	if (res < 0) {
 	if (res < 0) {
@@ -315,6 +316,15 @@ end:
 	return ret;
 	return ret;
 }
 }
 
 
+/*
+ * Authorize digest credentials
+ */
+static int digest_authenticate(sip_msg_t* msg, str *realm,
+				str *table, hdr_types_t hftype, str *method)
+{
+	return digest_authenticate_hdr(msg, realm, table, hftype, method, NULL);
+}
+
 
 
 /*
 /*
  * Authenticate using Proxy-Authorize header field
  * Authenticate using Proxy-Authorize header field
@@ -475,15 +485,15 @@ int auth_check(struct sip_msg* _m, char* _realm, char* _table, char *_flags)
 	LM_DBG("realm [%.*s] table [%.*s] flags [%d]\n", srealm.len, srealm.s,
 	LM_DBG("realm [%.*s] table [%.*s] flags [%d]\n", srealm.len, srealm.s,
 			stable.len,  stable.s, iflags);
 			stable.len,  stable.s, iflags);
 
 
+	hdr = NULL;
 	if(_m->REQ_METHOD==METHOD_REGISTER)
 	if(_m->REQ_METHOD==METHOD_REGISTER)
-		ret = digest_authenticate(_m, &srealm, &stable, HDR_AUTHORIZATION_T,
-						&_m->first_line.u.request.method);
+		ret = digest_authenticate_hdr(_m, &srealm, &stable, HDR_AUTHORIZATION_T,
+						&_m->first_line.u.request.method, &hdr);
 	else
 	else
-		ret = digest_authenticate(_m, &srealm, &stable, HDR_PROXYAUTH_T,
-						&_m->first_line.u.request.method);
+		ret = digest_authenticate_hdr(_m, &srealm, &stable, HDR_PROXYAUTH_T,
+						&_m->first_line.u.request.method, &hdr);
 
 
-	if(ret==AUTH_OK && (iflags&AUTH_CHECK_ID_F)) {
-		hdr = (_m->proxy_auth==0)?_m->authorization:_m->proxy_auth;
+	if(ret==AUTH_OK && hdr!=NULL && (iflags&AUTH_CHECK_ID_F)) {
 		srealm = ((auth_body_t*)(hdr->parsed))->digest.username.user;
 		srealm = ((auth_body_t*)(hdr->parsed))->digest.username.user;
 			
 			
 		if((furi=parse_from_uri(_m))==NULL)
 		if((furi=parse_from_uri(_m))==NULL)

+ 141 - 0
modules/cdp/cdp_rpc.c

@@ -0,0 +1,141 @@
+/*
+ * rpc.c
+ *
+ *  Created on: 27 May 2014
+ *      Author: jaybeepee
+ */
+#include "cdp_rpc.h"
+#include "peermanager.h"
+#include "peerstatemachine.h"
+#include "receiver.h"
+#include "../../str.h"
+#include "../../dprint.h"
+
+extern dp_config *config;
+extern peer_list_t *peer_list;
+extern gen_lock_t *peer_list_lock;
+extern char *dp_states[];
+
+static const char* cdp_rpc_disable_peer_doc[2] 	= 	{"disable diameter peer", 0 };
+static const char* cdp_rpc_enable_peer_doc[2] 	= 	{"enable diameter peer", 0 };
+static const char* cdp_rpc_list_peers_doc[2] 	= 	{"list diameter peers and their state", 0 };
+
+static void cdp_rpc_enable_peer(rpc_t* rpc, void* ctx)
+{
+	peer *cdp_peer;
+	str peer_fqdn;
+
+	if (rpc->scan(ctx, "S", &peer_fqdn) < 1) {
+		rpc->fault(ctx, 400, "required peer fqdn argument");
+		return;
+	}
+
+	cdp_peer = get_peer_by_fqdn(&peer_fqdn);
+	if (cdp_peer != NULL) {
+		LM_DBG("Enabling CDP Peer: [%.*s]\n", peer_fqdn.len, peer_fqdn.s);
+		cdp_peer->disabled = 0;
+		return;
+	}
+	rpc->fault(ctx, 400, "peer not found");
+	return;
+}
+
+static void cdp_rpc_disable_peer(rpc_t* rpc, void* ctx)
+{
+	peer *cdp_peer;
+	str peer_fqdn;
+
+	if (rpc->scan(ctx, "S", &peer_fqdn) < 1) {
+		rpc->fault(ctx, 400, "required peer fqdn argument");
+		return;
+	}
+	cdp_peer = get_peer_by_fqdn(&peer_fqdn);
+	if (cdp_peer != NULL) {
+		LM_DBG("Disabling CDP peer: [%.*s]\n", peer_fqdn.len, peer_fqdn.s);
+		cdp_peer->disabled = 1;
+		return;
+	}
+
+	rpc->fault(ctx, 400, "peer not found");
+	return;
+
+}
+
+static void cdp_rpc_list_peers(rpc_t* rpc, void* ctx)
+{
+    void *peers_header;
+    void *peers_container;
+    void *peerdetail_container;
+    void *peerapplication_container;
+    peer *i, *j;
+    int c;
+    char buf[100];
+
+    if (rpc->add(ctx, "{", &peers_header) < 0) {
+            rpc->fault(ctx, 500, "Internal error creating top rpc");
+            return;
+    }
+
+    if (rpc->struct_add(peers_header, "SSddddddd{",
+                            "Realm", &config->realm,
+                            "Identity", &config->identity,
+                            "Accept unknown peers", config->accept_unknown_peers,
+                            "Connect timeout", config->connect_timeout,
+                            "Transaction timeout", config->transaction_timeout,
+                            "Default auth session timeout", config->default_auth_session_timeout,
+                            "Queue length", config->queue_length,
+                            "Workers", config->workers,
+                            "Peer count", config->peers_cnt,
+                            "Peers", &peers_container) < 0) {
+            rpc->fault(ctx, 500, "Internal error creating peers header struct");
+            return;
+    }
+
+    lock_get(peer_list_lock);
+    i = peer_list->head;
+    while (i) {
+    		lock_get(i->lock);
+    		if (rpc->struct_add(peers_container, "S{",
+                            "FQDN", &i->fqdn,
+                            "Details", &peerdetail_container) < 0) {
+                    rpc->fault(ctx, 500, "Internal error creating peers container struct");
+                    lock_release(i->lock);
+                    return;
+            }
+            if (rpc->struct_add(peerdetail_container, "ssd",
+                    "State", dp_states[(int)i->state],
+                    "Disabled", i->disabled?"True":"False",
+            		"Last used", i->last_selected) < 0) {
+                    rpc->fault(ctx, 500, "Internal error creating peer detail container struct");
+                    lock_release(i->lock);
+                    return;
+            }
+            if (rpc->struct_add(peerdetail_container, "{", "Applications", &peerapplication_container) < 0) {
+            	rpc->fault(ctx, 500, "Internal error creating peer application container struct");
+            	lock_release(i->lock);
+            	return;
+            }
+
+            for (c = 0; c < i->applications_cnt; c++) {
+            	snprintf(buf, 100, "%d:%d", i->applications[c].id, i->applications[c].vendor);
+            	if (rpc->struct_add(peerapplication_container, "s",
+						"appid:vendorid", buf) < 0) {
+					rpc->fault(ctx, 500, "Internal error creating appid/vendorid information");
+					lock_release(i->lock);
+					return;
+				}
+            }
+            j=i;
+            i = i->next;
+            lock_release(j->lock);
+    }
+    lock_release(peer_list_lock);
+}
+
+rpc_export_t cdp_rpc[] = {
+	{"cdp.disable_peer",	cdp_rpc_disable_peer,   cdp_rpc_disable_peer_doc,   0},
+	{"cdp.enable_peer",   	cdp_rpc_enable_peer,   	cdp_rpc_enable_peer_doc,   	0},
+	{"cdp.list_peers",   	cdp_rpc_list_peers,   	cdp_rpc_list_peers_doc,   	0},
+	{0, 0, 0, 0}
+};
+

+ 16 - 0
modules/cdp/cdp_rpc.h

@@ -0,0 +1,16 @@
+/*
+ * rpc.h
+ *
+ *  Created on: 27 May 2014
+ *      Author: jaybeepee
+ */
+
+#ifndef RPC_H_
+#define RPC_H_
+
+#include "../../rpc.h"
+#include "config.h"
+
+extern rpc_export_t cdp_rpc[];
+
+#endif /* RPC_H_ */

+ 1 - 1
modules/cdp/config.h

@@ -124,7 +124,7 @@ typedef struct {
 	acceptor_config *acceptors;	/**< list of acceptors */
 	acceptor_config *acceptors;	/**< list of acceptors */
 	int acceptors_cnt;			/**< size of the list of acceptors */
 	int acceptors_cnt;			/**< size of the list of acceptors */
 	
 	
-	app_config *applications;	/**< list of supporter applications */
+	app_config *applications;	/**< list of supported applications */
 	int applications_cnt;		/**< size of list of supported applications*/
 	int applications_cnt;		/**< size of list of supported applications*/
 
 
 	int *supported_vendors;		/**< list of supported vendor ids */
 	int *supported_vendors;		/**< list of supported vendor ids */

+ 2 - 1
modules/cdp/diameter_comm.c

@@ -138,6 +138,7 @@ AAAReturnCode AAASendMessage(
 		LM_ERR("AAASendMessage(): Can't find a suitable connected peer in the routing table.\n");
 		LM_ERR("AAASendMessage(): Can't find a suitable connected peer in the routing table.\n");
 		goto error;
 		goto error;
 	}
 	}
+	LM_DBG("Found diameter peer [%.*s] from routing table\n", p->fqdn.len, p->fqdn.s);
 	if (p->state!=I_Open && p->state!=R_Open){
 	if (p->state!=I_Open && p->state!=R_Open){
 		LM_ERR("AAASendMessage(): Peer not connected to %.*s\n",p->fqdn.len,p->fqdn.s);
 		LM_ERR("AAASendMessage(): Peer not connected to %.*s\n",p->fqdn.len,p->fqdn.s);
 		goto error;
 		goto error;
@@ -194,7 +195,7 @@ AAAReturnCode AAASendMessageToPeer(
 			LM_ERR("AAASendMessageToPeer(): can't add transaction callback for answer.\n");
 			LM_ERR("AAASendMessageToPeer(): can't add transaction callback for answer.\n");
 	}
 	}
 
 
-//	if (!peer_send_msg(p,message))
+	p->last_selected = time(NULL);
 	if (!sm_process(p,Send_Message,message,0,0))
 	if (!sm_process(p,Send_Message,message,0,0))
 		goto error;
 		goto error;
 
 

+ 21 - 3
modules/cdp/doc/cdp_admin.xml

@@ -15,9 +15,9 @@
     <para>CDP (C Diameter Peer) allows Diameter communication to and from
     <para>CDP (C Diameter Peer) allows Diameter communication to and from
     Kamailio. Most of the code is inherited from DISC
     Kamailio. Most of the code is inherited from DISC
     http://developer.berlios.de/projects/disc/ and OpenIMS and modified for
     http://developer.berlios.de/projects/disc/ and OpenIMS and modified for
-    use within Kamailio. A few improvements and new functionality has been added
-    along the way, for example, threshold reporting on Diameter calls that are
-    serviced above a certain threshold.</para>
+    use within Kamailio. A few improvements and new functionality has been
+    added along the way, for example, threshold reporting on Diameter calls
+    that are serviced above a certain threshold.</para>
   </section>
   </section>
 
 
   <section>
   <section>
@@ -137,6 +137,24 @@ modparam("cdp", "latency_threshold", 1000)
     </section>
     </section>
   </section>
   </section>
 
 
+  <section>
+    <title>RPC Commands</title>
+
+    <para>exported RPC commands.</para>
+
+    <section>
+      <title>cdp.disable_peer</title>
+
+      <para>instantly disable a particular diameter peer.</para>
+    </section>
+
+    <section>
+      <title>cdp.enable_peer</title>
+
+      <para>enabe/re-enable a diameter peer</para>
+    </section>
+  </section>
+
   <section>
   <section>
     <title>Configuration Examples</title>
     <title>Configuration Examples</title>
 
 

+ 7 - 1
modules/cdp/mod.c

@@ -51,7 +51,9 @@
 #include "diameter_peer.h"
 #include "diameter_peer.h"
 #include "config.h"
 #include "config.h"
 #include "cdp_load.h"
 #include "cdp_load.h"
-
+#include "cdp_rpc.h"
+#include "../../rpc.h"
+#include "../../rpc_lookup.h"
 #include "../../cfg/cfg_struct.h"
 #include "../../cfg/cfg_struct.h"
 
 
 MODULE_VERSION
 MODULE_VERSION
@@ -198,6 +200,10 @@ struct module_exports exports = {
  */
  */
 static int cdp_init( void )
 static int cdp_init( void )
 {
 {
+	if (rpc_register_array(cdp_rpc) != 0) {
+		LM_ERR("failed to register RPC commands for CDP module\n");
+		return -1;
+	}
 #ifdef STATISTICS
 #ifdef STATISTICS
 	/* register statistics */
 	/* register statistics */
 	if ( register_stat("cdp", "replies_response_time", &replies_response_time,0 )!=0 ) {
 	if ( register_stat("cdp", "replies_response_time", &replies_response_time,0 )!=0 ) {

+ 2 - 0
modules/cdp/peer.h

@@ -111,7 +111,9 @@ typedef struct _peer_t{
 	int R_sock;				/**< socket used as receiver */
 	int R_sock;				/**< socket used as receiver */
 	
 	
 	time_t activity;		/**< timestamp of last activity */
 	time_t activity;		/**< timestamp of last activity */
+	time_t last_selected;	/**< timestamp this peer was last selected for routing - used in least recently used load balancing across metric */
 	int is_dynamic;			/**< whether this peer was accepted although it was not initially configured */
 	int is_dynamic;			/**< whether this peer was accepted although it was not initially configured */
+	int disabled;			/**< administratively enable/disable a peer - ie remove/re-add from service dynamically */
 	int waitingDWA;			/**< if a Diameter Watch-dog Request was sent out and waiting for an answer */
 	int waitingDWA;			/**< if a Diameter Watch-dog Request was sent out and waiting for an answer */
 	
 	
 	str send_pipe_name;		/**< pipe to signal messages to be sent out*/
 	str send_pipe_name;		/**< pipe to signal messages to be sent out*/

+ 16 - 2
modules/cdp/peermanager.c

@@ -264,6 +264,16 @@ int peer_timer(time_t now,void *ptr)
 	while(p){
 	while(p){
 		lock_get(p->lock);
 		lock_get(p->lock);
 		n = p->next;
 		n = p->next;
+
+		if (p->disabled && (p->state != Closed || p->state != Closing)) {
+			LM_DBG("Peer [%.*s] has been disabled - shutting down\n", p->fqdn.len, p->fqdn.s);
+			if (p->state == I_Open) sm_process(p, Stop, 0, 1, p->I_sock);
+			if (p->state == R_Open) sm_process(p, Stop, 0, 1, p->R_sock);
+			lock_release(p->lock);
+			p = n;
+			continue;
+		}
+
 		if (p->activity+config->tc<=now){
 		if (p->activity+config->tc<=now){
 			LM_INFO("peer_timer(): Peer %.*s \tState %d \n",p->fqdn.len,p->fqdn.s,p->state);
 			LM_INFO("peer_timer(): Peer %.*s \tState %d \n",p->fqdn.len,p->fqdn.s,p->state);
 			switch (p->state){
 			switch (p->state){
@@ -274,8 +284,10 @@ int peer_timer(time_t now,void *ptr)
 						free_peer(p,1);
 						free_peer(p,1);
 						break;
 						break;
 					}
 					}
-					touch_peer(p);
-					sm_process(p,Start,0,1,0);
+					if (!p->disabled) {
+						touch_peer(p);
+						sm_process(p,Start,0,1,0);
+					}
 					break;
 					break;
 				/* timeouts */
 				/* timeouts */
 				case Wait_Conn_Ack:
 				case Wait_Conn_Ack:
@@ -293,10 +305,12 @@ int peer_timer(time_t now,void *ptr)
 						p->waitingDWA = 0;
 						p->waitingDWA = 0;
 						if (p->state==I_Open) sm_process(p,I_Peer_Disc,0,1,p->I_sock);
 						if (p->state==I_Open) sm_process(p,I_Peer_Disc,0,1,p->I_sock);
 						if (p->state==R_Open) sm_process(p,R_Peer_Disc,0,1,p->R_sock);
 						if (p->state==R_Open) sm_process(p,R_Peer_Disc,0,1,p->R_sock);
+						LM_WARN("Inactivity on peer [%.*s] and no DWA, Closing peer...\n", p->fqdn.len, p->fqdn.s);
 					} else {
 					} else {
 						p->waitingDWA = 1;
 						p->waitingDWA = 1;
 						Snd_DWR(p);
 						Snd_DWR(p);
 						touch_peer(p);
 						touch_peer(p);
+						LM_WARN("Inactivity on peer [%.*s], sending DWR... - if we don't get a reply, the peer will be closed\n", p->fqdn.len, p->fqdn.s);
 					}
 					}
 					break;
 					break;
 				/* ignored states */
 				/* ignored states */

+ 42 - 4
modules/cdp/routing.c

@@ -48,7 +48,10 @@
 #include "peermanager.h"
 #include "peermanager.h"
 #include "diameter_api.h"
 #include "diameter_api.h"
 
 
+#define LB_MAX_PEERS 20			/**< maximum peers that can be loadbalanced accross i.e. same metric */
+
 extern dp_config *config;		/**< Configuration for this diameter peer 	*/
 extern dp_config *config;		/**< Configuration for this diameter peer 	*/
+int gcount = 0;
 
 
 /**
 /**
  * Returns if the peer advertised support for an Application ID
  * Returns if the peer advertised support for an Application ID
@@ -74,11 +77,19 @@ int peer_handles_application(peer *p,int app_id,int vendor_id)
  */
  */
 peer* get_first_connected_route(routing_entry *r,int app_id,int vendor_id)
 peer* get_first_connected_route(routing_entry *r,int app_id,int vendor_id)
 {
 {
+	peer *peers[LB_MAX_PEERS];
+	int peer_count=0;
+	int prev_metric=0;
 	routing_entry *i;
 	routing_entry *i;
 	peer *p;
 	peer *p;
+	int j;
+	time_t least_recent_time;
+
 	LM_DBG("get_first_connected_route in list %p for app_id %d and vendor_id %d\n",
 	LM_DBG("get_first_connected_route in list %p for app_id %d and vendor_id %d\n",
 		r,app_id,vendor_id);
 		r,app_id,vendor_id);
 	for(i=r;i;i=i->next){
 	for(i=r;i;i=i->next){
+		if (peer_count >= LB_MAX_PEERS)
+			break;
 		p = get_peer_by_fqdn(&(i->fqdn));
 		p = get_peer_by_fqdn(&(i->fqdn));
 		if (!p)
 		if (!p)
 			LM_DBG("The peer %.*s does not seem to be connected or configured\n",
 			LM_DBG("The peer %.*s does not seem to be connected or configured\n",
@@ -86,12 +97,33 @@ peer* get_first_connected_route(routing_entry *r,int app_id,int vendor_id)
 		else
 		else
 			LM_DBG("The peer %.*s state is %s\n",i->fqdn.len,i->fqdn.s,
 			LM_DBG("The peer %.*s state is %s\n",i->fqdn.len,i->fqdn.s,
 				(p->state==I_Open||p->state==R_Open)?"opened":"closed");
 				(p->state==I_Open||p->state==R_Open)?"opened":"closed");
-		if (p && (p->state==I_Open || p->state==R_Open) && peer_handles_application(p,app_id,vendor_id)) {			
+		if (p && !p->disabled && (p->state==I_Open || p->state==R_Open) && peer_handles_application(p,app_id,vendor_id)) {
 			LM_DBG("The peer %.*s matches - will forward there\n",i->fqdn.len,i->fqdn.s);
 			LM_DBG("The peer %.*s matches - will forward there\n",i->fqdn.len,i->fqdn.s);
-			return p;
+			if (peer_count!=0) {//check the metric
+				if (i->metric != prev_metric)
+					break;
+				//metric must be the same
+				peers[peer_count++] = p;
+			} else {//we're first
+				prev_metric = i->metric;
+				peers[peer_count++] = p;
+			}
 		}
 		}
 	}
 	}
-	return 0;
+
+	if (peer_count==0)
+		return 0;
+
+	least_recent_time = peers[0]->last_selected;
+	p = peers[0];
+	for (j=1; j<peer_count; j++) {
+		if (peers[j]->last_selected < least_recent_time) {
+			least_recent_time = peers[j]->last_selected;
+			p = peers[j];
+		}
+	}
+
+	return p;
 }
 }
 
 
 /**
 /**
@@ -112,6 +144,8 @@ peer* get_routing_peer(AAAMessage *m)
 	routing_realm *rr;
 	routing_realm *rr;
 	int app_id=0,vendor_id=0;
 	int app_id=0,vendor_id=0;
 	
 	
+	LM_DBG("getting diameter routing peer for realm: [%.*s]\n", m->dest_realm->data.len, m->dest_realm->data.s);
+
 	app_id = m->applicationId;	
 	app_id = m->applicationId;	
 	avp = AAAFindMatchingAVP(m,0,AVP_Vendor_Specific_Application_Id,0,AAA_FORWARD_SEARCH);
 	avp = AAAFindMatchingAVP(m,0,AVP_Vendor_Specific_Application_Id,0,AAA_FORWARD_SEARCH);
 	if (avp){
 	if (avp){
@@ -151,7 +185,10 @@ peer* get_routing_peer(AAAMessage *m)
 	if (destination_host.len){
 	if (destination_host.len){
 		/* There is a destination host present in the message try and route directly there */
 		/* There is a destination host present in the message try and route directly there */
 		p = get_peer_by_fqdn(&destination_host);
 		p = get_peer_by_fqdn(&destination_host);
-		if (p && (p->state==I_Open || p->state==R_Open) && peer_handles_application(p,app_id,vendor_id)) return p;
+		if (p && (p->state==I_Open || p->state==R_Open) && peer_handles_application(p,app_id,vendor_id)) {
+			p->last_selected = time(NULL);
+			return p;
+		}
 		/* the destination host peer is not connected at the moment, try a normal route then */
 		/* the destination host peer is not connected at the moment, try a normal route then */
 	}
 	}
 	
 	
@@ -178,6 +215,7 @@ peer* get_routing_peer(AAAMessage *m)
 	}
 	}
 	/* if not found in the realms or no destination_realm, 
 	/* if not found in the realms or no destination_realm, 
 	 * get the first connected host in default routes */
 	 * get the first connected host in default routes */
+	LM_DBG("no routing peer found, trying default route\n");
 	p = get_first_connected_route(config->r_table->routes,app_id,vendor_id);
 	p = get_first_connected_route(config->r_table->routes,app_id,vendor_id);
 	if (!p){
 	if (!p){
 		LM_ERR("get_routing_peer(): No connected DefaultRoute peer found for app_id %d and vendor id %d.\n",
 		LM_ERR("get_routing_peer(): No connected DefaultRoute peer found for app_id %d and vendor id %d.\n",

+ 5 - 0
modules/cnxcc/cnxcc_mod.c

@@ -1460,6 +1460,11 @@ static int set_max_credit(struct sip_msg* msg,
 			return -1;
 			return -1;
 		}
 		}
 
 
+		if (credit < cost_per_second) {
+			LM_ERR("Not enough credit to start the call: credit=[%f] < cost_per_sec=[%f]", credit, cost_per_second);
+			return -1;
+		}
+
 		if (client_id_val.rs.len == 0 || client_id_val.rs.s == NULL)
 		if (client_id_val.rs.len == 0 || client_id_val.rs.s == NULL)
 		{
 		{
 			LM_ERR("[%.*s]: client ID cannot be null\n", msg->callid->body.len, msg->callid->body.s);
 			LM_ERR("[%.*s]: client ID cannot be null\n", msg->callid->body.len, msg->callid->body.s);

+ 1 - 0
modules/db_flatstore/km_flat_con.c

@@ -115,6 +115,7 @@ struct flat_con* flat_new_connection(struct flat_id* id)
 	fn = get_name(id);
 	fn = get_name(id);
 	if (fn==0){
 	if (fn==0){
 		LM_ERR("get_name() failed\n");
 		LM_ERR("get_name() failed\n");
+		pkg_free(res);
 		return 0;
 		return 0;
 	}
 	}
 
 

+ 2 - 2
modules/db_mysql/km_dbase.c

@@ -258,7 +258,7 @@ static int db_mysql_store_result(const db1_con_t* _h, db1_res_t** _r)
 		db_mysql_free_result(_h, *_r);
 		db_mysql_free_result(_h, *_r);
 		*_r = 0;
 		*_r = 0;
 #if (MYSQL_VERSION_ID >= 40100)
 #if (MYSQL_VERSION_ID >= 40100)
-		while( mysql_more_results(CON_CONNECTION(_h)) && mysql_next_result(CON_CONNECTION(_h)) > 0 ) {
+		while( mysql_more_results(CON_CONNECTION(_h)) && mysql_next_result(CON_CONNECTION(_h)) == 0 ) {
 			MYSQL_RES *res = mysql_store_result( CON_CONNECTION(_h) );
 			MYSQL_RES *res = mysql_store_result( CON_CONNECTION(_h) );
 			mysql_free_result(res);
 			mysql_free_result(res);
 		}
 		}
@@ -268,7 +268,7 @@ static int db_mysql_store_result(const db1_con_t* _h, db1_res_t** _r)
 
 
 done:
 done:
 #if (MYSQL_VERSION_ID >= 40100)
 #if (MYSQL_VERSION_ID >= 40100)
-	while( mysql_more_results(CON_CONNECTION(_h)) && mysql_next_result(CON_CONNECTION(_h)) > 0 ) {
+	while( mysql_more_results(CON_CONNECTION(_h)) && mysql_next_result(CON_CONNECTION(_h)) == 0 ) {
 		MYSQL_RES *res = mysql_store_result( CON_CONNECTION(_h) );
 		MYSQL_RES *res = mysql_store_result( CON_CONNECTION(_h) );
 		mysql_free_result(res);
 		mysql_free_result(res);
 	}
 	}

+ 4 - 3
modules/dialog/dlg_handlers.c

@@ -544,6 +544,8 @@ static void dlg_onreply(struct cell* t, int type, struct tmcb_params *param)
 		LM_DBG("dialog %p failed (negative reply)\n", dlg);
 		LM_DBG("dialog %p failed (negative reply)\n", dlg);
 		/* dialog setup not completed (3456XX) */
 		/* dialog setup not completed (3456XX) */
 		run_dlg_callbacks( DLGCB_FAILED, dlg, req, rpl, DLG_DIR_UPSTREAM, 0);
 		run_dlg_callbacks( DLGCB_FAILED, dlg, req, rpl, DLG_DIR_UPSTREAM, 0);
+		if(dlg_wait_ack==1)
+			dlg_set_tm_waitack(t, dlg);
 		/* do unref */
 		/* do unref */
 		if (unref)
 		if (unref)
 			dlg_unref(dlg, unref);
 			dlg_unref(dlg, unref);
@@ -552,8 +554,6 @@ static void dlg_onreply(struct cell* t, int type, struct tmcb_params *param)
 
 
 		if_update_stat(dlg_enable_stats, failed_dlgs, 1);
 		if_update_stat(dlg_enable_stats, failed_dlgs, 1);
 
 
-		if(dlg_wait_ack==1)
-			dlg_set_tm_waitack(t, dlg);
 		goto done;
 		goto done;
 	}
 	}
 
 
@@ -1356,7 +1356,8 @@ void dlg_ontimeout(struct dlg_tl *tl)
 
 
 		if(dlg->iflags&DLG_IFLAG_TIMEOUTBYE)
 		if(dlg->iflags&DLG_IFLAG_TIMEOUTBYE)
 		{
 		{
-			dlg_bye_all(dlg, NULL);
+			if(dlg_bye_all(dlg, NULL)<0)
+				dlg_unref(dlg, 1);
 			/* run event route for end of dlg */
 			/* run event route for end of dlg */
 			dlg_run_event_route(dlg, NULL, dlg->state, DLG_STATE_DELETED);
 			dlg_run_event_route(dlg, NULL, dlg->state, DLG_STATE_DELETED);
 			dlg_unref(dlg, 1);
 			dlg_unref(dlg, 1);

+ 1 - 1
modules/dispatcher/dispatch.c

@@ -227,7 +227,7 @@ int ds_set_attrs(ds_dest_t *dest, str *attrs)
 				&& strncasecmp(pit->name.s, "duid", 4)==0) {
 				&& strncasecmp(pit->name.s, "duid", 4)==0) {
 			dest->attrs.duid = pit->body;
 			dest->attrs.duid = pit->body;
 		} else if(pit->name.len==6
 		} else if(pit->name.len==6
-				&& strncasecmp(pit->name.s, "weight", 4)==0) {
+				&& strncasecmp(pit->name.s, "weight", 6)==0) {
 			str2sint(&pit->body, &dest->attrs.weight);
 			str2sint(&pit->body, &dest->attrs.weight);
 		} else if(pit->name.len==7
 		} else if(pit->name.len==7
 				&& strncasecmp(pit->name.s, "maxload", 7)==0) {
 				&& strncasecmp(pit->name.s, "maxload", 7)==0) {

+ 50 - 13
modules/dispatcher/dispatcher.c

@@ -545,23 +545,39 @@ static void destroy(void)
 
 
 }
 }
 
 
+#define GET_VALUE(param_name,param,i_value,s_value,value_flags) do{ \
+	if(get_is_fparam(&(i_value), &(s_value), msg, (fparam_t*)(param), &(value_flags))!=0) { \
+		LM_ERR("no %s value\n", (param_name)); \
+		return -1; \
+	} \
+}while(0)
+
 /**
 /**
  *
  *
  */
  */
 static int w_ds_select(struct sip_msg* msg, char* set, char* alg, int mode)
 static int w_ds_select(struct sip_msg* msg, char* set, char* alg, int mode)
 {
 {
+	unsigned int algo_flags, set_flags;
+	str s_algo = {NULL, 0};
+	str s_set = {NULL, 0};
 	int a, s;
 	int a, s;
 	if(msg==NULL)
 	if(msg==NULL)
 		return -1;
 		return -1;
 
 
-	if(fixup_get_ivalue(msg, (gparam_p)set, &s)!=0)
-	{
-		LM_ERR("no dst set value\n");
+	GET_VALUE("destination set", set, s, s_set, set_flags);
+	if (!(set_flags&PARAM_INT)) {
+		if (set_flags&PARAM_STR)
+			LM_ERR("unable to get destination set from [%.*s]\n", s_set.len, s_set.s);
+		else
+			LM_ERR("unable to get destination set\n");
 		return -1;
 		return -1;
 	}
 	}
-	if(fixup_get_ivalue(msg, (gparam_p)alg, &a)!=0)
-	{
-		LM_ERR("no alg value\n");
+	GET_VALUE("algorithm", alg, a, s_algo, algo_flags);
+	if (!(algo_flags&PARAM_INT)) {
+		if (algo_flags&PARAM_STR)
+			LM_ERR("unable to get algorithm from [%.*s]\n", s_algo.len, s_algo.s);
+		else
+			LM_ERR("unable to get algorithm\n");
 		return -1;
 		return -1;
 	}
 	}
 
 
@@ -974,6 +990,7 @@ static void dispatcher_rpc_list(rpc_t* rpc, void* ctx)
 	void* rh;
 	void* rh;
 	void* sh;
 	void* sh;
 	void* vh;
 	void* vh;
+	void* wh;
 	int j;
 	int j;
 	char c[3];
 	char c[3];
 	str data = {"", 0};
 	str data = {"", 0};
@@ -1005,7 +1022,6 @@ static void dispatcher_rpc_list(rpc_t* rpc, void* ctx)
 		return;
 		return;
 	}
 	}
 
 
-
 	for(list = ds_list; list!= NULL; list= list->next)
 	for(list = ds_list; list!= NULL; list= list->next)
 	{
 	{
 		if (rpc->struct_add(ih, "{", "SET", &sh) < 0)
 		if (rpc->struct_add(ih, "{", "SET", &sh) < 0)
@@ -1045,15 +1061,36 @@ static void dispatcher_rpc_list(rpc_t* rpc, void* ctx)
 			else
 			else
 				c[1] = 'X';
 				c[1] = 'X';
 
 
-			if(rpc->struct_add(vh, "SsdS",
+			if (list->dlist[j].attrs.body.s)
+			{
+				if(rpc->struct_add(vh, "Ssd{",
 						"URI", &list->dlist[j].uri,
 						"URI", &list->dlist[j].uri,
 						"FLAGS", c,
 						"FLAGS", c,
 						"PRIORITY", list->dlist[j].priority,
 						"PRIORITY", list->dlist[j].priority,
-						"ATTRS", (list->dlist[j].attrs.body.s)?
-						&(list->dlist[j].attrs.body):&data)<0)
-			{
-				rpc->fault(ctx, 500, "Internal error creating dest struct");
-				return;
+						"ATTRS", &wh)<0)
+				{
+					rpc->fault(ctx, 500, "Internal error creating dest struct");
+					return;
+				}
+				if(rpc->struct_add(wh, "SSdd",
+						"BODY", &(list->dlist[j].attrs.body),
+						"DUID", (list->dlist[j].attrs.duid.s)?
+						&(list->dlist[j].attrs.duid):&data,
+						"MAXLOAD", list->dlist[j].attrs.maxload,
+						"WEIGHT", list->dlist[j].attrs.weight)<0)
+				{
+					rpc->fault(ctx, 500, "Internal error creating attrs struct");
+					return;
+				}
+			} else {
+				if(rpc->struct_add(vh, "Ssd",
+						"URI", &list->dlist[j].uri,
+						"FLAGS", c,
+						"PRIORITY", list->dlist[j].priority)<0)
+				{
+					rpc->fault(ctx, 500, "Internal error creating dest struct");
+					return;
+				}
 			}
 			}
 		}
 		}
 	}
 	}

+ 1 - 0
modules/ims_auth/api.h

@@ -53,6 +53,7 @@
  * return codes to config by auth functions
  * return codes to config by auth functions
  */
  */
 typedef enum auth_cfg_result {
 typedef enum auth_cfg_result {
+	AUTH_RESYNC_REQUESTED = -9,	/*!< resync requested from UE via auts param */
 	AUTH_USER_MISMATCH = -8,    /*!< Auth user != From/To user */
 	AUTH_USER_MISMATCH = -8,    /*!< Auth user != From/To user */
 	AUTH_NONCE_REUSED = -6,     /*!< Returned if nonce is used more than once */
 	AUTH_NONCE_REUSED = -6,     /*!< Returned if nonce is used more than once */
 	AUTH_NO_CREDENTIALS = -5,   /*!< Credentials missing */
 	AUTH_NO_CREDENTIALS = -5,   /*!< Credentials missing */

+ 1 - 0
modules/ims_auth/authims_mod.c

@@ -119,6 +119,7 @@ int ignore_failed_auth = 0;
 static cmd_export_t cmds[] = {
 static cmd_export_t cmds[] = {
     {"ims_www_authenticate", (cmd_function) www_authenticate, 1, auth_fixup, 0, REQUEST_ROUTE},
     {"ims_www_authenticate", (cmd_function) www_authenticate, 1, auth_fixup, 0, REQUEST_ROUTE},
     {"ims_www_challenge", (cmd_function) www_challenge, 2, challenge_fixup_async, 0, REQUEST_ROUTE},
     {"ims_www_challenge", (cmd_function) www_challenge, 2, challenge_fixup_async, 0, REQUEST_ROUTE},
+    {"ims_www_resync_auth", (cmd_function) www_resync_auth, 2, challenge_fixup_async, 0, REQUEST_ROUTE},
     {"ims_proxy_authenticate", (cmd_function) proxy_authenticate, 1, auth_fixup, 0, REQUEST_ROUTE},
     {"ims_proxy_authenticate", (cmd_function) proxy_authenticate, 1, auth_fixup, 0, REQUEST_ROUTE},
     {"ims_proxy_challenge", (cmd_function) proxy_challenge, 2, auth_fixup_async, 0, REQUEST_ROUTE},
     {"ims_proxy_challenge", (cmd_function) proxy_challenge, 2, auth_fixup_async, 0, REQUEST_ROUTE},
     {"bind_ims_auth", (cmd_function) bind_ims_auth, 0, 0, 0, 0},
     {"bind_ims_auth", (cmd_function) bind_ims_auth, 0, 0, 0, 0},

+ 187 - 27
modules/ims_auth/authorize.c

@@ -276,7 +276,6 @@ int challenge(struct sip_msg* msg, char* str1, char* str2, int is_proxy_auth, ch
     str private_identity, public_identity, auts = {0, 0}, nonce = {0, 0};
     str private_identity, public_identity, auts = {0, 0}, nonce = {0, 0};
     auth_vector *av = 0;
     auth_vector *av = 0;
     int algo_type;
     int algo_type;
-    
     str route_name;
     str route_name;
 
 
     saved_transaction_t* saved_t;
     saved_transaction_t* saved_t;
@@ -346,8 +345,8 @@ int challenge(struct sip_msg* msg, char* str1, char* str2, int is_proxy_auth, ch
 
 
     algo_type = registration_default_algorithm_type;
     algo_type = registration_default_algorithm_type;
 
 
-    /* check if it is a synchronization request */
-    //TODO this is MAR syncing - have removed it currently - TOD maybe put back in
+//    /* check if it is a synchronization request */
+//    //TODO this is MAR syncing - have removed it currently - TOD maybe put back in
 //    auts = ims_get_auts(msg, realm, is_proxy_auth);
 //    auts = ims_get_auts(msg, realm, is_proxy_auth);
 //    if (auts.len) {
 //    if (auts.len) {
 //        LM_DBG("IMS Auth Synchronization requested <%.*s>\n", auts.len, auts.s);
 //        LM_DBG("IMS Auth Synchronization requested <%.*s>\n", auts.len, auts.s);
@@ -363,19 +362,15 @@ int challenge(struct sip_msg* msg, char* str1, char* str2, int is_proxy_auth, ch
 //            av = get_auth_vector(private_identity, public_identity, AUTH_VECTOR_SENT, &nonce, &aud_hash);
 //            av = get_auth_vector(private_identity, public_identity, AUTH_VECTOR_SENT, &nonce, &aud_hash);
 //
 //
 //        if (!av) {
 //        if (!av) {
-//            LM_ERR("Nonce not regonized as sent, no sync!\n");
+//            LM_ERR("nonce not recognized as sent, no sync!\n");
 //            auts.len = 0;
 //            auts.len = 0;
 //            auts.s = 0;
 //            auts.s = 0;
 //        } else {
 //        } else {
 //            av->status = AUTH_VECTOR_USELESS;
 //            av->status = AUTH_VECTOR_USELESS;
 //            auth_data_unlock(aud_hash);
 //            auth_data_unlock(aud_hash);
 //            av = 0;
 //            av = 0;
+//            resync = 1;
 //        }
 //        }
-//
-//        //RICHARD REMOVED REALM - this is diameter realm set in cxdx not SIP domain
-//        // if synchronization - force MAR - if MAR ok, old avs will be droped
-//        multimedia_auth_request(msg, public_identity, private_identity, av_request_at_sync,
-//                auth_scheme_types[algo_type], nonce, auts, scscf_name_str);
 //    }
 //    }
 
 
     //RICHARD changed this
     //RICHARD changed this
@@ -446,7 +441,6 @@ int challenge(struct sip_msg* msg, char* str1, char* str2, int is_proxy_auth, ch
         memcpy(saved_t->realm.s, realm.s, realm.len);
         memcpy(saved_t->realm.s, realm.s, realm.len);
         saved_t->realm.len = realm.len;
         saved_t->realm.len = realm.len;
 
 
-
         saved_t->is_proxy_auth = is_proxy_auth;
         saved_t->is_proxy_auth = is_proxy_auth;
 
 
         LM_DBG("Suspending SIP TM transaction\n");
         LM_DBG("Suspending SIP TM transaction\n");
@@ -474,6 +468,158 @@ int www_challenge(struct sip_msg* msg, char* _route, char* str1, char* str2) {
     return challenge(msg, str1, str2, 0, _route);
     return challenge(msg, str1, str2, 0, _route);
 }
 }
 
 
+int www_resync_auth(struct sip_msg* msg, char* _route, char* str1, char* str2) {
+
+    str realm = {0, 0};
+    unsigned int aud_hash;
+    str private_identity, public_identity, auts = {0, 0}, nonce = {0, 0};
+    auth_vector *av = 0;
+    int algo_type;
+    int is_proxy_auth=0;
+    str route_name;
+
+    saved_transaction_t* saved_t;
+    tm_cell_t *t = 0;
+    cfg_action_t* cfg_action;
+
+    if (fixup_get_svalue(msg, (gparam_t*) _route, &route_name) != 0) {
+        LM_ERR("no async route block for assign_server_unreg\n");
+        return -1;
+    }
+
+    LM_DBG("Looking for route block [%.*s]\n", route_name.len, route_name.s);
+    int ri = route_get(&main_rt, route_name.s);
+    if (ri < 0) {
+        LM_ERR("unable to find route block [%.*s]\n", route_name.len, route_name.s);
+        return -1;
+    }
+    cfg_action = main_rt.rlist[ri];
+    if (cfg_action == NULL) {
+        LM_ERR("empty action lists in route block [%.*s]\n", route_name.len, route_name.s);
+        return -1;
+    }
+
+    if (get_str_fparam(&realm, msg, (fparam_t*) str1) < 0) {
+        LM_ERR("failed to get realm value\n");
+        return CSCF_RETURN_ERROR;
+    }
+
+    if (realm.len == 0) {
+        LM_ERR("invalid realm value - empty content\n");
+        return CSCF_RETURN_ERROR;
+    }
+
+    create_return_code(CSCF_RETURN_ERROR);
+
+    if (msg->first_line.type != SIP_REQUEST) {
+        LM_ERR("This message is not a request\n");
+        return CSCF_RETURN_ERROR;
+    }
+
+    /* get the private_identity */
+    private_identity = get_private_identity(msg, realm, is_proxy_auth);
+    if (!private_identity.len) {
+        LM_ERR("No private identity specified (Authorization: username)\n");
+        stateful_request_reply(msg, 403, MSG_403_NO_PRIVATE);
+        return CSCF_RETURN_BREAK;
+    }
+    /* get the public_identity */
+    public_identity = get_public_identity(msg);
+    if (!public_identity.len) {
+        LM_ERR("No public identity specified (To:)\n");
+        stateful_request_reply(msg, 403, MSG_403_NO_PUBLIC);
+        return CSCF_RETURN_BREAK;
+    }
+
+    algo_type = registration_default_algorithm_type;
+
+    /* check if it is a synchronization request */
+    //TODO this is MAR syncing - have removed it currently - TOD maybe put back in
+    auts = ims_get_auts(msg, realm, is_proxy_auth);
+    if (auts.len) {
+        LM_DBG("IMS Auth Synchronization requested <%.*s>\n", auts.len, auts.s);
+
+        nonce = ims_get_nonce(msg, realm);
+        if (nonce.len == 0) {
+            LM_DBG("Nonce not found (Authorization: nonce)\n");
+            stateful_request_reply(msg, 403, MSG_403_NO_NONCE);
+            return CSCF_RETURN_BREAK;
+        }
+        av = get_auth_vector(private_identity, public_identity, AUTH_VECTOR_USED, &nonce, &aud_hash);
+        if (!av)
+            av = get_auth_vector(private_identity, public_identity, AUTH_VECTOR_SENT, &nonce, &aud_hash);
+
+        if (!av) {
+            LM_ERR("nonce not recognized as sent, no sync!\n");
+            auts.len = 0;
+            auts.s = 0;
+        } else {
+            av->status = AUTH_VECTOR_USELESS;
+            auth_data_unlock(aud_hash);
+            av = 0;
+        }
+    }
+
+	//before we send lets suspend the transaction
+	t = tmb.t_gett();
+	if (t == NULL || t == T_UNDEFINED) {
+		if (tmb.t_newtran(msg) < 0) {
+			LM_ERR("cannot create the transaction for MAR async\n");
+			stateful_request_reply(msg, 480, MSG_480_DIAMETER_ERROR);
+			return CSCF_RETURN_BREAK;
+		}
+		t = tmb.t_gett();
+		if (t == NULL || t == T_UNDEFINED) {
+			LM_ERR("cannot lookup the transaction\n");
+			stateful_request_reply(msg, 480, MSG_480_DIAMETER_ERROR);
+			return CSCF_RETURN_BREAK;
+		}
+	}
+
+	saved_t = shm_malloc(sizeof(saved_transaction_t));
+	if (!saved_t) {
+		LM_ERR("no more memory trying to save transaction state\n");
+		return CSCF_RETURN_ERROR;
+
+	}
+	memset(saved_t, 0, sizeof(saved_transaction_t));
+	saved_t->act = cfg_action;
+
+	saved_t->realm.s = (char*) shm_malloc(realm.len + 1);
+	if (!saved_t->realm.s) {
+		LM_ERR("no more memory trying to save transaction state : callid\n");
+		shm_free(saved_t);
+		return CSCF_RETURN_ERROR;
+	}
+	memset(saved_t->realm.s, 0, realm.len + 1);
+	memcpy(saved_t->realm.s, realm.s, realm.len);
+	saved_t->realm.len = realm.len;
+
+	saved_t->is_proxy_auth = is_proxy_auth;
+	saved_t->is_resync = 1;
+
+	LM_DBG("Suspending SIP TM transaction\n");
+	if (tmb.t_suspend(msg, &saved_t->tindex, &saved_t->tlabel) < 0) {
+		LM_ERR("failed to suspend the TM processing\n");
+		free_saved_transaction_data(saved_t);
+
+		stateful_request_reply(msg, 480, MSG_480_DIAMETER_ERROR);
+		return CSCF_RETURN_BREAK;
+	}
+
+	if (multimedia_auth_request(msg, public_identity, private_identity,
+			av_request_at_sync, auth_scheme_types[algo_type], nonce, auts,
+			scscf_name_str, saved_t) != 0) {
+		LM_ERR("ERR:I_MAR: Error sending MAR or MAR time-out\n");
+		tmb.t_cancel_suspend(saved_t->tindex, saved_t->tlabel);
+		free_saved_transaction_data(saved_t);
+		stateful_request_reply(msg, 480, MSG_480_DIAMETER_ERROR);
+		return CSCF_RETURN_BREAK;
+	}
+
+	return CSCF_RETURN_BREAK;
+}
+
 int proxy_challenge(struct sip_msg* msg, char* _route, char* str1, char* str2) {
 int proxy_challenge(struct sip_msg* msg, char* _route, char* str1, char* str2) {
     return challenge(msg, str1, str2, 1, _route);
     return challenge(msg, str1, str2, 1, _route);
 }
 }
@@ -554,7 +700,7 @@ int authenticate(struct sip_msg* msg, char* _realm, char* str2, int is_proxy_aut
     unsigned int aud_hash = 0;
     unsigned int aud_hash = 0;
     str realm;
     str realm;
     str private_identity, public_identity;
     str private_identity, public_identity;
-    str nonce, response16, nc, cnonce, qop_str = {0, 0}, body, *next_nonce = &empty_s;
+    str nonce, response16, nc, cnonce, qop_str = {0, 0}, auts = {0, 0}, body, *next_nonce = &empty_s;
     enum qop_type qop = QOP_UNSPEC;
     enum qop_type qop = QOP_UNSPEC;
     str uri = {0, 0};
     str uri = {0, 0};
     HASHHEX expected, ha1, hbody, rspauth;
     HASHHEX expected, ha1, hbody, rspauth;
@@ -631,7 +777,7 @@ int authenticate(struct sip_msg* msg, char* _realm, char* str2, int is_proxy_aut
         /* if none found, or nonce reuse is disabled, look for a fresh vector
         /* if none found, or nonce reuse is disabled, look for a fresh vector
          * We should also drop every other used vector at this point
          * We should also drop every other used vector at this point
          * (there souldn't be more than one) */
          * (there souldn't be more than one) */
-
+    	LM_DBG("Looking for auth vector based on IMPI: [%.*s] and IMPU: [%.*s]\n", private_identity.len, private_identity.s, public_identity.len, public_identity.s);
         auth_userdata *aud;
         auth_userdata *aud;
         auth_vector *av_it;
         auth_vector *av_it;
         aud = get_auth_userdata(private_identity, public_identity);
         aud = get_auth_userdata(private_identity, public_identity);
@@ -815,7 +961,15 @@ int authenticate(struct sip_msg* msg, char* _realm, char* str2, int is_proxy_aut
                 authenticate_hex_len,authenticate_hex,
                 authenticate_hex_len,authenticate_hex,
                 authorise_len,
                 authorise_len,
                 authorise_len, authorise);
                 authorise_len, authorise);
-        ret = AUTH_INVALID_PASSWORD;
+//        /* check for auts in authorization header - if it is then we need to resync */
+		auts = ims_get_auts(msg, realm, is_proxy_auth);
+		if (auts.len) {
+			LM_DBG("IMS Auth Synchronization requested <%.*s>\n", auts.len, auts.s);
+			ret = AUTH_RESYNC_REQUESTED;
+			av->status = AUTH_VECTOR_SENT;
+		} else {
+			ret = AUTH_INVALID_PASSWORD;
+		}
     }
     }
 
 
     if (ignore_failed_auth) {
     if (ignore_failed_auth) {
@@ -1113,6 +1267,8 @@ auth_vector * new_auth_vector(int item_number, str auth_scheme, str authenticate
     x->status = AUTH_VECTOR_UNUSED;
     x->status = AUTH_VECTOR_UNUSED;
     x->expires = 0;
     x->expires = 0;
 
 
+    LM_DBG("new auth-vector with ck [%.*s] with status %d\n", x->ck.len, x->ck.s, x->status);
+
 done:
 done:
     return x;
     return x;
 }
 }
@@ -1315,26 +1471,28 @@ int multimedia_auth_request(struct sip_msg *msg, str public_identity, str privat
     str authorization = {0, 0};
     str authorization = {0, 0};
     int result = -1;
     int result = -1;
 
 
-    //TODO this is MAR syncing - have removed it currently - TOD maybe put back in
-    //int is_sync = 0;
-//    if (auts.len) {
-//        authorization.s = pkg_malloc(nonce.len * 3 / 4 + auts.len * 3 / 4 + 8);
-//        if (!authorization.s) goto done;
-//        authorization.len = base64_to_bin(nonce.s, nonce.len, authorization.s);
-//        authorization.len = RAND_LEN;
-//        authorization.len += base64_to_bin(auts.s, auts.len, authorization.s + authorization.len);
-//        is_sync = 1;
-//    }
+    int is_sync = 0;
+    if (auts.len) {
+        authorization.s = pkg_malloc(nonce.len * 3 / 4 + auts.len * 3 / 4 + 8);
+        if (!authorization.s)  {
+        	LM_ERR("no more pkg mem\n");
+        	return result;
+        }
+        authorization.len = base64_to_bin(nonce.s, nonce.len, authorization.s);
+        authorization.len = RAND_LEN;
+        authorization.len += base64_to_bin(auts.s, auts.len, authorization.s + authorization.len);
+        is_sync = 1;
+    }
+
+    if (is_sync) {
+    	drop_auth_userdata(private_identity, public_identity);
+    }
 
 
 
 
     LM_DBG("Sending MAR\n");
     LM_DBG("Sending MAR\n");
     result = cxdx_send_mar(msg, public_identity, private_identity, count, auth_scheme, authorization, servername, transaction_data);
     result = cxdx_send_mar(msg, public_identity, private_identity, count, auth_scheme, authorization, servername, transaction_data);
     if (authorization.s) pkg_free(authorization.s);
     if (authorization.s) pkg_free(authorization.s);
 
 
-    //TODO this is MAR syncing - have removed it currently - TOD maybe put back in
-    //if (is_sync)
-    //    drop_auth_userdata(private_identity, public_identity);
-
     return result;
     return result;
 }
 }
 
 
@@ -1500,12 +1658,14 @@ int drop_auth_userdata(str private_identity, str public_identity) {
 
 
     av = aud->head;
     av = aud->head;
     while (av) {
     while (av) {
+    	LM_DBG("dropping auth vector that was in status %d\n", av->status);
         av->status = AUTH_VECTOR_USELESS;
         av->status = AUTH_VECTOR_USELESS;
         av = av->next;
         av = av->next;
     }
     }
     auth_data_unlock(aud->hash);
     auth_data_unlock(aud->hash);
     return 1;
     return 1;
 error:
 error:
+	LM_DBG("no authdata to drop any auth vectors\n");
     if (aud) auth_data_unlock(aud->hash);
     if (aud) auth_data_unlock(aud->hash);
     return 0;
     return 0;
 }
 }

+ 1 - 0
modules/ims_auth/authorize.h

@@ -140,6 +140,7 @@ int proxy_challenge(struct sip_msg* msg, char* route, char* _realm, char* str2);
  */
  */
 int www_authenticate(struct sip_msg* _msg, char* _realm, char* _table);
 int www_authenticate(struct sip_msg* _msg, char* _realm, char* _table);
 int www_challenge(struct sip_msg* msg, char* route, char* _realm, char* str2);
 int www_challenge(struct sip_msg* msg, char* route, char* _realm, char* str2);
+int www_resync_auth(struct sip_msg* msg, char* _route, char* str1, char* str2);
 
 
 
 
 /*
 /*

+ 21 - 18
modules/ims_auth/cxdx_mar.c

@@ -387,8 +387,6 @@ success:
         //TODO need to confirm that removing this has done no problems
         //TODO need to confirm that removing this has done no problems
         //tmp->auth_data->code = -tmp->auth_data->code;
         //tmp->auth_data->code = -tmp->auth_data->code;
 
 
-	LM_DBG("Added new auth-vector.\n");
-
         tmp = tmp->next;
         tmp = tmp->next;
     }
     }
 
 
@@ -396,29 +394,34 @@ success:
     //right now we take the first and put the rest in the AV queue
     //right now we take the first and put the rest in the AV queue
     //then we use the first one and then add it to the queue as sent!
     //then we use the first one and then add it to the queue as sent!
 
 
-    for (i = 1; i < sip_number_auth_items; i++)
+    for (i = 1; i < sip_number_auth_items; i++) {
         if (!add_auth_vector(private_identity, public_identity, avlist[i]))
         if (!add_auth_vector(private_identity, public_identity, avlist[i]))
             free_auth_vector(avlist[i]);
             free_auth_vector(avlist[i]);
-
-    if (!pack_challenge(t->uas.request, data->realm, avlist[0], data->is_proxy_auth)) {
-        stateful_request_reply_async(t, t->uas.request, 500, MSG_500_PACK_AV);
-        result = CSCF_RETURN_FALSE;
-        goto done;
     }
     }
 
 
-    if (data->is_proxy_auth)
-        stateful_request_reply_async(t, t->uas.request, 407, MSG_407_CHALLENGE);
-    else
-        stateful_request_reply_async(t, t->uas.request, 401, MSG_401_CHALLENGE);
+    if (!data->is_resync) {
+		if (!pack_challenge(t->uas.request, data->realm, avlist[0], data->is_proxy_auth)) {
+			stateful_request_reply_async(t, t->uas.request, 500, MSG_500_PACK_AV);
+			result = CSCF_RETURN_FALSE;
+			goto done;
+		}
+
+		if (data->is_proxy_auth)
+			stateful_request_reply_async(t, t->uas.request, 407, MSG_407_CHALLENGE);
+		else
+			stateful_request_reply_async(t, t->uas.request, 401, MSG_401_CHALLENGE);
+    }
 
 
 done:
 done:
-    if (avlist) {
-        start_reg_await_timer(avlist[0]); //start the timer to remove stale or unused Auth Vectors
 
 
-        //now we add it to the queue as sent as we have already sent the challenge and used it and set the status to SENT
-        if (!add_auth_vector(private_identity, public_identity, avlist[0]))
-            free_auth_vector(avlist[0]);
-    }
+	if (avlist) {
+		if (!data->is_resync)	//only start the timer if we used the vector above - we dont use it resync mode
+		start_reg_await_timer(avlist[0]); //start the timer to remove stale or unused Auth Vectors
+
+		//now we add it to the queue as sent as we have already sent the challenge and used it and set the status to SENT
+		if (!add_auth_vector(private_identity, public_identity, avlist[0]))
+			free_auth_vector(avlist[0]);
+	}
 
 
     //free memory
     //free memory
     if (maa) cdpb.AAAFreeMessage(&maa);
     if (maa) cdpb.AAAFreeMessage(&maa);

+ 1 - 0
modules/ims_auth/cxdx_mar.h

@@ -63,6 +63,7 @@ typedef struct saved_transaction {
 	unsigned int ticks;
 	unsigned int ticks;
 	cfg_action_t *act;
 	cfg_action_t *act;
 	int is_proxy_auth;
 	int is_proxy_auth;
+	int is_resync;
     str realm;
     str realm;
 } saved_transaction_t;
 } saved_transaction_t;
 
 

+ 3 - 2
modules/ims_charging/ccr.c

@@ -2,8 +2,10 @@
 
 
 #include "ccr.h"
 #include "ccr.h"
 #include "Ro_data.h"
 #include "Ro_data.h"
+#include "ro_avp.h"
 
 
 extern cdp_avp_bind_t *cdp_avp;
 extern cdp_avp_bind_t *cdp_avp;
+extern struct cdp_binds cdpb;
 
 
 int Ro_write_event_type_avps(AAA_AVP_LIST * avp_list, event_type_t * x) {
 int Ro_write_event_type_avps(AAA_AVP_LIST * avp_list, event_type_t * x) {
     AAA_AVP_LIST aList = {0, 0};
     AAA_AVP_LIST aList = {0, 0};
@@ -187,9 +189,8 @@ AAAMessage * Ro_write_CCR_avps(AAAMessage * ccr, Ro_CCR_t* x) {
     if (!ccr) return 0;
     if (!ccr) return 0;
 
 
     if (!cdp_avp->base.add_Origin_Host(&(ccr->avpList), x->origin_host, 0)) goto error;
     if (!cdp_avp->base.add_Origin_Host(&(ccr->avpList), x->origin_host, 0)) goto error;
-
     if (!cdp_avp->base.add_Origin_Realm(&(ccr->avpList), x->origin_realm, 0)) goto error;
     if (!cdp_avp->base.add_Origin_Realm(&(ccr->avpList), x->origin_realm, 0)) goto error;
-    if (!cdp_avp->base.add_Destination_Realm(&(ccr->avpList), x->destination_realm, 0)) goto error;
+    if (!ro_add_destination_realm_avp(ccr, x->destination_realm)) goto error;
 
 
     if (!cdp_avp->base.add_Accounting_Record_Type(&(ccr->avpList), x->acct_record_type)) goto error;
     if (!cdp_avp->base.add_Accounting_Record_Type(&(ccr->avpList), x->acct_record_type)) goto error;
     if (!cdp_avp->base.add_Accounting_Record_Number(&(ccr->avpList), x->acct_record_number)) goto error;
     if (!cdp_avp->base.add_Accounting_Record_Number(&(ccr->avpList), x->acct_record_number)) goto error;

+ 0 - 1
modules/ims_charging/config.h

@@ -5,7 +5,6 @@ typedef struct {
     str origin_host;
     str origin_host;
     str origin_realm;
     str origin_realm;
     str destination_realm;
     str destination_realm;
-    str destination_host;
     str * service_context_id;
     str * service_context_id;
 } client_ro_cfg;
 } client_ro_cfg;
 
 

+ 24 - 49
modules/ims_charging/ims_ro.c

@@ -29,12 +29,14 @@
 #include "config.h"
 #include "config.h"
 #include "ro_session_hash.h"
 #include "ro_session_hash.h"
 #include "stats.h"
 #include "stats.h"
+#include "ro_avp.h"
 
 
 extern struct tm_binds tmb;
 extern struct tm_binds tmb;
 extern struct cdp_binds cdpb;
 extern struct cdp_binds cdpb;
 extern client_ro_cfg cfg;
 extern client_ro_cfg cfg;
 extern struct dlg_binds dlgb;
 extern struct dlg_binds dlgb;
 extern cdp_avp_bind_t *cdp_avp;
 extern cdp_avp_bind_t *cdp_avp;
+extern str ro_forced_peer;
 
 
 struct session_setup_data {
 struct session_setup_data {
 	struct ro_session *ro_session;
 	struct ro_session *ro_session;
@@ -84,34 +86,6 @@ struct sip_msg * trans_get_request_from_current_reply() {
     else return 0;
     else return 0;
 }
 }
 
 
-/**
- * Create and add an AVP to a Diameter message.
- * @param m - Diameter message to add to
- * @param d - the payload data
- * @param len - length of the payload data
- * @param avp_code - the code of the AVP
- * @param flags - flags for the AVP
- * @param vendorid - the value of the vendor id or 0 if none
- * @param data_do - what to do with the data when done
- * @param func - the name of the calling function, for debugging purposes
- * @returns 1 on success or 0 on failure
- */
-static inline int Ro_add_avp(AAAMessage *m, char *d, int len, int avp_code, int flags, int vendorid, int data_do, const char *func) {
-    AAA_AVP *avp;
-    if (vendorid != 0) flags |= AAA_AVP_FLAG_VENDOR_SPECIFIC;
-    avp = cdpb.AAACreateAVP(avp_code, flags, vendorid, d, len, data_do);
-    if (!avp) {
-        LM_ERR("%s: Failed creating avp\n", func);
-        return 0;
-    }
-    if (cdpb.AAAAddAVPToMessage(m, avp, m->avpList.tail) != AAA_ERR_SUCCESS) {
-        LM_ERR("%s: Failed adding avp to message\n", func);
-       cdpb.AAAFreeAVP(&avp);
-        return 0;
-    }
-    return 1;
-}
-
 /**
 /**
  * Create and add an AVP to a list of AVPs.
  * Create and add an AVP to a list of AVPs.
  * @param list - the AVP list to add to
  * @param list - the AVP list to add to
@@ -148,22 +122,6 @@ static inline int Ro_add_avp_list(AAA_AVP_LIST *list, char *d, int len, int avp_
     return 1;
     return 1;
 }
 }
 
 
-/**
- * Creates and adds a Destination-Realm AVP.
- * @param msg - the Diameter message to add to.
- * @param data - the value for the AVP payload
- * @returns 1 on success or 0 on error
- */
-inline int ro_add_destination_realm_avp(AAAMessage *msg, str data) {
-    return
-    Ro_add_avp(msg, data.s, data.len,
-            AVP_Destination_Realm,
-            AAA_AVP_FLAG_MANDATORY,
-            0,
-            AVP_DUPLICATE_DATA,
-            __FUNCTION__);
-}
-
 inline int Ro_add_cc_request(AAAMessage *msg, unsigned int cc_request_type, unsigned int cc_request_number) {
 inline int Ro_add_cc_request(AAAMessage *msg, unsigned int cc_request_type, unsigned int cc_request_number) {
     char x[4];
     char x[4];
     set_4bytes(x, cc_request_type);
     set_4bytes(x, cc_request_type);
@@ -631,8 +589,11 @@ void send_ccr_interim(struct ro_session* ro_session, unsigned int used, unsigned
 
 
     cdpb.AAASessionsUnlock(auth->hash);
     cdpb.AAASessionsUnlock(auth->hash);
 
 
-    //AAAMessage *cca = cdpb.AAASendRecvMessageToPeer(ccr, &cfg.destination_host);
-    cdpb.AAASendMessageToPeer(ccr, &cfg.destination_host, resume_on_interim_ccr, (void *) i_req);
+    if (ro_forced_peer.len > 0) {
+    	cdpb.AAASendMessageToPeer(ccr, &ro_forced_peer, resume_on_interim_ccr, (void *) i_req);
+    } else {
+    	cdpb.AAASendMessage(ccr, resume_on_interim_ccr, (void *) i_req);
+    }
 
 
 //    cdpb.AAASessionsUnlock(auth->hash);
 //    cdpb.AAASessionsUnlock(auth->hash);
 
 
@@ -850,7 +811,12 @@ void send_ccr_stop(struct ro_session *ro_session) {
     }
     }
 
 
     cdpb.AAASessionsUnlock(auth->hash);
     cdpb.AAASessionsUnlock(auth->hash);
-    cdpb.AAASendMessageToPeer(ccr, &cfg.destination_host, resume_on_termination_ccr, NULL);
+
+    if (ro_forced_peer.len > 0) {
+    	cdpb.AAASendMessageToPeer(ccr, &ro_forced_peer, resume_on_termination_ccr, NULL);
+    } else {
+    	cdpb.AAASendMessage(ccr, resume_on_termination_ccr, NULL);
+    }
 
 
     Ro_free_CCR(ro_ccr_data);
     Ro_free_CCR(ro_ccr_data);
 
 
@@ -1050,7 +1016,14 @@ int Ro_Send_CCR(struct sip_msg *msg, struct dlg_cell *dlg, int dir, str* charge_
 
 
     LM_DBG("Sending CCR Diameter message.\n");
     LM_DBG("Sending CCR Diameter message.\n");
     cdpb.AAASessionsUnlock(cc_acc_session->hash);
     cdpb.AAASessionsUnlock(cc_acc_session->hash);
-    cdpb.AAASendMessageToPeer(ccr, &cfg.destination_host, resume_on_initial_ccr, (void *) ssd);
+
+    if (ro_forced_peer.len > 0) {
+    	LM_DBG("Sending message with Peer\n");
+    	cdpb.AAASendMessageToPeer(ccr, &ro_forced_peer, resume_on_initial_ccr, (void *) ssd);
+    } else {
+    	LM_DBG("Sending message without Peer and realm is [%.*s]\n", ccr->dest_realm->data.len, ccr->dest_realm->data.s);
+    	cdpb.AAASendMessage(ccr, resume_on_initial_ccr, (void *) ssd);
+    }
 
 
     Ro_free_CCR(ro_ccr_data);
     Ro_free_CCR(ro_ccr_data);
 
 
@@ -1177,7 +1150,9 @@ error0:
     LM_DBG("Trying to reserve credit on initial INVITE failed on cdp callback\n");
     LM_DBG("Trying to reserve credit on initial INVITE failed on cdp callback\n");
     create_cca_return_code(error_code);
     create_cca_return_code(error_code);
 
 
-    cdpb.AAAFreeMessage(&cca);
+    if (!is_timeout && cca) {
+    	cdpb.AAAFreeMessage(&cca);
+    }
 
 
     if (t)
     if (t)
     	tmb.unref_cell(t);
     	tmb.unref_cell(t);

+ 1 - 4
modules/ims_charging/mod.c

@@ -122,7 +122,7 @@ stat_export_t charging_stats[] = {
     {"ccr_responses_time", STAT_NO_RESET, &ccr_responses_time},
     {"ccr_responses_time", STAT_NO_RESET, &ccr_responses_time},
     {"billed_secs", STAT_NO_RESET, &billed_secs},
     {"billed_secs", STAT_NO_RESET, &billed_secs},
     {"killed_calls", STAT_NO_RESET, &killed_calls},
     {"killed_calls", STAT_NO_RESET, &killed_calls},
-    {"ccr_timeouts", STAT_NO_RESET, &ccr_timeouts},
+    {"ccr_timeouts", 0, &ccr_timeouts},
     {0, 0, 0}
     {0, 0, 0}
 };
 };
 
 
@@ -150,9 +150,6 @@ int fix_parameters() {
 	cfg.destination_realm.s = ro_destination_realm_s;
 	cfg.destination_realm.s = ro_destination_realm_s;
 	cfg.destination_realm.len = strlen(ro_destination_realm_s);
 	cfg.destination_realm.len = strlen(ro_destination_realm_s);
 
 
-	cfg.destination_host.s = ro_destination_host_s;
-	cfg.destination_host.len = strlen(ro_destination_host_s);
-
 	cfg.service_context_id = shm_malloc(sizeof(str));
 	cfg.service_context_id = shm_malloc(sizeof(str));
 	if (!cfg.service_context_id) {
 	if (!cfg.service_context_id) {
 		LM_ERR("fix_parameters:not enough shm memory\n");
 		LM_ERR("fix_parameters:not enough shm memory\n");

+ 53 - 0
modules/ims_charging/ro_avp.c

@@ -0,0 +1,53 @@
+/*
+ * ro_avp.c
+ *
+ *  Created on: 29 May 2014
+ *      Author: jaybeepee
+ */
+#include "ro_avp.h"
+
+extern struct cdp_binds cdpb;
+/**
+ * Creates and adds a Destination-Realm AVP.
+ * @param msg - the Diameter message to add to.
+ * @param data - the value for the AVP payload
+ * @returns 1 on success or 0 on error
+ */
+int ro_add_destination_realm_avp(AAAMessage *msg, str data) {
+    return
+    Ro_add_avp(msg, data.s, data.len,
+            AVP_Destination_Realm,
+            AAA_AVP_FLAG_MANDATORY,
+            0,
+            AVP_DUPLICATE_DATA,
+            __FUNCTION__);
+}
+
+/**
+ * Create and add an AVP to a Diameter message.
+ * @param m - Diameter message to add to
+ * @param d - the payload data
+ * @param len - length of the payload data
+ * @param avp_code - the code of the AVP
+ * @param flags - flags for the AVP
+ * @param vendorid - the value of the vendor id or 0 if none
+ * @param data_do - what to do with the data when done
+ * @param func - the name of the calling function, for debugging purposes
+ * @returns 1 on success or 0 on failure
+ */
+int Ro_add_avp(AAAMessage *m, char *d, int len, int avp_code, int flags, int vendorid, int data_do, const char *func) {
+    AAA_AVP *avp;
+    if (vendorid != 0) flags |= AAA_AVP_FLAG_VENDOR_SPECIFIC;
+    avp = cdpb.AAACreateAVP(avp_code, flags, vendorid, d, len, data_do);
+    if (!avp) {
+        LM_ERR("%s: Failed creating avp\n", func);
+        return 0;
+    }
+    if (cdpb.AAAAddAVPToMessage(m, avp, m->avpList.tail) != AAA_ERR_SUCCESS) {
+        LM_ERR("%s: Failed adding avp to message\n", func);
+       cdpb.AAAFreeAVP(&avp);
+        return 0;
+    }
+    return 1;
+}
+

+ 17 - 0
modules/ims_charging/ro_avp.h

@@ -0,0 +1,17 @@
+/*
+ * ro_avp.h
+ *
+ *  Created on: 29 May 2014
+ *      Author: jaybeepee
+ */
+
+#ifndef RO_AVP_H_
+#define RO_AVP_H_
+
+#include "../cdp/cdp_load.h"
+
+int ro_add_destination_realm_avp(AAAMessage *msg, str data);
+int Ro_add_avp(AAAMessage *m, char *d, int len, int avp_code, int flags, int vendorid, int data_do, const char *func);
+
+
+#endif /* RO_AVP_H_ */

+ 4 - 0
modules/ims_registrar_pcscf/notify.c

@@ -68,6 +68,7 @@
 #define EVENT_CREATED 3
 #define EVENT_CREATED 3
 #define EVENT_REFRESHED 4
 #define EVENT_REFRESHED 4
 #define EVENT_EXPIRED 5
 #define EVENT_EXPIRED 5
+#define EVENT_DEACTIVATED 6
 
 
 #define RESULT_ERROR -1
 #define RESULT_ERROR -1
 #define RESULT_CONTACTS_FOUND 1
 #define RESULT_CONTACTS_FOUND 1
@@ -182,6 +183,9 @@ int reginfo_parse_event(char * s) {
 			if (strncmp(s, "registered", 10) ==  0) return EVENT_REGISTERED;
 			if (strncmp(s, "registered", 10) ==  0) return EVENT_REGISTERED;
 			if (strncmp(s, "terminated", 10) ==  0) return EVENT_TERMINATED;
 			if (strncmp(s, "terminated", 10) ==  0) return EVENT_TERMINATED;
 			break;
 			break;
+	    case 11:
+			if (strncmp(s, "deactivated", 11) ==  0) return EVENT_DEACTIVATED;
+			break;
 		case 12:
 		case 12:
 			if (strncmp(s, "unregistered", 12) ==  0) return EVENT_UNREGISTERED;
 			if (strncmp(s, "unregistered", 12) ==  0) return EVENT_UNREGISTERED;
 			break;
 			break;

+ 2 - 1
modules/ims_registrar_scscf/registrar_notify.c

@@ -1444,6 +1444,7 @@ str generate_reginfo_full(udomain_t* _t, str* impu_list, int num_impus) {
         res = ul.get_impurecord(_t, &(impu_list[i]), &r);
         res = ul.get_impurecord(_t, &(impu_list[i]), &r);
         if (res != 0) {
         if (res != 0) {
             LM_WARN("impu disappeared, ignoring it\n");
             LM_WARN("impu disappeared, ignoring it\n");
+	    ul.unlock_udomain(_t, &impu_list[i]);
             continue;
             continue;
         }
         }
         LM_DBG("Retrieved IMPU record");
         LM_DBG("Retrieved IMPU record");
@@ -1600,7 +1601,7 @@ str get_reginfo_partial(impurecord_t *r, ucontact_t *c, int event_type) {
             }
             }
             if (c->q != -1) {
             if (c->q != -1) {
                 float q = (float) c->q / 1000;
                 float q = (float) c->q / 1000;
-                sprintf(pad.s, contact_s_q.s, c, r_active.len, r_active.s, r_registered.len, r_registered.s, c->expires - act_time, q);
+		sprintf(pad.s, contact_s_q.s, c, state.len, state.s, event.len, event.s, expires, q);
             } else
             } else
                 sprintf(pad.s, contact_s.s, c, state.len, state.s, event.len, event.s, expires);
                 sprintf(pad.s, contact_s.s, c, state.len, state.s, event.len, event.s, expires);
             pad.len = strlen(pad.s);
             pad.len = strlen(pad.s);

+ 3 - 4
modules/ims_usrloc_pcscf/udomain.c

@@ -715,18 +715,17 @@ static inline pcontact_info_t* dbrow2info( db_val_t *vals, str *contact)
 	if (VAL_NULL(vals+5) || !rx_session_id.s || !rx_session_id.s[0]) {
 	if (VAL_NULL(vals+5) || !rx_session_id.s || !rx_session_id.s[0]) {
 		rx_session_id.len = 0;
 		rx_session_id.len = 0;
 		rx_session_id.s = 0;
 		rx_session_id.s = 0;
-		LM_DBG("2\n");
 	} else {
 	} else {
 		rx_session_id.len = strlen(rx_session_id.s);
 		rx_session_id.len = strlen(rx_session_id.s);
 	}
 	}
 	ci.rx_regsession_id = &rx_session_id;
 	ci.rx_regsession_id = &rx_session_id;
 	if (VAL_NULL(vals + 6)) {
 	if (VAL_NULL(vals + 6)) {
-		LM_CRIT("empty registration state in DB\n");
+		LM_ERR("empty registration state in DB\n");
 		return 0;
 		return 0;
 	}
 	}
 	ci.reg_state = VAL_INT(vals + 6);
 	ci.reg_state = VAL_INT(vals + 6);
 	if (VAL_NULL(vals + 7)) {
 	if (VAL_NULL(vals + 7)) {
-		LM_CRIT("empty expire\n");
+		LM_ERR("empty expire\n");
 		return 0;
 		return 0;
 	}
 	}
 	ci.expires = VAL_TIME(vals + 7);
 	ci.expires = VAL_TIME(vals + 7);
@@ -741,7 +740,7 @@ static inline pcontact_info_t* dbrow2info( db_val_t *vals, str *contact)
 
 
 	//public IDs - implicit set
 	//public IDs - implicit set
 	implicit_impus.s = (char*) VAL_STRING(vals + 10);
 	implicit_impus.s = (char*) VAL_STRING(vals + 10);
-	if (!VAL_NULL(vals + 8) && implicit_impus.s && implicit_impus.s[0]) {
+	if (!VAL_NULL(vals + 10) && implicit_impus.s && implicit_impus.s[0]) {
 		//how many
 		//how many
 		n=0;
 		n=0;
 		p = implicit_impus.s;
 		p = implicit_impus.s;

+ 6 - 0
modules/ims_usrloc_scscf/usrloc_db.c

@@ -637,6 +637,7 @@ int preload_udomain(db1_con_t* _c, udomain_t* _d) {
 			if (impu_id < 0) {
 			if (impu_id < 0) {
 				LM_ERR("impu_id has not been set [%.*s] - we cannot read contacts from DB....aborting preload\n", impu.len, impu.s);
 				LM_ERR("impu_id has not been set [%.*s] - we cannot read contacts from DB....aborting preload\n", impu.len, impu.s);
 				//TODO: check frees
 				//TODO: check frees
+				unlock_udomain(_d, &impu);
 				continue;
 				continue;
 			}
 			}
 			impu_id_len = int_to_str_len(impu_id);
 			impu_id_len = int_to_str_len(impu_id);
@@ -649,6 +650,7 @@ int preload_udomain(db1_con_t* _c, udomain_t* _d) {
 				if (!query_buffer.s) {
 				if (!query_buffer.s) {
 					LM_ERR("mo more pkg mem\n");
 					LM_ERR("mo more pkg mem\n");
 					//TODO: check free
 					//TODO: check free
+					unlock_udomain(_d, &impu);
 					return -1;
 					return -1;
 				}
 				}
 				query_buffer_len = len;
 				query_buffer_len = len;
@@ -661,11 +663,13 @@ int preload_udomain(db1_con_t* _c, udomain_t* _d) {
 				LM_ERR("Unable to query DB for contacts associated with impu [%.*s]\n",
 				LM_ERR("Unable to query DB for contacts associated with impu [%.*s]\n",
 						impu.len, impu.s);
 						impu.len, impu.s);
 				ul_dbf.free_result(_c, contact_rs);
 				ul_dbf.free_result(_c, contact_rs);
+				unlock_udomain(_d, &impu);
 				continue;
 				continue;
 			}
 			}
 			if (RES_ROW_N(contact_rs) == 0) {
 			if (RES_ROW_N(contact_rs) == 0) {
 				LM_DBG("no contacts associated with impu [%.*s]\n",impu.len, impu.s);
 				LM_DBG("no contacts associated with impu [%.*s]\n",impu.len, impu.s);
 				ul_dbf.free_result(_c, contact_rs);
 				ul_dbf.free_result(_c, contact_rs);
+				unlock_udomain(_d, &impu);
 				continue;
 				continue;
 			}
 			}
 
 
@@ -682,6 +686,7 @@ int preload_udomain(db1_con_t* _c, udomain_t* _d) {
 					}
 					}
 					if (dbrow2contact(contact_vals, &contact_data) != 0) {
 					if (dbrow2contact(contact_vals, &contact_data) != 0) {
 						LM_ERR("unable to convert contact row from DB into valid data... moving on\n");
 						LM_ERR("unable to convert contact row from DB into valid data... moving on\n");
+						unlock_udomain(_d, &impu);
 						continue;
 						continue;
 					}
 					}
 
 
@@ -695,6 +700,7 @@ int preload_udomain(db1_con_t* _c, udomain_t* _d) {
 					if (ul_dbf.fetch_result(_c, &contact_rs, ul_fetch_rows) < 0) {
 					if (ul_dbf.fetch_result(_c, &contact_rs, ul_fetch_rows) < 0) {
 						LM_ERR("fetching rows failed\n");
 						LM_ERR("fetching rows failed\n");
 						ul_dbf.free_result(_c, contact_rs);
 						ul_dbf.free_result(_c, contact_rs);
+						unlock_udomain(_d, &impu);
 						return -1;
 						return -1;
 					}
 					}
 				} else {
 				} else {

+ 1 - 0
modules/ipops/ipops_pv.c

@@ -262,6 +262,7 @@ int pv_parse_dns_name(pv_spec_t *sp, str *in)
 
 
 error:
 error:
 	LM_ERR("error at PV dns name: %.*s\n", in->len, in->s);
 	LM_ERR("error at PV dns name: %.*s\n", in->len, in->s);
+	if(dpv) pkg_free(dpv);
 	return -1;
 	return -1;
 }
 }
 
 

+ 3 - 1
modules/kex/core_stats.c

@@ -122,6 +122,8 @@ static int km_cb_req_stats(struct sip_msg *msg,
 		unsigned int flags, void *param)
 		unsigned int flags, void *param)
 {
 {
 	update_stat(rcv_reqs, 1);
 	update_stat(rcv_reqs, 1);
+	if(!IS_SIP(msg))
+		return 1;
 	if(msg->first_line.u.request.method_value==METHOD_OTHER)
 	if(msg->first_line.u.request.method_value==METHOD_OTHER)
 		update_stat(unsupported_methods, 1);
 		update_stat(unsupported_methods, 1);
 	return 1;
 	return 1;
@@ -462,7 +464,7 @@ static const char* rpc_stats_clear_statistics_doc[2] =
 rpc_export_t kex_stats_rpc[] =
 rpc_export_t kex_stats_rpc[] =
 {
 {
 	{"stats.get_statistics",   rpc_stats_get_statistics,
 	{"stats.get_statistics",   rpc_stats_get_statistics,
-							rpc_stats_get_statistics_doc,   0},
+							rpc_stats_get_statistics_doc,   RET_ARRAY},
 	{"stats.reset_statistics", rpc_stats_reset_statistics,
 	{"stats.reset_statistics", rpc_stats_reset_statistics,
 							rpc_stats_reset_statistics_doc, 0},
 							rpc_stats_reset_statistics_doc, 0},
 	{"stats.clear_statistics", rpc_stats_clear_statistics,
 	{"stats.clear_statistics", rpc_stats_clear_statistics,

+ 4 - 4
modules/mtree/mtree_mod.c

@@ -555,8 +555,7 @@ static int mt_load_db(m_tree_t *pt)
 		} else {
 		} else {
 			if(RES_ROW_N(db_res)==0)
 			if(RES_ROW_N(db_res)==0)
 			{
 			{
-				mt_dbf.free_result(db_con, db_res);
-				return 0;
+				goto dbreloaded;
 			}
 			}
 		}
 		}
 	} else {
 	} else {
@@ -566,8 +565,7 @@ static int mt_load_db(m_tree_t *pt)
 		{
 		{
 			if(ret==0)
 			if(ret==0)
 			{
 			{
-				mt_dbf.free_result(db_con, db_res);
-				return 0;
+				goto dbreloaded;
 			} else {
 			} else {
 				goto error;
 				goto error;
 			}
 			}
@@ -622,6 +620,8 @@ static int mt_load_db(m_tree_t *pt)
 			break;
 			break;
 		}
 		}
 	}  while(RES_ROW_N(db_res)>0);
 	}  while(RES_ROW_N(db_res)>0);
+
+dbreloaded:
 	mt_dbf.free_result(db_con, db_res);
 	mt_dbf.free_result(db_con, db_res);
 
 
 
 

+ 4 - 2
modules/presence_dialoginfo/notify_body.c

@@ -101,7 +101,7 @@ str* agregate_xmls(str* pres_user, str* pres_domain, str** body_array, int n)
 	xmlDocPtr  doc = NULL;
 	xmlDocPtr  doc = NULL;
 	xmlNodePtr root_node = NULL;
 	xmlNodePtr root_node = NULL;
 	xmlNsPtr   namespace = NULL;
 	xmlNsPtr   namespace = NULL;
-	int winner_priority = -1, priority;
+	/*int winner_priority = -1, priority;*/
 
 
 	xmlNodePtr p_root= NULL;
 	xmlNodePtr p_root= NULL;
 	xmlDocPtr* xml_array ;
 	xmlDocPtr* xml_array ;
@@ -111,6 +111,7 @@ str* agregate_xmls(str* pres_user, str* pres_domain, str** body_array, int n)
 	xmlNodePtr confirmed_node = NULL;
 	xmlNodePtr confirmed_node = NULL;
 	xmlNodePtr proceed_node = NULL;
 	xmlNodePtr proceed_node = NULL;
 	xmlNodePtr trying_node = NULL;
 	xmlNodePtr trying_node = NULL;
+	xmlNodePtr next_node = NULL;
 
 
 
 
 	char *state = NULL;
 	char *state = NULL;
@@ -214,7 +215,8 @@ str* agregate_xmls(str* pres_user, str* pres_domain, str** body_array, int n)
 			goto error;
 			goto error;
 		}
 		}
 		if (p_root->children) {
 		if (p_root->children) {
-			for (node = p_root->children; node; node = node->next) {
+			for (node = p_root->children; node; node = next_node) {
+				next_node = node->next;
 				if (node->type == XML_ELEMENT_NODE) {
 				if (node->type == XML_ELEMENT_NODE) {
 					LM_DBG("node type: Element, name: %s\n", node->name);
 					LM_DBG("node type: Element, name: %s\n", node->name);
 					/* we do not copy the node, but unlink it and then add it ot the new node
 					/* we do not copy the node, but unlink it and then add it ot the new node

+ 5 - 0
modules/pv/pv_core.c

@@ -994,6 +994,11 @@ int pv_get_pai(struct sip_msg *msg, pv_param_t *param,
 	}
 	}
 
 
 	pai_body = get_pai(msg);
 	pai_body = get_pai(msg);
+	if(pai_body==NULL || pai_body->id==NULL)
+	{
+		LM_DBG("no P-Asserted-Identity header or empty body\n");
+		return pv_get_null(msg, param, res);
+	}
 	pai_uri = &pai_body->id[0];
 	pai_uri = &pai_body->id[0];
 	cur_id = 0;
 	cur_id = 0;
 	i = 0;
 	i = 0;

+ 5 - 5
modules/pv/pv_trans.c

@@ -126,13 +126,13 @@ static int urlencode_param(str *sin, str *sout)
 {
 {
 	char *at, *p;
 	char *at, *p;
 
 
-	at = sout->s;
-	p  = sin->s;
-
 	if (sin==NULL || sout==NULL || sin->s==NULL || sout->s==NULL ||
 	if (sin==NULL || sout==NULL || sin->s==NULL || sout->s==NULL ||
 			sin->len<0 || sout->len < 3*sin->len+1)
 			sin->len<0 || sout->len < 3*sin->len+1)
 		return -1;
 		return -1;
 
 
+	at = sout->s;
+	p  = sin->s;
+
 	while (p < sin->s+sin->len) {
 	while (p < sin->s+sin->len) {
 		if (isalnum(*p) || *p == '-' || *p == '_' || *p == '.' || *p == '~')
 		if (isalnum(*p) || *p == '-' || *p == '_' || *p == '.' || *p == '~')
 			*at++ = *p;
 			*at++ = *p;
@@ -1655,7 +1655,7 @@ int tr_eval_line(struct sip_msg *msg, tr_param_t *tp, int subtype,
 					if(p==NULL)
 					if(p==NULL)
 					{
 					{
 						/* last line */
 						/* last line */
-						mv.len = (val->rs.s + val->rs.len) - p;
+						mv.len = (val->rs.s + val->rs.len) - mv.s;
 					} else {
 					} else {
 						mv.len = p - mv.s;
 						mv.len = p - mv.s;
 					}
 					}
@@ -1737,7 +1737,7 @@ int tr_eval_line(struct sip_msg *msg, tr_param_t *tp, int subtype,
 					if(p==NULL)
 					if(p==NULL)
 					{
 					{
 						/* last line */
 						/* last line */
-						mv.len = (val->rs.s + val->rs.len) - p;
+						mv.len = (val->rs.s + val->rs.len) - mv.s;
 					} else {
 					} else {
 						mv.len = p - mv.s;
 						mv.len = p - mv.s;
 					}
 					}

+ 8 - 2
modules/rls/list.h

@@ -41,8 +41,11 @@ static inline list_entry_t *list_insert(str *strng, list_entry_t *list, int *dup
 	if (cmp == 0)
 	if (cmp == 0)
 	{
 	{
 		if (duplicate != NULL)
 		if (duplicate != NULL)
+		{
 			*duplicate = 1;
 			*duplicate = 1;
-		return list;
+			pkg_free(p);
+			return list;
+		}
 	}
 	}
 	if (cmp > 0)
 	if (cmp > 0)
 	{
 	{
@@ -58,8 +61,11 @@ static inline list_entry_t *list_insert(str *strng, list_entry_t *list, int *dup
 		if (cmp == 0)
 		if (cmp == 0)
 		{
 		{
 			if (duplicate != NULL)
 			if (duplicate != NULL)
+			{
 				*duplicate = 1;
 				*duplicate = 1;
-			return list;
+				pkg_free(p);
+				return list;
+			}
 		}
 		}
 
 
 		p->next = q->next;
 		p->next = q->next;

+ 1 - 1
modules/rls/notify.c

@@ -1366,7 +1366,7 @@ int rls_get_resource_list(str *rl_uri, str *username, str *domain,
 	{
 	{
 		/* No path specified - use all resource-lists. */
 		/* No path specified - use all resource-lists. */
 		*rl_node = XMLDocGetNodeByName(*xmldoc,"resource-lists", NULL);
 		*rl_node = XMLDocGetNodeByName(*xmldoc,"resource-lists", NULL);
-		if(rl_node==NULL)
+		if(*rl_node==NULL)
 		{
 		{
 			LM_ERR("no resource-lists node in XML document\n");
 			LM_ERR("no resource-lists node in XML document\n");
 			goto error;
 			goto error;

+ 2 - 0
modules/rls/subscribe.c

@@ -1037,6 +1037,8 @@ int send_resource_subs(char* uri, void* param)
 		LM_WARN("%.*s has %.*s multiple times in the same resource list\n",
 		LM_WARN("%.*s has %.*s multiple times in the same resource list\n",
 			s->watcher_uri->len, s->watcher_uri->s,
 			s->watcher_uri->len, s->watcher_uri->s,
 			s->pres_uri->len, s->pres_uri->s);
 			s->pres_uri->len, s->pres_uri->s);
+		pkg_free(tmp_str->s);
+		pkg_free(tmp_str);
 		return 1;
 		return 1;
 	}
 	}
 
 

+ 1 - 1
modules/rls/utils.h

@@ -21,7 +21,7 @@
  *
  *
  */
  */
 
 
-#ifndef RLS_URILS_H
+#ifndef RLS_UTILS_H
 #define RLS_UTILS_H
 #define RLS_UTILS_H
 
 
 #include "../../ut.h"
 #include "../../ut.h"

+ 22 - 19
modules/sdpops/README

@@ -10,7 +10,7 @@ Daniel-Constantin Mierla
 
 
    <[email protected]>
    <[email protected]>
 
 
-   Copyright (c) 2011 asipto.com
+   Copyright © 2011 asipto.com
      __________________________________________________________________
      __________________________________________________________________
 
 
    Table of Contents
    Table of Contents
@@ -149,7 +149,7 @@ Chapter 1. Admin Guide
    4.17. sdp_with_ice()
    4.17. sdp_with_ice()
    4.18. sdp_get_line_startswith(avpvar, string)
    4.18. sdp_get_line_startswith(avpvar, string)
 
 
-4.1.  sdp_remove_codecs_by_id(list)
+4.1. sdp_remove_codecs_by_id(list)
 
 
    Remove the codecs provided in the parameter 'list' from all media
    Remove the codecs provided in the parameter 'list' from all media
    streams found in SDP payload. The parameter 'list' must be one item or
    streams found in SDP payload. The parameter 'list' must be one item or
@@ -166,7 +166,7 @@ sdp_remove_codecs_by_id("0");
 sdp_remove_codecs_by_id("0,8,3");
 sdp_remove_codecs_by_id("0,8,3");
 ...
 ...
 
 
-4.2.  sdp_remove_codecs_by_name(list)
+4.2. sdp_remove_codecs_by_name(list)
 
 
    Remove the codecs provided in the parameter 'list' from all media
    Remove the codecs provided in the parameter 'list' from all media
    streams found in SDP payload. The parameter 'list' must be one item or
    streams found in SDP payload. The parameter 'list' must be one item or
@@ -183,7 +183,7 @@ sdp_remove_codecs_by_name("PCMU");
 sdp_remove_codecs_by_name("PCMU,PCMA,GSM");
 sdp_remove_codecs_by_name("PCMU,PCMA,GSM");
 ...
 ...
 
 
-4.3.  sdp_remove_line_by_prefix(string)
+4.3. sdp_remove_line_by_prefix(string)
 
 
    Remove all SDP attribute lines beginning with 'string' in all media
    Remove all SDP attribute lines beginning with 'string' in all media
    streams.
    streams.
@@ -202,7 +202,7 @@ if ($si == "2001:DB8::8:800:200C:417A"
 
 
 ...
 ...
 
 
-4.4.  sdp_keep_codecs_by_id(list [, mtype])
+4.4. sdp_keep_codecs_by_id(list [, mtype])
 
 
    Keep only the codecs provided in the parameter 'list' from all media
    Keep only the codecs provided in the parameter 'list' from all media
    streams found in SDP payload. The parameter 'list' must be one item or
    streams found in SDP payload. The parameter 'list' must be one item or
@@ -222,13 +222,16 @@ sdp_keep_codecs_by_id("0");
 sdp_keep_codecs_by_id("0,8,3", "audio");
 sdp_keep_codecs_by_id("0,8,3", "audio");
 ...
 ...
 
 
-4.5.  sdp_keep_codecs_by_name(list [, mtype])
+4.5. sdp_keep_codecs_by_name(list [, mtype])
 
 
    Keep only the codecs provided in the parameter 'list' from all media
    Keep only the codecs provided in the parameter 'list' from all media
    streams found in SDP payload. The parameter 'list' must be one or a
    streams found in SDP payload. The parameter 'list' must be one or a
    comma separated list of codec names. The parameter can be a static
    comma separated list of codec names. The parameter can be a static
    string or a variable holding the list of codec names.
    string or a variable holding the list of codec names.
 
 
+   Note that you have to explicitely keep 'telephone-event' in the list of
+   names if you want to keep DTMF attributes.
+
    Optional parameter mtype can be provided to apply the operations only
    Optional parameter mtype can be provided to apply the operations only
    to the streams matching m=mtype.
    to the streams matching m=mtype.
 
 
@@ -242,7 +245,7 @@ sdp_keep_codecs_by_name("PCMU");
 sdp_keep_codecs_by_name("PCMU,PCMA,GSM");
 sdp_keep_codecs_by_name("PCMU,PCMA,GSM");
 ...
 ...
 
 
-4.6.  sdp_with_media(type)
+4.6. sdp_with_media(type)
 
 
    Return true of the SDP has 'media=type ...' line. Useful to check the
    Return true of the SDP has 'media=type ...' line. Useful to check the
    content of the RTP sessions, such as 'audio' or 'video'. The parameter
    content of the RTP sessions, such as 'audio' or 'video'. The parameter
@@ -259,7 +262,7 @@ if(sdp_with_media("video"))
 }
 }
 ...
 ...
 
 
-4.7.  sdp_remove_media(type)
+4.7. sdp_remove_media(type)
 
 
    Remove the streams that match on 'm=type ...' line. The parameter can
    Remove the streams that match on 'm=type ...' line. The parameter can
    be static string or variable holding the media type.
    be static string or variable holding the media type.
@@ -272,7 +275,7 @@ if(sdp_with_media("video"))
 sdp_remove_media("video");
 sdp_remove_media("video");
 ...
 ...
 
 
-4.8.  sdp_with_transport(type)
+4.8. sdp_with_transport(type)
 
 
    Return true of the SDP has 'media=media port type ...' line. Useful to
    Return true of the SDP has 'media=media port type ...' line. Useful to
    check the transport of the RTP sessions, such as 'RTP/AVP', 'RTP/SAVP'
    check the transport of the RTP sessions, such as 'RTP/AVP', 'RTP/SAVP'
@@ -290,7 +293,7 @@ if(sdp_with_transport("RTP/SAVP"))
 }
 }
 ...
 ...
 
 
-4.9.  sdp_with_transport_like(string)
+4.9. sdp_with_transport_like(string)
 
 
    Returns true if the SDP has 'media=media port type ...' line, where
    Returns true if the SDP has 'media=media port type ...' line, where
    type contains string. The parameter can be static string or variable
    type contains string. The parameter can be static string or variable
@@ -307,7 +310,7 @@ if(sdp_with_transport_like("SAVPF"))
 }
 }
 ...
 ...
 
 
-4.10.  sdp_transport(pv)
+4.10. sdp_transport(pv)
 
 
    Assigns common media transport (if any) of 'm' lines to pv argument.
    Assigns common media transport (if any) of 'm' lines to pv argument.
    Returns 1 if common media transport was found, -2 if there was no
    Returns 1 if common media transport was found, -2 if there was no
@@ -320,7 +323,7 @@ if(sdp_with_transport_like("SAVPF"))
 sdp_transport("$avp(caller_rtp_transport)");
 sdp_transport("$avp(caller_rtp_transport)");
 ...
 ...
 
 
-4.11.  sdp_remove_transport(type)
+4.11. sdp_remove_transport(type)
 
 
    Remove the streams that match on 'm=media port type ...' line. The
    Remove the streams that match on 'm=media port type ...' line. The
    parameter can be static string or variable holding the transport type.
    parameter can be static string or variable holding the transport type.
@@ -333,7 +336,7 @@ sdp_transport("$avp(caller_rtp_transport)");
 sdp_remove_transport("RTP/AVP");
 sdp_remove_transport("RTP/AVP");
 ...
 ...
 
 
-4.12.  sdp_with_codecs_by_id(list)
+4.12. sdp_with_codecs_by_id(list)
 
 
    Returns true if any of the codecs provided in the parameter 'list' from
    Returns true if any of the codecs provided in the parameter 'list' from
    all media streams is found in SDP payload. The parameter 'list' must be
    all media streams is found in SDP payload. The parameter 'list' must be
@@ -350,7 +353,7 @@ if(sdp_with_codecs_by_id("0")) { ... }
 if(sdp_with_codecs_by_id("0,8,3")) { ... }
 if(sdp_with_codecs_by_id("0,8,3")) { ... }
 ...
 ...
 
 
-4.13.  sdp_with_codecs_by_name(list)
+4.13. sdp_with_codecs_by_name(list)
 
 
    Returns true if any of the codecs provided in the parameter 'list' from
    Returns true if any of the codecs provided in the parameter 'list' from
    all media streams is found in SDP payload. The parameter 'list' must be
    all media streams is found in SDP payload. The parameter 'list' must be
@@ -367,7 +370,7 @@ if(sdp_with_codecs_by_name("PCMU")) { ... }
 if(sdp_with_codecs_by_name("PCMU,PCMA,GSM")) { ... }
 if(sdp_with_codecs_by_name("PCMU,PCMA,GSM")) { ... }
 ...
 ...
 
 
-4.14.  sdp_print(level)
+4.14. sdp_print(level)
 
 
    Print the SDP internal structure to log 'level'. The parameter can be
    Print the SDP internal structure to log 'level'. The parameter can be
    static integer or variable holding the integer value of the log level.
    static integer or variable holding the integer value of the log level.
@@ -380,7 +383,7 @@ if(sdp_with_codecs_by_name("PCMU,PCMA,GSM")) { ... }
 sdp_print("1");
 sdp_print("1");
 ...
 ...
 
 
-4.15.  sdp_get(avpvar)
+4.15. sdp_get(avpvar)
 
 
    Store the SDP part of message body in an AVP. Return 1 if SDP is found,
    Store the SDP part of message body in an AVP. Return 1 if SDP is found,
    -1 on error and -2 if there is no SDP part in the message body.
    -1 on error and -2 if there is no SDP part in the message body.
@@ -392,7 +395,7 @@ sdp_print("1");
 sdp_get("$avp(sdp)");
 sdp_get("$avp(sdp)");
 ...
 ...
 
 
-4.16.  sdp_content()
+4.16. sdp_content()
 
 
    Return true if the SIP message has SDP body or a SDP part in body.
    Return true if the SIP message has SDP body or a SDP part in body.
 
 
@@ -405,7 +408,7 @@ if(sdp_content()) {
 }
 }
 ...
 ...
 
 
-4.17.  sdp_with_ice()
+4.17. sdp_with_ice()
 
 
    Return true if the SIP message has SDP body that contains ICE candidate
    Return true if the SIP message has SDP body that contains ICE candidate
    attribute(s).
    attribute(s).
@@ -419,7 +422,7 @@ if(sdp_with_ice()) {
 }
 }
 ...
 ...
 
 
-4.18.  sdp_get_line_startswith(avpvar, string)
+4.18. sdp_get_line_startswith(avpvar, string)
 
 
    Store the search part of SDP body message with line beginning with
    Store the search part of SDP body message with line beginning with
    'string' in an AVP. Return 1 if 'string' is found in SDP, -1 on error
    'string' in an AVP. Return 1 if 'string' is found in SDP, -1 on error

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

@@ -185,6 +185,10 @@ sdp_keep_codecs_by_id("0,8,3", "audio");
 			be one or a comma separated list of codec names. The
 			be one or a comma separated list of codec names. The
 			parameter can be a static string or a variable holding the
 			parameter can be a static string or a variable holding the
 			list of codec names.
 			list of codec names.
+	    </para>
+		<para>
+			Note that you have to explicitely keep 'telephone-event' in the list
+			of names if you want to keep DTMF attributes.
 	    </para>
 	    </para>
 		<para>
 		<para>
 			Optional parameter mtype can be provided to apply the operations
 			Optional parameter mtype can be provided to apply the operations

+ 1 - 1
modules/siputils/checks.c

@@ -354,7 +354,7 @@ int tel2sip(struct sip_msg* _msg, char* _uri, char* _hostpart, char* _res)
     if (strncasecmp(uri.s, "tel:", 4) != 0) return 1;
     if (strncasecmp(uri.s, "tel:", 4) != 0) return 1;
     
     
     /* reserve memory for clean tel uri */
     /* reserve memory for clean tel uri */
-    tel_uri.s = pkg_malloc(uri.len);
+    tel_uri.s = pkg_malloc(uri.len+1);
     if (tel_uri.s == 0) {
     if (tel_uri.s == 0) {
 	LM_ERR("no more pkg memory\n");
 	LM_ERR("no more pkg memory\n");
 	return -1;
 	return -1;

+ 10 - 5
modules/siputils/sipops.c

@@ -92,7 +92,7 @@ int w_cmp_aor(struct sip_msg *msg, char *uri1, char *uri2)
 
 
 int w_is_gruu(sip_msg_t *msg, char *uri1, char *p2)
 int w_is_gruu(sip_msg_t *msg, char *uri1, char *p2)
 {
 {
-	str s1;
+        str s1, *s2;
 	sip_uri_t turi;
 	sip_uri_t turi;
 	sip_uri_t *puri;
 	sip_uri_t *puri;
 
 
@@ -103,12 +103,17 @@ int w_is_gruu(sip_msg_t *msg, char *uri1, char *p2)
 			LM_ERR("cannot get first parameter\n");
 			LM_ERR("cannot get first parameter\n");
 			return -8;
 			return -8;
 		}
 		}
-		if(parse_uri(s1.s, s1.len, &turi)!=0)
-			return -1;
+		if(parse_uri(s1.s, s1.len, &turi)!=0) {
+		    LM_ERR("parsing of uri '%.*s' failed\n", s1.len, s1.s);
+		    return -1;
+		}
 		puri = &turi;
 		puri = &turi;
 	} else {
 	} else {
-		if(parse_sip_msg_uri(msg)<0)
-			return -1;
+  	        if(parse_sip_msg_uri(msg)<0) {
+		    s2 = GET_RURI(msg);
+  		    LM_ERR("parsing of uri '%.*s' failed\n", s2->len, s2->s);
+		    return -1;
+		}
 		puri = &msg->parsed_uri;
 		puri = &msg->parsed_uri;
 	}
 	}
 	if(puri->gr.s!=NULL)
 	if(puri->gr.s!=NULL)

File diff suppressed because it is too large
+ 268 - 301
modules/textops/README


+ 140 - 0
modules/textops/doc/textops_admin.xml

@@ -1358,6 +1358,146 @@ if (starts_with("$rU", "+358"))
 		</example>
 		</example>
 	</section>
 	</section>
 
 
+	<section id="textops.f.set_body_multipart">
+		<title>
+		<function moreinfo="none">set_body_multipart([txt,content_type][,boundary])</function>
+		</title>
+		<para>
+		Set multipart body to a SIP message. If called with no parameters, will convert
+		present body to multipart.
+		</para>
+		<para>Meaning of the parameters is as follows:</para>
+		<itemizedlist>
+		<listitem>
+			<para><emphasis>txt</emphasis> - text for the body, can include
+				pseudo-variables.
+			</para>
+		</listitem>
+		<listitem>
+			<para><emphasis>content_type</emphasis> - value of Content-Type header,
+				can include pseudo-variables.
+			</para>
+		</listitem>
+		<listitem>
+			<para><emphasis>boundary</emphasis> - string to use as boundary,
+				can include pseudo-variables. Default: unique-boundary-1
+			</para>
+		</listitem>
+		</itemizedlist>
+		<para>
+		This function can be used from REQUEST_ROUTE, FAILURE_ROUTE, BRANCH_ROUTE.
+		</para>
+		<para>
+		The core will take care of the last boundary ending "--". Detecting wich one is
+		the last and fixing the others if needed.
+		</para>
+		<example>
+		<title><function>set_body_multipart</function> usage</title>
+		<programlisting format="linespecific">
+...
+set_body_multipart("test", "text/plain", "delimiter");
+...
+Will produce:
+...
+Content-Type: multipart/mixed;boundary="delimiter"
+Mime-Version: 1.0
+
+--delimiter
+Content-Type: text/plain
+
+text
+
+--delimiter
+...
+</programlisting>
+		</example>
+	</section>
+
+	<section id="textops.f.append_body_part">
+		<title>
+		<function moreinfo="none">append_body_part(txt,content_type[, content_disposition])</function>
+		</title>
+		<para>
+		Append a part on multipart body SIP message. Will use "unique-boundary-1" as boundary.
+		</para>
+		<para>Meaning of the parameters is as follows:</para>
+		<itemizedlist>
+		<listitem>
+			<para><emphasis>txt</emphasis> - text for the multipart body, can include
+				pseudo-variables.
+			</para>
+		</listitem>
+		<listitem>
+			<para><emphasis>content_type</emphasis> - value of Content-Type header,
+				can include pseudo-variables.
+			</para>
+		</listitem>
+		<listitem>
+			<para><emphasis>content_disposition</emphasis> - value of Content-Disposition header,
+				can include pseudo-variables.
+			</para>
+		</listitem>
+		</itemizedlist>
+		<para>
+		This function can be used from REQUEST_ROUTE, FAILURE_ROUTE, BRANCH_ROUTE.
+		</para>
+		<para>
+		The core will take care of the last boundary ending "--". Detecting wich one is
+		the last and fixing the others if needed.
+		</para>
+		<example>
+		<title><function>append_body_part</function> usage</title>
+		<programlisting format="linespecific">
+...
+$var(b) = "7e Od 04 55 75 69 20 4d 61 6b 65 43 61 6c 6c"
+append_body_part("$var(b)", "application/vnd.cirpack.isdn-ext", "signal;handling=required");
+...
+Will append this the body:
+...
+Content-Type: application/vnd.cirpack.isdn-ext
+Content-Disposition: signal;handling=required
+
+7e Od 04 55 75 69 20 4d 61 6b 65 43 61 6c 6c
+
+--unique-boundary-1
+...
+</programlisting>
+		</example>
+	</section>
+
+	<section id="textops.f.remove_body_part">
+		<title>
+		<function moreinfo="none">remove_body_part(content_type)</function>
+		</title>
+		<para>
+		Remove a part on a multipart body SIP message.
+		</para>
+		<para>Meaning of the parameters is as follows:</para>
+		<itemizedlist>
+		<listitem>
+			<para><emphasis>content_type</emphasis> - value of Content-Type header
+				of the part to be removed. If more than one exists the first
+				occurrence will be removed.
+			</para>
+		</listitem>
+		</itemizedlist>
+		<para>
+		This function can be used from REQUEST_ROUTE, FAILURE_ROUTE, BRANCH_ROUTE.
+		</para>
+		<para>
+		The core will take care of the last boundary ending "--". Detecting wich one is
+		the last and fixing the others if needed.
+		</para>
+		<example>
+		<title><function>remove_body_part</function> usage</title>
+		<programlisting format="linespecific">
+...
+remove_body_part("application/vnd.cirpack.isdn-ext");
+...
+</programlisting>
+		</example>
+	</section>
+
 	</section>
 	</section>
 	<section>
 	<section>
 		<title>Known Limitations</title>
 		<title>Known Limitations</title>

+ 673 - 94
modules/textops/textops.c

@@ -123,6 +123,14 @@ static int append_time_f(struct sip_msg* msg, char* , char *);
 static int append_time_request_f(struct sip_msg* msg, char* , char *);
 static int append_time_request_f(struct sip_msg* msg, char* , char *);
 static int set_body_f(struct sip_msg* msg, char*, char *);
 static int set_body_f(struct sip_msg* msg, char*, char *);
 static int set_rpl_body_f(struct sip_msg* msg, char*, char *);
 static int set_rpl_body_f(struct sip_msg* msg, char*, char *);
+static int set_multibody_0(struct sip_msg* msg, char*, char *, char *);
+static int set_multibody_1(struct sip_msg* msg, char*, char *, char *);
+static int set_multibody_2(struct sip_msg* msg, char*, char *, char *);
+static int set_multibody_3(struct sip_msg* msg, char*, char *, char *);
+static int append_multibody_2(struct sip_msg* msg, char*, char *);
+static int append_multibody_3(struct sip_msg* msg, char*, char *, char *);
+static int fixup_multibody_f(void** param, int param_no);
+static int remove_multibody_f(struct sip_msg *msg, char *);
 static int is_method_f(struct sip_msg* msg, char* , char *);
 static int is_method_f(struct sip_msg* msg, char* , char *);
 static int has_body_f(struct sip_msg *msg, char *type, char *str2 );
 static int has_body_f(struct sip_msg *msg, char *type, char *str2 );
 static int in_list_f(struct sip_msg* _msg, char* _subject, char* _list,
 static int in_list_f(struct sip_msg* _msg, char* _subject, char* _list,
@@ -275,6 +283,27 @@ static cmd_export_t cmds[]={
 
 
 	{"bind_textops",      (cmd_function)bind_textops,       0, 0, 0,
 	{"bind_textops",      (cmd_function)bind_textops,       0, 0, 0,
 		0},
 		0},
+	{"set_body_multipart",         (cmd_function)set_multibody_0,        0,
+		0, 0,
+		REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE },
+	{"set_body_multipart",         (cmd_function)set_multibody_1,        1,
+		fixup_spve_null, 0,
+		REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE },
+	{"set_body_multipart",         (cmd_function)set_multibody_2,        2,
+		fixup_spve_spve, 0,
+		REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE },
+	{"set_body_multipart",         (cmd_function)set_multibody_3,        3,
+		fixup_multibody_f, 0,
+		REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE },
+	{"append_body_part",     (cmd_function)append_multibody_2,    2,
+		fixup_spve_spve, 0,
+		REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE },
+	{"append_body_part",     (cmd_function)append_multibody_3,    3,
+		fixup_multibody_f, 0,
+		REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE },
+	{"remove_body_part",     (cmd_function)remove_multibody_f,    1,
+		fixup_spve_null, 0,
+		REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE },
 
 
 	{0,0,0,0,0,0}
 	{0,0,0,0,0,0}
 };
 };
@@ -866,6 +895,23 @@ static inline int find_line_start(char *text, unsigned int text_len,
     return 0;
     return 0;
 }
 }
 
 
+/**
+ * return:
+ *  1: multipart
+ */
+static int check_multipart(struct sip_msg *msg)
+{
+	int mime;
+
+	/* the function search for and parses the Content-Type hdr */
+	mime = parse_content_type_hdr (msg);
+	if(mime<0) {
+		LM_ERR("failed to extract content type hdr\n");
+		return -1;
+	}
+	if(mime!=MIMETYPE(MULTIPART,MIXED)) return 0;
+	return 1;
+}
 
 
 /* Filters multipart/mixed body by leaving out everything else except
 /* Filters multipart/mixed body by leaving out everything else except
  * first body part of given content type. */
  * first body part of given content type. */
@@ -874,10 +920,8 @@ static int filter_body_f(struct sip_msg* msg, char* _content_type,
 {
 {
 	char *start;
 	char *start;
 	unsigned int len;
 	unsigned int len;
-	str *content_type, body, params, boundary;
-	param_hooks_t hooks;
-	param_t *p, *list;
-	unsigned int mime;
+	str *content_type, body;
+	str boundary = {0,0};
 
 
 	body.s = get_body(msg);
 	body.s = get_body(msg);
 	if (body.s == 0) {
 	if (body.s == 0) {
@@ -889,106 +933,73 @@ static int filter_body_f(struct sip_msg* msg, char* _content_type,
 		LM_DBG("message body has zero length\n");
 		LM_DBG("message body has zero length\n");
 		return -1;
 		return -1;
 	}
 	}
-	
-	content_type = (str *)_content_type;
 
 
-	mime = parse_content_type_hdr(msg);
-	if (mime <= 0) {
-	    LM_ERR("failed to parse Content-Type hdr\n");
-	    return -1;
-	}
-	if (mime != ((TYPE_MULTIPART << 16) + SUBTYPE_MIXED)) {
-	    LM_ERR("content type is not multipart/mixed\n");
-	    return -1;
-	}
-
-	params.s = memchr(msg->content_type->body.s, ';', 
-			  msg->content_type->body.len);
-	if (params.s == NULL) {
-	    LM_ERR("Content-Type hdr has no params\n");
-	    return -1;
-	}
-	params.len = msg->content_type->body.len - 
-	    (params.s - msg->content_type->body.s);
-	if (parse_params(&params, CLASS_ANY, &hooks, &list) < 0) {
-	    LM_ERR("while parsing Content-Type params\n");
-	    return -1;
-	}
-	boundary.s = NULL;
-	boundary.len = 0;
-	for (p = list; p; p = p->next) {
-	    if ((p->name.len == 8)
-		&& (strncasecmp(p->name.s, "boundary", 8) == 0)) {
-		boundary.s = pkg_malloc(p->body.len + 2);
-		if (boundary.s == NULL) {
-		    free_params(list);
-		    LM_ERR("no memory for boundary string\n");
-		    return -1;
-		}
-		*(boundary.s) = '-';
-		*(boundary.s + 1) = '-';
-		memcpy(boundary.s + 2, p->body.s, p->body.len);
-		boundary.len = 2 + p->body.len;
-		LM_DBG("boundary is <%.*s>\n", boundary.len, boundary.s);
-		break;
-	    }
+	if(check_multipart(msg)!=1) {
+		LM_WARN("body not multipart\n");
+		return -1;
 	}
 	}
-	free_params(list);
-	if (boundary.s == NULL) {
-	    LM_ERR("no mandatory param \";boundary\"\n");
-	    return -1;
+	if(get_boundary(msg, &boundary)!=0) {
+		return -1;
 	}
 	}
-	
+	content_type = (str *)_content_type;
 	start = body.s;
 	start = body.s;
 	len = body.len;
 	len = body.len;
-	
-	while (find_line_start("Content-Type: ", 14, &start, &len)) {
-	    start = start + 14;
-	    len = len - 14;
-	    if (len > content_type->len + 2) {
-		if (strncasecmp(start, content_type->s, content_type->len)
-		    == 0) {
-		    LM_DBG("found content type %.*s\n",
-			    content_type->len, content_type->s);
-		    start = start + content_type->len;
-		    if ((*start != 13) || (*(start + 1) != 10)) {
-			LM_ERR("no CRLF found after content type\n");
-			goto err;
-		    }
-		    start = start + 2;
-		    len = len - content_type->len - 2;
-		    while ((len > 0) && ((*start == 13) || (*start == 10))) {
-			len = len - 1;
-			start = start + 1;
-		    }
-		    if (del_lump(msg, body.s - msg->buf, start - body.s, 0)
-			== 0) {
-			LM_ERR("deleting lump <%.*s> failed\n",
-			       (int)(start - body.s), body.s);
-			goto err;
-		    }
-		    if (find_line_start(boundary.s, boundary.len, &start,
-					&len)) { 
-			if (del_lump(msg, start - msg->buf, len, 0) == 0) {
-			    LM_ERR("deleting lump <%.*s> failed\n",
-				   len, start);
-			    goto err;
-			} else {
-			    pkg_free(boundary.s);
-			    return 1;
+
+	while (find_line_start("Content-Type: ", 14, &start, &len))
+	{
+		start = start + 14;
+		len = len - 14;
+		LM_DBG("line: [%.*s]\n", len, start);
+		if (len > content_type->len + 2) {
+			if (strncasecmp(start, content_type->s, content_type->len)== 0)
+			{
+				LM_DBG("found content type %.*s\n",
+					content_type->len, content_type->s);
+				start = start + content_type->len;
+				if ((*start != 13) || (*(start + 1) != 10))
+				{
+					LM_ERR("no CRLF found after content type\n");
+					goto err;
+				}
+				start = start + 2;
+				len = len - content_type->len - 2;
+				while ((len > 0) && ((*start == 13) || (*start == 10)))
+				{
+					len = len - 1;
+					start = start + 1;
+				}
+				if (del_lump(msg, body.s - msg->buf, start - body.s, 0)== 0)
+				{
+					LM_ERR("deleting lump <%.*s> failed\n",
+					(int)(start - body.s), body.s);
+					goto err;
+				}
+				if (find_line_start(boundary.s, boundary.len, &start,
+					&len))
+				{
+					if (del_lump(msg, start - msg->buf, len, 0) == 0)
+					{
+						LM_ERR("deleting lump <%.*s> failed\n", len, start);
+						goto err;
+					}
+					else
+					{
+						pkg_free(boundary.s);
+						return 1;
+					}
+				}
+				else
+				{
+					LM_ERR("boundary not found after content\n");
+					goto err;
+				}
 			}
 			}
-		    } else {
-			LM_ERR("boundary not found after content\n");
+		} else {
 			goto err;
 			goto err;
-		    }
 		}
 		}
-	    } else {
-		pkg_free(boundary.s);
-		return -1;
-	    }
 	}
 	}
  err:
  err:
-	pkg_free(boundary.s);
+	if(boundary.s) pkg_free(boundary.s);
 	return -1;
 	return -1;
 }
 }
 
 
@@ -1444,7 +1455,575 @@ static int set_rpl_body_f(struct sip_msg* msg, char* p1, char* p2)
 	return 1;
 	return 1;
 }
 }
 
 
+static str* generate_boundary(str txt, str content_type,
+	str content_disposition, str delimiter, unsigned int initial)
+{
+	unsigned int i = 0;
+	str cth = {"Content-Type: ", 14};
+	str cdh = {"Content-Disposition: ", 21};
+	str* n;
+	unsigned int flag = 0;
 
 
+	if(txt.len==0||content_type.len==0||delimiter.len==0)
+	{
+		LM_ERR("invalid parameters\n");
+		return NULL;
+	}
+	n = pkg_malloc(sizeof(str));
+	if(n==NULL)
+	{
+		LM_ERR("out of pkg memory\n");
+		return NULL;
+	}
+	n->len = delimiter.len + 2 + CRLF_LEN;
+	if(initial) n->len = 2*n->len;
+	if(strncmp("\r\n\r\n", txt.s+txt.len-4,4)!=0)
+	{
+		n->len = n->len + CRLF_LEN;
+		flag = 1;
+		LM_DBG("adding final CRLF+CRLF\n");
+	}
+	n->len=n->len + cth.len + content_type.len + 2*CRLF_LEN;
+	if(content_disposition.len>0)
+	{
+		n->len = n->len + cdh.len + content_disposition.len + CRLF_LEN;
+	}
+	n->len = n->len + txt.len;
+
+	n->s = pkg_malloc(sizeof(char)*(n->len));
+	if(n->s==0)
+	{
+		LM_ERR("out of pkg memory\n");
+		pkg_free(n);
+		return NULL;
+	}
+	if(initial)
+	{
+		memcpy(n->s, "--", 2); i=2;
+		memcpy(n->s+i, delimiter.s, delimiter.len); i=i+delimiter.len;
+		memcpy(n->s+i, CRLF, CRLF_LEN); i=i+CRLF_LEN;
+	}
+
+	memcpy(n->s+i, cth.s, cth.len); i=i+cth.len;
+	memcpy(n->s+i, content_type.s, content_type.len); i=i+content_type.len;
+	memcpy(n->s+i, CRLF, CRLF_LEN); i=i+CRLF_LEN;
+
+	if(content_disposition.len>0)
+	{
+		memcpy(n->s+i, cdh.s, cdh.len); i=i+cdh.len;
+		memcpy(n->s+i, content_disposition.s, content_disposition.len);
+		i=i+content_disposition.len;
+		memcpy(n->s+i, CRLF, CRLF_LEN); i=i+CRLF_LEN;
+	}
+	memcpy(n->s+i, CRLF, CRLF_LEN); i=i+CRLF_LEN;
+
+	memcpy(n->s+i, txt.s, txt.len); i=i+txt.len;
+	if(flag) { memcpy(n->s+i, CRLF, CRLF_LEN); i=i+CRLF_LEN; }
+
+	memcpy(n->s+i, "--", 2); i=i+2;
+	memcpy(n->s+i, delimiter.s, delimiter.len); i=i+delimiter.len;
+	memcpy(n->s+i, CRLF, CRLF_LEN); i=i+CRLF_LEN;
+
+	if(i!=n->len)
+	{
+		LM_ERR("out of bounds\n");
+	}
+	return n;
+}
+
+int set_multibody_helper(struct sip_msg* msg, char* p1, char* p2, char* p3)
+{
+	struct lump *anchor;
+	char* buf = NULL;
+	int len;
+	char* value_s;
+	int value_len;
+	str body = {0,0};
+	str nb = {0,0};
+	str oc = {0,0};
+	str cd = {0,0};
+	str delimiter = {0,0};
+	str default_delimiter = {"unique-boundary-1", 17};
+	str nc = {0,0};
+	str cth = {"Content-Type: ", 14};
+	str* nbb;
+	unsigned int convert = 0;
+	fparam_t header;
+	header.orig = NULL;
+	header.type = FPARAM_STR;
+	header.v.str.s = "Mime-Version: 1.0\r\n";
+	header.v.str.len = 19;
+
+	if(p3==0)
+	{
+		delimiter.s = default_delimiter.s;
+		delimiter.len = default_delimiter.len;
+	}
+	else
+	{
+		if(fixup_get_svalue(msg, (gparam_p)p3, &delimiter)!=0)
+		{
+			LM_ERR("unable to get p3\n");
+			return -1;
+		}
+		if(delimiter.s==NULL || delimiter.len == 0)
+		{
+			LM_ERR("invalid boundary parameter\n");
+			return -1;
+		}
+	}
+	LM_DBG("delimiter<%d>:[%.*s]\n", delimiter.len, delimiter.len, delimiter.s);
+	if(p1==0 || p2==0)
+	{
+		if(check_multipart(msg)==1) {
+			LM_WARN("body is already multipart. Do nothing\n");
+			return -1;
+		}
+		convert = 1;
+	}
+	else
+	{
+		if(fixup_get_svalue(msg, (gparam_p)p1, &nb)!=0)
+		{
+			LM_ERR("unable to get p1\n");
+			return -1;
+		}
+		if(nb.s==NULL || nb.len == 0)
+		{
+			LM_ERR("invalid body parameter\n");
+			return -1;
+		}
+		if(fixup_get_svalue(msg, (gparam_p)p2, &oc)!=0)
+		{
+			LM_ERR("unable to get p2\n");
+			return -1;
+		}
+		if(oc.s==NULL || oc.len==0)
+		{
+			LM_ERR("invalid content-type parameter\n");
+			return -1;
+		}
+		if(check_multipart(msg)==1) {
+			convert = -1;
+		}
+	}
+
+	body.len = 0;
+	body.s = get_body(msg);
+	if(body.s==0)
+	{
+		LM_ERR("malformed sip message\n");
+		return -1;
+	}
+	body.len = msg->len -(int)(body.s-msg->buf);
+
+	del_nonshm_lump( &(msg->body_lumps) );
+	msg->body_lumps = NULL;
+
+	if(msg->content_length)
+	{
+		if(body.len > 0)
+		{
+			if(body.s+body.len>msg->buf+msg->len)
+			{
+				LM_ERR("invalid content length: %d\n", body.len);
+				return -1;
+			}
+			if(convert==1)
+			{
+				/* need to copy body */
+				nb.s=pkg_malloc(sizeof(char)*body.len);
+				if (nb.s==0)
+				{
+					LM_ERR("out of pkg memory\n");
+					return -1;
+				}
+				memcpy(nb.s, body.s, body.len);
+				nb.len = body.len;
+				if(msg->content_type!=NULL && msg->content_type->body.s!=NULL)
+				{
+					oc.len = msg->content_type->body.len;
+					oc.s=pkg_malloc(sizeof(char)*oc.len);
+					if (oc.s==0)
+					{
+						LM_ERR("out of pkg memory\n");
+						goto error;
+					}
+					memcpy(oc.s, msg->content_type->body.s, oc.len);
+				}
+			}
+			if(del_lump(msg, body.s-msg->buf, body.len, 0) == 0)
+			{
+				LM_ERR("cannot delete existing body");
+				goto error;
+			}
+		}
+	}
+
+	anchor = anchor_lump(msg, msg->unparsed-msg->buf, 0, 0);
+	if(anchor==0)
+	{
+		LM_ERR("failed to get anchor\n");
+		goto error;
+	}
+
+	/* get initial boundary */
+	nbb = generate_boundary(nb, oc, cd, delimiter, 1);
+	if(nbb==NULL)
+	{
+		LM_ERR("couldn't create initial boundary\n");
+		goto error;
+	}
+
+	if(msg->content_length==0)
+	{
+		/* need to add Content-Length */
+		len = nbb->len;
+		value_s=int2str(len, &value_len);
+
+		len=CONTENT_LENGTH_LEN+value_len+CRLF_LEN;
+		buf=pkg_malloc(sizeof(char)*len);
+
+		if (buf==0)
+		{
+			LM_ERR("out of pkg memory\n");
+			goto error;
+		}
+
+		memcpy(buf, CONTENT_LENGTH, CONTENT_LENGTH_LEN);
+		memcpy(buf+CONTENT_LENGTH_LEN, value_s, value_len);
+		memcpy(buf+CONTENT_LENGTH_LEN+value_len, CRLF, CRLF_LEN);
+		if (insert_new_lump_after(anchor, buf, len, 0) == 0)
+		{
+			LM_ERR("failed to insert content-length lump\n");
+			goto error;
+		}
+		buf = NULL;
+	}
+
+	if(convert!=-1)
+	{
+		/* set new content type with delimiter */
+		nc.len = delimiter.len + 27;
+		nc.s = pkg_malloc(sizeof(char)*nc.len);
+		memcpy(nc.s, "multipart/mixed;boundary=\"", 26);
+		memcpy(nc.s+26, delimiter.s, delimiter.len);
+		nc.s[26+delimiter.len] = '"';
+		LM_DBG("content-type<%d>:[%.*s]\n", nc.len, nc.len, nc.s);
+		/* add content-type */
+		if(msg->content_type==NULL || msg->content_type->body.len!=nc.len
+				|| strncmp(msg->content_type->body.s, nc.s, nc.len)!=0)
+		{
+			if(msg->content_type!=NULL)
+				if(del_lump(msg, msg->content_type->name.s-msg->buf,
+							msg->content_type->len, 0) == 0)
+				{
+					LM_ERR("failed to delete content type\n");
+					goto error;
+				}
+			value_len = nc.len;
+			len = cth.len + value_len + CRLF_LEN;
+			buf = pkg_malloc(sizeof(char)*len);
+
+			if(buf==0)
+			{
+				LM_ERR("out of pkg memory\n");
+				goto error;
+			}
+			memcpy(buf, cth.s, cth.len);
+			memcpy(buf + cth.len, nc.s, value_len);
+			memcpy(buf + cth.len + value_len, CRLF, CRLF_LEN);
+			if (insert_new_lump_after(anchor, buf, len, 0) == 0)
+			{
+				LM_ERR("failed to insert content-type lump\n");
+				goto error;
+			}
+			buf = NULL;
+		}
+		/* add Mime-Version header */
+		if(add_hf_helper(msg, 0, 0, &header, 0, 0)<0)
+		{
+			LM_ERR("failed to add Mime-Version header\n");
+			goto error;
+		}
+	}
+	anchor = anchor_lump(msg, body.s - msg->buf, 0, 0);
+	if(anchor==0)
+	{
+		LM_ERR("failed to get body anchor\n");
+		goto error;
+	}
+
+	if(insert_new_lump_after(anchor, nbb->s, nbb->len, 0)==0)
+	{
+		LM_ERR("failed to insert body lump\n");
+		goto error;
+	}
+	pkg_free(nbb);
+	if(nc.s!=NULL) pkg_free(nc.s);
+	LM_DBG("set flag FL_BODY_MULTIPART\n");
+	msg->msg_flags |= FL_BODY_MULTIPART;
+	return 1;
+
+error:
+	if(nbb!=NULL) { pkg_free(nbb->s); pkg_free(nbb); }
+	if(nc.s!=NULL) pkg_free(nc.s);
+	if(buf!=NULL) pkg_free(buf);
+	if(convert && nb.s!=NULL) pkg_free(nb.s);
+	if(convert && oc.s!=NULL) pkg_free(oc.s);
+	return -1;
+}
+
+static int set_multibody_0(struct sip_msg* msg, char* p1, char* p2, char* p3)
+{
+	return set_multibody_helper(msg, NULL, NULL, NULL);
+}
+
+static int set_multibody_1(struct sip_msg* msg, char* p1, char* p2, char* p3)
+{
+	return set_multibody_helper(msg, NULL, NULL, p1);
+}
+
+static int set_multibody_2(struct sip_msg* msg, char* p1, char* p2, char* p3)
+{
+	return set_multibody_helper(msg, p1, p2, NULL);
+}
+
+static int set_multibody_3(struct sip_msg* msg, char* p1, char* p2, char *p3)
+{
+	return set_multibody_helper(msg, p1, p2, p3);
+}
+
+int append_multibody_helper(struct sip_msg* msg, char* p1, char* p2, char* p3)
+{
+	struct lump *l;
+	int off;
+	str body = {0,0};
+	str nc = {0,0};
+	str cd = {0,0};
+	str txt = {0,0};
+	str* nbb = NULL;
+	str delimiter = {0,0};
+
+	if(p1==0 || p2==0)
+	{
+		LM_ERR("invalid parameters\n");
+		return -1;
+	}
+
+	if(fixup_get_svalue(msg, (gparam_p)p1, &txt)!=0)
+	{
+		LM_ERR("unable to get p1\n");
+		return -1;
+	}
+	if(txt.s==NULL || txt.len==0)
+	{
+		LM_ERR("invalid body parameter\n");
+		return -1;
+	}
+	if(fixup_get_svalue(msg, (gparam_p)p2, &nc)!=0)
+	{
+		LM_ERR("unable to get p2\n");
+		return -1;
+	}
+	if(nc.s==NULL || nc.len==0)
+	{
+		LM_ERR("invalid content-type parameter\n");
+		return -1;
+	}
+	if(p3!=NULL)
+	{
+		if(fixup_get_svalue(msg, (gparam_p)p3, &cd)!=0)
+		{
+			LM_ERR("unable to get p3\n");
+			return -1;
+		}
+	}
+
+	body.s = get_body(msg);
+	if(body.s==0) {
+		LM_ERR("failed to get the message body\n");
+		return -1;
+	}
+	body.len = msg->len -(int)(body.s-msg->buf);
+	if(body.len==0) {
+		LM_DBG("message body has zero length\n");
+		return -1;
+	}
+
+	off=body.s-msg->buf;
+	if((l=anchor_lump(msg, off+body.len, 0, 0))==0)
+	{
+		LM_ERR("WTF\n");
+		return -1;
+	}
+	/* get boundary */
+	if(get_boundary(msg, &delimiter)!=0) {
+		LM_ERR("Cannot get boundary. Is body multipart?\n");
+		return -1;
+	}
+	nbb = generate_boundary(txt, nc, cd, delimiter, 0);
+	if(nbb==NULL)
+	{
+		LM_ERR("couldn't create initial boundary\n");
+		pkg_free(delimiter.s);
+		return -1;
+	}
+	pkg_free(delimiter.s);
+	if(insert_new_lump_after(l, nbb->s, nbb->len, 0)==0){
+		LM_ERR("could not insert new lump\n");
+		pkg_free(nbb->s); pkg_free(nbb);
+		return -1;
+	}
+	pkg_free(nbb);
+	if(!(msg->msg_flags&FL_BODY_MULTIPART))
+	{
+		LM_DBG("set flag FL_BODY_MULTIPART\n");
+		msg->msg_flags |= FL_BODY_MULTIPART;
+	}
+	return 1;
+}
+
+static int append_multibody_2(struct sip_msg* msg, char* p1, char* p2)
+{
+	return append_multibody_helper(msg, p1, p2, NULL);
+}
+
+static int append_multibody_3(struct sip_msg* msg, char* p1, char* p2, char *p3)
+{
+	return append_multibody_helper(msg, p1, p2, p3);
+}
+
+static int fixup_multibody_f(void** param, int param_no)
+{
+	int ret;
+	fparam_t* fp;
+
+	if(param_no<=3){
+		if((ret=fix_param_types(FPARAM_PVE, param))<0){
+			ERR("Cannot convert function parameter %d to spve \n",
+					param_no);
+			return E_UNSPEC;
+		} else {
+			fp=(fparam_t*)*param;
+			if((ret==0) && (fp->v.pve->spec==0
+						|| fp->v.pve->spec->getf==0)){
+				fparam_free_restore(param);
+				return fix_param_types(FPARAM_STR, param);
+			} else if(ret==1)
+				return fix_param_types(FPARAM_STR, param);
+			return ret;
+		}
+	} else {
+		LM_ERR("wrong number of parameters\n");
+		return E_UNSPEC;
+	}
+}
+
+static inline int get_line(char *s, int len)
+{
+	char *ch;
+
+	if ((ch = memchr(s, 13, len))) {
+		if (*(ch + 1) != 10) {
+			LM_ERR("No LF after CR\n");
+			return 0;
+		}
+		return ch - s + 2;
+	} else {
+		LM_ERR("No CRLF found\n");
+		return len;
+	}
+	return 0;
+}
+
+static int remove_multibody_f(struct sip_msg* msg, char* p1)
+{
+	char *start, *end;
+	unsigned int len, t;
+	str content_type, body;
+	str boundary = {0,0};
+
+	if(p1==0)
+	{
+		LM_ERR("invalid parameters\n");
+		return -1;
+	}
+
+	if(fixup_get_svalue(msg, (gparam_p)p1, &content_type)!=0)
+	{
+		LM_ERR("unable to get p1\n");
+		return -1;
+	}
+
+	body.s = get_body(msg);
+	if (body.s == 0) {
+		LM_ERR("failed to get the message body\n");
+		return -1;
+	}
+	body.len = msg->len - (int)(body.s - msg->buf);
+	if (body.len == 0) {
+		LM_DBG("message body has zero length\n");
+		return -1;
+	}
+
+	if(get_boundary(msg, &boundary)!=0) {
+		LM_ERR("Cannot get boundary. Is body multipart?\n");
+		return -1;
+	}
+
+	start = body.s;
+	len = body.len;
+
+	while (find_line_start("Content-Type: ", 14, &start, &len))
+	{
+		end = start + 14;
+		len = len - 14;
+		if (len > (content_type.len + 2)) {
+			if (strncasecmp(end, content_type.s, content_type.len)== 0)
+			{
+				LM_DBG("found content type %.*s\n",
+					content_type.len, content_type.s);
+				end = end + content_type.len;
+				if ((*end != 13) || (*(end + 1) != 10))
+				{
+					LM_ERR("no CRLF found after content type\n");
+					goto err;
+				}
+				end = end + 2;
+				len = len - content_type.len - 2;
+				if (find_line_start(boundary.s, boundary.len, &end,
+					&len))
+				{
+					LM_DBG("found boundary %.*s\n", boundary.len, boundary.s);
+					end = end + boundary.len;
+					len = len - boundary.len;
+					if (!(t = get_line(end, len))) goto err;
+					end += t; len = end-start;
+					if (del_lump(msg, start - msg->buf, len, 0) == 0)
+					{
+						LM_ERR("deleting lump <%.*s> failed\n", len, start);
+						goto err;
+					}
+					pkg_free(boundary.s);
+					if(!(msg->msg_flags&FL_BODY_MULTIPART))
+					{
+						LM_DBG("set flag FL_BODY_MULTIPART\n");
+						msg->msg_flags |= FL_BODY_MULTIPART;
+					}
+					return 1;
+				}
+				LM_ERR("boundary not found after content\n");
+				goto err;
+			}
+			start = end;
+		}
+		else goto err;
+	}
+ err:
+	pkg_free(boundary.s);
+	return -1;
+}
 
 
 static int append_to_reply_f(struct sip_msg* msg, char* key, char* str0)
 static int append_to_reply_f(struct sip_msg* msg, char* key, char* str0)
 {
 {

+ 1 - 0
modules/tls/tls_mod.c

@@ -348,6 +348,7 @@ static int mod_init(void)
 #ifndef OPENSSL_NO_DH
 #ifndef OPENSSL_NO_DH
 	LM_INFO("With Diffie Hellman\n");
 	LM_INFO("With Diffie Hellman\n");
 #endif
 #endif
+	tls_lookup_event_routes();
 	return 0;
 	return 0;
 error:
 error:
 	destroy_tls_h();
 	destroy_tls_h();

+ 10 - 0
modules/tls/tls_select.c

@@ -101,11 +101,21 @@ enum {
 
 
 
 
 
 
+static struct tcp_connection* _tls_pv_con = 0;
 
 
 
 
+void tls_set_pv_con(struct tcp_connection *c)
+{
+	_tls_pv_con = c;
+}
+
 struct tcp_connection* get_cur_connection(struct sip_msg* msg)
 struct tcp_connection* get_cur_connection(struct sip_msg* msg)
 {
 {
 	struct tcp_connection* c;
 	struct tcp_connection* c;
+
+	if(_tls_pv_con != 0)
+		return _tls_pv_con;
+
 	if (msg->rcv.proto != PROTO_TLS) {
 	if (msg->rcv.proto != PROTO_TLS) {
 		ERR("Transport protocol is not TLS (bug in config)\n");
 		ERR("Transport protocol is not TLS (bug in config)\n");
 		return 0;
 		return 0;

+ 3 - 0
modules/tls/tls_select.h

@@ -43,9 +43,12 @@
 
 
 #include "../../select.h"
 #include "../../select.h"
 #include "../../pvar.h"
 #include "../../pvar.h"
+#include "../../tcp_conn.h"
 
 
 extern select_row_t tls_sel[];
 extern select_row_t tls_sel[];
 
 
 extern pv_export_t tls_pv[];
 extern pv_export_t tls_pv[];
 
 
+void tls_set_pv_con(struct tcp_connection *c);
+
 #endif /* _TLS_SELECT_H */
 #endif /* _TLS_SELECT_H */

+ 46 - 0
modules/tls/tls_server.c

@@ -46,16 +46,22 @@
 #include "../../tcp_int_send.h"
 #include "../../tcp_int_send.h"
 #include "../../tcp_read.h"
 #include "../../tcp_read.h"
 #include "../../cfg/cfg.h"
 #include "../../cfg/cfg.h"
+#include "../../route.h"
+#include "../../forward.h"
+#include "../../onsend.h"
 
 
 #include "tls_init.h"
 #include "tls_init.h"
 #include "tls_domain.h"
 #include "tls_domain.h"
 #include "tls_util.h"
 #include "tls_util.h"
 #include "tls_mod.h"
 #include "tls_mod.h"
 #include "tls_server.h"
 #include "tls_server.h"
+#include "tls_select.h"
 #include "tls_bio.h"
 #include "tls_bio.h"
 #include "tls_dump_vf.h"
 #include "tls_dump_vf.h"
 #include "tls_cfg.h"
 #include "tls_cfg.h"
 
 
+int tls_run_event_routes(struct tcp_connection *c);
+
 /* low memory treshold for openssl bug #1491 workaround */
 /* low memory treshold for openssl bug #1491 workaround */
 #define LOW_MEM_NEW_CONNECTION_TEST() \
 #define LOW_MEM_NEW_CONNECTION_TEST() \
 	(cfg_get(tls, tls_cfg, low_mem_threshold1) && \
 	(cfg_get(tls, tls_cfg, low_mem_threshold1) && \
@@ -435,6 +441,7 @@ int tls_connect(struct tcp_connection *c, int* error)
 			LOG(tls_log, "tls_connect: server did not "
 			LOG(tls_log, "tls_connect: server did not "
 							"present a certificate\n");
 							"present a certificate\n");
 		}
 		}
+		tls_run_event_routes(c);
 	} else { /* 0 or < 0 */
 	} else { /* 0 or < 0 */
 		*error = SSL_get_error(ssl, ret);
 		*error = SSL_get_error(ssl, ret);
 	}
 	}
@@ -1343,3 +1350,42 @@ bug:
 					c, flags, ssl_read, *flags);
 					c, flags, ssl_read, *flags);
 	return -1;
 	return -1;
 }
 }
+
+
+static int _tls_evrt_connection_out = -1; /* default disabled */
+
+/*!
+ * lookup tls event routes
+ */
+void tls_lookup_event_routes(void)
+{
+	_tls_evrt_connection_out=route_lookup(&event_rt, "tls:connection-out");
+	if (_tls_evrt_connection_out>=0 && event_rt.rlist[_tls_evrt_connection_out]==0)
+		_tls_evrt_connection_out=-1; /* disable */
+	if(_tls_evrt_connection_out!=-1)
+		forward_set_send_info(1);
+}
+
+/**
+ *
+ */
+int tls_run_event_routes(struct tcp_connection *c)
+{
+	int backup_rt;
+	struct run_act_ctx ctx;
+	sip_msg_t tmsg;
+
+	if(_tls_evrt_connection_out<0)
+		return 0;
+	if(p_onsend==0 || p_onsend->msg==0)
+		return 0;
+
+	backup_rt = get_route_type();
+	set_route_type(LOCAL_ROUTE);
+	init_run_actions_ctx(&ctx);
+	tls_set_pv_con(c);
+	run_top_route(event_rt.rlist[_tls_evrt_connection_out], &tmsg, 0);
+	tls_set_pv_con(0);
+	set_route_type(backup_rt);
+	return 0;
+}

+ 2 - 0
modules/tls/tls_server.h

@@ -93,4 +93,6 @@ int tls_h_fix_read_conn(struct tcp_connection *c);
 
 
 int tls_connect(struct tcp_connection *c, int* error);
 int tls_connect(struct tcp_connection *c, int* error);
 int tls_accept(struct tcp_connection *c, int* error);
 int tls_accept(struct tcp_connection *c, int* error);
+
+void tls_lookup_event_routes(void);
 #endif /* _TLS_SERVER_H */
 #endif /* _TLS_SERVER_H */

+ 1 - 1
modules/topoh/th_msg.c

@@ -136,7 +136,7 @@ int th_get_uri_type(str *uri, int *mode, str *value)
 			return -1;
 			return -1;
 		return 2; /* decode */
 		return 2; /* decode */
 	} else {
 	} else {
-		if(check_self(&puri.host, (puri.port_no)?puri.port_no:SIP_PORT, 0)==1)
+		if(check_self(&puri.host, (puri.port_no)?puri.port_no:0, 0)==1)
 		{
 		{
 			/* myself -- matched on all protos */
 			/* myself -- matched on all protos */
 			ret = th_get_param_value(&puri.params, &r2, value);
 			ret = th_get_param_value(&puri.params, &r2, value);

+ 30 - 11
modules/utils/README

@@ -4,7 +4,13 @@ Juha Heinanen
 
 
    TutPro Inc.
    TutPro Inc.
 
 
-   Copyright © 2008-2009 Juha Heinanen
+Carsten Bock
+
+   ng-voice GmbH
+
+   Copyright (c) 2008-2009 Juha Heinanen
+
+   Copyright (c) 2013 Carsten Bock, ng-voice GmbH
      __________________________________________________________________
      __________________________________________________________________
 
 
    Table of Contents
    Table of Contents
@@ -26,7 +32,7 @@ Juha Heinanen
 
 
         4. Functions
         4. Functions
 
 
-              4.1. http_query(url, result)
+              4.1. http_query(url, [post-data], result)
               4.2. xcap_auth_status(watcher_uri, presentity_uri)
               4.2. xcap_auth_status(watcher_uri, presentity_uri)
 
 
         5. MI Commands
         5. MI Commands
@@ -70,7 +76,7 @@ Chapter 1. Admin Guide
 
 
    4. Functions
    4. Functions
 
 
-        4.1. http_query(url, result)
+        4.1. http_query(url, [post-data], result)
         4.2. xcap_auth_status(watcher_uri, presentity_uri)
         4.2. xcap_auth_status(watcher_uri, presentity_uri)
 
 
    5. MI Commands
    5. MI Commands
@@ -174,17 +180,20 @@ modparam("utils", "xcap_table", "pres_xcap")
 
 
 4. Functions
 4. Functions
 
 
-   4.1. http_query(url, result)
+   4.1. http_query(url, [post-data], result)
    4.2. xcap_auth_status(watcher_uri, presentity_uri)
    4.2. xcap_auth_status(watcher_uri, presentity_uri)
 
 
-4.1. http_query(url, result)
+4.1.  http_query(url, [post-data], result)
 
 
-   Sends HTTP GET request according to URL given in "url" parameter, which
-   is a string that may contain pseudo variables.
+   Sends HTTP GET or POST request according to URL given in "url"
+   parameter, which is a string that may contain pseudo variables.
 
 
-   If HTTP server returns a class 2xx or 3xx reply, the first line of the
-   reply's body (if any) is stored in "result" parameter, which must be a
-   writable pseudo variable.
+   If you want to make a POST-Request, you have to define the "post"-data,
+   that should be submitted in that request as the second parameter.
+
+   If HTTP server returns a class 2xx, 3xx or 4xx reply, the first line of
+   the reply's body (if any) is stored in "result" parameter, which must
+   be a writable pseudo variable.
 
 
    Function returns reply code of HTTP reply or -1 if something went
    Function returns reply code of HTTP reply or -1 if something went
    wrong.
    wrong.
@@ -194,6 +203,7 @@ modparam("utils", "xcap_table", "pres_xcap")
 
 
    Example 1.5. http_query() usage
    Example 1.5. http_query() usage
 ...
 ...
+# GET-Request
 http_query("http://tutpro.com/index.php?r_uri=$(ru{s.escape.param})&f_uri=$(fu{s
 http_query("http://tutpro.com/index.php?r_uri=$(ru{s.escape.param})&f_uri=$(fu{s
 .escape.param})",
 .escape.param})",
            "$var(result)")
            "$var(result)")
@@ -201,8 +211,17 @@ switch ($retcode) {
        ...
        ...
 }
 }
 ...
 ...
+...
+# POST-Request
+http_query("http://tutpro.com/index.php", "r_uri=$(ru{s.escape.param})&f_uri=$(f
+u{s.escape.param})",
+           "$var(result)")
+switch ($retcode) {
+       ...
+}
+...
 
 
-4.2. xcap_auth_status(watcher_uri, presentity_uri)
+4.2.  xcap_auth_status(watcher_uri, presentity_uri)
 
 
    Function checks in the presence server database if a watcher is
    Function checks in the presence server database if a watcher is
    authorized to subscribe to event "presence" of presentity. Sphere
    authorized to subscribe to event "presence" of presentity. Sphere

+ 1 - 1
modules/utils/doc/utils_admin.xml

@@ -171,7 +171,7 @@ modparam("utils", "xcap_table", "pres_xcap")
 			in that request as the second parameter.
 			in that request as the second parameter.
 	    	        </para>
 	    	        </para>
 		        <para>
 		        <para>
-			If HTTP server returns a class 2xx or 3xx reply,
+			If HTTP server returns a class 2xx, 3xx or 4xx reply,
 			the first line of the reply's body (if any) is
 			the first line of the reply's body (if any) is
 			stored in <quote>result</quote> parameter,
 			stored in <quote>result</quote> parameter,
 			which must be a	writable pseudo	variable.
 			which must be a	writable pseudo	variable.

+ 15 - 7
modules/utils/functions.c

@@ -139,16 +139,24 @@ int http_query(struct sip_msg* _m, char* _url, char* _dst, char* _post)
 	pkg_free(post);
 	pkg_free(post);
     }
     }
 
 
-    if (res != CURLE_OK) {
-	LM_ERR("failed to perform curl\n");
-	curl_easy_cleanup(curl);
-	if(stream)
-	    pkg_free(stream);
-	return -1;
+	if (res != CURLE_OK) {
+		/* http://curl.haxx.se/libcurl/c/libcurl-errors.html */
+		if (res == CURLE_COULDNT_CONNECT) {
+			LM_WARN("failed to connect() to host\n");
+		} else if ( res == CURLE_COULDNT_RESOLVE_HOST ) {
+			LM_WARN("couldn't resolve host\n");
+		} else {
+			LM_ERR("failed to perform curl (%d)\n", res);
+		}
+	
+		curl_easy_cleanup(curl);
+		if(stream)
+			pkg_free(stream);
+		return -1;
     }
     }
 
 
     curl_easy_getinfo(curl, CURLINFO_HTTP_CODE, &stat);
     curl_easy_getinfo(curl, CURLINFO_HTTP_CODE, &stat);
-    if ((stat >= 200) && (stat < 400)) {
+    if ((stat >= 200) && (stat < 500)) {
 	curl_easy_getinfo(curl, CURLINFO_SIZE_DOWNLOAD, &download_size);
 	curl_easy_getinfo(curl, CURLINFO_SIZE_DOWNLOAD, &download_size);
 	LM_DBG("http_query download size: %u\n", (unsigned int)download_size);
 	LM_DBG("http_query download size: %u\n", (unsigned int)download_size);
 	/* search for line feed */
 	/* search for line feed */

+ 161 - 19
modules/websocket/ws_conn.c

@@ -47,6 +47,9 @@ gen_lock_t *wsconn_lock = NULL;
 #define WSCONN_LOCK	lock_get(wsconn_lock)
 #define WSCONN_LOCK	lock_get(wsconn_lock)
 #define WSCONN_UNLOCK	lock_release(wsconn_lock)
 #define WSCONN_UNLOCK	lock_release(wsconn_lock)
 
 
+#define wsconn_ref(c)   atomic_inc(&((c)->refcnt))
+#define wsconn_unref(c) atomic_dec_and_test(&((c)->refcnt))
+
 gen_lock_t *wsstat_lock = NULL;
 gen_lock_t *wsstat_lock = NULL;
 
 
 ws_connection_used_list_t *wsconn_used_list = NULL;
 ws_connection_used_list_t *wsconn_used_list = NULL;
@@ -197,6 +200,8 @@ int wsconn_add(struct receive_info rcv, unsigned int sub_protocol)
 	int id_hash = tcp_id_hash(id);
 	int id_hash = tcp_id_hash(id);
 	ws_connection_t *wsc;
 	ws_connection_t *wsc;
 
 
+	LM_DBG("wsconn_add id [%d]\n", id);
+
 	/* Allocate and fill in new WebSocket connection */
 	/* Allocate and fill in new WebSocket connection */
 	wsc = shm_malloc(sizeof(ws_connection_t));
 	wsc = shm_malloc(sizeof(ws_connection_t));
 	if (wsc == NULL)
 	if (wsc == NULL)
@@ -210,6 +215,10 @@ int wsconn_add(struct receive_info rcv, unsigned int sub_protocol)
 	wsc->state = WS_S_OPEN;
 	wsc->state = WS_S_OPEN;
 	wsc->rcv = rcv;
 	wsc->rcv = rcv;
 	wsc->sub_protocol = sub_protocol;
 	wsc->sub_protocol = sub_protocol;
+	wsc->run_event = 0;
+	atomic_set(&wsc->refcnt, 0);
+
+	LM_DBG("wsconn_add new wsc => [%p], ref => [%d]\n", wsc, atomic_get(&wsc->refcnt));
 
 
 	WSCONN_LOCK;
 	WSCONN_LOCK;
 	/* Add to WebSocket connection table */
 	/* Add to WebSocket connection table */
@@ -225,8 +234,12 @@ int wsconn_add(struct receive_info rcv, unsigned int sub_protocol)
 		wsconn_used_list->tail->used_next = wsc;
 		wsconn_used_list->tail->used_next = wsc;
 		wsconn_used_list->tail = wsc;
 		wsconn_used_list->tail = wsc;
 	}
 	}
+	wsconn_ref(wsc);
+
 	WSCONN_UNLOCK;
 	WSCONN_UNLOCK;
 
 
+	LM_DBG("wsconn_add added to conn_table wsc => [%p], ref => [%d]\n", wsc, atomic_get(&wsc->refcnt));
+
 	/* Update connection statistics */
 	/* Update connection statistics */
 	lock_get(wsstat_lock);
 	lock_get(wsstat_lock);
 
 
@@ -290,32 +303,29 @@ static void wsconn_run_route(ws_connection_t *wsc)
 	set_route_type(backup_rt);
 	set_route_type(backup_rt);
 }
 }
 
 
-int wsconn_rm(ws_connection_t *wsc, ws_conn_eventroute_t run_event_route)
+static void wsconn_dtor(ws_connection_t *wsc)
 {
 {
 	if (!wsc)
 	if (!wsc)
-	{
-		LM_ERR("wsconn_rm: null pointer\n");
-		return -1;
-	}
+		return;
 
 
-	if (run_event_route == WSCONN_EVENTROUTE_YES)
+	LM_DBG("wsconn_dtor for [%p] refcnt [%d]\n", wsc, atomic_get(&wsc->refcnt));
+
+	if (wsc->run_event)
 		wsconn_run_route(wsc);
 		wsconn_run_route(wsc);
 
 
-	WSCONN_LOCK;
-	/* Remove from the WebSocket used list */
-	if (wsconn_used_list->head == wsc)
-		wsconn_used_list->head = wsc->used_next;
-	if (wsconn_used_list->tail == wsc)
-		wsconn_used_list->tail = wsc->used_prev;
-	if (wsc->used_prev)
-		wsc->used_prev->used_next = wsc->used_next;
-	if (wsc->used_next)
-		wsc->used_next->used_prev = wsc->used_prev;
+	shm_free(wsc);
 
 
-	_wsconn_rm(wsc);
-	WSCONN_UNLOCK;
+	LM_DBG("wsconn_dtor for [%p] destroyed\n", wsc);
+}
 
 
-	return 0;
+int wsconn_rm(ws_connection_t *wsc, ws_conn_eventroute_t run_event_route)
+{
+	LM_DBG("wsconn_rm for [%p] refcnt [%d]\n", wsc, atomic_get(&wsc->refcnt));
+
+	if (run_event_route == WSCONN_EVENTROUTE_YES)
+		wsc->run_event = 1;
+
+	return wsconn_put(wsc);
 }
 }
 
 
 int wsconn_update(ws_connection_t *wsc)
 int wsconn_update(ws_connection_t *wsc)
@@ -366,17 +376,70 @@ void wsconn_close_now(ws_connection_t *wsc)
 	con->timeout = get_ticks_raw();
 	con->timeout = get_ticks_raw();
 }
 }
 
 
+/* must be called with unlocked WSCONN_LOCK */
+int wsconn_put(ws_connection_t *wsc)
+{
+	int destroy = 0;
+
+	LM_DBG("wsconn_put start for [%p] refcnt [%d]\n", wsc, atomic_get(&wsc->refcnt));
+
+	if (!wsc)
+		return -1;
+
+	WSCONN_LOCK;
+	/* refcnt == 0*/
+	if (wsconn_unref(wsc))
+	{
+		/* Remove from the WebSocket used list */
+		if (wsconn_used_list->head == wsc)
+			wsconn_used_list->head = wsc->used_next;
+		if (wsconn_used_list->tail == wsc)
+			wsconn_used_list->tail = wsc->used_prev;
+		if (wsc->used_prev)
+			wsc->used_prev->used_next = wsc->used_next;
+		if (wsc->used_next)
+			wsc->used_next->used_prev = wsc->used_prev;
+
+		/* remove from wsconn_id_hash */
+		wsconn_listrm(wsconn_id_hash[wsc->id_hash], wsc, id_next, id_prev);
+
+		/* stat */
+		update_stat(ws_current_connections, -1);
+		if (wsc->sub_protocol == SUB_PROTOCOL_SIP)
+			update_stat(ws_sip_current_connections, -1);
+		else if (wsc->sub_protocol == SUB_PROTOCOL_MSRP)
+			update_stat(ws_msrp_current_connections, -1);
+
+		destroy = 1;
+	}
+	WSCONN_UNLOCK;
+
+	LM_DBG("wsconn_put end for [%p] refcnt [%d]\n", wsc, atomic_get(&wsc->refcnt));
+
+	/* wsc is removed from all lists and can be destroyed safely */
+	if (destroy)
+		wsconn_dtor(wsc);
+
+	return 0;
+}
+
 ws_connection_t *wsconn_get(int id)
 ws_connection_t *wsconn_get(int id)
 {
 {
 	int id_hash = tcp_id_hash(id);
 	int id_hash = tcp_id_hash(id);
 	ws_connection_t *wsc;
 	ws_connection_t *wsc;
 
 
+	LM_DBG("wsconn_get for id [%d]\n", id);
+
 	WSCONN_LOCK;
 	WSCONN_LOCK;
 	for (wsc = wsconn_id_hash[id_hash]; wsc; wsc = wsc->id_next)
 	for (wsc = wsconn_id_hash[id_hash]; wsc; wsc = wsc->id_next)
 	{
 	{
 		if (wsc->id == id)
 		if (wsc->id == id)
 		{
 		{
+			wsconn_ref(wsc);
+			LM_DBG("wsconn_get returns wsc [%p] refcnt [%d]\n", wsc, atomic_get(&wsc->refcnt));
+
 			WSCONN_UNLOCK;
 			WSCONN_UNLOCK;
+
 			return wsc;
 			return wsc;
 		}
 		}
 	}
 	}
@@ -385,6 +448,85 @@ ws_connection_t *wsconn_get(int id)
 	return NULL;
 	return NULL;
 }
 }
 
 
+ws_connection_t **wsconn_get_list(void)
+{
+	ws_connection_t **list = NULL;
+	ws_connection_t *wsc   = NULL;
+	size_t list_size = 0;
+	size_t list_len  = 0;
+	size_t i = 0;
+
+	LM_DBG("wsconn_get_list\n");
+
+	WSCONN_LOCK;
+
+	/* get the number of used connections */
+	wsc = wsconn_used_list->head;
+	while (wsc)
+	{
+		LM_DBG("counter wsc [%p] prev => [%p] next => [%p]\n", wsc, wsc->used_prev, wsc->used_next);
+		list_len++;
+		wsc = wsc->used_next;
+	}
+
+	if (!list_len)
+		goto end;
+
+	/* allocate a NULL terminated list of wsconn pointers */
+	list_size = (list_len + 1) * sizeof(ws_connection_t *);
+	list = pkg_malloc(list_size);
+	if (!list)
+		goto end;
+
+	memset(list, 0, list_size);
+
+	/* copy */
+	wsc = wsconn_used_list->head;
+	for(i = 0; i < list_len; i++)
+	{
+		if (!wsc) {
+			LM_ERR("Wrong list length\n");
+		}
+
+		list[i] = wsc;
+		wsconn_ref(wsc);
+		LM_DBG("wsc [%p] id [%d] ref++\n", wsc, wsc->id);
+
+		wsc = wsc->used_next;
+	}
+	list[list_len] = NULL; /* explicit NULL termination */
+
+end:
+	WSCONN_UNLOCK;
+
+	LM_DBG("wsconn_get_list returns list [%p] with [%d] members\n", list, (int)list_len);
+
+	return list;
+}
+
+int wsconn_put_list(ws_connection_t **list_head)
+{
+	ws_connection_t **list = NULL;
+	ws_connection_t *wsc   = NULL;
+
+	LM_DBG("wsconn_put_list [%p]\n", list_head);
+
+	if (!list_head)
+		return -1;
+
+	list =  list_head;
+	wsc  = *list_head;
+	while (wsc)
+	{
+		wsconn_put(wsc);
+		wsc = *(++list);
+	}
+
+	pkg_free(list_head);
+
+	return 0;
+}
+
 static int add_node(struct mi_root *tree, ws_connection_t *wsc)
 static int add_node(struct mi_root *tree, ws_connection_t *wsc)
 {
 {
 	int interval;
 	int interval;

+ 8 - 0
modules/websocket/ws_conn.h

@@ -29,6 +29,8 @@
 #ifndef _WS_CONN_H
 #ifndef _WS_CONN_H
 #define _WS_CONN_H
 #define _WS_CONN_H
 
 
+#include "../../atomic_ops.h"
+
 #include "../../lib/kcore/kstats_wrapper.h"
 #include "../../lib/kcore/kstats_wrapper.h"
 #include "../../lib/kmi/tree.h"
 #include "../../lib/kmi/tree.h"
 
 
@@ -57,6 +59,9 @@ typedef struct ws_connection
 	struct receive_info rcv;
 	struct receive_info rcv;
 
 
 	unsigned int sub_protocol;
 	unsigned int sub_protocol;
+
+	atomic_t refcnt;
+	int      run_event;
 } ws_connection_t;
 } ws_connection_t;
 
 
 typedef struct
 typedef struct
@@ -89,6 +94,9 @@ int wsconn_rm(ws_connection_t *wsc, ws_conn_eventroute_t run_event_route);
 int wsconn_update(ws_connection_t *wsc);
 int wsconn_update(ws_connection_t *wsc);
 void wsconn_close_now(ws_connection_t *wsc);
 void wsconn_close_now(ws_connection_t *wsc);
 ws_connection_t *wsconn_get(int id);
 ws_connection_t *wsconn_get(int id);
+int wsconn_put(ws_connection_t *wsc);
+ws_connection_t **wsconn_get_list(void);
+int wsconn_put_list(ws_connection_t **list);
 struct mi_root *ws_mi_dump(struct mi_root *cmd, void *param);
 struct mi_root *ws_mi_dump(struct mi_root *cmd, void *param);
 
 
 #endif /* _WS_CONN_H */
 #endif /* _WS_CONN_H */

+ 122 - 58
modules/websocket/ws_frame.c

@@ -240,7 +240,6 @@ static int encode_and_send_ws_frame(ws_frame_t *frame, conn_close_t conn_close)
 		pkg_free(send_buf);
 		pkg_free(send_buf);
 		if (wsconn_rm(frame->wsc, WSCONN_EVENTROUTE_YES) < 0)
 		if (wsconn_rm(frame->wsc, WSCONN_EVENTROUTE_YES) < 0)
 			LM_ERR("removing WebSocket connection\n");
 			LM_ERR("removing WebSocket connection\n");
-		frame->wsc = NULL;
 		return -1;
 		return -1;
 	}
 	}
 	init_dst_from_rcv(&dst, &con->rcv);
 	init_dst_from_rcv(&dst, &con->rcv);
@@ -252,10 +251,8 @@ static int encode_and_send_ws_frame(ws_frame_t *frame, conn_close_t conn_close)
 			LM_ERR("removing WebSocket connection\n");
 			LM_ERR("removing WebSocket connection\n");
 			tcpconn_put(con);
 			tcpconn_put(con);
 			pkg_free(send_buf);
 			pkg_free(send_buf);
-			frame->wsc = NULL;
 			return -1;
 			return -1;
 		}
 		}
-		frame->wsc = NULL;
 	}
 	}
 
 
 	if (dst.proto == PROTO_WS)
 	if (dst.proto == PROTO_WS)
@@ -308,7 +305,6 @@ static int encode_and_send_ws_frame(ws_frame_t *frame, conn_close_t conn_close)
 			update_stat(ws_msrp_failed_connections, 1);
 			update_stat(ws_msrp_failed_connections, 1);
 		if (wsconn_rm(frame->wsc, WSCONN_EVENTROUTE_YES) < 0)
 		if (wsconn_rm(frame->wsc, WSCONN_EVENTROUTE_YES) < 0)
 			LM_ERR("removing WebSocket connection\n");
 			LM_ERR("removing WebSocket connection\n");
-		frame->wsc = NULL;
 		tcpconn_put(con);
 		tcpconn_put(con);
 		return -1;
 		return -1;
 	}
 	}
@@ -394,20 +390,19 @@ static int close_connection(ws_connection_t **p_wsc, ws_close_type_t type,
 			else if (sub_proto == SUB_PROTOCOL_MSRP)
 			else if (sub_proto == SUB_PROTOCOL_MSRP)
 				update_stat(ws_msrp_remote_closed_connections,
 				update_stat(ws_msrp_remote_closed_connections,
 						1);
 						1);
-			*p_wsc = NULL;
 		}
 		}
 	}
 	}
 	else /* if (frame->wsc->state == WS_S_CLOSING) */
 	else /* if (frame->wsc->state == WS_S_CLOSING) */
 	{
 	{
 		wsconn_close_now(wsc);
 		wsconn_close_now(wsc);
-		*p_wsc = NULL;
 	}
 	}
 
 
 	return 0;
 	return 0;
 }
 }
 
 
 static int decode_and_validate_ws_frame(ws_frame_t *frame,
 static int decode_and_validate_ws_frame(ws_frame_t *frame,
-					tcp_event_info_t *tcpinfo)
+                                        tcp_event_info_t *tcpinfo,
+                                        short *err_code, str *err_text)
 {
 {
 	unsigned int i, len = tcpinfo->len;
 	unsigned int i, len = tcpinfo->len;
 	int mask_start, j;
 	int mask_start, j;
@@ -415,21 +410,14 @@ static int decode_and_validate_ws_frame(ws_frame_t *frame,
 
 
 	LM_DBG("decoding WebSocket frame\n");
 	LM_DBG("decoding WebSocket frame\n");
 
 
-	if ((frame->wsc = wsconn_get(tcpinfo->con->id)) == NULL)
-	{
-		LM_ERR("WebSocket connection not found\n");
-		return -1;
-	}
-
 	wsconn_update(frame->wsc);
 	wsconn_update(frame->wsc);
 
 
 	/* Decode and validate first 9 bits */
 	/* Decode and validate first 9 bits */
 	if (len < 2)
 	if (len < 2)
 	{
 	{
 		LM_WARN("message is too short\n");
 		LM_WARN("message is too short\n");
-		if (close_connection(&frame->wsc, LOCAL_CLOSE, 1002,
-					str_status_protocol_error) < 0)
-			LM_ERR("closing connection\n");
+		*err_code = 1002;
+		*err_text = str_status_protocol_error;
 		return -1;
 		return -1;
 	}
 	}
 	frame->fin = (buf[0] & 0xff) & BYTE0_MASK_FIN;
 	frame->fin = (buf[0] & 0xff) & BYTE0_MASK_FIN;
@@ -443,18 +431,16 @@ static int decode_and_validate_ws_frame(ws_frame_t *frame,
 	{
 	{
 		LM_WARN("WebSocket fragmentation not supported in the sip "
 		LM_WARN("WebSocket fragmentation not supported in the sip "
 			"sub-protocol\n");
 			"sub-protocol\n");
-		if (close_connection(&frame->wsc, LOCAL_CLOSE, 1002,
-					str_status_protocol_error) < 0)
-			LM_ERR("closing connection\n");
+		*err_code = 1002;
+		*err_text = str_status_protocol_error;
 		return -1;
 		return -1;
 	}
 	}
 
 
 	if (frame->rsv1 || frame->rsv2 || frame->rsv3)
 	if (frame->rsv1 || frame->rsv2 || frame->rsv3)
 	{
 	{
 		LM_WARN("WebSocket reserved fields with non-zero values\n");
 		LM_WARN("WebSocket reserved fields with non-zero values\n");
-		if (close_connection(&frame->wsc, LOCAL_CLOSE, 1002,
-					str_status_protocol_error) < 0)
-			LM_ERR("closing connection\n");
+		*err_code = 1002;
+		*err_text = str_status_protocol_error;
 		return -1;
 		return -1;
 	}
 	}
 
 
@@ -476,9 +462,8 @@ static int decode_and_validate_ws_frame(ws_frame_t *frame,
 	default:
 	default:
 		LM_WARN("unsupported opcode: 0x%x\n",
 		LM_WARN("unsupported opcode: 0x%x\n",
 			(unsigned char) frame->opcode);
 			(unsigned char) frame->opcode);
-		if (close_connection(&frame->wsc, LOCAL_CLOSE, 1008,
-					str_status_unsupported_opcode) < 0)
-			LM_ERR("closing connection\n");
+		*err_code = 1008;
+		*err_text = str_status_unsupported_opcode;
 		return -1;
 		return -1;
 	}
 	}
 
 
@@ -486,9 +471,8 @@ static int decode_and_validate_ws_frame(ws_frame_t *frame,
 	{
 	{
 		LM_WARN("this is a server - all received messages must be "
 		LM_WARN("this is a server - all received messages must be "
 			"masked\n");
 			"masked\n");
-		if (close_connection(&frame->wsc, LOCAL_CLOSE, 1002,
-					str_status_protocol_error) < 0)
-			LM_ERR("closing connection\n");
+		*err_code = 1002;
+		*err_text = str_status_protocol_error;
 		return -1;
 		return -1;
 	}
 	}
 
 
@@ -499,9 +483,8 @@ static int decode_and_validate_ws_frame(ws_frame_t *frame,
 		if (len < 4)
 		if (len < 4)
 		{
 		{
 			LM_WARN("message is too short\n");
 			LM_WARN("message is too short\n");
-			if (close_connection(&frame->wsc, LOCAL_CLOSE, 1002,
-						str_status_protocol_error) < 0)
-				LM_ERR("closing connection\n");
+			*err_code = 1002;
+			*err_text = str_status_protocol_error;
 			return -1;
 			return -1;
 		}
 		}
 		mask_start = 4;
 		mask_start = 4;
@@ -514,9 +497,8 @@ static int decode_and_validate_ws_frame(ws_frame_t *frame,
 		if (len < 10)
 		if (len < 10)
 		{
 		{
 			LM_WARN("message is too short\n");
 			LM_WARN("message is too short\n");
-			if (close_connection(&frame->wsc, LOCAL_CLOSE, 1002,
-						str_status_protocol_error) < 0)
-				LM_ERR("closing connection\n");
+			*err_code = 1002;
+			*err_text = str_status_protocol_error;
 			return -1;
 			return -1;
 		}
 		}
 		mask_start = 10;
 		mask_start = 10;
@@ -525,9 +507,8 @@ static int decode_and_validate_ws_frame(ws_frame_t *frame,
 			|| (buf[4] & 0xff) != 0 || (buf[5] & 0xff) != 0)
 			|| (buf[4] & 0xff) != 0 || (buf[5] & 0xff) != 0)
 		{
 		{
 			LM_WARN("message is too long\n");
 			LM_WARN("message is too long\n");
-			if (close_connection(&frame->wsc, LOCAL_CLOSE, 1009,
-						str_status_message_too_big) < 0)
-				LM_ERR("closing connection\n");
+			*err_code = 1009;
+			*err_text = str_status_message_too_big;
 			return -1;
 			return -1;
 		}
 		}
 
 
@@ -553,9 +534,8 @@ static int decode_and_validate_ws_frame(ws_frame_t *frame,
 	{
 	{
 		LM_WARN("message not complete frame size %u but received %u\n",
 		LM_WARN("message not complete frame size %u but received %u\n",
 			frame->payload_len + mask_start + 4, len);
 			frame->payload_len + mask_start + 4, len);
-		if (close_connection(&frame->wsc, LOCAL_CLOSE, 1002,
-					str_status_protocol_error) < 0)
-			LM_ERR("closing connection\n");
+		*err_code = 1002;
+		*err_text = str_status_protocol_error;
 		return -1;
 		return -1;
 	}
 	}
 	frame->payload_data = &buf[mask_start + 4];
 	frame->payload_data = &buf[mask_start + 4];
@@ -632,6 +612,11 @@ int ws_frame_receive(void *data)
 	ws_frame_t frame;
 	ws_frame_t frame;
 	tcp_event_info_t *tcpinfo = (tcp_event_info_t *) data;
 	tcp_event_info_t *tcpinfo = (tcp_event_info_t *) data;
 
 
+	int opcode      = -1;
+	int ret         = 0;
+	short err_code  = 0;
+	str   err_text  = {NULL, 0};
+
 	update_stat(ws_received_frames, 1);
 	update_stat(ws_received_frames, 1);
 
 
 	if (tcpinfo == NULL || tcpinfo->buf == NULL || tcpinfo->len <= 0)
 	if (tcpinfo == NULL || tcpinfo->buf == NULL || tcpinfo->len <= 0)
@@ -640,7 +625,26 @@ int ws_frame_receive(void *data)
 		return -1;
 		return -1;
 	}
 	}
 
 
-	switch(decode_and_validate_ws_frame(&frame, tcpinfo))
+	/* wsc refcnt++ */
+	frame.wsc = wsconn_get(tcpinfo->con->id);
+	if (frame.wsc == NULL)
+	{
+		LM_ERR("WebSocket connection not found\n");
+		return -1;
+	}
+
+	opcode = decode_and_validate_ws_frame(&frame, tcpinfo, &err_code, &err_text);
+	if (opcode < 0)
+	{
+		if (close_connection(&frame.wsc, LOCAL_CLOSE, err_code, err_text) < 0)
+			LM_ERR("closing connection\n");
+
+		wsconn_put(frame.wsc);
+
+		return -1;
+	}
+
+	switch(opcode)
 	{
 	{
 	case OPCODE_TEXT_FRAME:
 	case OPCODE_TEXT_FRAME:
 	case OPCODE_BINARY_FRAME:
 	case OPCODE_BINARY_FRAME:
@@ -649,6 +653,9 @@ int ws_frame_receive(void *data)
 			LM_DBG("Rx SIP message:\n%.*s\n", frame.payload_len,
 			LM_DBG("Rx SIP message:\n%.*s\n", frame.payload_len,
 				frame.payload_data);
 				frame.payload_data);
 			update_stat(ws_sip_received_frames, 1);
 			update_stat(ws_sip_received_frames, 1);
+
+			wsconn_put(frame.wsc);
+
 			return receive_msg(frame.payload_data,
 			return receive_msg(frame.payload_data,
 						frame.payload_len,
 						frame.payload_len,
 						tcpinfo->rcv);
 						tcpinfo->rcv);
@@ -667,30 +674,46 @@ int ws_frame_receive(void *data)
 				tev.len = frame.payload_len;
 				tev.len = frame.payload_len;
 				tev.rcv = tcpinfo->rcv;
 				tev.rcv = tcpinfo->rcv;
 				tev.con = tcpinfo->con;
 				tev.con = tcpinfo->con;
+
+				wsconn_put(frame.wsc);
+
 				return sr_event_exec(SREV_TCP_MSRP_FRAME,
 				return sr_event_exec(SREV_TCP_MSRP_FRAME,
 							(void *) &tev);
 							(void *) &tev);
 			}
 			}
 			else
 			else
 			{
 			{
 				LM_ERR("no callback registered for MSRP\n");
 				LM_ERR("no callback registered for MSRP\n");
+
+				wsconn_put(frame.wsc);
+
 				return -1;
 				return -1;
 			}
 			}
 		}
 		}
 
 
 	case OPCODE_CLOSE:
 	case OPCODE_CLOSE:
-		return handle_close(&frame);
+		ret = handle_close(&frame);
+		if (frame.wsc) wsconn_put(frame.wsc);
+		return ret;
 
 
 	case OPCODE_PING:
 	case OPCODE_PING:
-		return handle_ping(&frame);
+		ret = handle_ping(&frame);
+		if (frame.wsc) wsconn_put(frame.wsc);
+		return ret;
 
 
 	case OPCODE_PONG:
 	case OPCODE_PONG:
-		return handle_pong(&frame);
+		ret = handle_pong(&frame);
+		if (frame.wsc) wsconn_put(frame.wsc);
+		return ret;
 
 
 	default:
 	default:
 		LM_WARN("received bad frame\n");
 		LM_WARN("received bad frame\n");
+		wsconn_put(frame.wsc);
 		return -1;
 		return -1;
 	}
 	}
 
 
+	/* how can we get here ? */
+	wsconn_put(frame.wsc);
+
 	return 0;
 	return 0;
 }
 }
 
 
@@ -715,9 +738,14 @@ int ws_frame_transmit(void *data)
 	if (encode_and_send_ws_frame(&frame, CONN_CLOSE_DONT) < 0)
 	if (encode_and_send_ws_frame(&frame, CONN_CLOSE_DONT) < 0)
 	{	
 	{	
 		LM_ERR("sending message\n");
 		LM_ERR("sending message\n");
+
+		wsconn_put(frame.wsc);
+
 		return -1;
 		return -1;
 	}
 	}
 
 
+	wsconn_put(frame.wsc);
+
 	return 0;
 	return 0;
 }
 }
 
 
@@ -783,8 +811,11 @@ struct mi_root *ws_mi_close(struct mi_root *cmd, void *param)
 					str_status_bad_param.len);
 					str_status_bad_param.len);
 	}
 	}
 
 
-	if (close_connection(&wsc, LOCAL_CLOSE, 1000,
-				str_status_normal_closure) < 0)
+	int ret = close_connection(&wsc, LOCAL_CLOSE, 1000, str_status_normal_closure);
+
+	wsconn_put(wsc);
+
+	if (ret < 0)
 	{
 	{
 		LM_WARN("closing connection\n");
 		LM_WARN("closing connection\n");
 		return init_mi_tree(500, str_status_error_closing.s,
 		return init_mi_tree(500, str_status_error_closing.s,
@@ -834,7 +865,11 @@ static struct mi_root *mi_ping_pong(struct mi_root *cmd, void *param,
 					str_status_bad_param.len);
 					str_status_bad_param.len);
 	}
 	}
 
 
-	if (ping_pong(wsc, opcode) < 0)
+	int ret = ping_pong(wsc, opcode);
+
+	wsconn_put(wsc);
+
+	if (ret < 0)
 	{
 	{
 		LM_WARN("sending %s\n", OPCODE_PING ? "Ping" : "Pong");
 		LM_WARN("sending %s\n", OPCODE_PING ? "Ping" : "Pong");
 		return init_mi_tree(500, str_status_error_sending.s,
 		return init_mi_tree(500, str_status_error_sending.s,
@@ -858,36 +893,55 @@ void ws_keepalive(unsigned int ticks, void *param)
 {
 {
 	int check_time = (int) time(NULL)
 	int check_time = (int) time(NULL)
 		- cfg_get(websocket, ws_cfg, keepalive_timeout);
 		- cfg_get(websocket, ws_cfg, keepalive_timeout);
-	ws_connection_t *wsc = wsconn_used_list->head;
 
 
+	ws_connection_t **list      = NULL,
+	                **list_head = NULL;
+	ws_connection_t *wsc   = NULL;
+
+	/* get an array of pointer to all ws connection */
+	list_head = wsconn_get_list();
+	if (!list_head)
+		return;
+
+	list =  list_head;
+	wsc  = *list_head;
 	while (wsc && wsc->last_used < check_time)
 	while (wsc && wsc->last_used < check_time)
 	{
 	{
-		if (wsc->state == WS_S_CLOSING
-			|| wsc->awaiting_pong)
+		if (wsc->state == WS_S_CLOSING || wsc->awaiting_pong)
 		{
 		{
 			LM_WARN("forcibly closing connection\n");
 			LM_WARN("forcibly closing connection\n");
 			wsconn_close_now(wsc);
 			wsconn_close_now(wsc);
 		}
 		}
 		else
 		else
-			ping_pong(wsconn_used_list->head,
-			  ws_keepalive_mechanism == KEEPALIVE_MECHANISM_PING
-					? OPCODE_PING : OPCODE_PONG);
-		wsc = wsconn_used_list->head;
+		{
+			int opcode = (ws_keepalive_mechanism == KEEPALIVE_MECHANISM_PING)
+			             ? OPCODE_PING
+			             : OPCODE_PONG;
+			ping_pong(wsc, opcode);
+		}
+
+		wsc = *(++list);
 	}
 	}
-	
+
+	wsconn_put_list(list_head);
 }
 }
 
 
 int ws_close(sip_msg_t *msg)
 int ws_close(sip_msg_t *msg)
 {
 {
 	ws_connection_t *wsc;
 	ws_connection_t *wsc;
+	int ret;
 
 
 	if ((wsc = wsconn_get(msg->rcv.proto_reserved1)) == NULL) {
 	if ((wsc = wsconn_get(msg->rcv.proto_reserved1)) == NULL) {
 		LM_ERR("failed to retrieve WebSocket connection\n");
 		LM_ERR("failed to retrieve WebSocket connection\n");
 		return -1;
 		return -1;
 	}
 	}
 
 
-	return (close_connection(&wsc, LOCAL_CLOSE, 1000,
+	ret = (close_connection(&wsc, LOCAL_CLOSE, 1000,
 				 str_status_normal_closure) == 0) ? 1: 0;
 				 str_status_normal_closure) == 0) ? 1: 0;
+
+	wsconn_put(wsc);
+
+	return ret;
 }
 }
 
 
 int ws_close2(sip_msg_t *msg, char *_status, char *_reason)
 int ws_close2(sip_msg_t *msg, char *_status, char *_reason)
@@ -895,6 +949,7 @@ int ws_close2(sip_msg_t *msg, char *_status, char *_reason)
 	int status;
 	int status;
 	str reason;
 	str reason;
 	ws_connection_t *wsc;
 	ws_connection_t *wsc;
+	int ret;
 
 
 	if (get_int_fparam(&status, msg, (fparam_t *) _status) < 0) {
 	if (get_int_fparam(&status, msg, (fparam_t *) _status) < 0) {
 		LM_ERR("failed to get status code\n");
 		LM_ERR("failed to get status code\n");
@@ -911,7 +966,11 @@ int ws_close2(sip_msg_t *msg, char *_status, char *_reason)
 		return -1;
 		return -1;
 	}
 	}
 
 
-	return (close_connection(&wsc, LOCAL_CLOSE, status, reason) == 0) ? 1: 0;
+	ret = (close_connection(&wsc, LOCAL_CLOSE, status, reason) == 0) ? 1: 0;
+
+	wsconn_put(wsc);
+
+	return ret;
 }
 }
 
 
 int ws_close3(sip_msg_t *msg, char *_status, char *_reason, char *_con)
 int ws_close3(sip_msg_t *msg, char *_status, char *_reason, char *_con)
@@ -920,6 +979,7 @@ int ws_close3(sip_msg_t *msg, char *_status, char *_reason, char *_con)
 	str reason;
 	str reason;
 	int con;
 	int con;
 	ws_connection_t *wsc;
 	ws_connection_t *wsc;
+	int ret;
 
 
 	if (get_int_fparam(&status, msg, (fparam_t *) _status) < 0) {
 	if (get_int_fparam(&status, msg, (fparam_t *) _status) < 0) {
 		LM_ERR("failed to get status code\n");
 		LM_ERR("failed to get status code\n");
@@ -941,5 +1001,9 @@ int ws_close3(sip_msg_t *msg, char *_status, char *_reason, char *_con)
 		return -1;
 		return -1;
 	}
 	}
 
 
-	return (close_connection(&wsc, LOCAL_CLOSE, status, reason) == 0) ? 1: 0;
+	ret = (close_connection(&wsc, LOCAL_CLOSE, status, reason) == 0) ? 1: 0;
+
+	wsconn_put(wsc);
+
+	return ret;
 }
 }

+ 3 - 1
modules/websocket/ws_handshake.c

@@ -427,8 +427,10 @@ int ws_handle_handshake(struct sip_msg *msg)
 				&headers) < 0)
 				&headers) < 0)
 	{
 	{
 		if ((wsc = wsconn_get(msg->rcv.proto_reserved1)) != NULL)
 		if ((wsc = wsconn_get(msg->rcv.proto_reserved1)) != NULL)
+		{
 			wsconn_rm(wsc, WSCONN_EVENTROUTE_NO);
 			wsconn_rm(wsc, WSCONN_EVENTROUTE_NO);
-
+			wsconn_put(wsc);
+		}
 		goto end;
 		goto end;
 	}
 	}
 	else
 	else

+ 299 - 3
msg_translator.c

@@ -147,8 +147,9 @@
 #include "pt.h"
 #include "pt.h"
 #include "cfg/cfg.h"
 #include "cfg/cfg.h"
 #include "parser/parse_to.h"
 #include "parser/parse_to.h"
+#include "parser/parse_param.h"
 #include "forward.h"
 #include "forward.h"
-
+#include "str_list.h"
 
 
 #define append_str_trans(_dest,_src,_len,_msg) \
 #define append_str_trans(_dest,_src,_len,_msg) \
 	append_str( (_dest), (_src), (_len) );
 	append_str( (_dest), (_src), (_len) );
@@ -1620,7 +1621,301 @@ error:
 	return -1;
 	return -1;
 }
 }
 
 
+static inline int find_line_start(char *text, unsigned int text_len,
+				  char **buf, unsigned int *buf_len)
+{
+	char *ch, *start;
+	unsigned int len;
+
+	start = *buf;
+	len = *buf_len;
+
+	while (text_len <= len) {
+		if (strncmp(text, start, text_len) == 0) {
+			*buf = start;
+			*buf_len = len;
+			return 1;
+		}
+		if ((ch = memchr(start, 13, len - 1))) {
+			if (*(ch + 1) != 10) {
+				LM_ERR("No LF after CR\n");
+				return 0;
+			}
+			len = len - (ch - start + 2);
+			start = ch + 2;
+		} else {
+			LM_ERR("No CRLF found\n");
+			return 0;
+		}
+	}
+	return 0;
+}
+
+static inline int get_line(str s)
+{
+	char *ch;
+
+	if ((ch = memchr(s.s, 13, s.len))) {
+		if (*(ch + 1) != 10) {
+			LM_ERR("No LF after CR\n");
+			return 0;
+		}
+		return ch - s.s + 2;
+	} else {
+		LM_ERR("No CRLF found\n");
+		return s.len;
+	}
+	return 0;
+}
+
+int replace_body(struct sip_msg *msg, str txt)
+{
+	struct lump *anchor;
+	char *buf;
+	str body = {0,0};
+
+	body.s = get_body(msg);
+	if(body.s==0)
+	{
+		LM_ERR("malformed sip message\n");
+		return 0;
+	}
+	body.len = msg->len -(int)(body.s-msg->buf);
+	LM_DBG("old size body[%d] actual[%d]\n", body.len, txt.len);
+	if(body.s+body.len>msg->buf+msg->len)
+	{
+		LM_ERR("invalid content length: %d\n", body.len);
+		return 0;
+	}
+	del_nonshm_lump( &(msg->body_lumps) );
+	msg->body_lumps = NULL;
+
+	if(del_lump(msg, body.s-msg->buf, body.len, 0) == 0)
+	{
+		LM_ERR("cannot delete existing body");
+		return 0;
+	}
+
+	anchor = anchor_lump(msg, body.s - msg->buf, 0, 0);
+	if(anchor==0)
+	{
+		LM_ERR("failed to get anchor\n");
+		return 0;
+	}
+
+	buf=pkg_malloc(sizeof(char)*txt.len);
+	if(buf==0)
+	{
+		PKG_MEM_ERROR;
+		return 0;
+	}
+	memcpy(buf, txt.s, txt.len);
+	if(insert_new_lump_after(anchor, buf, txt.len, 0)==0)
+	{
+		LM_ERR("failed to insert body lump\n");
+		pkg_free(buf);
+		return 0;
+	}
+	return 1;
+}
+
+/**
+ * returns the boundary defined by the Content-Type
+ * header
+ */
+int get_boundary(struct sip_msg* msg, str* boundary)
+{
+	str params;
+	param_t *p, *list;
+	param_hooks_t hooks;
+
+	params.s = memchr(msg->content_type->body.s, ';',
+		msg->content_type->body.len);
+	if (params.s == NULL)
+	{
+		LM_ERR("Content-Type hdr has no params\n");
+		return -1;
+	}
+	params.len = msg->content_type->body.len -
+		(params.s - msg->content_type->body.s);
+	if (parse_params(&params, CLASS_ANY, &hooks, &list) < 0)
+	{
+		LM_ERR("while parsing Content-Type params\n");
+		return -1;
+	}
+	boundary->s = NULL;
+	boundary->len = 0;
+	for (p = list; p; p = p->next) {
+		if ((p->name.len == 8)
+			&& (strncasecmp(p->name.s, "boundary", 8) == 0))
+		{
+			boundary->s = pkg_malloc(p->body.len + 2);
+			if (boundary->s == NULL)
+			{
+				free_params(list);
+				LM_ERR("no memory for boundary string\n");
+				return -1;
+			}
+			*(boundary->s) = '-';
+			*(boundary->s + 1) = '-';
+			memcpy(boundary->s + 2, p->body.s, p->body.len);
+			boundary->len = 2 + p->body.len;
+			LM_DBG("boundary is <%.*s>\n", boundary->len, boundary->s);
+			break;
+		}
+	}
+	free_params(list);
+	return 0;
+}
+
+int check_boundaries(struct sip_msg *msg, struct dest_info *send_info)
+{
+	str b = {0,0};
+	str fb = {0,0};
+	str ob = {0,0};
+	str bsuffix = {"\r\n", 2};
+	str fsuffix = {"--\r\n", 4};
+	str body = {0,0};
+	str buf = {0,0};
+	str tmp = {0,0};
+	struct str_list* lb = NULL;
+	struct str_list* lb_t = NULL;
+	int lb_found = 0;
+	int t, ret, lb_size;
+	char *pb;
+
+	if(!(msg->msg_flags&FL_BODY_MULTIPART)) return 0;
+	else
+	{
+		buf.s = build_body(msg, (unsigned int *)&buf.len, &ret, send_info);
+		if(ret) {
+			LM_ERR("Can't get body\n");
+			return -1;
+		}
+		tmp.s = buf.s;
+		t = tmp.len = buf.len;
+		if(get_boundary(msg, &ob)!=0) return -1;
+		if(str_append(&ob, &bsuffix, &b)!=0) {
+			LM_ERR("Can't append suffix to boundary\n");
+			goto error;
+		}
+		if(str_append(&ob, &fsuffix,&fb)!=0) {
+			LM_ERR("Can't append suffix to final boundary\n");
+			goto error;
+		}
+		ret = b.len-2;
+		while(t>0)
+		{
+			if(find_line_start(b.s, ret, &tmp.s,
+				(unsigned int *)&tmp.len))
+			{
+				/*LM_DBG("found t[%d] tmp.len[%d]:[%.*s]\n",
+					t, tmp.len, tmp.len, tmp.s);*/
+				if(!lb)
+				{
+					lb = pkg_malloc(sizeof(struct str_list));
+					if (!lb) {
+						PKG_MEM_ERROR;
+						goto error;
+					}
+					lb->s.s = tmp.s;
+					lb->s.len = tmp.len;
+					lb->next = 0;
+					lb_t = lb;
+				}
+				else
+				{
+					lb_t = append_str_list(tmp.s, tmp.len, &lb_t, &lb_size);
+				}
+				lb_found = lb_found + 1;
+				tmp.s = tmp.s + ret;
+				t =  t - ret;
+				tmp.len = tmp.len - ret;
+			}
+			else { t=0; }
+		}
+		if(lb_found<2)
+		{
+			LM_ERR("found[%d] wrong number of boundaries\n", lb_found);
+			goto error;
+		}
+		/* adding 2 chars in advance */
+		body.len = buf.len + 2;
+		body.s = pkg_malloc(sizeof(char)*body.len);
+		if (!body.s) {
+			PKG_MEM_ERROR;
+			goto error;
+		}
+		pb = body.s; body.len = 0;
+		lb_t = lb;
+		while(lb_t)
+		{
+			tmp.s = lb_t->s.s; tmp.len = lb_t->s.len;
+			tmp.len = get_line(lb_t->s);
+			if(tmp.len!=b.len || strncmp(b.s, tmp.s, b.len)!=0)
+			{
+				LM_DBG("malformed bondary in the middle\n");
+				memcpy(pb, b.s, b.len); body.len = body.len + b.len;
+				pb = pb + b.len;
+				t = lb_t->s.s - (lb_t->s.s + tmp.len);
+				memcpy(pb, lb_t->s.s+tmp.len, t); pb = pb + t;
+				/*LM_DBG("new chunk[%d][%.*s]\n", t, t, pb-t);*/
+			}
+			else {
+				t = lb_t->next->s.s - lb_t->s.s;
+				memcpy(pb, lb_t->s.s, t);
+				/*LM_DBG("copy[%d][%.*s]\n", t, t, pb);*/
+				pb = pb + t;
+			}
+			body.len = body.len + t;
+			/*LM_DBG("body[%d][%.*s]\n", body.len, body.len, body.s);*/
+			lb_t = lb_t->next;
+			if(!lb_t->next) lb_t = NULL;
+		}
+		/* last boundary */
+		tmp.s = lb->s.s; tmp.len = lb->s.len;
+		tmp.len = get_line(lb->s);
+		if(tmp.len!=fb.len || strncmp(fb.s, tmp.s, fb.len)!=0)
+		{
+			LM_DBG("last bondary without -- at the end\n");
+			memcpy(pb, fb.s, fb.len);
+			/*LM_DBG("new chunk[%d][%.*s]\n", fb.len, fb.len, pb);*/
+			pb = pb + fb.len;
+			body.len = body.len + fb.len;
+		}
+		else {
+			memcpy(pb, lb->s.s, lb->s.len); pb = pb + lb->s.len;
+			body.len = body.len + lb->s.len;
+			/*LM_DBG("copy[%d][%.*s]\n", lb->s.len, lb->s.len, pb - lb->s.len);*/
+		}
+		/*LM_DBG("body[%d][%.*s] expected[%ld]\n",
+			body.len, body.len, body.s, pb-body.s); */
+		if(!replace_body(msg, body))
+		{
+			LM_ERR("Can't replace body\n");
+			goto error;
+		}
+		msg->msg_flags &= ~FL_BODY_MULTIPART;
+		ret = 1;
+		goto clean;
+	}
 
 
+error:
+	ret = -1;
+clean:
+	if(ob.s) pkg_free(ob.s);
+	if(b.s) pkg_free(b.s);
+	if(fb.s) pkg_free(fb.s);
+	if(body.s) pkg_free(body.s);
+	if(buf.s) pkg_free(buf.s);
+	while(lb)
+	{
+		lb_t = lb->next;
+		pkg_free(lb);
+		lb = lb_t;
+	}
+	return ret;
+}
 
 
 /** builds a request in memory from another sip request.
 /** builds a request in memory from another sip request.
   *
   *
@@ -1700,6 +1995,9 @@ char * build_req_buf_from_sip_req( struct sip_msg* msg,
 	path_buf.len=0;
 	path_buf.len=0;
 
 
 	flags=msg->msg_flags|global_req_flags;
 	flags=msg->msg_flags|global_req_flags;
+	if(check_boundaries(msg, send_info)<0){
+		LM_WARN("check_boundaries error\n");
+	}
 	/* Calculate message body difference and adjust Content-Length */
 	/* Calculate message body difference and adjust Content-Length */
 	body_delta = lumps_len(msg, msg->body_lumps, send_info);
 	body_delta = lumps_len(msg, msg->body_lumps, send_info);
 	if (adjust_clen(msg, body_delta, send_info->proto) < 0) {
 	if (adjust_clen(msg, body_delta, send_info->proto) < 0) {
@@ -1956,8 +2254,6 @@ error00:
 	return 0;
 	return 0;
 }
 }
 
 
-
-
 char * generate_res_buf_from_sip_res( struct sip_msg* msg,
 char * generate_res_buf_from_sip_res( struct sip_msg* msg,
 				unsigned int *returned_len, unsigned int mode)
 				unsigned int *returned_len, unsigned int mode)
 {
 {

+ 3 - 0
msg_translator.h

@@ -162,4 +162,7 @@ void fix_global_req_flags(str* gname, str* name);
 
 
 int build_sip_msg_from_buf(struct sip_msg *msg, char *buf, int len,
 int build_sip_msg_from_buf(struct sip_msg *msg, char *buf, int len,
 		unsigned int id);
 		unsigned int id);
+
+/* returns a copy in private memory of the boundary in a multipart body */
+int get_boundary(struct sip_msg* msg, str* boundary);
 #endif
 #endif

+ 7 - 5
onsend.h

@@ -43,10 +43,11 @@
 #include "sr_compat.h"
 #include "sr_compat.h"
 
 
 struct onsend_info{
 struct onsend_info{
-	union sockaddr_union* to;
-	struct socket_info* send_sock;
-	char* buf;
-	int len;
+	union sockaddr_union* to;       /* dest info */
+	struct socket_info* send_sock;  /* local send socket */
+	char* buf;                      /* outgoing buffer */
+	int len;                        /* outgoing buffer len */
+	sip_msg_t *msg;                 /* original sip msg struct */
 };
 };
 
 
 extern struct onsend_info* p_onsend;
 extern struct onsend_info* p_onsend;
@@ -61,7 +62,7 @@ extern struct onsend_info* p_onsend;
 static inline int run_onsend(struct sip_msg* orig_msg, struct dest_info* dst,
 static inline int run_onsend(struct sip_msg* orig_msg, struct dest_info* dst,
 								char* buf, int len)
 								char* buf, int len)
 {
 {
-	struct onsend_info onsnd_info;
+	struct onsend_info onsnd_info = {0};
 	int ret;
 	int ret;
 	struct run_act_ctx ra_ctx;
 	struct run_act_ctx ra_ctx;
 	int backup_route_type;
 	int backup_route_type;
@@ -74,6 +75,7 @@ static inline int run_onsend(struct sip_msg* orig_msg, struct dest_info* dst,
 		onsnd_info.send_sock=dst->send_sock;
 		onsnd_info.send_sock=dst->send_sock;
 		onsnd_info.buf=buf;
 		onsnd_info.buf=buf;
 		onsnd_info.len=len;
 		onsnd_info.len=len;
+		onsnd_info.msg=orig_msg;
 		p_onsend=&onsnd_info;
 		p_onsend=&onsnd_info;
 		backup_route_type=get_route_type();
 		backup_route_type=get_route_type();
 		set_route_type(ONSEND_ROUTE);
 		set_route_type(ONSEND_ROUTE);

+ 2 - 1
parser/sdp/sdp.c

@@ -871,12 +871,13 @@ void print_sdp_stream(sdp_stream_cell_t *stream, int log_level)
 
 
 void print_sdp_session(sdp_session_cell_t *session, int log_level)
 void print_sdp_session(sdp_session_cell_t *session, int log_level)
 {
 {
-	sdp_stream_cell_t *stream = session->streams;
+	sdp_stream_cell_t *stream;
 
 
 	if (session==NULL) {
 	if (session==NULL) {
 		LM_ERR("NULL session\n");
 		LM_ERR("NULL session\n");
 		return;
 		return;
 	}
 	}
+	stream = session->streams;
 
 
 	LOG(log_level, "..session[%d]:%p=>%p '%.*s' '%.*s' '%.*s' '%.*s:%.*s' (%d)=>%p\n",
 	LOG(log_level, "..session[%d]:%p=>%p '%.*s' '%.*s' '%.*s' '%.*s:%.*s' (%d)=>%p\n",
 		session->session_num, session, session->next,
 		session->session_num, session, session->next,

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

@@ -40,6 +40,7 @@ Build-Depends: bison,
                libxml2-dev,
                libxml2-dev,
                libxmlrpc-c3-dev,
                libxmlrpc-c3-dev,
                openssl,
                openssl,
+               pkg-config,
                python,
                python,
                python-dev,
                python-dev,
                unixodbc-dev,
                unixodbc-dev,

+ 1 - 0
pkg/kamailio/deb/jessie/control

@@ -39,6 +39,7 @@ Build-Depends: bison,
                libval-dev,
                libval-dev,
                libxml2-dev,
                libxml2-dev,
                openssl,
                openssl,
+               pkg-config,
                python,
                python,
                python-dev,
                python-dev,
                unixodbc-dev,
                unixodbc-dev,

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

@@ -38,6 +38,7 @@ Build-Depends: bison,
                libunistring-dev,
                libunistring-dev,
                libxml2-dev,
                libxml2-dev,
                openssl,
                openssl,
+               pkg-config,
                python,
                python,
                python-dev,
                python-dev,
                unixodbc-dev,
                unixodbc-dev,

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

@@ -33,6 +33,7 @@ Build-Depends: bison,
                libxml2-dev,
                libxml2-dev,
                libxmlrpc-c3-dev,
                libxmlrpc-c3-dev,
                openssl,
                openssl,
+               pkg-config,
                python,
                python,
                python-dev,
                python-dev,
                unixodbc-dev,
                unixodbc-dev,

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

@@ -37,6 +37,7 @@ Build-Depends: bison,
                libunistring-dev,
                libunistring-dev,
                libxml2-dev,
                libxml2-dev,
                openssl,
                openssl,
+               pkg-config,
                python,
                python,
                python-dev,
                python-dev,
                unixodbc-dev,
                unixodbc-dev,

+ 1 - 1
pkg/kamailio/rpm/kamailio.init

@@ -35,7 +35,7 @@ check_fork ()
 check_kamailio_config ()
 check_kamailio_config ()
 {
 {
         # Check if kamailio configuration is valid before starting the server
         # Check if kamailio configuration is valid before starting the server
-        out=$($KAM -c 2>&1 > /dev/null)
+        out=$($KAM -M $PKG_MEMORY -c 2>&1 > /dev/null)
         retcode=$?
         retcode=$?
         if [ "$retcode" != '0' ]; then
         if [ "$retcode" != '0' ]; then
             echo "Not starting $DESC: invalid configuration file!"
             echo "Not starting $DESC: invalid configuration file!"

+ 4 - 8
route.c

@@ -1886,8 +1886,7 @@ inline static int eval_elem(struct run_act_ctx* h, struct expr* e,
 			if (e->r_type==MYSELF_ST){
 			if (e->r_type==MYSELF_ST){
 				if (parse_sip_msg_uri(msg)<0) ret=-1;
 				if (parse_sip_msg_uri(msg)<0) ret=-1;
 				else ret=check_self_op(e->op, &msg->parsed_uri.host,
 				else ret=check_self_op(e->op, &msg->parsed_uri.host,
-						       msg->parsed_uri.port_no?
-						       msg->parsed_uri.port_no:SIP_PORT);
+								GET_URI_PORT(&msg->parsed_uri));
 			}else{
 			}else{
 				ret=comp_str(e->op, &msg->new_uri,
 				ret=comp_str(e->op, &msg->new_uri,
 								e->r_type, &e->r, msg, h);
 								e->r_type, &e->r, msg, h);
@@ -1896,8 +1895,7 @@ inline static int eval_elem(struct run_act_ctx* h, struct expr* e,
 			if (e->r_type==MYSELF_ST){
 			if (e->r_type==MYSELF_ST){
 				if (parse_sip_msg_uri(msg)<0) ret=-1;
 				if (parse_sip_msg_uri(msg)<0) ret=-1;
 				else ret=check_self_op(e->op, &msg->parsed_uri.host,
 				else ret=check_self_op(e->op, &msg->parsed_uri.host,
-						       msg->parsed_uri.port_no?
-						       msg->parsed_uri.port_no:SIP_PORT);
+								GET_URI_PORT(&msg->parsed_uri));
 			}else{
 			}else{
 				ret=comp_str(e->op, &msg->first_line.u.request.uri,
 				ret=comp_str(e->op, &msg->first_line.u.request.uri,
 								e->r_type, &e->r, msg, h);
 								e->r_type, &e->r, msg, h);
@@ -1917,8 +1915,7 @@ inline static int eval_elem(struct run_act_ctx* h, struct expr* e,
 				LOG(L_ERR, "ERROR: eval_elem: bad uri in From:\n");
 				LOG(L_ERR, "ERROR: eval_elem: bad uri in From:\n");
 				goto error;
 				goto error;
 			}
 			}
-			ret=check_self_op(e->op, &uri.host,
-					  uri.port_no?uri.port_no:SIP_PORT);
+			ret=check_self_op(e->op, &uri.host, GET_URI_PORT(&uri));
 		}else{
 		}else{
 			ret=comp_str(e->op, &get_from(msg)->uri,
 			ret=comp_str(e->op, &get_from(msg)->uri,
 							e->r_type, &e->r, msg, h);
 							e->r_type, &e->r, msg, h);
@@ -1939,8 +1936,7 @@ inline static int eval_elem(struct run_act_ctx* h, struct expr* e,
 				LOG(L_ERR, "ERROR: eval_elem: bad uri in To:\n");
 				LOG(L_ERR, "ERROR: eval_elem: bad uri in To:\n");
 				goto error;
 				goto error;
 			}
 			}
-			ret=check_self_op(e->op, &uri.host,
-					  uri.port_no?uri.port_no:SIP_PORT);
+			ret=check_self_op(e->op, &uri.host, GET_URI_PORT(&uri));
 		}else{
 		}else{
 			ret=comp_str(e->op, &get_to(msg)->uri,
 			ret=comp_str(e->op, &get_to(msg)->uri,
 							e->r_type, &e->r, msg, h);
 							e->r_type, &e->r, msg, h);

+ 1 - 0
rvalue.c

@@ -2554,6 +2554,7 @@ struct rval_expr* mk_rval_expr_v(enum rval_type rv_type, void* val,
 			s=(str*)val;
 			s=(str*)val;
 			v.s.s=pkg_malloc(s->len+1 /*0*/);
 			v.s.s=pkg_malloc(s->len+1 /*0*/);
 			if (v.s.s==0){
 			if (v.s.s==0){
+				pkg_free(rve);
 				ERR("memory allocation failure\n");
 				ERR("memory allocation failure\n");
 				return 0;
 				return 0;
 			}
 			}

+ 94 - 0
sr_module.c

@@ -1776,6 +1776,100 @@ int get_int_fparam(int* dst, struct sip_msg* msg, fparam_t* param)
 	return 0;
 	return 0;
 }
 }
 
 
+/** Get the function parameter value as string or/and integer (if possible).
+ *  @return  0 - Success
+ *          -1 - Cannot get value
+ */
+int get_is_fparam(int* i_dst, str* s_dst, struct sip_msg* msg, fparam_t* param, unsigned int *flags)
+{
+	int_str val;
+	int ret;
+	avp_t* avp;
+	str tmp;
+	pv_value_t pv_val;
+
+	*flags = 0;
+	switch(param->type) {
+		case FPARAM_INT:
+			*i_dst = param->v.i;
+			*flags |= PARAM_INT;
+			return 0;
+		case FPARAM_REGEX:
+		case FPARAM_UNSPEC:
+		case FPARAM_STRING:
+			s_dst->s = param->v.asciiz;
+			s_dst->len = strlen(param->v.asciiz);
+			*flags |= PARAM_STR;
+			break;
+		case FPARAM_STR:
+			*s_dst = param->v.str;
+			*flags |= PARAM_STR;
+			break;
+		case FPARAM_AVP:
+			avp = search_first_avp(param->v.avp.flags, param->v.avp.name,
+									&val, 0);
+			if (unlikely(!avp)) {
+				DBG("Could not find AVP from function parameter '%s'\n",
+						param->orig);
+				return -1;
+			}
+			if (avp->flags & AVP_VAL_STR) {
+				*s_dst = val.s;
+				*flags |= PARAM_STR;
+				if (str2int(&val.s, (unsigned int*)i_dst) < 0) {
+					ERR("Could not convert AVP string value to int\n");
+					return -1;
+				}
+			} else {
+				*i_dst = val.n;
+				*flags |= PARAM_INT;
+			}
+			break;
+		case FPARAM_SELECT:
+			ret = run_select(&tmp, param->v.select, msg);
+			if (unlikely(ret < 0 || ret > 0)) return -1;
+			if (unlikely(str2int(&tmp, (unsigned int*)i_dst) < 0)) {
+				ERR("Could not convert select result to int\n");
+				return -1;
+			}
+			*flags |= PARAM_INT;
+			break;
+		case FPARAM_PVS:
+			if (likely(pv_get_spec_value(msg, param->v.pvs, &pv_val)==0)) {
+				if ((pv_val.flags&(PV_VAL_NULL|PV_VAL_INT))==PV_VAL_INT){
+					*i_dst=pv_val.ri;
+					*flags |= PARAM_INT;
+				}
+				if ((pv_val.flags&(PV_VAL_NULL|PV_VAL_STR))==PV_VAL_STR){
+					*s_dst=pv_val.rs;
+					*flags |= PARAM_STR;
+				}
+			}else{
+				ERR("Could not get PV\n");
+				return -1;
+			}
+			break;
+		case FPARAM_PVE:
+			s_dst->s=pv_get_buffer();
+			s_dst->len=pv_get_buffer_size();
+			if (unlikely(pv_printf(msg, param->v.pve, s_dst->s, &s_dst->len)!=0)){
+				ERR("Could not convert the PV-formated string to str\n");
+				s_dst->len=0;
+				return -1;
+			}
+			*flags |= PARAM_STR;
+			break;
+	}
+
+	/* Let's convert to int, if possible */
+	if (!(*flags & PARAM_INT) && (*flags & PARAM_STR) && str2sint(s_dst, i_dst) == 0)
+		*flags |= PARAM_INT;
+
+	if (!*flags) return -1;
+
+	return 0;
+}
+
 /**
 /**
  * Retrieve the compiled RegExp.
  * Retrieve the compiled RegExp.
  * @return: 0 for success, negative on error.
  * @return: 0 for success, negative on error.

+ 11 - 0
sr_module.h

@@ -629,6 +629,17 @@ int get_str_fparam(str* dst, struct sip_msg* msg, fparam_t* param);
  */
  */
 int get_int_fparam(int* dst, struct sip_msg* msg, fparam_t* param);
 int get_int_fparam(int* dst, struct sip_msg* msg, fparam_t* param);
 
 
+/**
+ * @brief Get the function parameter value as integer/string
+ * @param i_dst int destination
+ * @param s_dst string destination
+ * @param msg SIP message
+ * @param param function parameters
+ * @param flags flags to indicate destiantions
+ * @return 0 on success, 1 on error, e.g. cannot get value
+ */
+int get_is_fparam(int* i_dst, str* s_dst, struct sip_msg* msg, fparam_t* param, unsigned int *flags);
+
 /**
 /**
  * @brief Get the function parameter value as compiled regular expression
  * @brief Get the function parameter value as compiled regular expression
  * @param dst string destination
  * @param dst string destination

+ 45 - 0
str.c

@@ -0,0 +1,45 @@
+/**
+ * $Id$
+ *
+ * Copyright (C) 2014 Victor Seva <[email protected]>
+ *
+ * This file is part of kamailio, a free SIP server.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <string.h>
+#include "str.h"
+#include "mem/mem.h"
+
+int str_append(str *orig, str *suffix, str *dest)
+{
+	if(orig == NULL || suffix == NULL || suffix->len == 0 || dest == NULL)
+	{
+		LM_ERR("wrong parameters\n");
+		return -1;
+	}
+	dest->len = orig->len + suffix->len;
+	dest->s = pkg_malloc(sizeof(char)*dest->len);
+	if(dest->s==NULL)
+	{
+		LOG(L_ERR, "memory allocation failure\n");
+		return -1;
+	}
+	if(orig->len>0)
+	{
+		memcpy(dest->s, orig->s, orig->len);
+	}
+	memcpy(dest->s+orig->len, suffix->s, suffix->len);
+	return 0;
+}

+ 9 - 0
str.h

@@ -121,4 +121,13 @@ typedef struct _str str;
 
 
 /** @} */
 /** @} */
 
 
+/** Appends a sufffix
+ * @param orig is the original string
+ * @param suffix is the suffix string
+ * @param dest is the result ::str of appending suffix to orig
+ * @return 0 if ok -1 if error
+ * remember to free the dest->s private memory
+ */
+int str_append(str *orig, str *suffix, str *dest);
+
 #endif
 #endif

+ 11 - 0
tcp_main.c

@@ -4934,6 +4934,17 @@ int tcp_init_children()
 			}
 			}
 		}
 		}
 	}
 	}
+#ifdef USE_TLS
+	for(si=tls_listen; si; si=si->next) {
+		if(si->workers>0) {
+			si->workers_tcpidx = i - si->workers + 1;
+			for(r=0; r<si->workers; r++) {
+				tcp_children[i].mysocket = si;
+				i--;
+			}
+		}
+	}
+#endif
 	tcp_sockets_gworkers = (i != tcp_children_no-1)?(1 + i + 1):0;
 	tcp_sockets_gworkers = (i != tcp_children_no-1)?(1 + i + 1):0;
 
 
 	/* create the tcp sock_info structures */
 	/* create the tcp sock_info structures */

Some files were not shown because too many files changed in this diff