Browse Source

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

Kevin Scott Adams 9 năm trước cách đây
mục cha
commit
890b37ff24

+ 29 - 0
lib/kcore/strcommon.c

@@ -373,3 +373,32 @@ int escape_param(str *sin, str *sout)
     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 escape_csv(str *sin, str *sout);
+
 #endif
 

+ 14 - 1
main.c

@@ -833,7 +833,20 @@ void sig_usr(int signo)
 					_exit(0);
 					break;
 			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;
 				/* ignored*/
 			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,
 		unsigned int direction)
 {
+	unsigned int ninc = 0;
+	unsigned int vinc = 0;
 	str nval;
 	str *pval;
 
@@ -225,7 +227,19 @@ int dlg_cseq_refresh(sip_msg_t *msg, dlg_cell_t *dlg,
 		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);
 
 	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,
 			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 */
-		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);
 		goto done;
 	}
@@ -369,9 +383,10 @@ int dlg_cseq_msg_sent(void *data)
 		goto done;
 	}
 
+	parse_headers(&msg, HDR_EOH_F, 0);
+
 	/* check if transaction is marked for a new increment */
 	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");
 		if(hfk!=NULL) {
 			LM_DBG("new cseq inc requested\n");
@@ -391,6 +406,7 @@ int dlg_cseq_msg_sent(void *data)
 		}
 	}
 	if(nval.len<=0) {
+		LM_DBG("cseq refresh requested, but no new value found\n");
 		goto done;
 	}
 

+ 2 - 1
modules/dispatcher/dispatcher.c

@@ -596,7 +596,8 @@ static void destroy(void)
 	ds_hash_load_destroy();
 	if(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{ \

+ 13 - 8
modules/http_async_client/http_async_client_mod.c

@@ -54,6 +54,7 @@
 #include "../../modules/tm/tm_load.h"
 #include "../../modules/pv/pv_api.h"
 
+
 #include "async_http.h"
 
 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
@@ -234,7 +247,6 @@ struct module_exports exports = {
 static int mod_init(void)
 {
 	unsigned int n;
-	pv_register_api_t pvra;
 	LM_INFO("Initializing Http Async module\n");
 
 #ifdef STATISTICS
@@ -295,13 +307,6 @@ static int mod_init(void)
 		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 */
 	workers = shm_malloc(num_workers * sizeof(*workers));
 	if(workers == NULL) {

+ 146 - 48
modules/ipops/README

@@ -32,14 +32,17 @@ Iñaki Baz Castillo
               4.4. is_ipv6 (ip)
               4.5. is_ipv6_reference (ip)
               4.6. ip_type (ip)
-              4.7. compare_ips (ip1, ip2)
-              4.8. compare_pure_ips (ip1, ip2)
-              4.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
 
@@ -49,14 +52,17 @@ Iñaki Baz Castillo
    1.4. is_ipv6 usage
    1.5. is_ipv6_reference usage
    1.6. ip_type usage
-   1.7. compare_ips usage
-   1.8. compare_pure_ips usage
-   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
 
@@ -77,14 +83,17 @@ Chapter 1. Admin Guide
         4.4. is_ipv6 (ip)
         4.5. is_ipv6_reference (ip)
         4.6. ip_type (ip)
-        4.7. compare_ips (ip1, ip2)
-        4.8. compare_pure_ips (ip1, ip2)
-        4.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
 
@@ -132,14 +141,17 @@ Chapter 1. Admin Guide
    4.4. is_ipv6 (ip)
    4.5. is_ipv6_reference (ip)
    4.6. ip_type (ip)
-   4.7. compare_ips (ip1, ip2)
-   4.8. compare_pure_ips (ip1, ip2)
-   4.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)
 
@@ -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
    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,
    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
 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
    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,
    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")) {
   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.
    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,
    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")) {
   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
    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,
    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")) {
   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
    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.
 
-   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")) {
     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
    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.
 
-   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")) {
     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
    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.
 
-   Example 1.13.  dns_query usage
+   Example 1.16.  dns_query usage
 ...
 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
    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
      * 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) {
   $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 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">
       <title>
         <function moreinfo="none">compare_ips (ip1, ip2)</function>

+ 134 - 2
modules/ipops/ipops_mod.c

@@ -51,10 +51,12 @@
 #include "../../mod_fix.h"
 #include "../../pvar.h"
 #include "../../resolve.h"
+#include "../../lvalue.h"
 #include "api.h"
 #include "ipops_pv.h"
 #include "ip_parser.h"
 #include "rfc1918_parser.h"
+#include "detailed_ip_type.h"
 
 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_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);
+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_reference(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_pure_ips(struct sip_msg*, char*, 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_dns_sys_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_srv_query(struct sip_msg* msg, char* str1, char* str2);
+static int mod_init(void);
 
 static pv_export_t mod_pvs[] = {
 	{ {"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 },
 	{ "ip_type", (cmd_function)w_ip_type, 1, fixup_spve_null, 0,
 		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,
 		REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE },
 	{ "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 */
 	mod_pvs,                   /*!< exported pseudo-variables */
 	0,                         /*!< extra processes */
-	0,                         /*!< module initialization function */
+	mod_init,                  /*!< module initialization function */
 	(response_function) 0,     /*!< response handling function */
 	0,                         /*!< destroy 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
  */
@@ -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. */
 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
 #
-# 
+#
 # WARNING: do not run this directly, it should be run by the master Makefile
 
 include ../../Makefile.defs
 auto_gen=
 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
-	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
+
 DEFS+=-DOPENSER_MOD_INTERFACE
 
 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 '[':
 			LM_ERR("Unsupported param type '%c'\n", *fmt);
-			jsonrpc_fault(ctx, 500, "Unsupported param type");
+			jsonrpc_fault(ctx, 400, "Unsupported param type");
 			goto error;
 		default:
 			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);
 	if(ctx->jreq==NULL) {
 		LM_ERR("Failed to init the json document\n");
-		return NONSIP_MSG_PASS;
+		return NONSIP_MSG_ERROR;
 	}
 
 	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)
 	{
 		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;
 

+ 2 - 6
modules/mqueue/mqueue_api.c

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

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

@@ -98,7 +98,7 @@
 	<section>
 		<title>External Libraries or Applications</title>
 		<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:
 			<itemizedlist>
 			<listitem>
@@ -113,7 +113,7 @@
 
 	<section>
 	<title>Parameters</title>
-	<section>
+	<section id="path.p.use_received">
 		<title><varname>use_received</varname> (int)</title>
 		<para>
 		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>
 	<title>Functions</title>
-	<section>
+	<section id="path.f.add_path">
 		<title>
 		<function moreinfo="none">add_path()</function>
 		</title>
 		<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
 		of the outgoing interface.
 		</para>
@@ -170,12 +170,12 @@ if (!add_path()) {
 		</example>
 	</section>
 
-	<section>
+	<section id="path.f.add_path_u">
 		<title>
 		<function moreinfo="none">add_path(user)</function>
 		</title>
 		<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>.
 		</para>
 		<para>Meaning of the parameters is as follows:</para>
@@ -203,12 +203,12 @@ if (!add_path("loadbalancer")) {
 		</example>
 	</section>
 
-	<section>
+	<section id="path.f.add_path_up">
 		<title>
 		<function moreinfo="none">add_path(user, parameters)</function>
 		</title>
 		<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
 		given <emphasis>parameters</emphasis> as additional URI parameters.
 		</para>
@@ -245,13 +245,13 @@ if (!add_path("loadbalancer", "ob")) {
 		</example>
 	</section>
 
-	<section>
+	<section id="path.f.add_path_rcv">
 		<title>
 		<function moreinfo="none">add_path_received()</function>
 		</title>
 		<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
 		received-parameter.
 		</para>
@@ -271,14 +271,14 @@ if (!add_path_received()) {
 		</example>
 	</section>
 
-	<section>
+	<section id="path.f.add_path_rcv_u">
 		<title>
 		<function moreinfo="none">add_path_received(user)</function>
 		</title>
 		<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
-		'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
 		received-parameter.
 		</para>
@@ -298,14 +298,14 @@ if (!add_path_received("inbound")) {
 		</example>
 	</section>
 
-	<section>
+	<section id="path.f.add_path_rcv_up">
 		<title>
 		<function moreinfo="none">add_path_received(user, parameters)</function>
 		</title>
 		<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
-		'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
 		received-parameter.
 		</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->rs = st;
 			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:
 			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) {
 		t->subtype = TR_S_UNESCAPEPARAM;
 		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) {
 		t->subtype = TR_S_PREFIXES;
 		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_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_URLENCODEPARAM, TR_S_URLDECODEPARAM, TR_S_NUMERIC
+	TR_S_URLENCODEPARAM, TR_S_URLDECODEPARAM, TR_S_NUMERIC, TR_S_ESCAPECSV
 };
 enum _tr_uri_subtype {
 	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;
 
 	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;
+	}
 
 	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->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;
-
+	}
 	memset(xname->next, 0, sizeof(pv_xavp_name_t));
 
 	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");
 		return -1;
 	}
-	*(sl_timeout)=get_ticks();
+	*(sl_timeout)=get_ticks_raw();
 
 	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_timeout) = get_ticks_raw() + SL_RPL_WAIT_TIME;
+
 	/* supress multhoming support when sending a reply back -- that makes sure
 	   that replies will come from where requests came in; good for NATs
 	   (there is no known use for mhomed for locally generated replies;
@@ -286,8 +288,6 @@ event_route_error:
 	if (ret<0) {
 		goto error;
 	}
-	
-	*(sl_timeout) = get_ticks() + SL_RPL_WAIT_TIME;
 
 	update_sl_stats(code);
 	return 1;
@@ -383,7 +383,7 @@ int sl_filter_ACK(struct sip_msg *msg, unsigned int flags, void *bar )
 		goto pass_it;
 
 	/*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");
 		goto pass_it;

+ 2 - 1
modules/sl/sl_funcs.h

@@ -24,8 +24,9 @@
 
 #include "../../sr_module.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 '.'
 

+ 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 */
 			dns_srv_handle_cpy(&t->uac[t->nr_of_outgoings].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)){
 				/* 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;
 		replies_dropped = 0;
+		tm_ctx_set_branch_index(picked_branch);
 		/* run ON_FAILURE handlers ( route and callbacks) */
 		if (unlikely(has_tran_tmcbs( Trans, TMCB_ON_FAILURE_RO|TMCB_ON_FAILURE)
 						|| Trans->uac[picked_branch].on_failure )) {

+ 268 - 179
modules/tm/uac.c

@@ -57,6 +57,7 @@
 #include "../../action.h"
 #include "../../onsend.h"
 #include "t_lookup.h"
+#include "t_fwd.h"
 #endif
 
 #define FROM_TAG_LEN (MD5_LEN + 1 /* - */ + CRC16_LEN) /* length of FROM tags */
@@ -190,6 +191,162 @@ error:
 	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
  *            (before using it make sure you REF() it first)
  *          - 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 cell *new_cell;
 	struct retr_buf *request;
-	char* buf;
+	char *buf;
 	int buf_len, ret;
 	unsigned int hi;
 	int is_ack;
 	ticks_t lifetime;
-#ifdef USE_DNS_FAILOVER
-	struct dns_srv_handle dns_h;
-#endif
 	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;
 	tm_xlinks_t backup_xd;
 	tm_xdata_t local_xd;
 	int refresh_shortcuts = 0;
+	int sip_msg_len;
+#ifdef USE_DNS_FAILOVER
+	static struct sip_msg lreq;
+#endif /* USE_DNS_FAILOVER */
 
 	ret=-1;
 	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 err's returned, the message is incorrect */
-		goto error2;
+		goto error3;
 
 	if (!uac_r->dialog->loc_seq.is_set) {
 		/* 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;
 	}
 
+	/* 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,
 			uac_r->dialog->hooks.next_hop->s);
 	/* new message => take the dialog send_socket if set, or the default
 	  send_socket if not*/
 	SND_FLAGS_INIT(&snd_flags);
 #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)){
-			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 */
 	if ((uri2dst2(&dst, uac_r->dialog->send_sock, snd_flags,
 					uac_r->dialog->hooks.next_hop, PROTO_NONE)==0) ||
 			(dst.send_sock==0)){
+#endif /* USE_DNS_FAILOVER */
 		ser_error = E_NO_SOCKET;
 		ret=ser_error;
 		LOG(L_ERR, "t_uac: no socket found\n");
 		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){
 		new_cell->flags |= T_IS_INVITE_FLAG;
 		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
 	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 */
 				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_failure = new_cell->on_failure;
@@ -518,14 +549,16 @@ normal_update:
 		LOCK_HASH(hi);
 		remove_from_hash_table_unsafe(new_cell);
 		UNLOCK_HASH(hi);
+	}
+
+error2:
 #ifdef TM_DEL_UNREF
+	if (!is_ack) {
 		UNREF_FREE(new_cell);
 	}else
-#else
-	}
 #endif
 		free_cell(new_cell);
-error2:
+error3:
 	return ret;
 }
 
@@ -558,23 +591,63 @@ int prepare_req_within(uac_req_t *uac_r,
 	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) {
 		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 */
-			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);
-	
-	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)
 {
-	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;
 	int ret;
 	int is_ack;
+	int branch_ret;
+	int i;
+	branch_bm_t added_branches = 1;
 
 	ret = t_uac_prepare(uac_r, &request, &cell);
 	if (ret < 0) return ret;
 	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 (cell) free_cell(cell);
 		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;
 
 	/* 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();
 		if(tcx != NULL)
 			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 vlen;
 	int r2;
+	int isreq;
 
 	if(ptsd->cp==NULL) {
 		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;
 	i = 0;
 	r2 = 0;
+	isreq = (msg->first_line.type==SIP_REQUEST)?1:0;
 	for(hdr=msg->record_route; hdr; hdr=next_sibling_hdr(hdr)) {
 		if (parse_rr(hdr) < 0) {
 			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");
 				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->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 {
-					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 {
-				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)"
 			" - 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;
 
 	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;
 	}
 
@@ -1015,6 +1015,7 @@ int tps_storage_update_dialog(sip_msg_t *msg, tps_data_t *md, tps_data_t *sd)
 		return 0;
 	}
 
+
 	ret = tps_storage_link_msg(msg, md, md->direction);
 	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);
 	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(sd->b_tag.len<=0
 				&& msg->first_line.u.reply.statuscode>=200
 				&& 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_uvals[nr_ucols].type = DB1_STR;
 			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_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++;
 		}
 	}

+ 3 - 0
modules/topos/tps_storage.h

@@ -34,6 +34,9 @@
 #define TPS_DIR_DOWNSTREAM	0
 #define TPS_DIR_UPSTREAM	1
 
+#define TPS_IFLAG_INIT	1
+#define TPS_IFLAG_DLGON	2
+
 #define TPS_DATA_SIZE	8192
 typedef struct tps_data {
 	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;){
 		next=si->next;
 		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((new_si=new_sock2list_after(ai_lst->name.s, 0, si->port_no,
 											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;
 	char c;
 	int ret;
-		
+
 		bytes=-1;
 		total_bytes=0;
 		resp=CONN_RELEASE;
@@ -1314,6 +1314,15 @@ again:
 			else
 #endif
 				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
 						/* if timeout state=0; goto end__req; */
 			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->start);
 #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;
 			/* eof check:
 			 * is EOF if eof on fd and req.  not complete yet,
 			 * if req. is complete we might have a second unparsed
 			 * 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)))) {
 				LM_DBG("EOF\n");
 				resp=CONN_EOF;
@@ -1343,10 +1346,19 @@ again:
 			}
 		}
 		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,
 					(int)(req->pos-req->buf), req->buf,
 					(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);
 			print_ip("received from: ip", &con->rcv.src_ip, "\n");
 			resp=CONN_ERROR;