Parcourir la source

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 il y a 16 ans
Parent
commit
44f7bf6214
2 fichiers modifiés avec 125 ajouts et 53 suppressions
  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
  *              to 0 to revert the change. (Miklos)
  * 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"
@@ -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".
- * 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 i_req - corresponding sip_msg, must be non-null, flags might be
  *                be modified (on_branch route)
@@ -153,16 +167,22 @@ unsigned int get_on_branch(void)
  * @param uri
  * @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>")
+ * @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 
- *              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;
 	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;
 	int parsed_uri_ok_bak, uri_backed_up;
 	str msg_uri_bak;
+	str dst_uri_bak;
 	str path_bak;
 	int path_backed_up;
 	int backup_route_type;
 	snd_flags_t fwd_snd_flags_bak;
 	snd_flags_t rpl_snd_flags_bak;
+	struct dest_info *dst;
 
 	shbuf=0;
 	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.len=0;
 	path_backed_up=0;
+	dst=&t->uac[branch].request.dst;
 
 	/* ... we calculate branch ... */	
 	if (!t_calc_branch(t, branch, i_req->add_to_branch_s,
 			&i_req->add_to_branch_len ))
 	{
 		LOG(L_ERR, "ERROR: print_uac_request: branch computation failed\n");
+		ser_error=E_UNSPEC;
 		goto error00;
 	}
-
+	
 	/* ... update uri ... */
 	msg_uri=GET_RURI(i_req);
 	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;
 		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
 	/* 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)))
 		run_trans_callbacks( TMCB_REQUEST_FWDED , t, i_req, 0,
 								-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 */
 	buf=build_req_buf_from_sip_req( i_req, len, dst, 0);
 #ifdef DBG_MSG_QA
@@ -285,6 +352,7 @@ error01:
 	     /* Restore the lists from backups */
 	i_req->add_rm = add_rm_backup;
 	i_req->body_lumps = body_lumps_backup;
+error03:
 	/* restore the new_uri from the backup */
 	if (uri_backed_up){
 		i_req->new_uri=msg_uri_bak;
@@ -294,6 +362,8 @@ error01:
 	if (unlikely(path_backed_up)){
 		i_req->path_vec=path_bak;
 	}
+	reset_dst_uri(i_req); /* free dst_uri */
+	i_req->dst_uri=dst_uri_bak;
 
 error00:
 	return shbuf;
@@ -420,13 +490,29 @@ int add_blind_uac( /*struct cell *t*/ )
 	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;
@@ -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.send_flags=request?
 												request->fwd_send_flags:0;
+		next_hop=0;
 	}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 ... */
-	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) {
-		ret=ser_error=E_OUT_OF_MEM;
+		ret=ser_error<0?ser_error:E_BUG;
 		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 =>
 				 *  re-create the whole uac */
 				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){
 				/* 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 
 	   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 */
 	if (cfg_get(tm, tm_cfg, reparse_invite)) {
 		/* 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, "
 			"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 {
 		/* 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) {
@@ -759,7 +830,6 @@ int e2e_cancel_branch( struct sip_msg *cancel_msg, struct cell *t_cancel,
 	}
 	
 	/* 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_len=len;
 	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
 		try_new=1;
 		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) 
 			added_branches |= 1<<branch_ret;
 		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,
 							(dst_uri.len) ? (&dst_uri) : &current_uri,
-							&path, proxy, proto);
+							&path, proxy, proto, 0);
 		/* pick some of the errors in case things go wrong;
 		   note that picking lowest error is just as good as
 		   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 );
 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,
 				str* path, struct proxy_l *proxy, int proto );
+*/
 #ifdef USE_DNS_FAILOVER
 int add_uac_dns_fallback( struct cell *t, struct sip_msg* msg, 
 									struct ua_client* old_uac,