Browse Source

Merge remote-tracking branch 'refs/remotes/kamailio/master'

Kevin Scott Adams 9 years ago
parent
commit
890b37ff24

+ 29 - 0
lib/kcore/strcommon.c

@@ -373,3 +373,32 @@ int escape_param(str *sin, str *sout)
     return 0;
     return 0;
 }
 }
 
 
+/*! \brief
+ * escapes a string to use as a CSV field, as specified in RFC4180:
+ * - enclose sting in double quotes
+ * - escape double quotes with a second double quote
+ */
+int escape_csv(str *sin, str *sout)
+{
+    char *at, *p;
+
+    if (sin==NULL || sout==NULL || sin->s==NULL || sout->s==NULL ||
+        sin->len<0 || sout->len < 2*sin->len+3)
+        return -1;
+
+    at = sout->s;
+    p  = sin->s;
+    *at++ = '"';
+    while (p < sin->s+sin->len) {
+		if(*p == '"') {
+			*at++ = '"';
+		}
+        *at++ = *p++;
+    }
+    *at++ = '"';
+    *at = 0;
+    sout->len = at - sout->s;
+    LM_DBG("escaped string is <%s>\n", sout->s);
+
+    return 0;
+}

+ 2 - 0
lib/kcore/strcommon.h

@@ -46,5 +46,7 @@ int escape_param(str *sin, str *sout);
 
 
 int unescape_param(str *sin, str *sout);
 int unescape_param(str *sin, str *sout);
 
 
+int escape_csv(str *sin, str *sout);
+
 #endif
 #endif
 
 

+ 14 - 1
main.c

@@ -833,7 +833,20 @@ void sig_usr(int signo)
 					_exit(0);
 					_exit(0);
 					break;
 					break;
 			case SIGUSR1:
 			case SIGUSR1:
-				/* statistics, do nothing, printed only from the main proc */
+#ifdef PKG_MALLOC
+					cfg_update_no_cbs();
+					memlog=cfg_get(core, core_cfg, memlog);
+					if (memlog <= cfg_get(core, core_cfg, debug)){
+						if (cfg_get(core, core_cfg, mem_summary) & 1) {
+							LOG(memlog, "Memory status (pkg):\n");
+							pkg_status();
+						}
+						if (cfg_get(core, core_cfg, mem_summary) & 2) {
+							LOG(memlog, "Memory still-in-use summary (pkg):\n");
+							pkg_sums();
+						}
+					}
+#endif
 					break;
 					break;
 				/* ignored*/
 				/* ignored*/
 			case SIGUSR2:
 			case SIGUSR2:

+ 20 - 4
modules/dialog/dlg_cseq.c

@@ -193,6 +193,8 @@ error:
 int dlg_cseq_refresh(sip_msg_t *msg, dlg_cell_t *dlg,
 int dlg_cseq_refresh(sip_msg_t *msg, dlg_cell_t *dlg,
 		unsigned int direction)
 		unsigned int direction)
 {
 {
+	unsigned int ninc = 0;
+	unsigned int vinc = 0;
 	str nval;
 	str nval;
 	str *pval;
 	str *pval;
 
 
@@ -225,7 +227,19 @@ int dlg_cseq_refresh(sip_msg_t *msg, dlg_cell_t *dlg,
 		goto done;
 		goto done;
 	}
 	}
 
 
-	nval = *pval;
+	if(str2int(pval, &vinc)<0) {
+		LM_ERR("invalid dlg cseq diff var value: %.*s\n",
+					pval->len, pval->s);
+		goto done;
+	}
+	if(vinc==0) {
+		LM_DBG("nothing to increment\n");
+		goto done;
+	}
+
+	str2int(&get_cseq(msg)->number, &ninc);
+	vinc += ninc;
+	nval.s = int2str(vinc, &nval.len);
 	trim(&nval);
 	trim(&nval);
 
 
 	LM_DBG("adding cseq refresh header value: %.*s\n", nval.len, nval.s);
 	LM_DBG("adding cseq refresh header value: %.*s\n", nval.len, nval.s);
@@ -291,9 +305,9 @@ int dlg_cseq_msg_received(void *data)
 	}
 	}
 	LM_DBG("via cseq cookie [%.*s] val [%.*s]\n", vcseq.len, vcseq.s,
 	LM_DBG("via cseq cookie [%.*s] val [%.*s]\n", vcseq.len, vcseq.s,
 			vcseq.len-3, vcseq.s+3);
 			vcseq.len-3, vcseq.s+3);
-	if(vcseq.len-3<get_cseq(&msg)->number.len) {
+	if(vcseq.len-3>get_cseq(&msg)->number.len) {
 		/* higher lenght to update - wrong */
 		/* higher lenght to update - wrong */
-		LM_DBG("cseq in message (%d) longer than in via (%d)\n",
+		LM_DBG("cseq in message (%d) shorter than in via (%d)\n",
 				get_cseq(&msg)->number.len, vcseq.len-3);
 				get_cseq(&msg)->number.len, vcseq.len-3);
 		goto done;
 		goto done;
 	}
 	}
@@ -369,9 +383,10 @@ int dlg_cseq_msg_sent(void *data)
 		goto done;
 		goto done;
 	}
 	}
 
 
+	parse_headers(&msg, HDR_EOH_F, 0);
+
 	/* check if transaction is marked for a new increment */
 	/* check if transaction is marked for a new increment */
 	if(get_cseq(&msg)->method_id!=METHOD_ACK) {
 	if(get_cseq(&msg)->method_id!=METHOD_ACK) {
-		parse_headers(&msg, HDR_EOH_F, 0);
 		hfk = sr_hdr_get_z(&msg, "P-K-Auth-CSeq");
 		hfk = sr_hdr_get_z(&msg, "P-K-Auth-CSeq");
 		if(hfk!=NULL) {
 		if(hfk!=NULL) {
 			LM_DBG("new cseq inc requested\n");
 			LM_DBG("new cseq inc requested\n");
@@ -391,6 +406,7 @@ int dlg_cseq_msg_sent(void *data)
 		}
 		}
 	}
 	}
 	if(nval.len<=0) {
 	if(nval.len<=0) {
+		LM_DBG("cseq refresh requested, but no new value found\n");
 		goto done;
 		goto done;
 	}
 	}
 
 

+ 2 - 1
modules/dispatcher/dispatcher.c

@@ -596,7 +596,8 @@ static void destroy(void)
 	ds_hash_load_destroy();
 	ds_hash_load_destroy();
 	if(ds_ping_reply_codes)
 	if(ds_ping_reply_codes)
 		shm_free(ds_ping_reply_codes);
 		shm_free(ds_ping_reply_codes);
-
+	if(ds_ping_reply_codes_cnt)
+		shm_free(ds_ping_reply_codes_cnt);
 }
 }
 
 
 #define GET_VALUE(param_name,param,i_value,s_value,value_flags) do{ \
 #define GET_VALUE(param_name,param,i_value,s_value,value_flags) do{ \

+ 13 - 8
modules/http_async_client/http_async_client_mod.c

@@ -54,6 +54,7 @@
 #include "../../modules/tm/tm_load.h"
 #include "../../modules/tm/tm_load.h"
 #include "../../modules/pv/pv_api.h"
 #include "../../modules/pv/pv_api.h"
 
 
+
 #include "async_http.h"
 #include "async_http.h"
 
 
 MODULE_VERSION
 MODULE_VERSION
@@ -227,6 +228,18 @@ struct module_exports exports = {
 };
 };
 
 
 
 
+int mod_register(char *path, int *dlflags, void *p1, void *p2)
+{
+	pv_register_api_t pvra;
+
+	pvra = (pv_register_api_t)find_export("pv_register_api", NO_SCRIPT, 0);
+	if (!pvra) {
+		LM_ERR("Cannot import pv functions (pv module must be loaded before this module)\n");
+		return -1;
+	}
+	pvra(&pv_api);
+	return 0;
+}
 
 
 /**
 /**
  * init module function
  * init module function
@@ -234,7 +247,6 @@ struct module_exports exports = {
 static int mod_init(void)
 static int mod_init(void)
 {
 {
 	unsigned int n;
 	unsigned int n;
-	pv_register_api_t pvra;
 	LM_INFO("Initializing Http Async module\n");
 	LM_INFO("Initializing Http Async module\n");
 
 
 #ifdef STATISTICS
 #ifdef STATISTICS
@@ -295,13 +307,6 @@ static int mod_init(void)
 		memset(&tmb, 0, sizeof(tm_api_t));
 		memset(&tmb, 0, sizeof(tm_api_t));
 	}
 	}
 
 
-	pvra = (pv_register_api_t)find_export("pv_register_api", NO_SCRIPT, 0);
-	if (!pvra) {
-		LM_ERR("Cannot import pv functions (pv module must be loaded before this module)\n");
-		return -1;
-	}
-	pvra(&pv_api);
-
 	/* allocate workers array */
 	/* allocate workers array */
 	workers = shm_malloc(num_workers * sizeof(*workers));
 	workers = shm_malloc(num_workers * sizeof(*workers));
 	if(workers == NULL) {
 	if(workers == NULL) {

+ 146 - 48
modules/ipops/README

@@ -32,14 +32,17 @@ Iñaki Baz Castillo
               4.4. is_ipv6 (ip)
               4.4. is_ipv6 (ip)
               4.5. is_ipv6_reference (ip)
               4.5. is_ipv6_reference (ip)
               4.6. ip_type (ip)
               4.6. ip_type (ip)
-              4.7. compare_ips (ip1, ip2)
-              4.8. compare_pure_ips (ip1, ip2)
-              4.9. is_ip_rfc1918 (ip)
-              4.10. is_in_subnet (ip, subnets_list)
-              4.11. dns_sys_match_ip(hostname, ipaddr)
-              4.12. dns_int_match_ip(hostname, ipaddr)
-              4.13. dns_query(hostname, pvid)
-              4.14. srv_query(srvcname, pvid)
+              4.7. detailed_ip_type (ip, result)
+              4.8. detailed_ipv4_type (ip, result)
+              4.9. detailed_ipv6_type (ip, result)
+              4.10. compare_ips (ip1, ip2)
+              4.11. compare_pure_ips (ip1, ip2)
+              4.12. is_ip_rfc1918 (ip)
+              4.13. is_in_subnet (ip, subnets_list)
+              4.14. dns_sys_match_ip(hostname, ipaddr)
+              4.15. dns_int_match_ip(hostname, ipaddr)
+              4.16. dns_query(hostname, pvid)
+              4.17. srv_query(srvcname, pvid)
 
 
    List of Examples
    List of Examples
 
 
@@ -49,14 +52,17 @@ Iñaki Baz Castillo
    1.4. is_ipv6 usage
    1.4. is_ipv6 usage
    1.5. is_ipv6_reference usage
    1.5. is_ipv6_reference usage
    1.6. ip_type usage
    1.6. ip_type usage
-   1.7. compare_ips usage
-   1.8. compare_pure_ips usage
-   1.9. is_ip_rfc1918 usage
-   1.10. is_in_subnet usage
-   1.11. dns_sys_match_ip usage
-   1.12. dns_int_match_ip usage
-   1.13. dns_query usage
-   1.14. srv_query usage
+   1.7. detailed_ip_type usage
+   1.8. detailed_ipv4_type usage
+   1.9. detailed_ipv6_type usage
+   1.10. compare_ips usage
+   1.11. compare_pure_ips usage
+   1.12. is_ip_rfc1918 usage
+   1.13. is_in_subnet usage
+   1.14. dns_sys_match_ip usage
+   1.15. dns_int_match_ip usage
+   1.16. dns_query usage
+   1.17. srv_query usage
 
 
 Chapter 1. Admin Guide
 Chapter 1. Admin Guide
 
 
@@ -77,14 +83,17 @@ Chapter 1. Admin Guide
         4.4. is_ipv6 (ip)
         4.4. is_ipv6 (ip)
         4.5. is_ipv6_reference (ip)
         4.5. is_ipv6_reference (ip)
         4.6. ip_type (ip)
         4.6. ip_type (ip)
-        4.7. compare_ips (ip1, ip2)
-        4.8. compare_pure_ips (ip1, ip2)
-        4.9. is_ip_rfc1918 (ip)
-        4.10. is_in_subnet (ip, subnets_list)
-        4.11. dns_sys_match_ip(hostname, ipaddr)
-        4.12. dns_int_match_ip(hostname, ipaddr)
-        4.13. dns_query(hostname, pvid)
-        4.14. srv_query(srvcname, pvid)
+        4.7. detailed_ip_type (ip, result)
+        4.8. detailed_ipv4_type (ip, result)
+        4.9. detailed_ipv6_type (ip, result)
+        4.10. compare_ips (ip1, ip2)
+        4.11. compare_pure_ips (ip1, ip2)
+        4.12. is_ip_rfc1918 (ip)
+        4.13. is_in_subnet (ip, subnets_list)
+        4.14. dns_sys_match_ip(hostname, ipaddr)
+        4.15. dns_int_match_ip(hostname, ipaddr)
+        4.16. dns_query(hostname, pvid)
+        4.17. srv_query(srvcname, pvid)
 
 
 1. Overview
 1. Overview
 
 
@@ -132,14 +141,17 @@ Chapter 1. Admin Guide
    4.4. is_ipv6 (ip)
    4.4. is_ipv6 (ip)
    4.5. is_ipv6_reference (ip)
    4.5. is_ipv6_reference (ip)
    4.6. ip_type (ip)
    4.6. ip_type (ip)
-   4.7. compare_ips (ip1, ip2)
-   4.8. compare_pure_ips (ip1, ip2)
-   4.9. is_ip_rfc1918 (ip)
-   4.10. is_in_subnet (ip, subnets_list)
-   4.11. dns_sys_match_ip(hostname, ipaddr)
-   4.12. dns_int_match_ip(hostname, ipaddr)
-   4.13. dns_query(hostname, pvid)
-   4.14. srv_query(srvcname, pvid)
+   4.7. detailed_ip_type (ip, result)
+   4.8. detailed_ipv4_type (ip, result)
+   4.9. detailed_ipv6_type (ip, result)
+   4.10. compare_ips (ip1, ip2)
+   4.11. compare_pure_ips (ip1, ip2)
+   4.12. is_ip_rfc1918 (ip)
+   4.13. is_in_subnet (ip, subnets_list)
+   4.14. dns_sys_match_ip(hostname, ipaddr)
+   4.15. dns_int_match_ip(hostname, ipaddr)
+   4.16. dns_query(hostname, pvid)
+   4.17. srv_query(srvcname, pvid)
 
 
 4.1.  is_ip (ip)
 4.1.  is_ip (ip)
 
 
@@ -265,7 +277,93 @@ switch($rc) {
 }
 }
 ...
 ...
 
 
-4.7.  compare_ips (ip1, ip2)
+4.7.  detailed_ip_type (ip, result)
+
+   Returns the detailed type of the given IP () (see
+   http://www.iana.org/assignments/ipv6-address-space/ipv6-address-space.t
+   xt,
+   http://www.iana.org/assignments/iana-ipv6-special-registry/iana-ipv6-sp
+   ecial-registry.txt, RFC 5735 and RFC 6598: PRIVATE, SHARED, LOOPBACK,
+   IPV4MAP, DISCARD etc).
+
+   Parameters:
+     * ip - String or pseudo-variable containing the IP to evaluate.
+     * result - String or pseudo-variable containing the detailed type of
+       the IP.
+          + IPv4 - PUBLIC, RIVATE, SHARED, LOOPBACK, LINK-LOCAL, RESERVED,
+            TEST-NET, 6TO4-RELAY, MULTICAST, BROADCAST
+          + IPv6 - UNSPECIFIED, LOOPBACK, IPV4MAP, RESERVED, DISCARD,
+            GLOBAL-UNICAST, TEREDO, BMWG, DOCUMENTATION, ORCHID, 6TO4,
+            UNIQUE-LOCAL-UNICAST, LINK-LOCAL-UNICAST, MULTICAST
+
+   Return value:
+     * 1 - successful operation
+     * negative value - error occured
+
+   This function can be used from ALL ROUTES
+
+   Example 1.7.  detailed_ip_type usage
+...
+    detailed_ip_type("192.168.1.2","$var(result)");
+    xlog("L_ERR","IP address is of detailed type: $var(result) ");
+...
+
+4.8.  detailed_ipv4_type (ip, result)
+
+   Returns the detailed type of the given IP () (see RFC 5735 and RFC
+   6598).
+
+   Parameters:
+     * ip - String or pseudo-variable containing the IP to evaluate.
+     * result - String or pseudo-variable containing the detailed type of
+       the IP.
+          + IPv4 - PUBLIC, PRIVATE, SHARED, LOOPBACK, LINK-LOCAL,
+            RESERVED, TEST-NET, 6TO4-RELAY, MULTICAST, BROADCAST
+
+   Return value:
+     * 1 - successful operation
+     * negative value - error occured
+
+   This function can be used from ALL ROUTES
+
+   Example 1.8.  detailed_ipv4_type usage
+...
+    detailed_ipv4_type("192.168.1.2","$var(result)");
+    xlog("L_ERR","IP address is of detailed type: $var(result) ");
+...
+
+4.9.  detailed_ipv6_type (ip, result)
+
+   Returns the detailed type of the given IP () (see
+   http://www.iana.org/assignments/ipv6-address-space/ipv6-address-space.t
+   xt,
+   http://www.iana.org/assignments/iana-ipv6-special-registry/iana-ipv6-sp
+   ecial-registry.txt).
+
+   Parameters:
+     * ip - String or pseudo-variable containing the IP to evaluate.
+     * result - String or pseudo-variable containing the detailed type of
+       the IP.
+          + IPv6 - UNSPECIFIED, LOOPBACK, IPV4MAP, RESERVED, DISCARD,
+            GLOBAL-UNICAST, TEREDO, BMWG, DOCUMENTATION, ORCHID, 6TO4,
+            UNIQUE-LOCAL-UNICAST, LINK-LOCAL-UNICAST, MULTICAST
+
+   Return value:
+     * 1 - successful operation
+     * negative value - error occured
+
+   This function can be used from ALL ROUTES
+
+   Example 1.9.  detailed_ipv6_type usage
+...
+    detailed_ipv6_type("2001:8d8:7c0:402:217:72:194:30","$var(result)");
+    xlog("L_ERR","IP address is of detailed type: $var(result) ");
+
+    detailed_ipv6_type("[2001:8d8:7c0:402:217:72:194:30]","$var(result)");
+    xlog("L_ERR","IP address is of detailed type: $var(result) ");
+...
+
+4.10.  compare_ips (ip1, ip2)
 
 
    Returns TRUE if both IP addresses are the same. FALSE otherwise. This
    Returns TRUE if both IP addresses are the same. FALSE otherwise. This
    function also allows comparing an IPv6 address against an IPv6
    function also allows comparing an IPv6 address against an IPv6
@@ -279,7 +377,7 @@ switch($rc) {
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
    ONREPLY_ROUTE, BRANCH_ROUTE and LOCAL_ROUTE.
    ONREPLY_ROUTE, BRANCH_ROUTE and LOCAL_ROUTE.
 
 
-   Example 1.7.  compare_ips usage
+   Example 1.10.  compare_ips usage
 ...
 ...
 if (compare_ips("1080:0000:0000:0000:0008:0800:200C:417A", "[1080::8:800:200C:41
 if (compare_ips("1080:0000:0000:0000:0008:0800:200C:417A", "[1080::8:800:200C:41
 7A]")) {
 7A]")) {
@@ -287,7 +385,7 @@ if (compare_ips("1080:0000:0000:0000:0008:0800:200C:417A", "[1080::8:800:200C:41
 }
 }
 ...
 ...
 
 
-4.8.  compare_pure_ips (ip1, ip2)
+4.11.  compare_pure_ips (ip1, ip2)
 
 
    Returns TRUE if both IP's are the same. FALSE otherwise. This function
    Returns TRUE if both IP's are the same. FALSE otherwise. This function
    does NOT allow comparing an IPv6 against an IPv6 reference.
    does NOT allow comparing an IPv6 against an IPv6 reference.
@@ -301,14 +399,14 @@ if (compare_ips("1080:0000:0000:0000:0008:0800:200C:417A", "[1080::8:800:200C:41
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
    ONREPLY_ROUTE, BRANCH_ROUTE and LOCAL_ROUTE.
    ONREPLY_ROUTE, BRANCH_ROUTE and LOCAL_ROUTE.
 
 
-   Example 1.8.  compare_pure_ips usage
+   Example 1.11.  compare_pure_ips usage
 ...
 ...
 if (compare_pure_ips($si, "1080::8:800:200C:417A")) {
 if (compare_pure_ips($si, "1080::8:800:200C:417A")) {
   xlog("L_INFO", "both are the same IP\n");
   xlog("L_INFO", "both are the same IP\n");
 }
 }
 ...
 ...
 
 
-4.9.  is_ip_rfc1918 (ip)
+4.12.  is_ip_rfc1918 (ip)
 
 
    Returns TRUE if the argument is a private IPv4 according to RFC 1918.
    Returns TRUE if the argument is a private IPv4 according to RFC 1918.
    FALSE otherwise.
    FALSE otherwise.
@@ -319,14 +417,14 @@ if (compare_pure_ips($si, "1080::8:800:200C:417A")) {
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
    ONREPLY_ROUTE, BRANCH_ROUTE and LOCAL_ROUTE.
    ONREPLY_ROUTE, BRANCH_ROUTE and LOCAL_ROUTE.
 
 
-   Example 1.9.  is_ip_rfc1918 usage
+   Example 1.12.  is_ip_rfc1918 usage
 ...
 ...
 if (is_ip_rfc1918("10.0.123.123")) {
 if (is_ip_rfc1918("10.0.123.123")) {
   xlog("L_INFO", "it's a private IPv4\n");
   xlog("L_INFO", "it's a private IPv4\n");
 }
 }
 ...
 ...
 
 
-4.10.  is_in_subnet (ip, subnets_list)
+4.13.  is_in_subnet (ip, subnets_list)
 
 
    Returns TRUE if the first argument is an IP address within the (CIDR
    Returns TRUE if the first argument is an IP address within the (CIDR
    notation) subnets list in the second argument. FALSE otherwise.
    notation) subnets list in the second argument. FALSE otherwise.
@@ -339,7 +437,7 @@ if (is_ip_rfc1918("10.0.123.123")) {
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
    ONREPLY_ROUTE, BRANCH_ROUTE and LOCAL_ROUTE.
    ONREPLY_ROUTE, BRANCH_ROUTE and LOCAL_ROUTE.
 
 
-   Example 1.10.  is_in_subnet usage
+   Example 1.13.  is_in_subnet usage
 ...
 ...
 if (is_in_subnet("10.0.123.123", "10.0.123.1/24")) {
 if (is_in_subnet("10.0.123.123", "10.0.123.1/24")) {
   xlog("L_INFO", "it's in the subnet\n");
   xlog("L_INFO", "it's in the subnet\n");
@@ -350,7 +448,7 @@ if (is_in_subnet("10.0.123.123", "10.0.0.0/16,192.168.0.0/24")) {
 }
 }
 ...
 ...
 
 
-4.11.  dns_sys_match_ip(hostname, ipaddr)
+4.14.  dns_sys_match_ip(hostname, ipaddr)
 
 
    Returns TRUE if ipaddr is associated by DNS to hostname. FALSE
    Returns TRUE if ipaddr is associated by DNS to hostname. FALSE
    otherwise. It does not use the internal DNS resolver, but directly
    otherwise. It does not use the internal DNS resolver, but directly
@@ -366,14 +464,14 @@ if (is_in_subnet("10.0.123.123", "10.0.0.0/16,192.168.0.0/24")) {
 
 
    This function can be used from ANY_ROUTE.
    This function can be used from ANY_ROUTE.
 
 
-   Example 1.11.  dns_sys_match_ip usage
+   Example 1.14.  dns_sys_match_ip usage
 ...
 ...
 if (!dns_sys_match_ip("myhost.com", "1.2.3.4")) {
 if (!dns_sys_match_ip("myhost.com", "1.2.3.4")) {
     xdbg("ip address not associated with hostname\n");
     xdbg("ip address not associated with hostname\n");
 }
 }
 ...
 ...
 
 
-4.12.  dns_int_match_ip(hostname, ipaddr)
+4.15.  dns_int_match_ip(hostname, ipaddr)
 
 
    Returns TRUE if ipaddr is associated by DNS to hostname. FALSE
    Returns TRUE if ipaddr is associated by DNS to hostname. FALSE
    otherwise. It uses internal DNS resolver. At this moment, the function
    otherwise. It uses internal DNS resolver. At this moment, the function
@@ -390,14 +488,14 @@ if (!dns_sys_match_ip("myhost.com", "1.2.3.4")) {
 
 
    This function can be used from ANY_ROUTE.
    This function can be used from ANY_ROUTE.
 
 
-   Example 1.12.  dns_int_match_ip usage
+   Example 1.15.  dns_int_match_ip usage
 ...
 ...
 if (!dns_int_match_ip("myhost.com", "1.2.3.4")) {
 if (!dns_int_match_ip("myhost.com", "1.2.3.4")) {
     xdbg("ip address not associated with hostname\n");
     xdbg("ip address not associated with hostname\n");
 }
 }
 ...
 ...
 
 
-4.13.  dns_query(hostname, pvid)
+4.16.  dns_query(hostname, pvid)
 
 
    Store the IP addresses and their type that correspond to hostname in a
    Store the IP addresses and their type that correspond to hostname in a
    config variable $dns(pvid=>key).
    config variable $dns(pvid=>key).
@@ -409,7 +507,7 @@ if (!dns_int_match_ip("myhost.com", "1.2.3.4")) {
 
 
    This function can be used from ANY_ROUTE.
    This function can be used from ANY_ROUTE.
 
 
-   Example 1.13.  dns_query usage
+   Example 1.16.  dns_query usage
 ...
 ...
 if(dns_query("test.com", "xyz"))
 if(dns_query("test.com", "xyz"))
 {
 {
@@ -425,7 +523,7 @@ if(dns_query("test.com", "xyz"))
 }
 }
 ...
 ...
 
 
-4.14.  srv_query(srvcname, pvid)
+4.17.  srv_query(srvcname, pvid)
 
 
    Queries DNS SRV records to resolve a service/protocol name into a list
    Queries DNS SRV records to resolve a service/protocol name into a list
    of priorities, weights, ports, and targets sorted by priority and
    of priorities, weights, ports, and targets sorted by priority and
@@ -451,7 +549,7 @@ if(dns_query("test.com", "xyz"))
      * target [index] - target host name
      * target [index] - target host name
      * weight [index] - weight number as defined by RFC 2782
      * weight [index] - weight number as defined by RFC 2782
 
 
-   Example 1.14.  srv_query usage
+   Example 1.17.  srv_query usage
 ...
 ...
 if (srv_query ("_sip._udp.example.com", "udp") > 0) {
 if (srv_query ("_sip._udp.example.com", "udp") > 0) {
   $var(cnt) = $srvquery(udp=>count);
   $var(cnt) = $srvquery(udp=>count);

+ 177 - 0
modules/ipops/detailed_ip_type.c

@@ -0,0 +1,177 @@
+/*
+ * $Id$
+ *
+ * Functions that operate on IP addresses
+ *
+ * Copyright (C) 2012 Hugh Waite (crocodile-rcs.com)
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <arpa/inet.h>
+#include <string.h>
+#include <unistd.h>
+#include "../../dprint.h"
+#include "../../trim.h"
+#include "../../str.h"
+#include "detailed_ip_type.h"
+
+static ip4_node IPv4ranges[IPv4RANGES_SIZE] = {
+        { 0xffffffff,  "BROADCAST",  0xffffffff },  // 255.255.255.255/32
+        { 0xcb007100,  "TEST-NET",   0xffffff00 },  // 203.0.113/24
+        { 0xc6336400,  "TEST-NET",   0xffffff00 },  // 198.51.100/24
+        { 0xc0586300,  "6TO4-RELAY", 0xffffff00 },  // 192.88.99.0/24
+        { 0xc0000200,  "TEST-NET",   0xffffff00 },  // 192.0.2/24
+        { 0xc0000000,  "RESERVED",   0xffffff00 },  // 192.0.0/24
+        { 0xc0a80000,  "PRIVATE",    0xffff0000 },  // 192.168/16
+        { 0xa9fe0000,  "LINK-LOCAL", 0xffff0000 },  // 169.254/16
+        { 0xc6120000,  "RESERVED",   0xfffe0000 },  // 198.18/15
+        { 0xac100000,  "PRIVATE",    0xfffe0000 },  // 172.16/12
+        { 0x64400000,  "SHARED",     0xffc00000 },  // 100.64/10
+        { 0x7f000000,  "LOOPBACK",   0xff000000 },  // 127.0/8
+        { 0x0a000000,  "PRIVATE",    0xff000000 },  // 10/8
+        { 0x0,         "PRIVATE",    0xff000000 },  // 0/8
+        { 0xf0000000,  "RESERVED",   0xf0000000 },  // 240/4
+        { 0xe0000000,  "MULTICAST",  0xf0000000 }   // 224/4
+};
+
+static  ip6_node IPv6ranges[IPv6RANGES_SIZE] = {
+    { {0x00000000, 0x00000000, 0x00000000, 0x00000000} , "UNSPECIFIED",         {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF} },  //::/128
+    { {0x00000000, 0x00000000, 0x00000000, 0x00000001} , "LOOPBACK",            {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF} },  //::1/128
+    { {0x00000000, 0x00000000, 0x0000FFFF, 0x00000000} , "IPV4MAP",             {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000} },  //::FFFF:0:0/96
+    { {0x01000000, 0x00000000, 0x00000000, 0x00000000} , "DISCARD",             {0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000} },  //0100::/64
+    { {0x20010002, 0x00000000, 0x00000000, 0x00000000} , "BMWG",                {0xFFFFFFFF, 0xFFFF0000, 0x00000000, 0x00000000} },  //2001:0002::/48
+    { {0x20010000, 0x00000000, 0x00000000, 0x00000000} , "TEREDO",              {0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000} },  //2001::/32
+    { {0x20010DB8, 0x00000000, 0x00000000, 0x00000000} , "DOCUMENTATION",       {0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000} },  //2001:DB8::/32
+    { {0x20010010, 0x00000000, 0x00000000, 0x00000000} , "ORCHID",              {0xFFFFFFF0, 0x00000000, 0x00000000, 0x00000000} },  //2001:10::/28
+    { {0x20020000, 0x00000000, 0x00000000, 0x00000000} , "6TO4",                {0xFFFF0000, 0x00000000, 0x00000000, 0x00000000} },  //2002::/16
+    { {0xFEC00000, 0x00000000, 0x00000000, 0x00000000} , "RESERVED",            {0xFFC00000, 0x00000000, 0x00000000, 0x00000000} },  //FEC0::/10
+    { {0xFE800000, 0x00000000, 0x00000000, 0x00000000} , "LINK-LOCAL-UNICAST",  {0xFFc00000, 0x00000000, 0x00000000, 0x00000000} },  //FE80::/10
+    { {0xFE000000, 0x00000000, 0x00000000, 0x00000000} , "RESERVED",            {0xFF800000, 0x00000000, 0x00000000, 0x00000000} },  //FE00::/9
+    { {0x00000000, 0x00000000, 0x00000000, 0x00000000} , "RESERVED",            {0xFF000000, 0x00000000, 0x00000000, 0x00000000} },  //::/8
+    { {0x01000000, 0x00000000, 0x00000000, 0x00000000} , "RESERVED",            {0xFF000000, 0x00000000, 0x00000000, 0x00000000} },  //0100::/8
+    { {0xFF000000, 0x00000000, 0x00000000, 0x00000000} , "MULTICAST",           {0xFF000000, 0x00000000, 0x00000000, 0x00000000} },  //FF00::/8
+    { {0x02000000, 0x00000000, 0x00000000, 0x00000000} , "RESERVED",            {0xFE000000, 0x00000000, 0x00000000, 0x00000000} },  //0200::/7
+    { {0xFC000000, 0x00000000, 0x00000000, 0x00000000} , "UNIQUE-LOCAL-UNICAST",{0xFE000000, 0x00000000, 0x00000000, 0x00000000} },  //FC00::/7
+    { {0x04000000, 0x00000000, 0x00000000, 0x00000000} , "RESERVED",            {0xFC000000, 0x00000000, 0x00000000, 0x00000000} },  //400::/6
+    { {0xF8000000, 0x00000000, 0x00000000, 0x00000000} , "RESERVED",            {0xFC000000, 0x00000000, 0x00000000, 0x00000000} },  //F800::/6
+    { {0x08000000, 0x00000000, 0x00000000, 0x00000000} , "RESERVED",            {0xF8000000, 0x00000000, 0x00000000, 0x00000000} },  //0800::/5
+    { {0xF0000000, 0x00000000, 0x00000000, 0x00000000} , "RESERVED",            {0xF8000000, 0x00000000, 0x00000000, 0x00000000} },  //F000::/5
+    { {0xE0000000, 0x00000000, 0x00000000, 0x00000000} , "RESERVED",            {0xF0000000, 0x00000000, 0x00000000, 0x00000000} },  //E000::/4
+    { {0x10000000, 0x00000000, 0x00000000, 0x00000000} , "RESERVED",            {0xF0000000, 0x00000000, 0x00000000, 0x00000000} },  //1000::/4
+    { {0xC0000000, 0x00000000, 0x00000000, 0x00000000} , "RESERVED",            {0xE0000000, 0x00000000, 0x00000000, 0x00000000} },  //C000::/3
+    { {0x20000000, 0x00000000, 0x00000000, 0x00000000} , "GLOBAL-UNICAST",      {0xE0000000, 0x00000000, 0x00000000, 0x00000000} },  //2000::/3
+    { {0x40000000, 0x00000000, 0x00000000, 0x00000000} , "RESERVED",            {0xE0000000, 0x00000000, 0x00000000, 0x00000000} },  //4000::/3
+    { {0x60000000, 0x00000000, 0x00000000, 0x00000000} , "RESERVED",            {0xE0000000, 0x00000000, 0x00000000, 0x00000000} },  //6000::/3
+    { {0x80000000, 0x00000000, 0x00000000, 0x00000000} , "RESERVED",            {0xE0000000, 0x00000000, 0x00000000, 0x00000000} },  //8000::/3
+    { {0xA0000000, 0x00000000, 0x00000000, 0x00000000} , "RESERVED",            {0xE0000000, 0x00000000, 0x00000000, 0x00000000} }   //A000::/3
+
+};
+
+
+int ip6_iptype(str string_ip, char **res)
+{
+  uint32_t in6_addr[4];
+  char in6_string[INET6_ADDRSTRLEN];
+  int i;
+
+  trim(&string_ip);
+  if (string_ip.len >= INET6_ADDRSTRLEN)
+        return 0;
+
+  memcpy(in6_string, string_ip.s, string_ip.len);
+  in6_string[string_ip.len] = '\0';
+
+  if (inet_pton(AF_INET6, in6_string, in6_addr) != 1)  return 0;
+
+  for (i = 0; i < IPv6RANGES_SIZE; i++) {
+      if (((in6_addr[0] & IPv6ranges[i].sub_mask[0]) == IPv6ranges[i].value[0]) &&
+          ((in6_addr[1] & IPv6ranges[i].sub_mask[1]) == IPv6ranges[i].value[1]) &&
+          ((in6_addr[2] & IPv6ranges[i].sub_mask[2]) == IPv6ranges[i].value[2]) &&
+          ((in6_addr[3] & IPv6ranges[i].sub_mask[3]) == IPv6ranges[i].value[3])) {
+          *res = IPv6ranges[i].ip_type;
+          return 1;
+      }
+  }
+  /* the ip must be in the interval, else there is some problem */
+  return 0;
+}
+
+int ip4_iptype(str string_ip, char **res)
+{
+  uint32_t in4_addr;
+  char in4_string[INET_ADDRSTRLEN];
+  int i;
+
+  trim(&string_ip);
+  if (string_ip.len >= INET_ADDRSTRLEN)
+      return 0;
+
+  memcpy(in4_string, string_ip.s, string_ip.len);
+  in4_string[string_ip.len] = '\0';
+
+  if (inet_pton(AF_INET, in4_string, &in4_addr) != 1)  return 0;
+
+  *res = "PUBLIC";
+  for (i = 0; i < IPv4RANGES_SIZE; i++) {
+      if ( (in4_addr & IPv4ranges[i].sub_mask) == IPv4ranges[i].value ) {
+          *res = IPv4ranges[i].ip_type;
+          return 1;
+      }
+  }
+  return 1;
+}
+
+void ipv4ranges_hton() {
+    int pos;
+    uint32_t tmp;
+
+    for (pos=0; pos < IPv4RANGES_SIZE; pos++) {
+        tmp = IPv4ranges[pos].value;
+        IPv4ranges[pos].value = ntohl(tmp);
+        tmp = IPv4ranges[pos].sub_mask;
+        IPv4ranges[pos].sub_mask = ntohl(tmp);
+    }
+}
+
+void ipv6ranges_hton() {
+    int pos;
+    uint32_t tmp;
+
+    for (pos=0; pos < IPv6RANGES_SIZE; pos++) {
+        tmp = IPv6ranges[pos].value[0];
+        IPv6ranges[pos].value[0] = ntohl(tmp);
+        tmp = IPv6ranges[pos].value[1];
+        IPv6ranges[pos].value[1] = ntohl(tmp);
+        tmp = IPv6ranges[pos].value[2];
+        IPv6ranges[pos].value[2] = ntohl(tmp);
+        tmp = IPv6ranges[pos].value[3];
+        IPv6ranges[pos].value[3] = ntohl(tmp);
+
+        tmp = IPv6ranges[pos].sub_mask[0];
+        IPv6ranges[pos].sub_mask[0] = ntohl(tmp);
+        tmp = IPv6ranges[pos].sub_mask[1];
+        IPv6ranges[pos].sub_mask[1] = ntohl(tmp);
+        tmp = IPv6ranges[pos].sub_mask[2];
+        IPv6ranges[pos].sub_mask[2] = ntohl(tmp);
+        tmp = IPv6ranges[pos].sub_mask[3];
+        IPv6ranges[pos].sub_mask[3] = ntohl(tmp);
+    }
+}

+ 53 - 0
modules/ipops/detailed_ip_type.h

@@ -0,0 +1,53 @@
+/*
+ * $Id$
+ *
+ * Functions that operate on IP addresses
+ *
+ * Copyright (C) 2012 Hugh Waite (crocodile-rcs.com)
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+
+#ifndef _IPOPS_DETAILED_IP_TYPE_H
+#define _IPOPS_DETAILED_IP_TYPE_H
+
+#define IPv4RANGES_SIZE 16
+#define IPv6RANGES_SIZE 29
+
+#include <stdint.h>
+#include "../../str.h"
+
+typedef struct ip4_node {
+    uint32_t value;
+    char *ip_type;
+    uint32_t sub_mask;
+} ip4_node;
+
+typedef struct ip6_node {
+    uint32_t value[4];
+    char *ip_type;
+    uint32_t sub_mask[4];
+} ip6_node;
+
+void ipv6ranges_hton();
+void ipv4ranges_hton();
+int ip6_iptype(str string_ip, char **res);
+int ip4_iptype(str string_ip, char **res);
+
+#endif

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

@@ -359,6 +359,205 @@ switch($rc) {
 
 
     </section>
     </section>
 
 
+    <section id="ipops.f.detailed_ip_type">
+      <title>
+        <function moreinfo="none">detailed_ip_type (ip, result)</function>
+      </title>
+
+      <para>
+        Returns the detailed type of the given IP () (see http://www.iana.org/assignments/ipv6-address-space/ipv6-address-space.txt, http://www.iana.org/assignments/iana-ipv6-special-registry/iana-ipv6-special-registry.txt, RFC 5735 and RFC 6598: PRIVATE, SHARED, LOOPBACK, IPV4MAP, DISCARD etc).
+      </para>
+
+      <para>Parameters:</para>
+
+      <itemizedlist>
+        <listitem>
+          <para>
+            <emphasis>ip</emphasis> - String or pseudo-variable containing the IP to evaluate.
+          </para>
+	</listitem>
+        <listitem> 
+   	  <para>
+            <emphasis>result</emphasis> - String or pseudo-variable containing the detailed type of the IP.
+          </para>
+          <para>
+            <itemizedlist>
+              <listitem>  
+		<emphasis> IPv4 </emphasis> - PUBLIC, RIVATE, SHARED, LOOPBACK, LINK-LOCAL, RESERVED, TEST-NET, 6TO4-RELAY, MULTICAST, BROADCAST     
+ 	      </listitem>
+	      <listitem>  
+		<emphasis> IPv6 </emphasis> - UNSPECIFIED,  LOOPBACK, IPV4MAP, RESERVED, DISCARD, GLOBAL-UNICAST, TEREDO, BMWG, DOCUMENTATION, ORCHID, 6TO4, UNIQUE-LOCAL-UNICAST, LINK-LOCAL-UNICAST, MULTICAST     
+ 	      </listitem>              
+  	    </itemizedlist>		
+	  </para>	
+        </listitem>
+      </itemizedlist>
+
+      <para>Return value:</para>
+
+      <itemizedlist>
+        <listitem>
+          <para>
+            <emphasis>1</emphasis> - successful operation
+          </para>
+        </listitem>
+        <listitem>
+          <para>
+            <emphasis>negative value</emphasis> - error occured
+          </para>
+        </listitem>       
+      </itemizedlist>
+
+      <para>
+        This function can be used from ALL ROUTES
+      </para>
+
+      <example>
+        <title>
+          <function>detailed_ip_type</function> usage
+        </title>
+        <programlisting format="linespecific">
+...
+    detailed_ip_type("192.168.1.2","$var(result)");
+    xlog("L_ERR","IP address is of detailed type: $var(result) ");
+...
+        </programlisting>
+      </example>
+
+    </section>
+
+    <section id="ipops.f.detailed_ipv4_type">
+      <title>
+        <function moreinfo="none">detailed_ipv4_type (ip, result)</function>
+      </title>
+
+      <para>
+        Returns the detailed type of the given IP () (see RFC 5735 and RFC 6598).
+      </para>
+
+      <para>Parameters:</para>
+
+      <itemizedlist>
+        <listitem>
+          <para>
+            <emphasis>ip</emphasis> - String or pseudo-variable containing the IP to evaluate.
+          </para>
+	</listitem>
+        <listitem> 
+   	  <para>
+            <emphasis>result</emphasis> - String or pseudo-variable containing the detailed type of the IP.
+          </para>
+          <para>
+            <itemizedlist>
+              <listitem>  
+		<emphasis> IPv4 </emphasis> - PUBLIC, PRIVATE, SHARED, LOOPBACK, LINK-LOCAL, RESERVED, TEST-NET, 6TO4-RELAY, MULTICAST, BROADCAST     
+ 	      </listitem>	                 
+  	    </itemizedlist>		
+	  </para>	
+        </listitem>
+      </itemizedlist>
+
+      <para>Return value:</para>
+
+      <itemizedlist>
+        <listitem>
+          <para>
+            <emphasis>1</emphasis> - successful operation
+          </para>
+        </listitem>
+        <listitem>
+          <para>
+            <emphasis>negative value</emphasis> - error occured
+          </para>
+        </listitem>       
+      </itemizedlist>
+
+      <para>
+        This function can be used from ALL ROUTES
+      </para>
+
+      <example>
+        <title>
+          <function>detailed_ipv4_type</function> usage
+        </title>
+        <programlisting format="linespecific">
+...
+    detailed_ipv4_type("192.168.1.2","$var(result)");
+    xlog("L_ERR","IP address is of detailed type: $var(result) ");
+...
+        </programlisting>
+      </example>
+
+    </section>	
+
+    <section id="ipops.f.detailed_ipv6_type">
+      <title>
+        <function moreinfo="none">detailed_ipv6_type (ip, result)</function>
+      </title>
+
+      <para>
+        Returns the detailed type of the given IP () (see http://www.iana.org/assignments/ipv6-address-space/ipv6-address-space.txt, http://www.iana.org/assignments/iana-ipv6-special-registry/iana-ipv6-special-registry.txt).
+      </para>
+
+      <para>Parameters:</para>
+
+      <itemizedlist>
+        <listitem>
+          <para>
+            <emphasis>ip</emphasis> - String or pseudo-variable containing the IP to evaluate.
+          </para>
+	</listitem>
+        <listitem> 
+   	  <para>
+            <emphasis>result</emphasis> - String or pseudo-variable containing the detailed type of the IP.
+          </para>
+          <para>
+            <itemizedlist>
+              <listitem>  
+		<emphasis> IPv6 </emphasis> - UNSPECIFIED,  LOOPBACK, IPV4MAP, RESERVED, DISCARD, GLOBAL-UNICAST, TEREDO, BMWG, DOCUMENTATION, ORCHID, 6TO4, UNIQUE-LOCAL-UNICAST, LINK-LOCAL-UNICAST, MULTICAST    
+ 	      </listitem>	                 
+  	    </itemizedlist>		
+	  </para>	
+        </listitem>
+      </itemizedlist>
+
+      <para>Return value:</para>
+
+      <itemizedlist>
+        <listitem>
+          <para>
+            <emphasis>1</emphasis> - successful operation
+          </para>
+        </listitem>
+        <listitem>
+          <para>
+            <emphasis>negative value</emphasis> - error occured
+          </para>
+        </listitem>       
+      </itemizedlist>
+
+      <para>
+        This function can be used from ALL ROUTES
+      </para>
+
+      <example>
+        <title>
+          <function>detailed_ipv6_type</function> usage
+        </title>
+        <programlisting format="linespecific">
+...
+    detailed_ipv6_type("2001:8d8:7c0:402:217:72:194:30","$var(result)");
+    xlog("L_ERR","IP address is of detailed type: $var(result) ");
+
+    detailed_ipv6_type("[2001:8d8:7c0:402:217:72:194:30]","$var(result)");
+    xlog("L_ERR","IP address is of detailed type: $var(result) ");	
+...
+        </programlisting>
+      </example>
+
+    </section>	
+
+
     <section id="ipops.f.compare_ips">
     <section id="ipops.f.compare_ips">
       <title>
       <title>
         <function moreinfo="none">compare_ips (ip1, ip2)</function>
         <function moreinfo="none">compare_ips (ip1, ip2)</function>

+ 134 - 2
modules/ipops/ipops_mod.c

@@ -51,10 +51,12 @@
 #include "../../mod_fix.h"
 #include "../../mod_fix.h"
 #include "../../pvar.h"
 #include "../../pvar.h"
 #include "../../resolve.h"
 #include "../../resolve.h"
+#include "../../lvalue.h"
 #include "api.h"
 #include "api.h"
 #include "ipops_pv.h"
 #include "ipops_pv.h"
 #include "ip_parser.h"
 #include "ip_parser.h"
 #include "rfc1918_parser.h"
 #include "rfc1918_parser.h"
+#include "detailed_ip_type.h"
 
 
 MODULE_VERSION
 MODULE_VERSION
 
 
@@ -80,6 +82,7 @@ int _ip_is_in_subnet_v4(struct in_addr *ip, char *net, size_t netlen, int netmas
 int _ip_is_in_subnet_v6(struct in6_addr *ip, char *net, size_t netlen, int netmask);
 int _ip_is_in_subnet_v6(struct in6_addr *ip, char *net, size_t netlen, int netmask);
 int _ip_is_in_subnet_str(void *ip, enum enum_ip_type type, char *s, int slen);
 int _ip_is_in_subnet_str(void *ip, enum enum_ip_type type, char *s, int slen);
 int _ip_is_in_subnet_str_trimmed(void *ip, enum enum_ip_type type, char *b, char *e);
 int _ip_is_in_subnet_str_trimmed(void *ip, enum enum_ip_type type, char *b, char *e);
+static int _detailed_ip_type(unsigned int _type, struct sip_msg* _msg, char* _s,  char *_dst);
 
 
 
 
 /*
 /*
@@ -91,15 +94,20 @@ static int w_is_ipv4(struct sip_msg*, char*);
 static int w_is_ipv6(struct sip_msg*, char*);
 static int w_is_ipv6(struct sip_msg*, char*);
 static int w_is_ipv6_reference(struct sip_msg*, char*);
 static int w_is_ipv6_reference(struct sip_msg*, char*);
 static int w_ip_type(struct sip_msg*, char*);
 static int w_ip_type(struct sip_msg*, char*);
+static int w_detailed_ipv6_type(struct sip_msg* _msg, char* _s,  char *res);
+static int w_detailed_ipv4_type(struct sip_msg* _msg, char* _s,  char *res);
+static int w_detailed_ip_type(struct sip_msg* _msg, char* _s,  char *res);
 static int w_compare_ips(struct sip_msg*, char*, char*);
 static int w_compare_ips(struct sip_msg*, char*, char*);
 static int w_compare_pure_ips(struct sip_msg*, char*, char*);
 static int w_compare_pure_ips(struct sip_msg*, char*, char*);
 static int w_is_ip_rfc1918(struct sip_msg*, char*);
 static int w_is_ip_rfc1918(struct sip_msg*, char*);
 static int w_ip_is_in_subnet(struct sip_msg*, char*, char*);
 static int w_ip_is_in_subnet(struct sip_msg*, char*, char*);
 static int w_dns_sys_match_ip(sip_msg_t*, char*, char*);
 static int w_dns_sys_match_ip(sip_msg_t*, char*, char*);
 static int w_dns_int_match_ip(sip_msg_t*, char*, char*);
 static int w_dns_int_match_ip(sip_msg_t*, char*, char*);
-
+static int fixup_detailed_ip_type(void** param, int param_no);
+static int fixup_free_detailed_ip_type(void** param, int param_no);
 static int w_dns_query(struct sip_msg* msg, char* str1, char* str2);
 static int w_dns_query(struct sip_msg* msg, char* str1, char* str2);
 static int w_srv_query(struct sip_msg* msg, char* str1, char* str2);
 static int w_srv_query(struct sip_msg* msg, char* str1, char* str2);
+static int mod_init(void);
 
 
 static pv_export_t mod_pvs[] = {
 static pv_export_t mod_pvs[] = {
 	{ {"dns", sizeof("dns")-1}, PVT_OTHER, pv_get_dns, 0,
 	{ {"dns", sizeof("dns")-1}, PVT_OTHER, pv_get_dns, 0,
@@ -128,6 +136,12 @@ static cmd_export_t cmds[] =
 		REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE },
 		REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE },
 	{ "ip_type", (cmd_function)w_ip_type, 1, fixup_spve_null, 0,
 	{ "ip_type", (cmd_function)w_ip_type, 1, fixup_spve_null, 0,
 		REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE },
 		REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE },
+	{ "detailed_ipv4_type", (cmd_function)w_detailed_ipv4_type, 2,
+		fixup_detailed_ip_type, fixup_free_detailed_ip_type, ANY_ROUTE },
+	{ "detailed_ipv6_type", (cmd_function)w_detailed_ipv6_type, 2,
+		fixup_detailed_ip_type, fixup_free_detailed_ip_type, ANY_ROUTE },
+	{ "detailed_ip_type", (cmd_function)w_detailed_ip_type, 2,
+		fixup_detailed_ip_type, fixup_free_detailed_ip_type, ANY_ROUTE },
 	{ "compare_ips", (cmd_function)w_compare_ips, 2, fixup_spve_spve, 0,
 	{ "compare_ips", (cmd_function)w_compare_ips, 2, fixup_spve_spve, 0,
 		REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE },
 		REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE },
 	{ "compare_pure_ips", (cmd_function)w_compare_pure_ips, 2, fixup_spve_spve, 0,
 	{ "compare_pure_ips", (cmd_function)w_compare_pure_ips, 2, fixup_spve_spve, 0,
@@ -161,13 +175,64 @@ struct module_exports exports = {
 	0,                         /*!< exported MI functions */
 	0,                         /*!< exported MI functions */
 	mod_pvs,                   /*!< exported pseudo-variables */
 	mod_pvs,                   /*!< exported pseudo-variables */
 	0,                         /*!< extra processes */
 	0,                         /*!< extra processes */
-	0,                         /*!< module initialization function */
+	mod_init,                  /*!< module initialization function */
 	(response_function) 0,     /*!< response handling function */
 	(response_function) 0,     /*!< response handling function */
 	0,                         /*!< destroy function */
 	0,                         /*!< destroy function */
 	0                          /*!< per-child init function */
 	0                          /*!< per-child init function */
 };
 };
 
 
 
 
+static int mod_init(void) {
+    /* turn detailed_ip_type relevant structures to netowork byte order so no need to
+     * transform each ip to host order before comparing */
+    ipv4ranges_hton();
+    ipv6ranges_hton();
+    return 0;
+}
+
+
+/* Fixup functions */
+
+/*
+ * Fix detailed_ipv6_type param: result (writable pvar).
+ */
+static int fixup_detailed_ip_type(void** param, int param_no)
+{
+    if (param_no == 1) {
+        return fixup_spve_null(param, 1);
+    }
+
+    if (param_no == 2) {
+        if (fixup_pvar_null(param, 1) != 0) {
+            LM_ERR("failed to fixup result pvar\n");
+            return -1;
+        }
+        if (((pv_spec_t *) (*param))->setf == NULL) {
+            LM_ERR("result pvar is not writeble\n");
+            return -1;
+        }
+        return 0;
+    }
+
+    LM_ERR("invalid parameter number <%d>\n", param_no);
+    return -1;
+}
+
+static int fixup_free_detailed_ip_type(void** param, int param_no)
+{
+    if (param_no == 1) {
+    //LM_WARN("free function has not been defined for spve\n");
+    return 0;
+    }
+
+    if (param_no == 2) {
+    return fixup_free_pvar_null(param, 1);
+    }
+
+    LM_ERR("invalid parameter number <%d>\n", param_no);
+    return -1;
+}
+
 /*
 /*
  * Module internal functions
  * Module internal functions
  */
  */
@@ -577,6 +642,73 @@ static int w_ip_type(struct sip_msg* _msg, char* _s)
 	}
 	}
 }
 }
 
 
+static int w_detailed_ipv4_type(struct sip_msg* _msg, char* _s,  char *_dst)
+{
+    return _detailed_ip_type(ip_type_ipv4, _msg, _s, _dst);
+}
+
+static int w_detailed_ipv6_type(struct sip_msg* _msg, char* _s,  char *_dst)
+{
+    return _detailed_ip_type(ip_type_ipv6, _msg, _s, _dst);
+}
+
+static int w_detailed_ip_type(struct sip_msg* _msg, char* _s,  char *_dst)
+{
+    /* `ip_type_error` should read `unknown type` */
+    return _detailed_ip_type(ip_type_error, _msg, _s, _dst);
+}
+
+static int _detailed_ip_type(unsigned int _type, struct sip_msg* _msg, char* _s,  char *_dst)
+{
+  str string;
+  pv_spec_t *dst;
+  pv_value_t val;
+  char *res;
+  unsigned int assumed_type;
+
+  if (_s == NULL) {
+    LM_ERR("bad parameter\n");
+    return -2;
+  }
+
+  if (fixup_get_svalue(_msg, (gparam_p)_s, &string))
+  {
+    LM_ERR("cannot print the format for string\n");
+    return -3;
+  }
+
+  assumed_type = (ip_type_error == _type)? ip_parser_execute(string.s, string.len) : _type;
+
+  switch (assumed_type) {
+      case ip_type_ipv4:
+          if (!ip4_iptype(string, &res)) {
+              LM_ERR("bad ip parameter\n");
+              return -1;
+          }
+          break;
+      case ip_type_ipv6_reference:
+      case ip_type_ipv6:
+          /* consider this reference */
+          if (string.s[0] == '[') {
+              string.s++;
+              string.len -= 2;
+          }
+          if (!ip6_iptype(string, &res)) {
+              LM_ERR("bad ip parameter\n");
+              return -1;
+          }
+          break;
+      default:
+          return -1;
+  }
+
+  val.rs.s = res;
+  val.rs.len = strlen(res);
+  val.flags = PV_VAL_STR;
+  dst = (pv_spec_t *)_dst;
+  dst->setf(_msg, &dst->pvp, (int)EQ_T, &val);
+  return 1;
+}
 
 
 /*! \brief Return true if both IP's (string or pv) are equal. This function also allows comparing an IPv6 with an IPv6 reference. */
 /*! \brief Return true if both IP's (string or pv) are equal. This function also allows comparing an IPv6 with an IPv6 reference. */
 static int w_compare_ips(struct sip_msg* _msg, char* _s1, char* _s2)
 static int w_compare_ips(struct sip_msg* _msg, char* _s1, char* _s2)

+ 14 - 7
modules/jansson/Makefile

@@ -1,21 +1,28 @@
 #
 #
 # jansson module makefile
 # jansson module makefile
 #
 #
-# 
+#
 # WARNING: do not run this directly, it should be run by the master Makefile
 # WARNING: do not run this directly, it should be run by the master Makefile
 
 
 include ../../Makefile.defs
 include ../../Makefile.defs
 auto_gen=
 auto_gen=
 NAME=jansson.so
 NAME=jansson.so
 
 
-BUILDER = $(shell which pkg-config)
-ifeq ($(BUILDER),)
-	DEFS+=-I$(LOCALBASE)/include \
-	LIBS+=-L$(SYSBASE)/include/lib -L$(LOCALBASE)/lib -ljansson
+ifeq ($(CROSS_COMPILE),)
+JNS_BUILDER=$(shell \
+	if pkg-config --exists jansson; then \
+		echo 'pkg-config jansson'; \
+	fi)
+endif
+
+ifneq ($(JNS_BUILDER),)
+	DEFS += $(shell $(JNS_BUILDER) --cflags)
+	LIBS += $(shell $(JNS_BUILDER) --libs)
 else
 else
-	DEFS+= $(shell pkg-config --cflags jansson)
-	LIBS+= $(shell pkg-config --libs jansson)
+	DEFS+=-I$(LOCALBASE)/include
+	LIBS+=-L$(SYSBASE)/include/lib -L$(LOCALBASE)/lib -ljansson
 endif
 endif
+
 DEFS+=-DOPENSER_MOD_INTERFACE
 DEFS+=-DOPENSER_MOD_INTERFACE
 
 
 SERLIBPATH=../../lib
 SERLIBPATH=../../lib

+ 3 - 3
modules/jsonrpc-s/jsonrpc-s_mod.c

@@ -571,7 +571,7 @@ static int jsonrpc_scan(jsonrpc_ctx_t* ctx, char* fmt, ...)
 		case '{':
 		case '{':
 		case '[':
 		case '[':
 			LM_ERR("Unsupported param type '%c'\n", *fmt);
 			LM_ERR("Unsupported param type '%c'\n", *fmt);
-			jsonrpc_fault(ctx, 500, "Unsupported param type");
+			jsonrpc_fault(ctx, 400, "Unsupported param type");
 			goto error;
 			goto error;
 		default:
 		default:
 			LM_ERR("Invalid param type in formatting string: [%c]\n", *fmt);
 			LM_ERR("Invalid param type in formatting string: [%c]\n", *fmt);
@@ -1041,7 +1041,7 @@ static int jsonrpc_dispatch(sip_msg_t* msg, char* s1, char* s2)
 	ctx->jreq = srjson_NewDoc(NULL);
 	ctx->jreq = srjson_NewDoc(NULL);
 	if(ctx->jreq==NULL) {
 	if(ctx->jreq==NULL) {
 		LM_ERR("Failed to init the json document\n");
 		LM_ERR("Failed to init the json document\n");
-		return NONSIP_MSG_PASS;
+		return NONSIP_MSG_ERROR;
 	}
 	}
 
 
 	ctx->jreq->buf.s = get_body(msg);
 	ctx->jreq->buf.s = get_body(msg);
@@ -1050,7 +1050,7 @@ static int jsonrpc_dispatch(sip_msg_t* msg, char* s1, char* s2)
 	if(ctx->jreq->root == NULL)
 	if(ctx->jreq->root == NULL)
 	{
 	{
 		LM_ERR("invalid json doc [[%s]]\n", ctx->jreq->buf.s);
 		LM_ERR("invalid json doc [[%s]]\n", ctx->jreq->buf.s);
-		return NONSIP_MSG_PASS;
+		return NONSIP_MSG_ERROR;
 	}
 	}
 	if (jsonrpc_init_reply(ctx) < 0) goto send_reply;
 	if (jsonrpc_init_reply(ctx) < 0) goto send_reply;
 
 

+ 2 - 6
modules/mqueue/mqueue_api.c

@@ -44,7 +44,6 @@ typedef struct _mq_item
 {
 {
 	str key;
 	str key;
 	str val;
 	str val;
-	struct _mq_item *prev;
 	struct _mq_item *next;
 	struct _mq_item *next;
 } mq_item_t;
 } mq_item_t;
 
 
@@ -266,8 +265,6 @@ int mq_head_fetch(str *name)
 	mh->ifirst = mh->ifirst->next;
 	mh->ifirst = mh->ifirst->next;
 	if(mh->ifirst==NULL) {
 	if(mh->ifirst==NULL) {
 		mh->ilast = NULL;
 		mh->ilast = NULL;
-	} else {
-		mh->ifirst->prev = NULL;
 	}
 	}
 	mh->csize--;
 	mh->csize--;
 
 
@@ -332,7 +329,6 @@ int mq_item_add(str *qname, str *key, str *val)
 		mh->ilast = mi;
 		mh->ilast = mi;
 	} else {
 	} else {
 		mh->ilast->next = mi;
 		mh->ilast->next = mi;
-		mi->prev = mh->ilast;
 		mh->ilast = mi;
 		mh->ilast = mi;
 	}
 	}
 	mh->csize++;
 	mh->csize++;
@@ -341,9 +337,9 @@ int mq_item_add(str *qname, str *key, str *val)
 		mi = mh->ifirst;
 		mi = mh->ifirst;
 		mh->ifirst = mh->ifirst->next;
 		mh->ifirst = mh->ifirst->next;
 		if(mh->ifirst==NULL)
 		if(mh->ifirst==NULL)
+		{
 			mh->ilast = NULL;
 			mh->ilast = NULL;
-		else
-			mh->ifirst->prev = NULL;
+		}
 		mh->csize--;
 		mh->csize--;
 		shm_free(mi);
 		shm_free(mi);
 	}
 	}

+ 17 - 17
modules/path/doc/path_admin.xml

@@ -98,7 +98,7 @@
 	<section>
 	<section>
 		<title>External Libraries or Applications</title>
 		<title>External Libraries or Applications</title>
 		<para>
 		<para>
-		The following libraries or applications must be installed before 
+		The following libraries or applications must be installed before
 		running &kamailio; with this module loaded:
 		running &kamailio; with this module loaded:
 			<itemizedlist>
 			<itemizedlist>
 			<listitem>
 			<listitem>
@@ -113,7 +113,7 @@
 
 
 	<section>
 	<section>
 	<title>Parameters</title>
 	<title>Parameters</title>
-	<section>
+	<section id="path.p.use_received">
 		<title><varname>use_received</varname> (int)</title>
 		<title><varname>use_received</varname> (int)</title>
 		<para>
 		<para>
 		If set to 1, the <quote>received</quote> parameter of the first Route &uri; is evaluated and
 		If set to 1, the <quote>received</quote> parameter of the first Route &uri; is evaluated and
@@ -137,12 +137,12 @@ modparam("path", "use_received", 1)
 
 
 	<section>
 	<section>
 	<title>Functions</title>
 	<title>Functions</title>
-	<section>
+	<section id="path.f.add_path">
 		<title>
 		<title>
 		<function moreinfo="none">add_path()</function>
 		<function moreinfo="none">add_path()</function>
 		</title>
 		</title>
 		<para>
 		<para>
-		This function is used to insert a Path header in the form 
+		This function is used to insert a Path header in the form
 		<quote>Path: &lt;sip:1.2.3.4;lr&gt;</quote>, where <quote>1.2.3.4</quote> is the address
 		<quote>Path: &lt;sip:1.2.3.4;lr&gt;</quote>, where <quote>1.2.3.4</quote> is the address
 		of the outgoing interface.
 		of the outgoing interface.
 		</para>
 		</para>
@@ -170,12 +170,12 @@ if (!add_path()) {
 		</example>
 		</example>
 	</section>
 	</section>
 
 
-	<section>
+	<section id="path.f.add_path_u">
 		<title>
 		<title>
 		<function moreinfo="none">add_path(user)</function>
 		<function moreinfo="none">add_path(user)</function>
 		</title>
 		</title>
 		<para>
 		<para>
-		This function adds a Path header in the form 
+		This function adds a Path header in the form
 		<quote>Path: &lt;sip:[email protected];lr&gt;</quote>.
 		<quote>Path: &lt;sip:[email protected];lr&gt;</quote>.
 		</para>
 		</para>
 		<para>Meaning of the parameters is as follows:</para>
 		<para>Meaning of the parameters is as follows:</para>
@@ -203,12 +203,12 @@ if (!add_path("loadbalancer")) {
 		</example>
 		</example>
 	</section>
 	</section>
 
 
-	<section>
+	<section id="path.f.add_path_up">
 		<title>
 		<title>
 		<function moreinfo="none">add_path(user, parameters)</function>
 		<function moreinfo="none">add_path(user, parameters)</function>
 		</title>
 		</title>
 		<para>
 		<para>
-		This function adds a Path header in the form 
+		This function adds a Path header in the form
 		<quote>Path: &lt;sip:[email protected];lr&gt;</quote> and appends the
 		<quote>Path: &lt;sip:[email protected];lr&gt;</quote> and appends the
 		given <emphasis>parameters</emphasis> as additional URI parameters.
 		given <emphasis>parameters</emphasis> as additional URI parameters.
 		</para>
 		</para>
@@ -245,13 +245,13 @@ if (!add_path("loadbalancer", "ob")) {
 		</example>
 		</example>
 	</section>
 	</section>
 
 
-	<section>
+	<section id="path.f.add_path_rcv">
 		<title>
 		<title>
 		<function moreinfo="none">add_path_received()</function>
 		<function moreinfo="none">add_path_received()</function>
 		</title>
 		</title>
 		<para>
 		<para>
-		This function adds a Path header in the form 
-		<quote>Path: &lt;sip:1.2.3.4;received=sip:2.3.4.5:1234;lr&gt;</quote>, setting its own 
+		This function adds a Path header in the form
+		<quote>Path: &lt;sip:1.2.3.4;received=sip:2.3.4.5:1234;lr&gt;</quote>, setting its own
 		outgoing address as domain-part, and the address the request has been received from as
 		outgoing address as domain-part, and the address the request has been received from as
 		received-parameter.
 		received-parameter.
 		</para>
 		</para>
@@ -271,14 +271,14 @@ if (!add_path_received()) {
 		</example>
 		</example>
 	</section>
 	</section>
 
 
-	<section>
+	<section id="path.f.add_path_rcv_u">
 		<title>
 		<title>
 		<function moreinfo="none">add_path_received(user)</function>
 		<function moreinfo="none">add_path_received(user)</function>
 		</title>
 		</title>
 		<para>
 		<para>
-		This function adds a Path header in the form 
+		This function adds a Path header in the form
 		<quote>Path: &lt;sip:[email protected];received=sip:2.3.4.5:1234;lr&gt;</quote>, setting
 		<quote>Path: &lt;sip:[email protected];received=sip:2.3.4.5:1234;lr&gt;</quote>, setting
-		'user' as username part of address, its own 
+		'user' as username part of address, its own
 		outgoing address as domain-part, and the address the request has been received from as
 		outgoing address as domain-part, and the address the request has been received from as
 		received-parameter.
 		received-parameter.
 		</para>
 		</para>
@@ -298,14 +298,14 @@ if (!add_path_received("inbound")) {
 		</example>
 		</example>
 	</section>
 	</section>
 
 
-	<section>
+	<section id="path.f.add_path_rcv_up">
 		<title>
 		<title>
 		<function moreinfo="none">add_path_received(user, parameters)</function>
 		<function moreinfo="none">add_path_received(user, parameters)</function>
 		</title>
 		</title>
 		<para>
 		<para>
-		This function adds a Path header in the form 
+		This function adds a Path header in the form
 		<quote>Path: &lt;sip:[email protected];received=sip:2.3.4.5:1234;lr&gt;</quote>, setting
 		<quote>Path: &lt;sip:[email protected];received=sip:2.3.4.5:1234;lr&gt;</quote>, setting
-		'user' as username part of address, its own 
+		'user' as username part of address, its own
 		outgoing address as domain-part, and the address the request has been received from as
 		outgoing address as domain-part, and the address the request has been received from as
 		received-parameter.
 		received-parameter.
 		</para>
 		</para>

+ 14 - 0
modules/pv/pv_trans.c

@@ -514,6 +514,17 @@ int tr_eval_string(struct sip_msg *msg, tr_param_t *tp, int subtype,
 			val->flags = PV_VAL_STR;
 			val->flags = PV_VAL_STR;
 			val->rs = st;
 			val->rs = st;
 			break;
 			break;
+		case TR_S_ESCAPECSV:
+			if(!(val->flags&PV_VAL_STR))
+				val->rs.s = int2str(val->ri, &val->rs.len);
+			st.s = _tr_buffer;
+			st.len = TR_BUFFER_SIZE;
+			if (escape_csv(&val->rs, &st))
+				return -1;
+			memset(val, 0, sizeof(pv_value_t));
+			val->flags = PV_VAL_STR;
+			val->rs = st;
+			break;
 		case TR_S_SUBSTR:
 		case TR_S_SUBSTR:
 			if(tp==NULL || tp->next==NULL)
 			if(tp==NULL || tp->next==NULL)
 			{
 			{
@@ -2093,6 +2104,9 @@ char* tr_parse_string(str* in, trans_t *t)
 	} else if(name.len==14 && strncasecmp(name.s, "unescape.param", 14)==0) {
 	} else if(name.len==14 && strncasecmp(name.s, "unescape.param", 14)==0) {
 		t->subtype = TR_S_UNESCAPEPARAM;
 		t->subtype = TR_S_UNESCAPEPARAM;
 		goto done;
 		goto done;
+	} else if(name.len==10 && strncasecmp(name.s, "escape.csv", 10)==0) {
+		t->subtype = TR_S_ESCAPECSV;
+		goto done;
 	} else if(name.len==8 && strncasecmp(name.s, "prefixes", 8)==0) {
 	} else if(name.len==8 && strncasecmp(name.s, "prefixes", 8)==0) {
 		t->subtype = TR_S_PREFIXES;
 		t->subtype = TR_S_PREFIXES;
 		if(*p!=TR_PARAM_MARKER)
 		if(*p!=TR_PARAM_MARKER)

+ 1 - 1
modules/pv/pv_trans.h

@@ -40,7 +40,7 @@ enum _tr_s_subtype {
 	TR_S_ESCAPEPARAM, TR_S_UNESCAPEPARAM, TR_S_TOLOWER, TR_S_TOUPPER,
 	TR_S_ESCAPEPARAM, TR_S_UNESCAPEPARAM, TR_S_TOLOWER, TR_S_TOUPPER,
 	TR_S_STRIP, TR_S_STRIPTAIL, TR_S_PREFIXES, TR_S_PREFIXES_QUOT, TR_S_REPLACE,
 	TR_S_STRIP, TR_S_STRIPTAIL, TR_S_PREFIXES, TR_S_PREFIXES_QUOT, TR_S_REPLACE,
 	TR_S_TIMEFORMAT, TR_S_TRIM, TR_S_RTRIM, TR_S_LTRIM, TR_S_RM, TR_S_STRIPTO,
 	TR_S_TIMEFORMAT, TR_S_TRIM, TR_S_RTRIM, TR_S_LTRIM, TR_S_RM, TR_S_STRIPTO,
-	TR_S_URLENCODEPARAM, TR_S_URLDECODEPARAM, TR_S_NUMERIC
+	TR_S_URLENCODEPARAM, TR_S_URLDECODEPARAM, TR_S_NUMERIC, TR_S_ESCAPECSV
 };
 };
 enum _tr_uri_subtype {
 enum _tr_uri_subtype {
 	TR_URI_NONE=0, TR_URI_USER, TR_URI_HOST, TR_URI_PASSWD, TR_URI_PORT,
 	TR_URI_NONE=0, TR_URI_USER, TR_URI_HOST, TR_URI_PASSWD, TR_URI_PORT,

+ 6 - 3
modules/pv/pv_xavp.c

@@ -506,8 +506,10 @@ int pv_parse_xavp_name(pv_spec_p sp, str *in)
 		return -1;
 		return -1;
 
 
 	xname = (pv_xavp_name_t*)pkg_malloc(sizeof(pv_xavp_name_t));
 	xname = (pv_xavp_name_t*)pkg_malloc(sizeof(pv_xavp_name_t));
-	if(xname==NULL)
+	if(xname==NULL) {
+		LM_ERR("not enough pkg mem\n");
 		return -1;
 		return -1;
+	}
 
 
 	memset(xname, 0, sizeof(pv_xavp_name_t));
 	memset(xname, 0, sizeof(pv_xavp_name_t));
 
 
@@ -530,9 +532,10 @@ int pv_parse_xavp_name(pv_spec_p sp, str *in)
 			xname->name.s, s.len, s.s);
 			xname->name.s, s.len, s.s);
 
 
 	xname->next = (pv_xavp_name_t*)pkg_malloc(sizeof(pv_xavp_name_t));
 	xname->next = (pv_xavp_name_t*)pkg_malloc(sizeof(pv_xavp_name_t));
-	if(xname->next==NULL)
+	if(xname->next==NULL) {
+		LM_ERR("not enough pkg mem\n");
 		goto error;
 		goto error;
-
+	}
 	memset(xname->next, 0, sizeof(pv_xavp_name_t));
 	memset(xname->next, 0, sizeof(pv_xavp_name_t));
 
 
 	p = pv_xavp_fill_ni(&s, xname->next);
 	p = pv_xavp_fill_ni(&s, xname->next);

+ 4 - 4
modules/sl/sl_funcs.c

@@ -86,7 +86,7 @@ int sl_startup()
 		LOG(L_ERR,"ERROR:sl_startup: no more free memory!\n");
 		LOG(L_ERR,"ERROR:sl_startup: no more free memory!\n");
 		return -1;
 		return -1;
 	}
 	}
-	*(sl_timeout)=get_ticks();
+	*(sl_timeout)=get_ticks_raw();
 
 
 	return 1;
 	return 1;
 }
 }
@@ -182,6 +182,8 @@ int sl_reply_helper(struct sip_msg *msg, int code, char *reason, str *tag)
 	
 	
 	sl_run_callbacks(SLCB_REPLY_READY, msg, code, reason, &buf, &dst);
 	sl_run_callbacks(SLCB_REPLY_READY, msg, code, reason, &buf, &dst);
 
 
+	*(sl_timeout) = get_ticks_raw() + SL_RPL_WAIT_TIME;
+
 	/* supress multhoming support when sending a reply back -- that makes sure
 	/* supress multhoming support when sending a reply back -- that makes sure
 	   that replies will come from where requests came in; good for NATs
 	   that replies will come from where requests came in; good for NATs
 	   (there is no known use for mhomed for locally generated replies;
 	   (there is no known use for mhomed for locally generated replies;
@@ -286,8 +288,6 @@ event_route_error:
 	if (ret<0) {
 	if (ret<0) {
 		goto error;
 		goto error;
 	}
 	}
-	
-	*(sl_timeout) = get_ticks() + SL_RPL_WAIT_TIME;
 
 
 	update_sl_stats(code);
 	update_sl_stats(code);
 	return 1;
 	return 1;
@@ -383,7 +383,7 @@ int sl_filter_ACK(struct sip_msg *msg, unsigned int flags, void *bar )
 		goto pass_it;
 		goto pass_it;
 
 
 	/*check the timeout value*/
 	/*check the timeout value*/
-	if ( *(sl_timeout)<= get_ticks() )
+	if ( *(sl_timeout)<= get_ticks_raw() )
 	{
 	{
 		DBG("DEBUG : sl_filter_ACK: to late to be a local ACK!\n");
 		DBG("DEBUG : sl_filter_ACK: to late to be a local ACK!\n");
 		goto pass_it;
 		goto pass_it;

+ 2 - 1
modules/sl/sl_funcs.h

@@ -24,8 +24,9 @@
 
 
 #include "../../sr_module.h"
 #include "../../sr_module.h"
 #include "../../parser/msg_parser.h"
 #include "../../parser/msg_parser.h"
+#include "../../timer_ticks.h"
 
 
-#define SL_RPL_WAIT_TIME  2  /* in sec */
+#define SL_RPL_WAIT_TIME  S_TO_TICKS(2)   /* in sec */
 
 
 #define SL_TOTAG_SEPARATOR '.'
 #define SL_TOTAG_SEPARATOR '.'
 
 

+ 4 - 0
modules/tm/t_fwd.c

@@ -1019,6 +1019,10 @@ int add_uac_dns_fallback(struct cell *t, struct sip_msg* msg,
 			/* copy the dns handle into the new uac */
 			/* copy the dns handle into the new uac */
 			dns_srv_handle_cpy(&t->uac[t->nr_of_outgoings].dns_h,
 			dns_srv_handle_cpy(&t->uac[t->nr_of_outgoings].dns_h,
 								&old_uac->dns_h);
 								&old_uac->dns_h);
+			/* copy the onreply and onfailure routes */
+			t->uac[t->nr_of_outgoings].on_failure = old_uac->on_failure;
+			t->uac[t->nr_of_outgoings].on_reply = old_uac->on_reply;
+			t->uac[t->nr_of_outgoings].on_branch_failure = old_uac->on_branch_failure;
 
 
 			if (cfg_get(tm, tm_cfg, reparse_on_dns_failover)){
 			if (cfg_get(tm, tm_cfg, reparse_on_dns_failover)){
 				/* Reuse the old buffer and only replace the via header.
 				/* Reuse the old buffer and only replace the via header.

+ 1 - 0
modules/tm/t_reply.c

@@ -1352,6 +1352,7 @@ static enum rps t_should_relay_response( struct cell *Trans , int new_code,
 
 
 		drop_replies = failure_reply_mode;
 		drop_replies = failure_reply_mode;
 		replies_dropped = 0;
 		replies_dropped = 0;
+		tm_ctx_set_branch_index(picked_branch);
 		/* run ON_FAILURE handlers ( route and callbacks) */
 		/* run ON_FAILURE handlers ( route and callbacks) */
 		if (unlikely(has_tran_tmcbs( Trans, TMCB_ON_FAILURE_RO|TMCB_ON_FAILURE)
 		if (unlikely(has_tran_tmcbs( Trans, TMCB_ON_FAILURE_RO|TMCB_ON_FAILURE)
 						|| Trans->uac[picked_branch].on_failure )) {
 						|| Trans->uac[picked_branch].on_failure )) {

+ 268 - 179
modules/tm/uac.c

@@ -57,6 +57,7 @@
 #include "../../action.h"
 #include "../../action.h"
 #include "../../onsend.h"
 #include "../../onsend.h"
 #include "t_lookup.h"
 #include "t_lookup.h"
+#include "t_fwd.h"
 #endif
 #endif
 
 
 #define FROM_TAG_LEN (MD5_LEN + 1 /* - */ + CRC16_LEN) /* length of FROM tags */
 #define FROM_TAG_LEN (MD5_LEN + 1 /* - */ + CRC16_LEN) /* length of FROM tags */
@@ -190,6 +191,162 @@ error:
 	return -1;
 	return -1;
 }
 }
 
 
+
+#if defined(USE_DNS_FAILOVER) || defined(WITH_EVENT_LOCAL_REQUEST)
+static inline int t_build_msg_from_buf(
+			struct sip_msg *msg, char *buf, int buf_len,
+			uac_req_t *uac_r, struct dest_info *dst)
+{
+	if (unlikely(build_sip_msg_from_buf(msg, buf, buf_len, inc_msg_no()) != 0)) {
+		return -1;
+	}
+	msg->force_send_socket = uac_r->dialog->send_sock;
+	msg->rcv.proto = dst->send_sock->proto;
+	msg->rcv.src_ip = dst->send_sock->address;
+	su2ip_addr(&msg->rcv.dst_ip, &dst->to);
+	msg->rcv.src_port = dst->send_sock->port_no;
+	msg->rcv.dst_port = su_getport(&dst->to);
+	msg->rcv.src_su=dst->send_sock->su;
+	msg->rcv.bind_address=dst->send_sock;
+#ifdef USE_COMP
+	msg->rcv.comp=dst->comp;
+#endif /* USE_COMP */
+
+	return 0;
+}
+
+#ifdef WITH_EVENT_LOCAL_REQUEST
+static inline int t_run_local_req(
+		char **buf, int *buf_len,
+		uac_req_t *uac_r,
+		struct cell *new_cell, struct retr_buf *request)
+{
+	static struct sip_msg lreq;
+	struct onsend_info onsnd_info;
+	tm_xlinks_t backup_xd;
+	int sflag_bk;
+	char *buf1;
+	int buf_len1;
+	int backup_route_type;
+	struct cell *backup_t;
+	int backup_branch;
+	unsigned int backup_msgid;
+	int refresh_shortcuts = 0;
+
+	DBG("executing event_route[tm:local-request]\n");
+	if (unlikely(t_build_msg_from_buf(&lreq, *buf, *buf_len, uac_r, &request->dst))) {
+		return -1;
+	}
+	if (unlikely(set_dst_uri(&lreq, uac_r->dialog->hooks.next_hop))) {
+		LM_ERR("failed to set dst_uri");
+		free_sip_msg(&lreq);
+		return -1;
+	}
+	sflag_bk = getsflags();
+	tm_xdata_swap(new_cell, &backup_xd, 0);
+
+	onsnd_info.to=&request->dst.to;
+	onsnd_info.send_sock=request->dst.send_sock;
+	onsnd_info.buf=*buf;
+	onsnd_info.len=*buf_len;
+	p_onsend=&onsnd_info;
+
+	/* run the route */
+	backup_route_type = get_route_type();
+	set_route_type(LOCAL_ROUTE);
+	/* set T to the current transaction */
+	backup_t=get_t();
+	backup_branch=get_t_branch();
+	backup_msgid=global_msg_id;
+	/* fake transaction and message id */
+	global_msg_id=lreq.id;
+	set_t(new_cell, T_BR_UNDEFINED);
+	run_top_route(event_rt.rlist[goto_on_local_req], &lreq, 0);
+	/* restore original environment */
+	set_t(backup_t, backup_branch);
+	global_msg_id=backup_msgid;
+	set_route_type( backup_route_type );
+	p_onsend=0;
+
+	/* restore original environment */
+	tm_xdata_swap(new_cell, &backup_xd, 1);
+	setsflagsval(sflag_bk);
+
+	/* rebuild the new message content */
+	if(lreq.force_send_socket != uac_r->dialog->send_sock) {
+		LM_DBG("Send socket updated to: %.*s",
+				lreq.force_send_socket->address_str.len,
+				lreq.force_send_socket->address_str.s);
+
+		/* rebuild local Via - remove previous value
+			* and add the one for the new send socket */
+		if (!del_lump(&lreq, lreq.h_via1->name.s - lreq.buf,
+					lreq.h_via1->len, 0)) {
+			LM_ERR("Failed to remove previous local Via\n");
+			/* attempt a normal update to give it a chance */
+			goto normal_update;
+		}
+
+		/* reuse same branch value from previous local Via */
+		memcpy(lreq.add_to_branch_s, lreq.via1->branch->value.s,
+				lreq.via1->branch->value.len);
+		lreq.add_to_branch_len = lreq.via1->branch->value.len;
+
+		/* update also info about new destination and send sock */
+		uac_r->dialog->send_sock=lreq.force_send_socket;
+		request->dst.send_sock = lreq.force_send_socket;
+		request->dst.proto = lreq.force_send_socket->proto;
+
+		LM_DBG("apply new updates with Via to sip msg\n");
+		buf1 = build_req_buf_from_sip_req(&lreq,
+				(unsigned int*)&buf_len1, &request->dst, BUILD_IN_SHM);
+		if (likely(buf1)){
+			shm_free(*buf);
+			*buf = buf1;
+			*buf_len = buf_len1;
+			/* a possible change of the method is not handled! */
+			refresh_shortcuts = 1;
+		}
+
+	} else {
+normal_update:
+		if (unlikely(lreq.add_rm || lreq.body_lumps || lreq.new_uri.s)) {
+			LM_DBG("apply new updates without Via to sip msg\n");
+			buf1 = build_req_buf_from_sip_req(&lreq,
+					(unsigned int*)&buf_len1,
+					&request->dst, BUILD_NO_LOCAL_VIA|BUILD_NO_VIA1_UPDATE|
+					BUILD_IN_SHM);
+			if (likely(buf1)){
+				shm_free(*buf);
+				*buf = buf1;
+				*buf_len = buf_len1;
+				/* a possible change of the method is not handled! */
+				refresh_shortcuts = 1;
+			}
+		}
+	}
+
+	/* clean local msg structure */
+	if (unlikely(lreq.new_uri.s))
+	{
+		pkg_free(lreq.new_uri.s);
+		lreq.new_uri.s=0;
+		lreq.new_uri.len=0;
+	}
+	if (unlikely(lreq.dst_uri.s))
+	{
+		pkg_free(lreq.dst_uri.s);
+		lreq.dst_uri.s=0;
+		lreq.dst_uri.len=0;
+	}
+	lreq.buf=0; /* covers the obsolete DYN_BUF */
+	free_sip_msg(&lreq);
+	return refresh_shortcuts;
+}
+#endif /* WITH_EVENT_LOCAL_REQUEST */
+#endif /* defined(USE_DNS_FAILOVER) || defined(WITH_EVENT_LOCAL_REQUEST) */
+
+
 /* WARNING: - dst_cell contains the created cell, but it is un-referenced
 /* WARNING: - dst_cell contains the created cell, but it is un-referenced
  *            (before using it make sure you REF() it first)
  *            (before using it make sure you REF() it first)
  *          - if  ACK (method==ACK), a cell will be created but it will not
  *          - if  ACK (method==ACK), a cell will be created but it will not
@@ -203,29 +360,20 @@ static inline int t_uac_prepare(uac_req_t *uac_r,
 	struct dest_info dst;
 	struct dest_info dst;
 	struct cell *new_cell;
 	struct cell *new_cell;
 	struct retr_buf *request;
 	struct retr_buf *request;
-	char* buf;
+	char *buf;
 	int buf_len, ret;
 	int buf_len, ret;
 	unsigned int hi;
 	unsigned int hi;
 	int is_ack;
 	int is_ack;
 	ticks_t lifetime;
 	ticks_t lifetime;
-#ifdef USE_DNS_FAILOVER
-	struct dns_srv_handle dns_h;
-#endif
 	long nhtype;
 	long nhtype;
-#ifdef WITH_EVENT_LOCAL_REQUEST
-	struct cell *backup_t;
-	int backup_branch;
-	unsigned int backup_msgid;
-	static struct sip_msg lreq;
-	char *buf1;
-	int buf_len1;
-	int sflag_bk;
-	int backup_route_type;
-#endif
 	snd_flags_t snd_flags;
 	snd_flags_t snd_flags;
 	tm_xlinks_t backup_xd;
 	tm_xlinks_t backup_xd;
 	tm_xdata_t local_xd;
 	tm_xdata_t local_xd;
 	int refresh_shortcuts = 0;
 	int refresh_shortcuts = 0;
+	int sip_msg_len;
+#ifdef USE_DNS_FAILOVER
+	static struct sip_msg lreq;
+#endif /* USE_DNS_FAILOVER */
 
 
 	ret=-1;
 	ret=-1;
 	hi=0; /* make gcc happy */
 	hi=0; /* make gcc happy */
@@ -237,7 +385,7 @@ static inline int t_uac_prepare(uac_req_t *uac_r,
 	 */
 	 */
 	if ((nhtype = w_calculate_hooks(uac_r->dialog)) < 0)
 	if ((nhtype = w_calculate_hooks(uac_r->dialog)) < 0)
 		/* if err's returned, the message is incorrect */
 		/* if err's returned, the message is incorrect */
-		goto error2;
+		goto error3;
 
 
 	if (!uac_r->dialog->loc_seq.is_set) {
 	if (!uac_r->dialog->loc_seq.is_set) {
 		/* this is the first request in the dialog,
 		/* this is the first request in the dialog,
@@ -246,57 +394,40 @@ static inline int t_uac_prepare(uac_req_t *uac_r,
 		uac_r->dialog->loc_seq.is_set = 1;
 		uac_r->dialog->loc_seq.is_set = 1;
 	}
 	}
 
 
+	/* build cell sets X/AVP lists to new transaction structure
+	 * => backup in a tmp struct and restore afterwards */
+	memset(&local_xd, 0, sizeof(tm_xdata_t));
+	tm_xdata_replace(&local_xd, &backup_xd);
+	new_cell = build_cell(0);
+	tm_xdata_replace(0, &backup_xd);
+
+	if (!new_cell) {
+		ret=E_OUT_OF_MEM;
+		LOG(L_ERR, "t_uac: short of cell shmem\n");
+		goto error3;
+	}
+
 	DBG("DEBUG:tm:t_uac: next_hop=<%.*s>\n",uac_r->dialog->hooks.next_hop->len,
 	DBG("DEBUG:tm:t_uac: next_hop=<%.*s>\n",uac_r->dialog->hooks.next_hop->len,
 			uac_r->dialog->hooks.next_hop->s);
 			uac_r->dialog->hooks.next_hop->s);
 	/* new message => take the dialog send_socket if set, or the default
 	/* new message => take the dialog send_socket if set, or the default
 	  send_socket if not*/
 	  send_socket if not*/
 	SND_FLAGS_INIT(&snd_flags);
 	SND_FLAGS_INIT(&snd_flags);
 #ifdef USE_DNS_FAILOVER
 #ifdef USE_DNS_FAILOVER
-	if (cfg_get(core, core_cfg, use_dns_failover)){
-		dns_srv_handle_init(&dns_h);
-		if ((uri2dst2(&dns_h, &dst, uac_r->dialog->send_sock, snd_flags,
-							uac_r->dialog->hooks.next_hop, PROTO_NONE)==0)
+	if ((uri2dst2(cfg_get(core, core_cfg, use_dns_failover) ? &new_cell->uac[0].dns_h : 0,
+			&dst, uac_r->dialog->send_sock, snd_flags,
+			uac_r->dialog->hooks.next_hop, PROTO_NONE)==0)
 				|| (dst.send_sock==0)){
 				|| (dst.send_sock==0)){
-			dns_srv_handle_put(&dns_h);
-			ser_error = E_NO_SOCKET;
-			ret=ser_error;
-			LOG(L_ERR, "t_uac: no socket found\n");
-			goto error2;
-		}
-		dns_srv_handle_put(&dns_h); /* not needed anymore */
-	}else{
-		if ((uri2dst2(0, &dst, uac_r->dialog->send_sock, snd_flags,
-						uac_r->dialog->hooks.next_hop, PROTO_NONE)==0) ||
-				(dst.send_sock==0)){
-			ser_error = E_NO_SOCKET;
-			ret=ser_error;
-			LOG(L_ERR, "t_uac: no socket found\n");
-			goto error2;
-		}
-	}
 #else /* USE_DNS_FAILOVER */
 #else /* USE_DNS_FAILOVER */
 	if ((uri2dst2(&dst, uac_r->dialog->send_sock, snd_flags,
 	if ((uri2dst2(&dst, uac_r->dialog->send_sock, snd_flags,
 					uac_r->dialog->hooks.next_hop, PROTO_NONE)==0) ||
 					uac_r->dialog->hooks.next_hop, PROTO_NONE)==0) ||
 			(dst.send_sock==0)){
 			(dst.send_sock==0)){
+#endif /* USE_DNS_FAILOVER */
 		ser_error = E_NO_SOCKET;
 		ser_error = E_NO_SOCKET;
 		ret=ser_error;
 		ret=ser_error;
 		LOG(L_ERR, "t_uac: no socket found\n");
 		LOG(L_ERR, "t_uac: no socket found\n");
 		goto error2;
 		goto error2;
 	}
 	}
-#endif /* USE_DNS_FAILOVER */
-
-	/* build cell sets X/AVP lists to new transaction structure
-	 * => bakup in a tmp struct and restore afterwards */
-	memset(&local_xd, 0, sizeof(tm_xdata_t));
-	tm_xdata_replace(&local_xd, &backup_xd);
-	new_cell = build_cell(0); 
-	tm_xdata_replace(0, &backup_xd);
 
 
-	if (!new_cell) {
-		ret=E_OUT_OF_MEM;
-		LOG(L_ERR, "t_uac: short of cell shmem\n");
-		goto error2;
-	}
 	if (uac_r->method->len==INVITE_LEN && memcmp(uac_r->method->s, INVITE, INVITE_LEN)==0){
 	if (uac_r->method->len==INVITE_LEN && memcmp(uac_r->method->s, INVITE, INVITE_LEN)==0){
 		new_cell->flags |= T_IS_INVITE_FLAG;
 		new_cell->flags |= T_IS_INVITE_FLAG;
 		new_cell->flags|=T_AUTO_INV_100 &
 		new_cell->flags|=T_AUTO_INV_100 &
@@ -349,131 +480,31 @@ static inline int t_uac_prepare(uac_req_t *uac_r,
 
 
 #ifdef WITH_EVENT_LOCAL_REQUEST
 #ifdef WITH_EVENT_LOCAL_REQUEST
 	if (unlikely(goto_on_local_req>=0)) {
 	if (unlikely(goto_on_local_req>=0)) {
-		DBG("executing event_route[tm:local-request]\n");
-		if(likely(build_sip_msg_from_buf(&lreq, buf, buf_len, inc_msg_no())
-					== 0)) {
-			/* fill some field in sip_msg */
-			if (unlikely(set_dst_uri(&lreq, uac_r->dialog->hooks.next_hop))) {
-				LM_ERR("failed to set dst_uri");
-				free_sip_msg(&lreq);
-			} else {
-				struct onsend_info onsnd_info;
-
-				lreq.force_send_socket = uac_r->dialog->send_sock;
-				lreq.rcv.proto = dst.send_sock->proto;
-				lreq.rcv.src_ip = dst.send_sock->address;
-				lreq.rcv.src_port = dst.send_sock->port_no;
-				lreq.rcv.dst_port = su_getport(&dst.to);
-				su2ip_addr(&lreq.rcv.dst_ip, &dst.to);
-				lreq.rcv.src_su=dst.send_sock->su;
-				lreq.rcv.bind_address=dst.send_sock;
-			#ifdef USE_COMP
-				lreq.rcv.comp=dst.comp;
-			#endif /* USE_COMP */
-				sflag_bk = getsflags();
-				tm_xdata_swap(new_cell, &backup_xd, 0);
-
-				onsnd_info.to=&dst.to;
-				onsnd_info.send_sock=dst.send_sock;
-				onsnd_info.buf=buf;
-				onsnd_info.len=buf_len;
-				p_onsend=&onsnd_info;
-
-				/* run the route */
-				backup_route_type = get_route_type();
-				set_route_type(LOCAL_ROUTE);
-				/* set T to the current transaction */
-				backup_t=get_t();
-				backup_branch=get_t_branch();
-				backup_msgid=global_msg_id;
-				/* fake transaction and message id */
-				global_msg_id=lreq.id;
-				set_t(new_cell, T_BR_UNDEFINED);
-				run_top_route(event_rt.rlist[goto_on_local_req], &lreq, 0);
-				/* restore original environment */
-				set_t(backup_t, backup_branch);
-				global_msg_id=backup_msgid;
-				set_route_type( backup_route_type );
-				p_onsend=0;
-
-				/* restore original environment */
-				tm_xdata_swap(new_cell, &backup_xd, 1);
-				setsflagsval(sflag_bk);
-
-				/* rebuild the new message content */
-				if(lreq.force_send_socket != uac_r->dialog->send_sock) {
-					LM_DBG("Send socket updated to: %.*s",
-							lreq.force_send_socket->address_str.len,
-							lreq.force_send_socket->address_str.s);
-
-					/* rebuild local Via - remove previous value
-					 * and add the one for the new send socket */
-					if (!del_lump(&lreq, lreq.h_via1->name.s - lreq.buf,
-								lreq.h_via1->len, 0)) {
-						LM_ERR("Failed to remove previous local Via\n");
-						/* attempt a normal update to give it a chance */
-						goto normal_update;
-					}
-
-					/* reuse same branch value from previous local Via */
-					memcpy(lreq.add_to_branch_s, lreq.via1->branch->value.s,
-							lreq.via1->branch->value.len);
-					lreq.add_to_branch_len = lreq.via1->branch->value.len;
-
-					/* update also info about new destination and send sock */
-					uac_r->dialog->send_sock=lreq.force_send_socket;
-					request->dst.send_sock = lreq.force_send_socket;
-					request->dst.proto = lreq.force_send_socket->proto;
-
-					LM_DBG("apply new updates with Via to sip msg\n");
-					buf1 = build_req_buf_from_sip_req(&lreq,
-							(unsigned int*)&buf_len1, &dst, BUILD_IN_SHM);
-					if (likely(buf1)){
-						shm_free(buf);
-						buf = buf1;
-						buf_len = buf_len1;
-						/* a possible change of the method is not handled! */
-						refresh_shortcuts = 1;
-					}
-
-				} else {
-normal_update:
-					if (unlikely(lreq.add_rm || lreq.body_lumps
-								|| lreq.new_uri.s)) {
-						LM_DBG("apply new updates without Via to sip msg\n");
-						buf1 = build_req_buf_from_sip_req(&lreq,
-								(unsigned int*)&buf_len1,
-								&dst, BUILD_NO_LOCAL_VIA|BUILD_NO_VIA1_UPDATE|
-								BUILD_IN_SHM);
-						if (likely(buf1)){
-							shm_free(buf);
-							buf = buf1;
-							buf_len = buf_len1;
-							/* a possible change of the method is not handled! */
-							refresh_shortcuts = 1;
-						}
-					}
-				}
+		refresh_shortcuts = t_run_local_req(&buf, &buf_len, uac_r, new_cell, request);
+	}
+#endif
 
 
-				/* clean local msg structure */
-				if (unlikely(lreq.new_uri.s))
-				{
-					pkg_free(lreq.new_uri.s);
-					lreq.new_uri.s=0;
-					lreq.new_uri.len=0;
-				}
-				if (unlikely(lreq.dst_uri.s))
-				{
-					pkg_free(lreq.dst_uri.s);
-					lreq.dst_uri.s=0;
-					lreq.dst_uri.len=0;
-				}
+#ifdef USE_DNS_FAILOVER
+	/* Set the outgoing message as UAS, so the failover code has something to work with */
+	if(cfg_get(core, core_cfg, use_dns_failover)) {
+		if(likely(t_build_msg_from_buf(&lreq, buf, buf_len, uac_r, &dst) == 0)) {
+			if (parse_headers(&lreq, HDR_EOH_F, 0) == -1) {
+				LM_ERR("failed to parse headers on uas for failover\n");
+			} else {
+				new_cell->uas.request = sip_msg_cloner(&lreq, &sip_msg_len);
 				lreq.buf=0; /* covers the obsolete DYN_BUF */
 				lreq.buf=0; /* covers the obsolete DYN_BUF */
 				free_sip_msg(&lreq);
 				free_sip_msg(&lreq);
+				if (!new_cell->uas.request) {
+					LM_ERR("no more shmem\n");
+					goto error1;
+				}
+				new_cell->uas.end_request=((char*)new_cell->uas.request)+sip_msg_len;
 			}
 			}
+		} else {
+			LM_WARN("failed to build uas for failover\n");
 		}
 		}
 	}
 	}
-#endif
+#endif /* USE_DNS_FAILOVER */
 
 
 	new_cell->uac[0].on_reply = new_cell->on_reply;
 	new_cell->uac[0].on_reply = new_cell->on_reply;
 	new_cell->uac[0].on_failure = new_cell->on_failure;
 	new_cell->uac[0].on_failure = new_cell->on_failure;
@@ -518,14 +549,16 @@ normal_update:
 		LOCK_HASH(hi);
 		LOCK_HASH(hi);
 		remove_from_hash_table_unsafe(new_cell);
 		remove_from_hash_table_unsafe(new_cell);
 		UNLOCK_HASH(hi);
 		UNLOCK_HASH(hi);
+	}
+
+error2:
 #ifdef TM_DEL_UNREF
 #ifdef TM_DEL_UNREF
+	if (!is_ack) {
 		UNREF_FREE(new_cell);
 		UNREF_FREE(new_cell);
 	}else
 	}else
-#else
-	}
 #endif
 #endif
 		free_cell(new_cell);
 		free_cell(new_cell);
-error2:
+error3:
 	return ret;
 	return ret;
 }
 }
 
 
@@ -558,23 +591,63 @@ int prepare_req_within(uac_req_t *uac_r,
 	return -1;
 	return -1;
 }
 }
 
 
-static inline void send_prepared_request_impl(struct retr_buf *request, int retransmit)
+static inline int send_prepared_request_impl(struct retr_buf *request, int retransmit, int branch)
 {
 {
+	struct cell *t;
+	struct sip_msg *p_msg;
+	struct ua_client *uac;
+	struct ip_addr ip; /* logging */
+	int ret;
+
+	t = request->my_T;
+	uac = &t->uac[branch];
+	p_msg = t->uas.request;
+
 	if (SEND_BUFFER(request) == -1) {
 	if (SEND_BUFFER(request) == -1) {
 		LOG(L_ERR, "t_uac: Attempt to send to precreated request failed\n");
 		LOG(L_ERR, "t_uac: Attempt to send to precreated request failed\n");
 	}
 	}
-	else if (unlikely(has_tran_tmcbs(request->my_T, TMCB_REQUEST_SENT)))
+	else if (unlikely(has_tran_tmcbs(t, TMCB_REQUEST_SENT)))
 		/* we don't know the method here */
 		/* we don't know the method here */
-			run_trans_callbacks_with_buf(TMCB_REQUEST_SENT, request, 0, 0,
+		run_trans_callbacks_with_buf(TMCB_REQUEST_SENT, &uac->request, 0, 0,
 			TMCB_LOCAL_F);
 			TMCB_LOCAL_F);
-	
-	if (retransmit && (start_retr(request)!=0))
-		LOG(L_CRIT, "BUG: t_uac: failed to start retr. for %p\n", request);
+
+	su2ip_addr(&ip, &uac->request.dst.to);
+	DBG("send_prepared_request_impl: uac: %p  branch: %d  to %s:%d\n",
+			uac, branch, ip_addr2a(&ip), su_getport(&uac->request.dst.to));
+
+	if (run_onsend(p_msg, &uac->request.dst, uac->request.buffer,
+			uac->request.buffer_len)==0){
+		uac->last_received=408;
+		su2ip_addr(&ip, &uac->request.dst.to);
+		DBG("t_uac: onsend_route dropped msg. to %s:%d (%d)\n",
+						ip_addr2a(&ip), su_getport(&uac->request.dst.to),
+						uac->request.dst.proto);
+#ifdef USE_DNS_FAILOVER
+		/* if the destination resolves to more ips, add another
+			*  branch/uac */
+		ret = add_uac_dns_fallback(t, p_msg, uac, retransmit);
+		if (ret > 0) {
+			su2ip_addr(&ip, &uac->request.dst.to);
+			DBG("t_uac: send on branch %d failed "
+					"(onsend_route), trying another ip %s:%d (%d)\n",
+					branch, ip_addr2a(&ip),
+					su_getport(&uac->request.dst.to),
+					uac->request.dst.proto);
+			/* success, return new branch */
+			return ret;
+		}
+#endif /* USE_DNS_FAILOVER*/
+		return -1;
+	}
+
+	if (retransmit && (start_retr(&uac->request)!=0))
+		LOG(L_CRIT, "BUG: t_uac: failed to start retr. for %p\n", &uac->request);
+	return 0;
 }
 }
 
 
 void send_prepared_request(struct retr_buf *request)
 void send_prepared_request(struct retr_buf *request)
 {
 {
-	send_prepared_request_impl(request, 1 /* retransmit */);
+	send_prepared_request_impl(request, 1 /* retransmit */, 0);
 }
 }
 
 
 /*
 /*
@@ -596,11 +669,27 @@ int t_uac_with_ids(uac_req_t *uac_r,
 	struct cell *cell;
 	struct cell *cell;
 	int ret;
 	int ret;
 	int is_ack;
 	int is_ack;
+	int branch_ret;
+	int i;
+	branch_bm_t added_branches = 1;
 
 
 	ret = t_uac_prepare(uac_r, &request, &cell);
 	ret = t_uac_prepare(uac_r, &request, &cell);
 	if (ret < 0) return ret;
 	if (ret < 0) return ret;
 	is_ack = (uac_r->method->len == 3) && (memcmp("ACK", uac_r->method->s, 3)==0) ? 1 : 0;
 	is_ack = (uac_r->method->len == 3) && (memcmp("ACK", uac_r->method->s, 3)==0) ? 1 : 0;
-	send_prepared_request_impl(request, !is_ack /* retransmit */);
+
+	/* equivalent loop to the one in t_forward_nonack */
+	for (i=0; i<cell->nr_of_outgoings; i++) {
+		if (added_branches & (1<<i)) {
+			branch_ret=send_prepared_request_impl(request, !is_ack /* retransmit */, i);
+			if (branch_ret>=0){ /* some kind of success */
+				if (branch_ret>i) {
+					/* new branch added */
+					added_branches |= 1<<branch_ret;
+				}
+			}
+		}
+	}
+
 	if (is_ack) {
 	if (is_ack) {
 		if (cell) free_cell(cell);
 		if (cell) free_cell(cell);
 		if (ret_index && ret_label)
 		if (ret_index && ret_label)

+ 1 - 1
modules/tmx/t_var.c

@@ -396,7 +396,7 @@ int pv_get_tm_branch_idx(struct sip_msg *msg, pv_param_t *param,
 		return -1;
 		return -1;
 
 
 	/* statefull replies have the branch_index set */
 	/* statefull replies have the branch_index set */
-	if(msg->first_line.type == SIP_REPLY && route_type != CORE_ONREPLY_ROUTE) {
+	if(msg->first_line.type == SIP_REPLY) {
 		tcx = _tmx_tmb.tm_ctx_get();
 		tcx = _tmx_tmb.tm_ctx_get();
 		if(tcx != NULL)
 		if(tcx != NULL)
 			idx = tcx->branch_index;
 			idx = tcx->branch_index;

+ 69 - 50
modules/topos/tps_msg.c

@@ -296,6 +296,7 @@ int tps_pack_message(sip_msg_t *msg, tps_data_t *ptsd)
 	int i;
 	int i;
 	int vlen;
 	int vlen;
 	int r2;
 	int r2;
+	int isreq;
 
 
 	if(ptsd->cp==NULL) {
 	if(ptsd->cp==NULL) {
 		ptsd->cp = ptsd->cbuf;
 		ptsd->cp = ptsd->cbuf;
@@ -344,6 +345,7 @@ int tps_pack_message(sip_msg_t *msg, tps_data_t *ptsd)
 	ptsd->s_rr.len = 0;
 	ptsd->s_rr.len = 0;
 	i = 0;
 	i = 0;
 	r2 = 0;
 	r2 = 0;
+	isreq = (msg->first_line.type==SIP_REQUEST)?1:0;
 	for(hdr=msg->record_route; hdr; hdr=next_sibling_hdr(hdr)) {
 	for(hdr=msg->record_route; hdr; hdr=next_sibling_hdr(hdr)) {
 		if (parse_rr(hdr) < 0) {
 		if (parse_rr(hdr) < 0) {
 			LM_ERR("failed to parse RR\n");
 			LM_ERR("failed to parse RR\n");
@@ -356,67 +358,84 @@ int tps_pack_message(sip_msg_t *msg, tps_data_t *ptsd)
 				LM_ERR("no more spage to pack rr headers\n");
 				LM_ERR("no more spage to pack rr headers\n");
 				return -1;
 				return -1;
 			}
 			}
-			if(i>1) {
-				if(i==2 &&r2==0) {
-					ptsd->s_rr.len = ptsd->a_rr.len;
+			if(isreq==1) {
+				/* sip request - get a+s-side record route */
+				if(i>1) {
+					if(i==2 &&r2==0) {
+						ptsd->s_rr.len = ptsd->a_rr.len;
+					}
+					if(i==3 &&r2==1) {
+						ptsd->s_rr.len = ptsd->a_rr.len;
+					}
+					*ptsd->cp = ',';
+					ptsd->cp++;
+					ptsd->a_rr.len++;
 				}
 				}
-				if(i==3 &&r2==1) {
-					ptsd->s_rr.len = ptsd->a_rr.len;
+				*ptsd->cp = '<';
+				if(i==1) {
+					ptsd->a_rr.s = ptsd->cp;
+					ptsd->s_rr.s = ptsd->cp;
 				}
 				}
-				*ptsd->cp = ',';
+				if(i==2 && r2==0) {
+					ptsd->a_rr.s = ptsd->cp;
+					ptsd->a_rr.len = 0;
+				}
+				if(i==3 && r2==1) {
+					ptsd->a_rr.s = ptsd->cp;
+					ptsd->a_rr.len = 0;
+				}
+
 				ptsd->cp++;
 				ptsd->cp++;
 				ptsd->a_rr.len++;
 				ptsd->a_rr.len++;
-			}
-			*ptsd->cp = '<';
-			if(i==1) {
-				ptsd->a_rr.s = ptsd->cp;
-				ptsd->s_rr.s = ptsd->cp;
-			}
-			if(i==2 && r2==0) {
-				ptsd->a_rr.s = ptsd->cp;
-				ptsd->a_rr.len = 0;
-			}
-			if(i==3 && r2==1) {
-				ptsd->a_rr.s = ptsd->cp;
-				ptsd->a_rr.len = 0;
-			}
 
 
-			ptsd->cp++;
-			ptsd->a_rr.len++;
-
-			memcpy(ptsd->cp, rr->nameaddr.uri.s, rr->nameaddr.uri.len);
-			if(i==1) {
-				ptsd->bs_contact.s = ptsd->cp;
-				ptsd->bs_contact.len = rr->nameaddr.uri.len;
-				if(_strnstr(ptsd->bs_contact.s, ";r2=on",
-							ptsd->bs_contact.len)==0) {
-					LM_DBG("single record routing by proxy\n");
-					ptsd->as_contact.s = ptsd->cp;
-					ptsd->as_contact.len = rr->nameaddr.uri.len;
+				memcpy(ptsd->cp, rr->nameaddr.uri.s, rr->nameaddr.uri.len);
+				if(i==1) {
+					ptsd->bs_contact.s = ptsd->cp;
+					ptsd->bs_contact.len = rr->nameaddr.uri.len;
+					if(_strnstr(ptsd->bs_contact.s, ";r2=on",
+								ptsd->bs_contact.len)==0) {
+						LM_DBG("single record routing by proxy\n");
+						ptsd->as_contact.s = ptsd->cp;
+						ptsd->as_contact.len = rr->nameaddr.uri.len;
+					} else {
+						r2 = 1;
+					}
 				} else {
 				} else {
-					r2 = 1;
+					if(i==2 && ptsd->as_contact.len==0) {
+						LM_DBG("double record routing by proxy\n");
+						ptsd->as_contact.s = ptsd->cp;
+						ptsd->as_contact.len = rr->nameaddr.uri.len;
+					}
 				}
 				}
+				ptsd->a_rr.len += rr->nameaddr.uri.len;
+				ptsd->cp += rr->nameaddr.uri.len;
+				*ptsd->cp = '>';
+				ptsd->cp++;
+				ptsd->a_rr.len++;
 			} else {
 			} else {
-				if(i==2 && ptsd->as_contact.len==0) {
-					LM_DBG("double record routing by proxy\n");
-					ptsd->as_contact.s = ptsd->cp;
-					ptsd->as_contact.len = rr->nameaddr.uri.len;
-				}
+				/* sip response - get b-side record route */
+				*ptsd->cp = '<';
+				ptsd->b_rr.s = ptsd->cp;
+				ptsd->cp++;
+				ptsd->b_rr.len++;
+				memcpy(ptsd->cp, rr->nameaddr.uri.s, rr->nameaddr.uri.len);
+				ptsd->cp += rr->nameaddr.uri.len;
+				ptsd->b_rr.len += rr->nameaddr.uri.len;
+				*ptsd->cp = '>';
+				ptsd->cp++;
+				ptsd->b_rr.len++;
 			}
 			}
-			ptsd->a_rr.len += rr->nameaddr.uri.len;
-			ptsd->cp += rr->nameaddr.uri.len;
-			*ptsd->cp = '>';
-			ptsd->cp++;
-			ptsd->a_rr.len++;
 		}
 		}
 	}
 	}
-	if(i==1) {
-		ptsd->s_rr.len = ptsd->a_rr.len;
-		ptsd->a_rr.len = 0;
-	}
-	if(i==2 && r2==1) {
-		ptsd->s_rr.len = ptsd->a_rr.len;
-		ptsd->a_rr.len = 0;
+	if(isreq==1) {
+		if(i==1) {
+			ptsd->s_rr.len = ptsd->a_rr.len;
+			ptsd->a_rr.len = 0;
+		}
+		if(i==2 && r2==1) {
+			ptsd->s_rr.len = ptsd->a_rr.len;
+			ptsd->a_rr.len = 0;
+		}
 	}
 	}
 	LM_DBG("compacted headers - a_rr: [%.*s](%d) - b_rr: [%.*s](%d)"
 	LM_DBG("compacted headers - a_rr: [%.*s](%d) - b_rr: [%.*s](%d)"
 			" - s_rr: [%.*s](%d)\n",
 			" - s_rr: [%.*s](%d)\n",

+ 11 - 7
modules/topos/tps_storage.c

@@ -871,7 +871,7 @@ int tps_storage_load_dialog(sip_msg_t *msg, tps_data_t *md, tps_data_t *sd)
 		return -1;
 		return -1;
 
 
 	if(md->a_uuid.len<=0 && md->b_uuid.len<=0) {
 	if(md->a_uuid.len<=0 && md->b_uuid.len<=0) {
-		LM_ERR("no dlg uuid provided\n");
+		LM_DBG("no dlg uuid provided\n");
 		return -1;
 		return -1;
 	}
 	}
 
 
@@ -1015,6 +1015,7 @@ int tps_storage_update_dialog(sip_msg_t *msg, tps_data_t *md, tps_data_t *sd)
 		return 0;
 		return 0;
 	}
 	}
 
 
+
 	ret = tps_storage_link_msg(msg, md, md->direction);
 	ret = tps_storage_link_msg(msg, md, md->direction);
 	if(ret<0) return -1;
 	if(ret<0) return -1;
 
 
@@ -1044,15 +1045,18 @@ int tps_storage_update_dialog(sip_msg_t *msg, tps_data_t *md, tps_data_t *sd)
 	db_uvals[nr_ucols].val.str_val = TPS_STRZ(md->b_contact);
 	db_uvals[nr_ucols].val.str_val = TPS_STRZ(md->b_contact);
 	nr_ucols++;
 	nr_ucols++;
 
 
-	db_ucols[nr_ucols] = &td_col_b_rr;
-	db_uvals[nr_ucols].type = DB1_STR;
-	db_uvals[nr_ucols].val.str_val = TPS_STRZ(md->b_rr);
-	nr_ucols++;
-
 	if(msg->first_line.type==SIP_REPLY) {
 	if(msg->first_line.type==SIP_REPLY) {
 		if(sd->b_tag.len<=0
 		if(sd->b_tag.len<=0
 				&& msg->first_line.u.reply.statuscode>=200
 				&& msg->first_line.u.reply.statuscode>=200
 				&& msg->first_line.u.reply.statuscode<300) {
 				&& msg->first_line.u.reply.statuscode<300) {
+
+			if((sd->iflags&TPS_IFLAG_DLGON) == 0) {
+				db_ucols[nr_ucols] = &td_col_b_rr;
+				db_uvals[nr_ucols].type = DB1_STR;
+				db_uvals[nr_ucols].val.str_val = TPS_STRZ(md->b_rr);
+				nr_ucols++;
+			}
+
 			db_ucols[nr_ucols] = &td_col_b_tag;
 			db_ucols[nr_ucols] = &td_col_b_tag;
 			db_uvals[nr_ucols].type = DB1_STR;
 			db_uvals[nr_ucols].type = DB1_STR;
 			db_uvals[nr_ucols].val.str_val = TPS_STRZ(md->b_tag);
 			db_uvals[nr_ucols].val.str_val = TPS_STRZ(md->b_tag);
@@ -1060,7 +1064,7 @@ int tps_storage_update_dialog(sip_msg_t *msg, tps_data_t *md, tps_data_t *sd)
 
 
 			db_ucols[nr_ucols] = &td_col_iflags;
 			db_ucols[nr_ucols] = &td_col_iflags;
 			db_uvals[nr_ucols].type = DB1_INT;
 			db_uvals[nr_ucols].type = DB1_INT;
-			db_uvals[nr_ucols].val.int_val = 1;
+			db_uvals[nr_ucols].val.int_val = sd->iflags|TPS_IFLAG_DLGON;
 			nr_ucols++;
 			nr_ucols++;
 		}
 		}
 	}
 	}

+ 3 - 0
modules/topos/tps_storage.h

@@ -34,6 +34,9 @@
 #define TPS_DIR_DOWNSTREAM	0
 #define TPS_DIR_DOWNSTREAM	0
 #define TPS_DIR_UPSTREAM	1
 #define TPS_DIR_UPSTREAM	1
 
 
+#define TPS_IFLAG_INIT	1
+#define TPS_IFLAG_DLGON	2
+
 #define TPS_DATA_SIZE	8192
 #define TPS_DATA_SIZE	8192
 typedef struct tps_data {
 typedef struct tps_data {
 	char cbuf[TPS_DATA_SIZE];
 	char cbuf[TPS_DATA_SIZE];

+ 2 - 2
socket_info.c

@@ -1406,8 +1406,8 @@ static int fix_socket_list(struct socket_info **list, int* type_flags)
 	for (si=*list;si;){
 	for (si=*list;si;){
 		next=si->next;
 		next=si->next;
 		ai_lst=0;
 		ai_lst=0;
-		if (add_interfaces(si->name.s, 0, si->port_no,
-							si->proto, &ai_lst)!=-1){
+		if (add_interfaces(si->name.s, auto_bind_ipv6 ? 0 : AF_INET,
+							si->port_no, si->proto, &ai_lst)!=-1){
 			if (si->flags & SI_IS_MHOMED){
 			if (si->flags & SI_IS_MHOMED){
 				if((new_si=new_sock2list_after(ai_lst->name.s, 0, si->port_no,
 				if((new_si=new_sock2list_after(ai_lst->name.s, 0, si->port_no,
 											si->proto, si->useinfo.name.s,
 											si->proto, si->useinfo.name.s,

+ 21 - 9
tcp_read.c

@@ -1300,7 +1300,7 @@ int tcp_read_req(struct tcp_connection* con, int* bytes_read, int* read_flags)
 	struct dest_info dst;
 	struct dest_info dst;
 	char c;
 	char c;
 	int ret;
 	int ret;
-		
+
 		bytes=-1;
 		bytes=-1;
 		total_bytes=0;
 		total_bytes=0;
 		resp=CONN_RELEASE;
 		resp=CONN_RELEASE;
@@ -1314,6 +1314,15 @@ again:
 			else
 			else
 #endif
 #endif
 				bytes=tcp_read_headers(con, read_flags);
 				bytes=tcp_read_headers(con, read_flags);
+
+			if (unlikely(bytes==-1)){
+				LOG(cfg_get(core, core_cfg, corelog),
+						"ERROR: tcp_read_req: error reading - c: %p r: %p\n",
+						con, req);
+				resp=CONN_ERROR;
+				goto end_req;
+			}
+
 #ifdef EXTRA_DEBUG
 #ifdef EXTRA_DEBUG
 						/* if timeout state=0; goto end__req; */
 						/* if timeout state=0; goto end__req; */
 			LM_DBG("read= %d bytes, parsed=%d, state=%d, error=%d\n",
 			LM_DBG("read= %d bytes, parsed=%d, state=%d, error=%d\n",
@@ -1323,19 +1332,13 @@ again:
 					*(req->parsed-1), (int)(req->parsed-req->start),
 					*(req->parsed-1), (int)(req->parsed-req->start),
 					req->start);
 					req->start);
 #endif
 #endif
-			if (unlikely(bytes==-1)){
-				LOG(cfg_get(core, core_cfg, corelog),
-						"ERROR: tcp_read_req: error reading \n");
-				resp=CONN_ERROR;
-				goto end_req;
-			}
 			total_bytes+=bytes;
 			total_bytes+=bytes;
 			/* eof check:
 			/* eof check:
 			 * is EOF if eof on fd and req.  not complete yet,
 			 * is EOF if eof on fd and req.  not complete yet,
 			 * if req. is complete we might have a second unparsed
 			 * if req. is complete we might have a second unparsed
 			 * request after it, so postpone release_with_eof
 			 * request after it, so postpone release_with_eof
 			 */
 			 */
-			if (unlikely((con->state==S_CONN_EOF) && 
+			if (unlikely((con->state==S_CONN_EOF) &&
 						(! TCP_REQ_COMPLETE(req)))) {
 						(! TCP_REQ_COMPLETE(req)))) {
 				LM_DBG("EOF\n");
 				LM_DBG("EOF\n");
 				resp=CONN_EOF;
 				resp=CONN_EOF;
@@ -1343,10 +1346,19 @@ again:
 			}
 			}
 		}
 		}
 		if (unlikely(req->error!=TCP_REQ_OK)){
 		if (unlikely(req->error!=TCP_REQ_OK)){
-			LM_ERR("bad request, state=%d, error=%d buf:\n%.*s\nparsed:\n%.*s\n",
+			if(req->buf!=NULL && req->start!=NULL && req->pos!=NULL
+					&& req->pos>=req->buf && req->parsed>=req->start) {
+				LM_ERR("bad request, state=%d, error=%d buf:\n%.*s\nparsed:\n%.*s\n",
 					req->state, req->error,
 					req->state, req->error,
 					(int)(req->pos-req->buf), req->buf,
 					(int)(req->pos-req->buf), req->buf,
 					(int)(req->parsed-req->start), req->start);
 					(int)(req->parsed-req->start), req->start);
+			} else {
+				LM_ERR("bad request, state=%d, error=%d buf:%d - %p,"
+						" parsed:%d - %p\n",
+					req->state, req->error,
+					(int)(req->pos-req->buf), req->buf,
+					(int)(req->parsed-req->start), req->start);
+			}
 			LM_DBG("received from: port %d\n", con->rcv.src_port);
 			LM_DBG("received from: port %d\n", con->rcv.src_port);
 			print_ip("received from: ip", &con->rcv.src_ip, "\n");
 			print_ip("received from: ip", &con->rcv.src_ip, "\n");
 			resp=CONN_ERROR;
 			resp=CONN_ERROR;