Selaa lähdekoodia

tm: Reason header copy for received CANCELs

When canceling branches due to a received CANCEL, use the Reason
headers in the received CANCEL (all the Reason headers from the
received CANCEL will be copied in the generated CANCELs, see
RFC3326 for more details).
Andrei Pelinescu-Onciul 15 vuotta sitten
vanhempi
commit
23e0d801e5
3 muutettua tiedostoa jossa 45 lisäystä ja 8 poistoa
  1. 8 3
      modules/tm/t_fwd.c
  2. 33 4
      modules/tm/t_msgbuilder.c
  3. 4 1
      modules/tm/t_reply.c

+ 8 - 3
modules/tm/t_fwd.c

@@ -951,13 +951,15 @@ error:
 
 
 
 
 
 
-void e2e_cancel( struct sip_msg *cancel_msg, 
+void e2e_cancel( struct sip_msg *cancel_msg,
 	struct cell *t_cancel, struct cell *t_invite )
 	struct cell *t_cancel, struct cell *t_invite )
 {
 {
 	branch_bm_t cancel_bm;
 	branch_bm_t cancel_bm;
 #ifndef E2E_CANCEL_HOP_BY_HOP
 #ifndef E2E_CANCEL_HOP_BY_HOP
 	branch_bm_t tmp_bm;
 	branch_bm_t tmp_bm;
-#endif
+#else /* def E2E_CANCEL_HOP_BY_HOP */
+	struct cancel_reason reason;
+#endif /* E2E_CANCEL_HOP_BY_HOP */
 	int i;
 	int i;
 	int lowest_error;
 	int lowest_error;
 	int ret;
 	int ret;
@@ -1002,6 +1004,9 @@ void e2e_cancel( struct sip_msg *cancel_msg,
 	 * have 0 branches and we check for the branch number in 
 	 * have 0 branches and we check for the branch number in 
 	 * t_reply_matching() ).
 	 * t_reply_matching() ).
 	 */
 	 */
+	init_cancel_reason(&reason);
+	reason.cause=CANCEL_REAS_RCVD_CANCEL;
+	reason.u.e2e_cancel=cancel_msg;
 	for (i=0; i<t_invite->nr_of_outgoings; i++)
 	for (i=0; i<t_invite->nr_of_outgoings; i++)
 		if (cancel_bm & (1<<i)) {
 		if (cancel_bm & (1<<i)) {
 			/* it's safe to get the reply lock since e2e_cancel is
 			/* it's safe to get the reply lock since e2e_cancel is
@@ -1011,7 +1016,7 @@ void e2e_cancel( struct sip_msg *cancel_msg,
 			ret=cancel_branch(
 			ret=cancel_branch(
 				t_invite,
 				t_invite,
 				i,
 				i,
-				0,
+				&reason,
 				cfg_get(tm,tm_cfg, cancel_b_flags)
 				cfg_get(tm,tm_cfg, cancel_b_flags)
 					| ((t_invite->uac[i].request.buffer==NULL)?
 					| ((t_invite->uac[i].request.buffer==NULL)?
 						F_CANCEL_B_FAKE_REPLY:0) /* blind UAC? */
 						F_CANCEL_B_FAKE_REPLY:0) /* blind UAC? */

+ 33 - 4
modules/tm/t_msgbuilder.c

@@ -104,6 +104,7 @@ char *build_local(struct cell *Trans,unsigned int branch,
 	str via_id;
 	str via_id;
 	struct hostport hp;
 	struct hostport hp;
 	int reason_len, code_len;
 	int reason_len, code_len;
+	struct hdr_field *reas1, *reas_last;
 
 
 	/* init */
 	/* init */
 	via_id.s=0;
 	via_id.s=0;
@@ -169,6 +170,7 @@ char *build_local(struct cell *Trans,unsigned int branch,
 	/* Content Length, EoM */
 	/* Content Length, EoM */
 	*len+=CONTENT_LENGTH_LEN+1 + CRLF_LEN;
 	*len+=CONTENT_LENGTH_LEN+1 + CRLF_LEN;
 	reason_len = 0;
 	reason_len = 0;
+	reas1 = 0;
 	/* compute reason size */
 	/* compute reason size */
 	if (reason && reason->cause != CANCEL_REAS_UNKNOWN){
 	if (reason && reason->cause != CANCEL_REAS_UNKNOWN){
 		if (likely(reason->cause > 0)){
 		if (likely(reason->cause > 0)){
@@ -179,7 +181,14 @@ char *build_local(struct cell *Trans,unsigned int branch,
 				CRLF_LEN;
 				CRLF_LEN;
 		} else if (reason->cause == CANCEL_REAS_RCVD_CANCEL &&
 		} else if (reason->cause == CANCEL_REAS_RCVD_CANCEL &&
 					reason->u.e2e_cancel) {
 					reason->u.e2e_cancel) {
-			/* FIXME: TODO */
+			/* parse the entire cancel, to get all the Reason headers */
+			parse_headers(reason->u.e2e_cancel, HDR_EOH_F, 0);
+			for(hdr=get_hdr(reason->u.e2e_cancel, HDR_REASON_T), reas1=hdr;
+					hdr; hdr=next_sibling_hdr(hdr)) {
+				/* hdr->len includes CRLF */
+				reason_len += hdr->len;
+				reas_last=hdr;
+			}
 		} else if (unlikely(reason->cause != -1))
 		} else if (unlikely(reason->cause != -1))
 			BUG("unhandled reason cause %d\n", reason->cause);
 			BUG("unhandled reason cause %d\n", reason->cause);
 	}
 	}
@@ -243,7 +252,12 @@ char *build_local(struct cell *Trans,unsigned int branch,
 			}
 			}
 			append_str(p, CRLF, CRLF_LEN);
 			append_str(p, CRLF, CRLF_LEN);
 		} else if (reason->cause == CANCEL_REAS_RCVD_CANCEL) {
 		} else if (reason->cause == CANCEL_REAS_RCVD_CANCEL) {
-			/* FIXME: handle cancel */
+			for(hdr=reas1; hdr; hdr=next_sibling_hdr(hdr)) {
+				/* hdr->len includes CRLF */
+				append_str(p, hdr->name.s, hdr->len);
+				if (likely(hdr==reas_last))
+					break;
+			}
 		}
 		}
 	}
 	}
 	append_str(p, CRLF, CRLF_LEN); /* msg. end */
 	append_str(p, CRLF, CRLF_LEN); /* msg. end */
@@ -274,6 +288,7 @@ char *build_local_reparse(struct cell *Trans,unsigned int branch,
 	enum _hdr_types_t	hf_type;
 	enum _hdr_types_t	hf_type;
 	int	first_via, to_len;
 	int	first_via, to_len;
 	int cancel_buf_len, reason_len, code_len;
 	int cancel_buf_len, reason_len, code_len;
+	struct hdr_field *reas1, *reas_last, *hdr;
 
 
 	invite_buf = Trans->uac[branch].request.buffer;
 	invite_buf = Trans->uac[branch].request.buffer;
 	invite_len = Trans->uac[branch].request.buffer_len;
 	invite_len = Trans->uac[branch].request.buffer_len;
@@ -289,6 +304,7 @@ char *build_local_reparse(struct cell *Trans,unsigned int branch,
 	}
 	}
 	
 	
 	reason_len = 0;
 	reason_len = 0;
+	reas1 = 0;
 	/* compute reason size */
 	/* compute reason size */
 	if (reason && reason->cause != CANCEL_REAS_UNKNOWN){
 	if (reason && reason->cause != CANCEL_REAS_UNKNOWN){
 		if (likely(reason->cause > 0)){
 		if (likely(reason->cause > 0)){
@@ -299,7 +315,14 @@ char *build_local_reparse(struct cell *Trans,unsigned int branch,
 				CRLF_LEN;
 				CRLF_LEN;
 		} else if (reason->cause == CANCEL_REAS_RCVD_CANCEL &&
 		} else if (reason->cause == CANCEL_REAS_RCVD_CANCEL &&
 					reason->u.e2e_cancel) {
 					reason->u.e2e_cancel) {
-			/* FIXME: TODO */
+			/* parse the entire cancel, to get all the Reason headers */
+			parse_headers(reason->u.e2e_cancel, HDR_EOH_F, 0);
+			for(hdr=get_hdr(reason->u.e2e_cancel, HDR_REASON_T), reas1=hdr;
+					hdr; hdr=next_sibling_hdr(hdr)) {
+				/* hdr->len includes CRLF */
+				reason_len += hdr->len;
+				reas_last=hdr;
+			}
 		} else if (unlikely(reason->cause != -1))
 		} else if (unlikely(reason->cause != -1))
 			BUG("unhandled reason cause %d\n", reason->cause);
 			BUG("unhandled reason cause %d\n", reason->cause);
 	}
 	}
@@ -424,9 +447,15 @@ char *build_local_reparse(struct cell *Trans,unsigned int branch,
 						}
 						}
 						append_str(d, CRLF, CRLF_LEN);
 						append_str(d, CRLF, CRLF_LEN);
 					} else if (reason->cause == CANCEL_REAS_RCVD_CANCEL) {
 					} else if (reason->cause == CANCEL_REAS_RCVD_CANCEL) {
-						/* FIXME: handle cancel */
+						for(hdr=reas1; hdr; hdr=next_sibling_hdr(hdr)) {
+							/* hdr->len includes CRLF */
+							append_str(d, hdr->name.s, hdr->len);
+							if (likely(hdr==reas_last))
+								break;
+						}
 					}
 					}
 				}
 				}
+				/* final (end-of-headers) CRLF */
 				append_str(d, CRLF, CRLF_LEN);
 				append_str(d, CRLF, CRLF_LEN);
 				*len = d - cancel_buf;
 				*len = d - cancel_buf;
 				/* LOG(L_DBG, "DBG: build_local: %.*s\n", *len, cancel_buf); */
 				/* LOG(L_DBG, "DBG: build_local: %.*s\n", *len, cancel_buf); */

+ 4 - 1
modules/tm/t_reply.c

@@ -2035,12 +2035,15 @@ int reply_received( struct sip_msg  *p_msg )
 				SEND_BUFFER( &uac->local_cancel );
 				SEND_BUFFER( &uac->local_cancel );
 #endif
 #endif
 				/* retrs. should be already started so do nothing */
 				/* retrs. should be already started so do nothing */
-			}else if (atomic_cmpxchg_long((void*)&uac->local_cancel.buffer, 0, 
+			}else if (atomic_cmpxchg_long((void*)&uac->local_cancel.buffer, 0,
 										(long)BUSY_BUFFER)==0){
 										(long)BUSY_BUFFER)==0){
 				/* try to rebuild it if empty (not set or marked as BUSY).
 				/* try to rebuild it if empty (not set or marked as BUSY).
 				 * if BUSY or set just exit, a cancel will be (or was) sent 
 				 * if BUSY or set just exit, a cancel will be (or was) sent 
 				 * shortly on this branch */
 				 * shortly on this branch */
 				DBG("tm: reply_received: branch CANCEL created\n");
 				DBG("tm: reply_received: branch CANCEL created\n");
+				/* note that in this case we do not know the reason
+				   (it could be a final reply or a received cancel)
+				   and we don't want to wait for it => no reason */
 				cancel_branch(t, branch, 0, F_CANCEL_B_FORCE_C);
 				cancel_branch(t, branch, 0, F_CANCEL_B_FORCE_C);
 			}
 			}
 			goto done; /* nothing to do */
 			goto done; /* nothing to do */