[sr-dev] git:andrei/cancel_reason: tm: Reason header copy for received CANCELs

Andrei Pelinescu-Onciul andrei at iptel.org
Tue Mar 2 17:31:32 CET 2010


Module: sip-router
Branch: andrei/cancel_reason
Commit: 23e0d801e5717586da6c696460f5a30d04467028
URL:    http://git.sip-router.org/cgi-bin/gitweb.cgi/sip-router/?a=commit;h=23e0d801e5717586da6c696460f5a30d04467028

Author: Andrei Pelinescu-Onciul <andrei at iptel.org>
Committer: Andrei Pelinescu-Onciul <andrei at iptel.org>
Date:   Tue Mar  2 17:28:16 2010 +0100

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).

---

 modules/tm/t_fwd.c        |   11 ++++++++---
 modules/tm/t_msgbuilder.c |   37 +++++++++++++++++++++++++++++++++----
 modules/tm/t_reply.c      |    5 ++++-
 3 files changed, 45 insertions(+), 8 deletions(-)

diff --git a/modules/tm/t_fwd.c b/modules/tm/t_fwd.c
index 4f7cb02..0e1a00e 100644
--- a/modules/tm/t_fwd.c
+++ b/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? */
diff --git a/modules/tm/t_msgbuilder.c b/modules/tm/t_msgbuilder.c
index bf49c64..4ccf3d2 100644
--- a/modules/tm/t_msgbuilder.c
+++ b/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); */
diff --git a/modules/tm/t_reply.c b/modules/tm/t_reply.c
index a42820e..6ee3fae 100644
--- a/modules/tm/t_reply.c
+++ b/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 */




More information about the sr-dev mailing list