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