Blob Blame History Raw
From: Bogdan-Andrei Iancu <bogdan@opensips.org>
Date: Tue, 12 Jul 2016 15:26:12 +0300
Subject: [PATCH] Fix advertised port and address per branch.

Before the advertised_port/address are preserved only in the UAS part of the transaction - that means it is only one value and it is from the setting done in Request Route; whatever later setting done in Failure Route or Branch Route are not preserved at transaction level (even if they are used on the spot, for sending out the INVITE).
So, when we have to build a local request (ACK or CANCEL), we do not remember which specific address/port were advertised for that particular UAC (branch).

Fixes #917.

(cherry picked from commit eb850a22f0af83bf75e75dfadbe1320e8b92784b)

diff --git a/modules/tm/h_table.c b/modules/tm/h_table.c
index e14a305..6263311 100644
--- a/modules/tm/h_table.c
+++ b/modules/tm/h_table.c
@@ -178,6 +178,12 @@ void free_cell( struct cell* dead_cell )
 		if (dead_cell->uac[i].path_vec.s) {
 			__shm_free(dead_cell->uac[i].path_vec.s);
 		}
+		if (dead_cell->uac[i].adv_address.s) {
+			__shm_free(dead_cell->uac[i].adv_address.s);
+		}
+		if (dead_cell->uac[i].adv_port.s) {
+			__shm_free(dead_cell->uac[i].adv_port.s);
+		}
 		if (dead_cell->uac[i].duri.s) {
 			__shm_free(dead_cell->uac[i].duri.s);
 		}
diff --git a/modules/tm/h_table.h b/modules/tm/h_table.h
index 1661f94..a06fc8c 100644
--- a/modules/tm/h_table.h
+++ b/modules/tm/h_table.h
@@ -149,6 +149,10 @@ typedef struct ua_client
 	str              duri;
 	/* the path vector used for this branch */
 	str              path_vec;
+	/* the advertised address used for this branch */
+	str              adv_address;
+	/* the advertised port used for this branch */
+	str              adv_port;
 	/* number of RR headers that were locally added for this branch */
 	unsigned int     added_rr;
 	/* if we store a reply (branch picking), this is where it is */
diff --git a/modules/tm/t_fwd.c b/modules/tm/t_fwd.c
index 9ebf909..489f9e2 100644
--- a/modules/tm/t_fwd.c
+++ b/modules/tm/t_fwd.c
@@ -118,6 +118,33 @@ static inline int pre_print_uac_request( struct cell *t, int branch,
 			request->path_vec.len+1);
 	}
 
+	/* do the same for the advertised port & address */
+	if (request->set_global_address.len) {
+		t->uac[branch].adv_address.s = shm_resize(t->uac[branch].adv_address.s,
+			request->set_global_address.len+1);
+		if (t->uac[branch].adv_address.s==NULL) {
+			LM_ERR("shm_resize failed for storing the advertised address "
+				"(len=%d)\n",request->set_global_address.len);
+			goto error;
+		}
+		t->uac[branch].adv_address.len = request->set_global_address.len;
+		memcpy( t->uac[branch].adv_address.s, request->set_global_address.s,
+			request->set_global_address.len+1);
+	}
+	if (request->set_global_port.len) {
+		t->uac[branch].adv_port.s = shm_resize(t->uac[branch].adv_port.s,
+			request->set_global_port.len+1);
+		if (t->uac[branch].adv_port.s==NULL) {
+			LM_ERR("shm_resize failed for storing the advertised port "
+				"(len=%d)\n",request->set_global_port.len);
+			goto error;
+		}
+		t->uac[branch].adv_port.len = request->set_global_port.len;
+		memcpy( t->uac[branch].adv_port.s, request->set_global_port.s,
+			request->set_global_port.len+1);
+	}
+
+
 	/********** run route & callback ************/
 
 	/* run branch route, if any; run it before RURI's DNS lookup
@@ -426,6 +453,10 @@ error01:
 			destroy_avp_list(&t->uac[branch].user_avps);
 		if (t->uac[branch].path_vec.s)
 			shm_free(t->uac[branch].path_vec.s);
+		if (t->uac[branch].adv_address.s)
+			shm_free(t->uac[branch].adv_address.s);
+		if (t->uac[branch].adv_port.s)
+			shm_free(t->uac[branch].adv_port.s);
 		if (t->uac[branch].duri.s)
 			shm_free(t->uac[branch].duri.s);
 		memset(&t->uac[branch],0,sizeof(t->uac[branch]));
@@ -443,6 +474,8 @@ int e2e_cancel_branch( struct sip_msg *cancel_msg, struct cell *t_cancel,
 	unsigned int len;
 	str bk_dst_uri;
 	str bk_path_vec;
+	str bk_adv_address;
+	str bk_adv_port;
 
 	if (t_cancel->uac[branch].request.buffer.s) {
 		LM_CRIT("buffer rewrite attempt\n");
@@ -454,9 +487,13 @@ int e2e_cancel_branch( struct sip_msg *cancel_msg, struct cell *t_cancel,
 	cancel_msg->parsed_uri_ok=0;
 	bk_dst_uri = cancel_msg->dst_uri;
 	bk_path_vec = cancel_msg->path_vec;
+	bk_adv_address = cancel_msg->set_global_address;
+	bk_adv_port = cancel_msg->set_global_port;
 
-	/* force same path as for request */
+	/* force same path & advertising as for request */
 	cancel_msg->path_vec = t_invite->uac[branch].path_vec;
+	cancel_msg->set_global_address = t_invite->uac[branch].adv_address;
+	cancel_msg->set_global_port = t_invite->uac[branch].adv_port;
 
 	if ( pre_print_uac_request( t_cancel, branch, cancel_msg)!= 0 ) {
 		ret = -1;
@@ -498,6 +535,8 @@ error01:
 		&bk_dst_uri);
 	cancel_msg->dst_uri = bk_dst_uri;
 	cancel_msg->path_vec = bk_path_vec;
+	cancel_msg->set_global_address = bk_adv_address;
+	cancel_msg->set_global_port = bk_adv_port;
 error:
 	return ret;
 }
@@ -623,6 +662,7 @@ int t_forward_nonack( struct cell *t, struct sip_msg* p_msg ,
 	bk_sock = p_msg->force_send_socket;
 	bk_br_flags = getb0flags();
 	bk_path = p_msg->path_vec;
+	/* advertised address/port are not changed */
 
 	/* check if the UAS retranmission port needs to be updated */
 	if ( (p_msg->msg_flags ^ t->uas.request->msg_flags) & FL_FORCE_RPORT )
diff --git a/modules/tm/t_msgbuilder.c b/modules/tm/t_msgbuilder.c
index 9ce0cd6..6de9a4b 100644
--- a/modules/tm/t_msgbuilder.c
+++ b/modules/tm/t_msgbuilder.c
@@ -150,6 +150,10 @@ char *build_local(struct cell *Trans,unsigned int branch,
 	if (!t_calc_branch(Trans,  branch, branch_str.s, &branch_str.len ))
 		goto error;
 	set_hostport(&hp, (is_local(Trans))?0:req);
+	if (Trans->uac[branch].adv_address.len)
+		hp.host = &Trans->uac[branch].adv_address;
+	if (Trans->uac[branch].adv_port.len)
+		hp.port = &Trans->uac[branch].adv_port;
 	via=via_builder(&via_len, Trans->uac[branch].request.dst.send_sock,
 		&branch_str, 0, Trans->uac[branch].request.dst.proto, &hp );
 	if (!via){