Prechádzať zdrojové kódy

tm: support for changing dst_uri in branch routes

- dst_uri can now be changed in branch routes, if the branch
  route is not called during dns failover (which never happens,
  but might be enabled in the future).
- dst_uri can now be checked in branch routes. The
  dst_uri on branch route entry will be the branch next hop
  (initial next hop and not the dns resolved one) if a
  t_relay() based on uri was used, or empty if a destination was
  forced (e.g. t_relay_to_udp(127.0.0.1, 9)).
- s/print_uac_request/prepare_uac_request to better reflect what
  is actually doing
- prepare_uac_request() will now perform the DNS lookups and directly
  update the branch dst inside the transaction.
- add_uac() must now be called with a special flag during DNS
  failover (UAC_DNS_FAILOVER).
Andrei Pelinescu-Onciul 16 rokov pred
rodič
commit
44f7bf6214
2 zmenil súbory, kde vykonal 125 pridanie a 53 odobranie
  1. 123 53
      modules/tm/t_fwd.c
  2. 2 0
      modules/tm/t_fwd.h

+ 123 - 53
modules/tm/t_fwd.c

@@ -78,7 +78,10 @@
  *              t saved, thus, are not available. Set reparse_on_dns_failover
  *              t saved, thus, are not available. Set reparse_on_dns_failover
  *              to 0 to revert the change. (Miklos)
  *              to 0 to revert the change. (Miklos)
  * 2008-06-04  T_CANCELED is now set each time a CANCEL is received (andrei)
  * 2008-06-04  T_CANCELED is now set each time a CANCEL is received (andrei)
- * 2009-06-01  Pre- and post-script callbacks of branch route are executed (Miklos)
+ * 2009-06-01  Pre- and post-script callbacks of branch route are 
+ *             executed (Miklos)
+ * 2009-10-26  support for changing dst_uri in branch routes,
+ *             s/print_uac_request/prepare_uac_request/ (andrei)
  */
  */
 
 
 #include "defs.h"
 #include "defs.h"
@@ -144,8 +147,19 @@ unsigned int get_on_branch(void)
 }
 }
 
 
 
 
+
+/* prepare_uac_request flags */
+#define UAC_DNS_FAILOVER_F 1 /**< new branch due to dns failover */
+
+
 /** create a branch "buffer".
 /** create a branch "buffer".
- * Creates the buffer used in the branch rb and runs the on_branch route.
+ * Creates the buffer used in the branch rb, fills the sending information
+ * (t->uac[branch].request.dst) if next_hop!=0 and runs the on_branch route.
+ * t->uac[branch].request.dst will be filled if next_hop !=0 with the result
+ * of the DNS resolution (next_hop and fproto).
+ * If next_hop is 0 all the dst members except the send_flags are read-only
+ * (send_flags it's updated).
+ *
  * @param t  - transaction
  * @param t  - transaction
  * @param i_req - corresponding sip_msg, must be non-null, flags might be
  * @param i_req - corresponding sip_msg, must be non-null, flags might be
  *                be modified (on_branch route)
  *                be modified (on_branch route)
@@ -153,16 +167,22 @@ unsigned int get_on_branch(void)
  * @param uri
  * @param uri
  * @param path  - path vector (list of route like destination in text form,
  * @param path  - path vector (list of route like destination in text form,
  *                 e.g.: "<sip:1.2.3.4;lr>, <sip:5.6.7.8;lr>")
  *                 e.g.: "<sip:1.2.3.4;lr>, <sip:5.6.7.8;lr>")
+ * @param next_hop - uri of the next hop. If non 0 it will be used
+ *              for DNS resolution and the branch request.dst structure will
+ *              be filled. If 0 the branch must already have
+ *              a pre-filled valid request.dst.
+ * @param fproto - forced proto for forwarding. Used only if next_hop!=0.
+ * @param flags - 0 or UAC_DNS_FAILOVER_F for now.
  * @param len - resul parameter, it will be filled with the created buffer 
  * @param len - resul parameter, it will be filled with the created buffer 
- *              lenght.
- * @param dst - value/result parameter. It will be used to generate the
- *              message. All the values except the send_flags are read-only.
- *              send_flags it's updated.
- * @return pointer to shm alloc'ed buffer on success (*len and dst->send_flags
- *  are filled/modified), 0 on failure
+ *              length.
+ * @return pointer to shm alloc'ed buffer on success (*len and dst
+ *  are filled/modified), 0 on failure and sets ser_error.
  */
  */
-static char *print_uac_request( struct cell *t, struct sip_msg *i_req,
-	int branch, str *uri, str* path, unsigned int *len, struct dest_info* dst)
+static char *prepare_uac_request( struct cell *t, struct sip_msg *i_req,
+									int branch, str *uri, str* path,
+									str* next_hop, int fproto,
+									int flags,
+									unsigned int *len)
 {
 {
 	char *buf, *shbuf;
 	char *buf, *shbuf;
 	str* msg_uri;
 	str* msg_uri;
@@ -170,11 +190,13 @@ static char *print_uac_request( struct cell *t, struct sip_msg *i_req,
 	struct sip_uri parsed_uri_bak;
 	struct sip_uri parsed_uri_bak;
 	int parsed_uri_ok_bak, uri_backed_up;
 	int parsed_uri_ok_bak, uri_backed_up;
 	str msg_uri_bak;
 	str msg_uri_bak;
+	str dst_uri_bak;
 	str path_bak;
 	str path_bak;
 	int path_backed_up;
 	int path_backed_up;
 	int backup_route_type;
 	int backup_route_type;
 	snd_flags_t fwd_snd_flags_bak;
 	snd_flags_t fwd_snd_flags_bak;
 	snd_flags_t rpl_snd_flags_bak;
 	snd_flags_t rpl_snd_flags_bak;
+	struct dest_info *dst;
 
 
 	shbuf=0;
 	shbuf=0;
 	msg_uri_bak.s=0; /* kill warnings */
 	msg_uri_bak.s=0; /* kill warnings */
@@ -184,15 +206,17 @@ static char *print_uac_request( struct cell *t, struct sip_msg *i_req,
 	path_bak.s=0;
 	path_bak.s=0;
 	path_bak.len=0;
 	path_bak.len=0;
 	path_backed_up=0;
 	path_backed_up=0;
+	dst=&t->uac[branch].request.dst;
 
 
 	/* ... we calculate branch ... */	
 	/* ... we calculate branch ... */	
 	if (!t_calc_branch(t, branch, i_req->add_to_branch_s,
 	if (!t_calc_branch(t, branch, i_req->add_to_branch_s,
 			&i_req->add_to_branch_len ))
 			&i_req->add_to_branch_len ))
 	{
 	{
 		LOG(L_ERR, "ERROR: print_uac_request: branch computation failed\n");
 		LOG(L_ERR, "ERROR: print_uac_request: branch computation failed\n");
+		ser_error=E_UNSPEC;
 		goto error00;
 		goto error00;
 	}
 	}
-
+	
 	/* ... update uri ... */
 	/* ... update uri ... */
 	msg_uri=GET_RURI(i_req);
 	msg_uri=GET_RURI(i_req);
 	if ((msg_uri->s!=uri->s) || (msg_uri->len!=uri->len)){
 	if ((msg_uri->s!=uri->s) || (msg_uri->len!=uri->len)){
@@ -210,6 +234,17 @@ static char *print_uac_request( struct cell *t, struct sip_msg *i_req,
 		i_req->path_vec=*path;
 		i_req->path_vec=*path;
 		path_backed_up=1;
 		path_backed_up=1;
 	}
 	}
+	/* backup dst uri  & zero it*/
+	dst_uri_bak=i_req->dst_uri;
+	i_req->dst_uri.s=0;
+	i_req->dst_uri.len=0;
+	if (likely(next_hop)){
+		/* set dst uri to next_hop for the on_branch route */
+		if (unlikely(set_dst_uri(i_req, next_hop)<0)){
+			ser_error=E_OUT_OF_MEM;
+			goto error03;
+		}
+	}
 
 
 #ifdef POSTPONE_MSG_CLONING
 #ifdef POSTPONE_MSG_CLONING
 	/* lumps can be set outside of the lock, make sure that we read
 	/* lumps can be set outside of the lock, make sure that we read
@@ -249,7 +284,39 @@ static char *print_uac_request( struct cell *t, struct sip_msg *i_req,
 	if (unlikely(has_tran_tmcbs(t, TMCB_REQUEST_FWDED)))
 	if (unlikely(has_tran_tmcbs(t, TMCB_REQUEST_FWDED)))
 		run_trans_callbacks( TMCB_REQUEST_FWDED , t, i_req, 0,
 		run_trans_callbacks( TMCB_REQUEST_FWDED , t, i_req, 0,
 								-i_req->REQ_METHOD);
 								-i_req->REQ_METHOD);
-
+	
+	if (likely( !(flags & UAC_DNS_FAILOVER_F) && i_req->dst_uri.s &&
+				i_req->dst_uri.len)){
+		/* no dns failover and non-empty dst_uri => use it as dst
+		  (on dns failover dns_h will be non-empty => next_hop will be
+		   ignored) */
+		next_hop=&i_req->dst_uri;
+	}
+	if (likely(next_hop!=0 || (flags & UAC_DNS_FAILOVER_F))){
+		/* next_hop present => use it for dns resolution */
+#ifdef USE_DNS_FAILOVER
+		if (uri2dst(&t->uac[branch].dns_h, dst, i_req,
+							next_hop?next_hop:uri, fproto) == 0)
+#else
+		/* dst filled from the uri & request (send_socket) */
+		if (uri2dst(dst, i_req, next_hop?next_hop:uri, fproto)==0)
+#endif
+		{
+			ser_error=E_BAD_ADDRESS;
+			goto error01;
+		}
+	} /* else next_hop==0 =>
+		no dst_uri / empty dst_uri and initial next_hop==0 =>
+		dst is pre-filled with a valid dst => use the pre-filled dst */
+	
+	/* check if send_sock is ok */
+	if (t->uac[branch].request.dst.send_sock==0) {
+		LOG(L_ERR, "ERROR: can't fwd to af %d, proto %d "
+			" (no corresponding listening socket)\n",
+			dst->to.s.sa_family, dst->proto );
+		ser_error=E_NO_SOCKET;
+		goto error01;
+	}
 	/* ... and build it now */
 	/* ... and build it now */
 	buf=build_req_buf_from_sip_req( i_req, len, dst, 0);
 	buf=build_req_buf_from_sip_req( i_req, len, dst, 0);
 #ifdef DBG_MSG_QA
 #ifdef DBG_MSG_QA
@@ -285,6 +352,7 @@ error01:
 	     /* Restore the lists from backups */
 	     /* Restore the lists from backups */
 	i_req->add_rm = add_rm_backup;
 	i_req->add_rm = add_rm_backup;
 	i_req->body_lumps = body_lumps_backup;
 	i_req->body_lumps = body_lumps_backup;
+error03:
 	/* restore the new_uri from the backup */
 	/* restore the new_uri from the backup */
 	if (uri_backed_up){
 	if (uri_backed_up){
 		i_req->new_uri=msg_uri_bak;
 		i_req->new_uri=msg_uri_bak;
@@ -294,6 +362,8 @@ error01:
 	if (unlikely(path_backed_up)){
 	if (unlikely(path_backed_up)){
 		i_req->path_vec=path_bak;
 		i_req->path_vec=path_bak;
 	}
 	}
+	reset_dst_uri(i_req); /* free dst_uri */
+	i_req->dst_uri=dst_uri_bak;
 
 
 error00:
 error00:
 	return shbuf;
 	return shbuf;
@@ -420,13 +490,29 @@ int add_blind_uac( /*struct cell *t*/ )
 	return 1; /* success */
 	return 1; /* success */
 }
 }
 
 
-/* introduce a new uac to transaction; returns its branch id (>=0)
-   or error (<0); it doesn't send a message yet -- a reply to it
-   might interfere with the processes of adding multiple branches;
-   On error returns <0 & sets ser_error to the same value
+/** introduce a new uac to transaction.
+ *  It doesn't send a message yet -- a reply to it might interfere with the
+ *  processes of adding multiple branches; On error returns <0 & sets ser_error
+ *  to the same value.
+ *  @param t - transaction
+ *  @param request - corresponding sip_mst, must be non-null, flags might be
+ *                   modified (on_branch route).
+ *  @param uri - uri used for the branch (must be non-null).
+ *  @param next_hop - next_hop in sip uri format. If null and proxy is null
+ *                    too, the uri will be used 
+ *  @param path     - path vector (list of route like destinations in sip
+ *                     uri format, e.g.: "<sip:1.2.3.4;lr>, <sip:5.6.7.8;lr>").
+ *  @param proxy    - proxy structure. If non-null it takes precedence over
+ *                    next_hop/uri and it will be used for forwarding.
+ *  @param proto    - forced protocol for forwarding (overrides the protocol
+ *                    in next_hop/uri or proxy if != PROTO_NONE).
+ *  @param flags    - special flags passed to prepare_uac_request().
+ *                    @see prepare_uac_request().
+ *  @returns branch id (>=0) or error (<0)
 */
 */
-int add_uac( struct cell *t, struct sip_msg *request, str *uri, str* next_hop,
-				str* path, struct proxy_l *proxy, int proto )
+static int add_uac( struct cell *t, struct sip_msg *request, str *uri,
+					str* next_hop, str* path, struct proxy_l *proxy,
+					int proto, int flags)
 {
 {
 
 
 	int ret;
 	int ret;
@@ -460,36 +546,16 @@ int add_uac( struct cell *t, struct sip_msg *request, str *uri, str* next_hop,
 								t->uac[branch].request.dst.proto);
 								t->uac[branch].request.dst.proto);
 		t->uac[branch].request.dst.send_flags=request?
 		t->uac[branch].request.dst.send_flags=request?
 												request->fwd_send_flags:0;
 												request->fwd_send_flags:0;
+		next_hop=0;
 	}else {
 	}else {
-#ifdef USE_DNS_FAILOVER
-		if (uri2dst(&t->uac[branch].dns_h, &t->uac[branch].request.dst,
-					request, next_hop?next_hop:uri, proto) == 0)
-#else
-		/* dst filled from the uri & request (send_socket) */
-		if (uri2dst(&t->uac[branch].request.dst, request,
-						next_hop ? next_hop: uri, proto)==0)
-#endif
-		{
-			ret=ser_error=E_BAD_ADDRESS;
-			goto error;
-		}
-	}
-	
-	/* check if send_sock is ok */
-	if (t->uac[branch].request.dst.send_sock==0) {
-		LOG(L_ERR, "ERROR: add_uac: can't fwd to af %d, proto %d "
-			" (no corresponding listening socket)\n",
-			t->uac[branch].request.dst.to.s.sa_family, 
-			t->uac[branch].request.dst.proto );
-		ret=ser_error=E_NO_SOCKET;
-		goto error01;
+		next_hop= next_hop?next_hop:uri;
 	}
 	}
 
 
 	/* now message printing starts ... */
 	/* now message printing starts ... */
-	shbuf=print_uac_request(t, request, branch, uri, path,
-							&len, &t->uac[branch].request.dst);
+	shbuf=prepare_uac_request(t, request, branch, uri, path, next_hop,
+								proto, flags, &len);
 	if (!shbuf) {
 	if (!shbuf) {
-		ret=ser_error=E_OUT_OF_MEM;
+		ret=ser_error<0?ser_error:E_BUG;
 		goto error01;
 		goto error01;
 	}
 	}
 
 
@@ -692,7 +758,7 @@ int add_uac_dns_fallback(struct cell *t, struct sip_msg* msg,
 				 *  must be changed and the send_socket might be different =>
 				 *  must be changed and the send_socket might be different =>
 				 *  re-create the whole uac */
 				 *  re-create the whole uac */
 				ret=add_uac(t,  msg, &old_uac->uri, 0, &old_uac->path, 0,
 				ret=add_uac(t,  msg, &old_uac->uri, 0, &old_uac->path, 0,
-							old_uac->request.dst.proto);
+							old_uac->request.dst.proto, UAC_DNS_FAILOVER_F);
 
 
 			if (ret<0){
 			if (ret<0){
 				/* failed, delete the copied dns_h */
 				/* failed, delete the copied dns_h */
@@ -729,7 +795,9 @@ int e2e_cancel_branch( struct sip_msg *cancel_msg, struct cell *t_cancel,
 	/* note -- there is a gap in proxy stats -- we don't update 
 	/* note -- there is a gap in proxy stats -- we don't update 
 	   proxy stats with CANCEL (proxy->ok, proxy->tx, etc.)
 	   proxy stats with CANCEL (proxy->ok, proxy->tx, etc.)
 	*/
 	*/
-
+	
+	/* set same dst as the invite */
+	t_cancel->uac[branch].request.dst=t_invite->uac[branch].request.dst;
 	/* print */
 	/* print */
 	if (cfg_get(tm, tm_cfg, reparse_invite)) {
 	if (cfg_get(tm, tm_cfg, reparse_invite)) {
 		/* buffer is built localy from the INVITE which was sent out */
 		/* buffer is built localy from the INVITE which was sent out */
@@ -742,14 +810,17 @@ int e2e_cancel_branch( struct sip_msg *cancel_msg, struct cell *t_cancel,
 			LOG(L_WARN, "WARNING: e2e_cancel_branch: CANCEL is built locally, "
 			LOG(L_WARN, "WARNING: e2e_cancel_branch: CANCEL is built locally, "
 			"thus lumps are not applied to the message!\n");
 			"thus lumps are not applied to the message!\n");
 		}
 		}
-		shbuf=build_local_reparse( t_invite, branch, &len, CANCEL, CANCEL_LEN, &t_invite->to);
+		shbuf=build_local_reparse( t_invite, branch, &len, CANCEL,
+									CANCEL_LEN, &t_invite->to);
 
 
 	} else {
 	} else {
 		/* buffer is constructed from the received CANCEL with applying lumps */
 		/* buffer is constructed from the received CANCEL with applying lumps */
-		shbuf=print_uac_request( t_cancel, cancel_msg, branch,
-							&t_invite->uac[branch].uri,
-							&t_invite->uac[branch].path,
-							&len, &t_invite->uac[branch].request.dst);
+		/*  t_cancel...request.dst is already filled (see above) */
+		shbuf=prepare_uac_request( t_cancel, cancel_msg, branch,
+									&t_invite->uac[branch].uri,
+									&t_invite->uac[branch].path,
+									0, PROTO_NONE, 0,
+									&len);
 	}
 	}
 
 
 	if (!shbuf) {
 	if (!shbuf) {
@@ -759,7 +830,6 @@ int e2e_cancel_branch( struct sip_msg *cancel_msg, struct cell *t_cancel,
 	}
 	}
 	
 	
 	/* install buffer */
 	/* install buffer */
-	t_cancel->uac[branch].request.dst=t_invite->uac[branch].request.dst;
 	t_cancel->uac[branch].request.buffer=shbuf;
 	t_cancel->uac[branch].request.buffer=shbuf;
 	t_cancel->uac[branch].request.buffer_len=len;
 	t_cancel->uac[branch].request.buffer_len=len;
 	t_cancel->uac[branch].uri.s=t_cancel->uac[branch].request.buffer+
 	t_cancel->uac[branch].uri.s=t_cancel->uac[branch].request.buffer+
@@ -1158,7 +1228,7 @@ int t_forward_nonack( struct cell *t, struct sip_msg* p_msg ,
 #endif
 #endif
 		try_new=1;
 		try_new=1;
 		branch_ret=add_uac( t, p_msg, GET_RURI(p_msg), GET_NEXT_HOP(p_msg),
 		branch_ret=add_uac( t, p_msg, GET_RURI(p_msg), GET_NEXT_HOP(p_msg),
-							&p_msg->path_vec, proxy, proto );
+							&p_msg->path_vec, proxy, proto, 0);
 		if (branch_ret>=0) 
 		if (branch_ret>=0) 
 			added_branches |= 1<<branch_ret;
 			added_branches |= 1<<branch_ret;
 		else
 		else
@@ -1174,7 +1244,7 @@ int t_forward_nonack( struct cell *t, struct sip_msg* p_msg ,
 
 
 		branch_ret=add_uac( t, p_msg, &current_uri,
 		branch_ret=add_uac( t, p_msg, &current_uri,
 							(dst_uri.len) ? (&dst_uri) : &current_uri,
 							(dst_uri.len) ? (&dst_uri) : &current_uri,
-							&path, proxy, proto);
+							&path, proxy, proto, 0);
 		/* pick some of the errors in case things go wrong;
 		/* pick some of the errors in case things go wrong;
 		   note that picking lowest error is just as good as
 		   note that picking lowest error is just as good as
 		   any other algorithm which picks any other negative
 		   any other algorithm which picks any other negative

+ 2 - 0
modules/tm/t_fwd.h

@@ -59,8 +59,10 @@ char *print_uac_request( struct cell *t, struct sip_msg *i_req,
 */
 */
 void e2e_cancel( struct sip_msg *cancel_msg, struct cell *t_cancel, struct cell *t_invite );
 void e2e_cancel( struct sip_msg *cancel_msg, struct cell *t_cancel, struct cell *t_invite );
 int e2e_cancel_branch( struct sip_msg *cancel_msg, struct cell *t_cancel, struct cell *t_invite, int branch );
 int e2e_cancel_branch( struct sip_msg *cancel_msg, struct cell *t_cancel, struct cell *t_invite, int branch );
+/*
 int add_uac(struct cell *t, struct sip_msg *request, str *uri, str* next_hop,
 int add_uac(struct cell *t, struct sip_msg *request, str *uri, str* next_hop,
 				str* path, struct proxy_l *proxy, int proto );
 				str* path, struct proxy_l *proxy, int proto );
+*/
 #ifdef USE_DNS_FAILOVER
 #ifdef USE_DNS_FAILOVER
 int add_uac_dns_fallback( struct cell *t, struct sip_msg* msg, 
 int add_uac_dns_fallback( struct cell *t, struct sip_msg* msg, 
 									struct ua_client* old_uac,
 									struct ua_client* old_uac,