소스 검색

Merge branch 'master' of ssh://git.sip-router.org/sip-router

Jason Penton 11 년 전
부모
커밋
6e23e6159c
5개의 변경된 파일235개의 추가작업 그리고 50개의 파일을 삭제
  1. 5 0
      modules/rtpproxy/rtpproxy.c
  2. 0 3
      modules/sca/sca_call_info.c
  3. 33 10
      modules/siptrace/README
  4. 32 2
      modules/siptrace/doc/siptrace_admin.xml
  5. 165 35
      modules/siptrace/siptrace.c

+ 5 - 0
modules/rtpproxy/rtpproxy.c

@@ -2454,6 +2454,11 @@ force_rtp_proxy(struct sip_msg* msg, char* str1, char* str2, int offer, int forc
 		if (to_tag.len == 0) {
 		if (to_tag.len == 0) {
 			FORCE_RTP_PROXY_RET (-1);
 			FORCE_RTP_PROXY_RET (-1);
 		}
 		}
+		if (msg->first_line.type == SIP_REQUEST) {
+			tmp = from_tag;
+			from_tag = to_tag;
+			to_tag = tmp;
+		}
 		create = 0;
 		create = 0;
 	} else if ((msg->first_line.type == SIP_REPLY && offer != 0)
 	} else if ((msg->first_line.type == SIP_REPLY && offer != 0)
 			|| (msg->first_line.type == SIP_REQUEST && offer == 0)) {
 			|| (msg->first_line.type == SIP_REQUEST && offer == 0)) {

+ 0 - 3
modules/sca/sca_call_info.c

@@ -1072,9 +1072,6 @@ sca_call_info_invite_reply_18x_handler( sip_msg_t *msg,
 
 
     switch ( msg->REPLY_STATUS ) {
     switch ( msg->REPLY_STATUS ) {
     case 180:
     case 180:
-	state = SCA_APPEARANCE_STATE_ALERTING;
-	break;
-
     case 183:
     case 183:
 	state = SCA_APPEARANCE_STATE_PROGRESSING;
 	state = SCA_APPEARANCE_STATE_PROGRESSING;
 	break;
 	break;

+ 33 - 10
modules/siptrace/README

@@ -16,9 +16,9 @@ Daniel-Constantin Mierla
 
 
    <[email protected]>
    <[email protected]>
 
 
-   Copyright © 2010 asipto.com
+   Copyright © 2010 asipto.com
 
 
-   Copyright © 2006 voice-system.ro
+   Copyright © 2006 voice-system.ro
      __________________________________________________________________
      __________________________________________________________________
 
 
    Table of Contents
    Table of Contents
@@ -49,10 +49,11 @@ Daniel-Constantin Mierla
               3.14. hep_version (integer)
               3.14. hep_version (integer)
               3.15. hep_capture_id (integer)
               3.15. hep_capture_id (integer)
               3.16. trace_delayed (integer)
               3.16. trace_delayed (integer)
+              3.17. force_send_sock (str)
 
 
         4. Functions
         4. Functions
 
 
-              4.1. sip_trace()
+              4.1. sip_trace([address])
 
 
         5. MI Commands
         5. MI Commands
 
 
@@ -83,7 +84,8 @@ Daniel-Constantin Mierla
    1.14. Set hep_version parameter
    1.14. Set hep_version parameter
    1.15. Set hep_capture_id parameter
    1.15. Set hep_capture_id parameter
    1.16. Set trace_delayed parameter
    1.16. Set trace_delayed parameter
-   1.17. sip_trace() usage
+   1.17. Set force_send_sock parameter
+   1.18. sip_trace() usage
 
 
 Chapter 1. Admin Guide
 Chapter 1. Admin Guide
 
 
@@ -113,10 +115,11 @@ Chapter 1. Admin Guide
         3.14. hep_version (integer)
         3.14. hep_version (integer)
         3.15. hep_capture_id (integer)
         3.15. hep_capture_id (integer)
         3.16. trace_delayed (integer)
         3.16. trace_delayed (integer)
+        3.17. force_send_sock (str)
 
 
    4. Functions
    4. Functions
 
 
-        4.1. sip_trace()
+        4.1. sip_trace([address])
 
 
    5. MI Commands
    5. MI Commands
 
 
@@ -186,6 +189,7 @@ Chapter 1. Admin Guide
    3.14. hep_version (integer)
    3.14. hep_version (integer)
    3.15. hep_capture_id (integer)
    3.15. hep_capture_id (integer)
    3.16. trace_delayed (integer)
    3.16. trace_delayed (integer)
+   3.17. force_send_sock (str)
 
 
 3.1. db_url (str)
 3.1. db_url (str)
 
 
@@ -404,22 +408,41 @@ modparam("siptrace", "hep_capture_id", 234)
 modparam("siptrace", "trace_delayed", 1)
 modparam("siptrace", "trace_delayed", 1)
 ...
 ...
 
 
+3.17. force_send_sock (str)
+
+   The local interface in form of SIP uri from where to send the
+   duplicated traffic. In the absence of this parameter kamailio
+   automatically picks an interface.
+
+   Example 1.17. Set force_send_sock parameter
+...
+modparam("siptrace", "force_send_sock", "sip:10.1.1.2:5000")
+...
+
 4. Functions
 4. Functions
 
 
-   4.1. sip_trace()
+   4.1. sip_trace([address])
 
 
-4.1.  sip_trace()
+4.1.  sip_trace([address])
 
 
    Store current processed SIP message in database. It is stored in the
    Store current processed SIP message in database. It is stored in the
    form prior applying chages made to it.
    form prior applying chages made to it.
 
 
+   Meaning of the parameters is as follows:
+     * address - The address in form of SIP uri where to send a duplicate
+       of traced message. This parameter trumps duplicate_uri and allows
+       tracing to more than one server.
+
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
    ONREPLY_ROUTE, BRANCH_ROUTE.
    ONREPLY_ROUTE, BRANCH_ROUTE.
+   Default value is "NULL".
 
 
-   Example 1.17. sip_trace() usage
+   Example 1.18. sip_trace() usage
 ...
 ...
 sip_trace();
 sip_trace();
 ...
 ...
+sip_trace("sip:10.1.1.2:5085");
+...
 
 
 5. MI Commands
 5. MI Commands
 
 
@@ -434,7 +457,7 @@ sip_trace();
           + on
           + on
           + off
           + off
        The parameter is optional - if missing, the command will return the
        The parameter is optional - if missing, the command will return the
-       status of the SIP message tracing (as string "on" or "off" )
+       status of the SIP message tracing (as string “on� or “off� )
        without changing anything.
        without changing anything.
 
 
    MI FIFO Command Format:
    MI FIFO Command Format:
@@ -454,7 +477,7 @@ sip_trace();
      * on or off: turns on/off SIP message tracing.. Possible values are:
      * on or off: turns on/off SIP message tracing.. Possible values are:
           + on
           + on
           + off
           + off
-     * "check" does not change siptrace status, just reports the current
+     * “check� does not change siptrace status, just reports the current
        status.
        status.
 
 
 7. Database setup
 7. Database setup

+ 32 - 2
modules/siptrace/doc/siptrace_admin.xml

@@ -450,29 +450,59 @@ modparam("siptrace", "trace_delayed", 1)
 </programlisting>
 </programlisting>
                 </example>
                 </example>
         </section>
         </section>
-
+<section>
+                <title><varname>force_send_sock</varname> (str)</title>
+                <para>
+				The local interface in form of SIP uri from where to send
+				the duplicated traffic. In the absence of this parameter
+				kamailio automatically picks an interface.
+                </para>
+                <example>
+                <title>Set <varname>force_send_sock</varname>
+                parameter</title>
+                <programlisting format="linespecific">
+...
+modparam("siptrace", "force_send_sock", "sip:10.1.1.2:5000")
+...
+</programlisting>
+                </example>
+        </section>
 	</section>
 	</section>
 	
 	
 	<section>
 	<section>
 	<title>Functions</title>
 	<title>Functions</title>
 	<section>
 	<section>
 		<title>
 		<title>
-		<function moreinfo="none">sip_trace()</function>
+		<function moreinfo="none">sip_trace([address])</function>
 		</title>
 		</title>
 		<para>
 		<para>
 		Store current processed SIP message in database. It is stored in the
 		Store current processed SIP message in database. It is stored in the
 		form prior applying chages made to it.
 		form prior applying chages made to it.
 		</para>
 		</para>
+		<para>Meaning of the parameters is as follows:</para>
+		<itemizedlist>
+		<listitem>
+		<para><emphasis>address</emphasis> - The address in form of SIP uri
+		where to send a duplicate of traced message. This parameter trumps
+		duplicate_uri and allows tracing to more than one server.
+		</para>
+		</listitem>
+		</itemizedlist>
 		<para>
 		<para>
 		This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
 		This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
 		ONREPLY_ROUTE, BRANCH_ROUTE.
 		ONREPLY_ROUTE, BRANCH_ROUTE.
 		</para>
 		</para>
+		<emphasis>
+			Default value is "NULL".
+		</emphasis>
 		<example>
 		<example>
 		<title><function>sip_trace()</function> usage</title>
 		<title><function>sip_trace()</function> usage</title>
 		<programlisting format="linespecific">
 		<programlisting format="linespecific">
 ...
 ...
 sip_trace();
 sip_trace();
 ...
 ...
+sip_trace("sip:10.1.1.2:5085");
+...
 </programlisting>
 </programlisting>
 		</example>
 		</example>
 	</section>
 	</section>

+ 165 - 35
modules/siptrace/siptrace.c

@@ -91,10 +91,11 @@ static int mod_init(void);
 static int siptrace_init_rpc(void);
 static int siptrace_init_rpc(void);
 static int child_init(int rank);
 static int child_init(int rank);
 static void destroy(void);
 static void destroy(void);
-static int sip_trace(struct sip_msg*, char*, char*);
+static int sip_trace(struct sip_msg*, struct dest_info*, char*);
+static int fixup_siptrace(void ** param, int param_no);
 
 
 static int sip_trace_store_db(struct _siptrace_data* sto);
 static int sip_trace_store_db(struct _siptrace_data* sto);
-static int trace_send_duplicate(char *buf, int len);
+static int trace_send_duplicate(char *buf, int len, struct dest_info*);
 
 
 static void trace_onreq_in(struct cell* t, int type, struct tmcb_params *ps);
 static void trace_onreq_in(struct cell* t, int type, struct tmcb_params *ps);
 static void trace_onreq_out(struct cell* t, int type, struct tmcb_params *ps);
 static void trace_onreq_out(struct cell* t, int type, struct tmcb_params *ps);
@@ -103,7 +104,7 @@ static void trace_onreply_out(struct cell* t, int type, struct tmcb_params *ps);
 static void trace_sl_onreply_out(sl_cbp_t *slcb);
 static void trace_sl_onreply_out(sl_cbp_t *slcb);
 static void trace_sl_ack_in(sl_cbp_t *slcb);
 static void trace_sl_ack_in(sl_cbp_t *slcb);
 
 
-static int trace_send_hep_duplicate(str *body, str *from, str *to);
+static int trace_send_hep_duplicate(str *body, str *from, str *to, struct dest_info*);
 static int pipport2su (char *pipport, union sockaddr_union *tmp_su, unsigned int *proto);
 static int pipport2su (char *pipport, union sockaddr_union *tmp_su, unsigned int *proto);
 
 
 
 
@@ -140,6 +141,9 @@ int hep_capture_id = 1;
 int xheaders_write = 0;
 int xheaders_write = 0;
 int xheaders_read = 0;
 int xheaders_read = 0;
 
 
+str force_send_sock_str = {0, 0};
+struct sip_uri * force_send_sock_uri = 0;
+
 str    dup_uri_str      = {0, 0};
 str    dup_uri_str      = {0, 0};
 struct sip_uri *dup_uri = 0;
 struct sip_uri *dup_uri = 0;
 
 
@@ -169,7 +173,7 @@ db_func_t db_funcs;      		/*!< Database functions */
  */
  */
 static cmd_export_t cmds[] = {
 static cmd_export_t cmds[] = {
 	{"sip_trace", (cmd_function)sip_trace, 0, 0, 0, ANY_ROUTE},
 	{"sip_trace", (cmd_function)sip_trace, 0, 0, 0, ANY_ROUTE},
-	{"sip_trace", (cmd_function)sip_trace, 1, 0, 0, ANY_ROUTE},
+    {"sip_trace", (cmd_function)sip_trace, 1, fixup_siptrace, 0, ANY_ROUTE},
 	{0, 0, 0, 0, 0, 0}
 	{0, 0, 0, 0, 0, 0}
 };
 };
 
 
@@ -201,6 +205,7 @@ static param_export_t params[] = {
 	{"xheaders_write",     INT_PARAM, &xheaders_write       },
 	{"xheaders_write",     INT_PARAM, &xheaders_write       },
 	{"xheaders_read",      INT_PARAM, &xheaders_read        },
 	{"xheaders_read",      INT_PARAM, &xheaders_read        },
 	{"hep_mode_on",        INT_PARAM, &hep_mode_on          },	 
 	{"hep_mode_on",        INT_PARAM, &hep_mode_on          },	 
+    {"force_send_sock",    PARAM_STR, &force_send_sock_str	},
 	{"hep_version",        INT_PARAM, &hep_version          },
 	{"hep_version",        INT_PARAM, &hep_version          },
 	{"hep_capture_id",     INT_PARAM, &hep_capture_id       },	        
 	{"hep_capture_id",     INT_PARAM, &hep_capture_id       },	        
 	{"trace_delayed",      INT_PARAM, &trace_delayed        },
 	{"trace_delayed",      INT_PARAM, &trace_delayed        },
@@ -289,6 +294,11 @@ static int mod_init(void)
 
 
 	*trace_to_database_flag = trace_to_database;
 	*trace_to_database_flag = trace_to_database;
 
 
+	if(hep_version != 1 && hep_version != 2) {
+	    LM_ERR("unsupported version of HEP");
+	    return -1;
+	}
+
 	/* Find a database module if needed */
 	/* Find a database module if needed */
 	if(trace_to_database_flag!=NULL && *trace_to_database_flag!=0) {
 	if(trace_to_database_flag!=NULL && *trace_to_database_flag!=0) {
 		if (db_bind_mod(&db_url, &db_funcs))
 		if (db_bind_mod(&db_url, &db_funcs))
@@ -377,6 +387,23 @@ static int mod_init(void)
 		}
 		}
 	}
 	}
 
 
+	if(force_send_sock_str.s!=0)
+	{
+	    force_send_sock_str.len = strlen(force_send_sock_str.s);
+	    force_send_sock_uri = (struct sip_uri *)pkg_malloc(sizeof(struct sip_uri));
+	    if(force_send_sock_uri==0)
+	    {
+	        LM_ERR("no more pkg memory left\n");
+	        return -1;
+	    }
+	    memset(force_send_sock_uri, 0, sizeof(struct sip_uri));
+	    if(parse_uri(force_send_sock_str.s, force_send_sock_str.len, force_send_sock_uri)<0)
+	    {
+	        LM_ERR("bad dup uri\n");
+	        return -1;
+	    }
+	}
+
 	if(traced_user_avp_str.s && traced_user_avp_str.len > 0)
 	if(traced_user_avp_str.s && traced_user_avp_str.len > 0)
 	{
 	{
 		if (pv_parse_spec(&traced_user_avp_str, &avp_spec)==0
 		if (pv_parse_spec(&traced_user_avp_str, &avp_spec)==0
@@ -687,7 +714,7 @@ static int sip_trace_xheaders_free(struct _siptrace_data *sto)
 	return 0;
 	return 0;
 }
 }
 
 
-static int sip_trace_store(struct _siptrace_data *sto)
+static int sip_trace_store(struct _siptrace_data *sto, struct dest_info *dst)
 {
 {
 	if(sto==NULL)
 	if(sto==NULL)
 	{
 	{
@@ -704,8 +731,8 @@ static int sip_trace_store(struct _siptrace_data *sto)
 	if (sip_trace_xheaders_write(sto) != 0)
 	if (sip_trace_xheaders_write(sto) != 0)
 		return -1;
 		return -1;
 
 
-	if(hep_mode_on) trace_send_hep_duplicate(&sto->body, &sto->fromip, &sto->toip);
-	else trace_send_duplicate(sto->body.s, sto->body.len);
+	if(hep_mode_on) trace_send_hep_duplicate(&sto->body, &sto->fromip, &sto->toip, dst);
+    else trace_send_duplicate(sto->body.s, sto->body.len, dst);
 
 
 	if (sip_trace_xheaders_free(sto) != 0)
 	if (sip_trace_xheaders_free(sto) != 0)
 		return -1;
 		return -1;
@@ -844,11 +871,76 @@ error:
 	return -1;
 	return -1;
 }
 }
 
 
-static int sip_trace(struct sip_msg *msg, char *dir, char *s2)
+static int fixup_siptrace(void** param, int param_no) {
+	char *duri = (char*) *param;
+	struct sip_uri dup_uri;
+	struct dest_info *dst = NULL;
+	struct proxy_l * p = NULL;
+	str dup_uri_str = { 0, 0 };
+
+	if (param_no != 1) {
+		LM_DBG("params:%s\n", (char*)*param);
+		return 0;
+	}
+	if (!(*duri)) {
+		LM_ERR("invalid dup URI\n");
+		return -1;
+	}
+	LM_DBG("sip_trace URI:%s\n", (char*)*param);
+
+	dup_uri_str.s = duri;
+	dup_uri_str.len = strlen(dup_uri_str.s);
+	memset(&dup_uri, 0, sizeof(struct sip_uri));
+
+	if (parse_uri(dup_uri_str.s, dup_uri_str.len, &dup_uri) < 0) {
+		LM_ERR("bad dup uri\n");
+		return -1;
+	}
+
+	dst = (struct dest_info *) pkg_malloc(sizeof(struct dest_info));
+	if (dst == 0) {
+		LM_ERR("no more pkg memory left\n");
+		return -1;
+	}
+	init_dest_info(dst);
+	/* create a temporary proxy*/
+	dst->proto = PROTO_UDP;
+	p = mk_proxy(&dup_uri.host, (dup_uri.port_no) ? dup_uri.port_no : SIP_PORT,
+			dst->proto);
+	if (p == 0) {
+		LM_ERR("bad host name in uri\n");
+		pkg_free(dst);
+		return -1;
+	}
+	hostent2su(&dst->to, &p->host, p->addr_idx, (p->port) ? p->port : SIP_PORT);
+
+	pkg_free(*param);
+	/* free temporary proxy*/
+	if (p) {
+		free_proxy(p); /* frees only p content, not p itself */
+		pkg_free(p);
+	}
+
+	*param = (void*) dst;
+	return 0;
+}
+
+static int sip_trace(struct sip_msg *msg, struct dest_info * dst, char *dir)
 {
 {
 	struct _siptrace_data sto;
 	struct _siptrace_data sto;
 	struct onsend_info *snd_inf = NULL;
 	struct onsend_info *snd_inf = NULL;
 
 
+	if (dst){
+	    if (dst->send_sock == 0){
+	        dst->send_sock=get_send_socket(0, &dst->to, dst->proto);
+	        if (dst->send_sock==0){
+	            LM_ERR("can't forward to af %d, proto %d no corresponding"
+	                    " listening socket\n", dst->to.s.sa_family, dst->proto);
+	            return -1;
+	        }
+	    }
+	}
+
 	if(msg==NULL) {
 	if(msg==NULL) {
 		LM_DBG("nothing to trace\n");
 		LM_DBG("nothing to trace\n");
 		return -1;
 		return -1;
@@ -934,7 +1026,7 @@ static int sip_trace(struct sip_msg *msg, char *dir, char *s2)
 		sto.stat = siptrace_req;
 		sto.stat = siptrace_req;
 	}
 	}
 #endif
 #endif
-	return sip_trace_store(&sto);
+	return sip_trace_store(&sto, dst);
 }
 }
 
 
 #define trace_is_off(_msg) \
 #define trace_is_off(_msg) \
@@ -1116,7 +1208,7 @@ static void trace_onreq_out(struct cell* t, int type, struct tmcb_params *ps)
 	sto.stat = siptrace_req;
 	sto.stat = siptrace_req;
 #endif
 #endif
 
 
-	sip_trace_store(&sto);
+	sip_trace_store(&sto, NULL);
 	return;
 	return;
 }
 }
 
 
@@ -1187,7 +1279,7 @@ static void trace_onreply_in(struct cell* t, int type, struct tmcb_params *ps)
 	sto.stat = siptrace_rpl;
 	sto.stat = siptrace_rpl;
 #endif
 #endif
 
 
-	sip_trace_store(&sto);
+	sip_trace_store(&sto, NULL);
 	return;
 	return;
 }
 }
 
 
@@ -1296,7 +1388,7 @@ static void trace_onreply_out(struct cell* t, int type, struct tmcb_params *ps)
 	sto.stat = siptrace_rpl;
 	sto.stat = siptrace_rpl;
 #endif
 #endif
 
 
-	sip_trace_store(&sto);
+	sip_trace_store(&sto, NULL);
 	return;
 	return;
 }
 }
 
 
@@ -1382,7 +1474,7 @@ static void trace_sl_onreply_out(sl_cbp_t *slcbp)
 	sto.stat = siptrace_rpl;
 	sto.stat = siptrace_rpl;
 #endif
 #endif
 
 
-	sip_trace_store(&sto);
+	sip_trace_store(&sto, NULL);
 	return;
 	return;
 }
 }
 
 
@@ -1434,10 +1526,10 @@ static struct mi_root* sip_trace_mi(struct mi_root* cmd_tree, void* param )
 	}
 	}
 }
 }
 
 
-static int trace_send_duplicate(char *buf, int len)
+static int trace_send_duplicate(char *buf, int len, struct dest_info *dst2)
 {
 {
 	struct dest_info dst;
 	struct dest_info dst;
-	struct proxy_l * p;
+	struct proxy_l * p = NULL;
 
 
 	if(buf==NULL || len <= 0)
 	if(buf==NULL || len <= 0)
 		return -1;
 		return -1;
@@ -1456,34 +1548,50 @@ static int trace_send_duplicate(char *buf, int len)
 		return -1;
 		return -1;
 	}
 	}
 
 
-	hostent2su(&dst.to, &p->host, p->addr_idx, (p->port)?p->port:SIP_PORT);
+	if (!dst2){
+	    init_dest_info(&dst);
+	    /* create a temporary proxy*/
+	    dst.proto = PROTO_UDP;
+	    p=mk_proxy(&dup_uri->host, (dup_uri->port_no)?dup_uri->port_no:SIP_PORT,
+	             dst.proto);
+	    if (p==0){
+	        LM_ERR("bad host name in uri\n");
+	        return -1;
+	    }
+	    hostent2su(&dst.to, &p->host, p->addr_idx, (p->port)?p->port:SIP_PORT);
 
 
-	dst.send_sock=get_send_socket(0, &dst.to, dst.proto);
-	if (dst.send_sock==0)
-	{
-		LM_ERR("can't forward to af %d, proto %d no corresponding"
-				" listening socket\n", dst.to.s.sa_family, dst.proto);
-		goto error;
+	    dst.send_sock=get_send_socket(0, &dst.to, dst.proto);
+	    if (dst.send_sock==0){
+	        LM_ERR("can't forward to af %d, proto %d no corresponding"
+	                " listening socket\n", dst.to.s.sa_family, dst.proto);
+	        goto error;
+	    }
 	}
 	}
 
 
-	if (msg_send(&dst, buf, len)<0)
+	if (msg_send((dst2)?dst2:&dst, buf, len)<0)
 	{
 	{
 		LM_ERR("cannot send duplicate message\n");
 		LM_ERR("cannot send duplicate message\n");
 		goto error;
 		goto error;
 	}
 	}
 
 
-	free_proxy(p); /* frees only p content, not p itself */
-	pkg_free(p);
+	if (p){
+	    free_proxy(p); /* frees only p content, not p itself */
+	    pkg_free(p);
+	}
 	return 0;
 	return 0;
 error:
 error:
+    if (p){
 	free_proxy(p); /* frees only p content, not p itself */
 	free_proxy(p); /* frees only p content, not p itself */
 	pkg_free(p);
 	pkg_free(p);
+    }
 	return -1;
 	return -1;
 }
 }
 
 
-static int trace_send_hep_duplicate(str *body, str *from, str *to)
+static int trace_send_hep_duplicate(str *body, str *from, str *to, struct dest_info * dst2)
 {
 {
 	struct dest_info dst;
 	struct dest_info dst;
+	struct socket_info *si;
+	struct dest_info* dst_fin = NULL;
 	struct proxy_l * p=NULL /* make gcc happy */;
 	struct proxy_l * p=NULL /* make gcc happy */;
 	void* buffer = NULL;
 	void* buffer = NULL;
 	union sockaddr_union from_su;
 	union sockaddr_union from_su;
@@ -1528,6 +1636,7 @@ static int trace_send_hep_duplicate(str *body, str *from, str *to)
 		goto error;
 		goto error;
 	}
 	}
 
 
+    if (!dst2){
 	init_dest_info(&dst);
 	init_dest_info(&dst);
 	/* create a temporary proxy*/
 	/* create a temporary proxy*/
 	dst.proto = PROTO_UDP;
 	dst.proto = PROTO_UDP;
@@ -1540,14 +1649,33 @@ static int trace_send_hep_duplicate(str *body, str *from, str *to)
 	}
 	}
 
 
 	hostent2su(&dst.to, &p->host, p->addr_idx, (p->port)?p->port:SIP_PORT);
 	hostent2su(&dst.to, &p->host, p->addr_idx, (p->port)?p->port:SIP_PORT);
-
-	dst.send_sock=get_send_socket(0, &dst.to, dst.proto);
-	if (dst.send_sock==0)
-	{
-		LM_ERR("can't forward to af %d, proto %d no corresponding"
-				" listening socket\n", dst.to.s.sa_family, dst.proto);
-		goto error;
-	}
+	LM_DBG("setting up the socket_info\n");
+	dst_fin = &dst;
+    } else {
+        dst_fin = dst2;
+    }
+
+    if (force_send_sock_str.s) {
+        LM_DBG("force_send_sock activated, grep for the sock_info\n");
+        si = grep_sock_info(&force_send_sock_uri->host,
+                (force_send_sock_uri->port_no)?force_send_sock_uri->port_no:SIP_PORT,
+                PROTO_UDP);
+        if (!si) {
+             LM_WARN("cannot grep socket info\n");
+        } else {
+            LM_DBG("found socket while grep: [%.*s] [%.*s]\n", si->name.len, si->name.s, si->address_str.len, si->address_str.s);
+            dst_fin->send_sock = si;
+        }
+    }
+
+    if (dst_fin->send_sock == 0) {
+        dst_fin->send_sock=get_send_socket(0, &dst_fin->to, dst_fin->proto);
+        if (dst_fin->send_sock == 0) {
+            LM_ERR("can't forward to af %d, proto %d no corresponding"
+                    " listening socket\n", dst_fin->to.s.sa_family, dst_fin->proto);
+            goto error;
+        }
+    }
 
 
 	/* Version && proto && length */
 	/* Version && proto && length */
 	hdr.hp_l = sizeof(struct hep_hdr);
 	hdr.hp_l = sizeof(struct hep_hdr);
@@ -1627,14 +1755,16 @@ static int trace_send_hep_duplicate(str *body, str *from, str *to)
 	memcpy((void*)(buffer + buflen) , (void*)body->s, body->len);
 	memcpy((void*)(buffer + buflen) , (void*)body->s, body->len);
 	buflen +=body->len;
 	buflen +=body->len;
 
 
-	if (msg_send(&dst, buffer, buflen)<0)
+	if (msg_send(dst_fin, buffer, buflen)<0)
 	{
 	{
 		LM_ERR("cannot send hep duplicate message\n");
 		LM_ERR("cannot send hep duplicate message\n");
 		goto error;
 		goto error;
 	}
 	}
 
 
+    if (p) {
 	free_proxy(p); /* frees only p content, not p itself */
 	free_proxy(p); /* frees only p content, not p itself */
 	pkg_free(p);
 	pkg_free(p);
+    }
 	pkg_free(buffer);
 	pkg_free(buffer);
 	return 0;
 	return 0;
 error:
 error: