From a181544299291664b241ae09be3092be67467546 Mon Sep 17 00:00:00 2001 From: Mark Michelson Date: Wed, 28 Aug 2013 15:43:15 +0000 Subject: [PATCH] Fix dialog matching in the SIP distributor. Dialog matching is performed in the distributor for the sole purpose of retrieving an associated serializer so the request may be serialized. This patch fixes two problems. First, incoming CANCEL requests that had no to-tag (which really should be *all* CANCEL requests) would not match with a dialog. An earlier bug fix to deal with early CANCEL requests would result in the CANCEL being replied to with a 481. The fix for this is to find the matching INVITE transaction and get the dialog from that transaction. Second, no SIP responses were matching dialogs. This is because we were inverting the tags that we were passing into PJSIP's dialog finding function. This logic has been corrected by setting local and remote tag variables based on whether the incoming message is a request or response. ........ Merged revisions 397854 from http://svn.asterisk.org/svn/asterisk/branches/12 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@397855 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- res/res_pjsip/pjsip_distributor.c | 54 ++++++++++++++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) diff --git a/res/res_pjsip/pjsip_distributor.c b/res/res_pjsip/pjsip_distributor.c index 7597ae79e5..d7a92abde6 100644 --- a/res/res_pjsip/pjsip_distributor.c +++ b/res/res_pjsip/pjsip_distributor.c @@ -92,9 +92,61 @@ struct ast_sip_endpoint *ast_sip_dialog_get_endpoint(pjsip_dialog *dlg) return dist->endpoint; } +static pjsip_dialog *find_dialog(pjsip_rx_data *rdata) +{ + pj_str_t tsx_key; + pjsip_transaction *tsx; + pjsip_dialog *dlg; + pj_str_t *local_tag; + pj_str_t *remote_tag; + + if (rdata->msg_info.msg->type == PJSIP_REQUEST_MSG) { + local_tag = &rdata->msg_info.to->tag; + remote_tag = &rdata->msg_info.from->tag; + } else { + local_tag = &rdata->msg_info.from->tag; + remote_tag = &rdata->msg_info.to->tag; + } + + /* We can only call the convenient method for + * 1) responses + * 2) non-CANCEL requests + * 3) CANCEL requests with a to-tag + */ + if (rdata->msg_info.msg->type == PJSIP_RESPONSE_MSG || + pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_cancel_method) || + rdata->msg_info.to->tag.slen != 0) { + return pjsip_ua_find_dialog(&rdata->msg_info.cid->id, local_tag, + remote_tag, PJ_TRUE); + } + + /* Incoming CANCEL without a to-tag can't use same method for finding the + * dialog. Instead, we have to find the matching INVITE transaction and + * then get the dialog from the transaction + */ + pjsip_tsx_create_key(rdata->tp_info.pool, &tsx_key, PJSIP_ROLE_UAS, + pjsip_get_invite_method(), rdata); + + tsx = pjsip_tsx_layer_find_tsx(&tsx_key, PJ_TRUE); + if (!tsx) { + ast_log(LOG_ERROR, "Could not find matching INVITE transaction for CANCEL request\n"); + return NULL; + } + + dlg = pjsip_tsx_get_dlg(tsx); + pj_mutex_unlock(tsx->mutex); + + if (!dlg) { + return NULL; + } + + pjsip_dlg_inc_lock(dlg); + return dlg; +} + static pj_bool_t distributor(pjsip_rx_data *rdata) { - pjsip_dialog *dlg = pjsip_ua_find_dialog(&rdata->msg_info.cid->id, &rdata->msg_info.to->tag, &rdata->msg_info.from->tag, PJ_TRUE); + pjsip_dialog *dlg = find_dialog(rdata); struct distributor_dialog_data *dist = NULL; struct ast_taskprocessor *serializer = NULL; pjsip_rx_data *clone; -- 2.47.3