Module: sip-router
Branch: andrei/cancel_reason
Commit: 23e0d801e5717586da6c696460f5a30d04467028
URL:
http://git.sip-router.org/cgi-bin/gitweb.cgi/sip-router/?a=commit;h=23e0d80…
Author: Andrei Pelinescu-Onciul <andrei(a)iptel.org>
Committer: Andrei Pelinescu-Onciul <andrei(a)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 */