瀏覽代碼

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 年之前
父節點
當前提交
23e0d801e5
共有 3 個文件被更改,包括 45 次插入8 次删除
  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 )
 {
 	branch_bm_t cancel_bm;
 #ifndef E2E_CANCEL_HOP_BY_HOP
 	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 lowest_error;
 	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 
 	 * 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++)
 		if (cancel_bm & (1<<i)) {
 			/* 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(
 				t_invite,
 				i,
-				0,
+				&reason,
 				cfg_get(tm,tm_cfg, cancel_b_flags)
 					| ((t_invite->uac[i].request.buffer==NULL)?
 						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;
 	struct hostport hp;
 	int reason_len, code_len;
+	struct hdr_field *reas1, *reas_last;
 
 	/* init */
 	via_id.s=0;
@@ -169,6 +170,7 @@ char *build_local(struct cell *Trans,unsigned int branch,
 	/* Content Length, EoM */
 	*len+=CONTENT_LENGTH_LEN+1 + CRLF_LEN;
 	reason_len = 0;
+	reas1 = 0;
 	/* compute reason size */
 	if (reason && reason->cause != CANCEL_REAS_UNKNOWN){
 		if (likely(reason->cause > 0)){
@@ -179,7 +181,14 @@ char *build_local(struct cell *Trans,unsigned int branch,
 				CRLF_LEN;
 		} else if (reason->cause == CANCEL_REAS_RCVD_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))
 			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);
 		} 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 */
@@ -274,6 +288,7 @@ char *build_local_reparse(struct cell *Trans,unsigned int branch,
 	enum _hdr_types_t	hf_type;
 	int	first_via, to_len;
 	int cancel_buf_len, reason_len, code_len;
+	struct hdr_field *reas1, *reas_last, *hdr;
 
 	invite_buf = Trans->uac[branch].request.buffer;
 	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;
+	reas1 = 0;
 	/* compute reason size */
 	if (reason && reason->cause != CANCEL_REAS_UNKNOWN){
 		if (likely(reason->cause > 0)){
@@ -299,7 +315,14 @@ char *build_local_reparse(struct cell *Trans,unsigned int branch,
 				CRLF_LEN;
 		} else if (reason->cause == CANCEL_REAS_RCVD_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))
 			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);
 					} 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);
 				*len = d - 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 );
 #endif
 				/* 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){
 				/* 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 
 				 * shortly on this branch */
 				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);
 			}
 			goto done; /* nothing to do */