From aec816dad7302dd6d2709258d212bd70a9c8e7ea Mon Sep 17 00:00:00 2001 From: Donat Zenichev Date: Thu, 26 Jan 2023 11:43:01 +0100 Subject: [PATCH] MT#56321 Add 'Allow:' header to the 200OK, if present in the request We have to take care of keeping the actual 'Allow:' header in the request, if the incoming request has had it. One of the use cases for that is for example the INVITE coming to the AA, when we must respond with the 200OK, but there is no 'Allow:' header inside the 200OK. Certain systems can be confused by that, even though the RFCs are not forcing us to do so. Which can even lead to an impossibility to use a normal call clearing with the BYE method, from behalf of the caller. Change-Id: I9bafb89e4aa5e53077450068f847c07a497b43f1 --- core/AmBasicSipDialog.cpp | 102 +++++++++++++++++++++++--------------- core/AmBasicSipDialog.h | 6 +++ 2 files changed, 69 insertions(+), 39 deletions(-) diff --git a/core/AmBasicSipDialog.cpp b/core/AmBasicSipDialog.cpp index 4432e1aa..067a0177 100644 --- a/core/AmBasicSipDialog.cpp +++ b/core/AmBasicSipDialog.cpp @@ -306,43 +306,49 @@ void AmBasicSipDialog::onRxRequest(const AmSipRequest& req) { DBG("AmBasicSipDialog::onRxRequest(req = %s)\n", req.method.c_str()); - if(logger && (req.method != SIP_METH_ACK)) { - // log only non-initial received requests, the initial one is already logged - // or will be logged at application level (problem with SBCSimpleRelay) + if (logger && (req.method != SIP_METH_ACK)) { + /* log only non-initial received requests, the initial one is already logged + * or will be logged at application level (problem with SBCSimpleRelay) */ if (!callid.empty()) req.log(logger); } - if(!onRxReqSanity(req)) + if (!onRxReqSanity(req)) return; - + uas_trans[req.cseq] = req; - - // target refresh requests - if (req.from_uri.length() && + + /* target refresh requests */ + if (req.from_uri.length() && (remote_uri.empty() || - (req.method == SIP_METH_INVITE || - req.method == SIP_METH_UPDATE || - req.method == SIP_METH_SUBSCRIBE || - req.method == SIP_METH_NOTIFY))) { - - // refresh the target + (req.method == SIP_METH_INVITE || + req.method == SIP_METH_UPDATE || + req.method == SIP_METH_SUBSCRIBE || + req.method == SIP_METH_NOTIFY) + ) + ) { + + /* refresh the target */ if (remote_uri != req.from_uri) { setRemoteUri(req.from_uri); - if(nat_handling && req.first_hop) { - string nh = req.remote_ip + ":" - + int2str(req.remote_port) - + "/" + req.trsp; - setNextHop(nh); - setNextHop1stReq(false); + + if (nat_handling && req.first_hop) { + string nh = req.remote_ip + ":" + + int2str(req.remote_port) + + "/" + req.trsp; + setNextHop(nh); + setNextHop1stReq(false); } } - string ua = getHeader(req.hdrs,"User-Agent"); + string ua = getHeader(req.hdrs, SIP_HDR_USER_AGENT); setRemoteUA(ua); + + string allow = getHeader(req.hdrs, SIP_HDR_ALLOW); + setRemoteAllowHf(allow); } - - // Dlg not yet initialized? - if(callid.empty()){ + + /* Dlg not yet initialized? */ + if (callid.empty()) { user = req.user; domain = req.domain; @@ -355,9 +361,14 @@ void AmBasicSipDialog::onRxRequest(const AmSipRequest& req) setRouteSet( req.route ); set1stBranch( req.via_branch ); setOutboundInterface( req.local_if ); + + if (allow_hf.empty()) { /* if Allow hf is still empty */ + string allow = getHeader(req.hdrs, SIP_HDR_ALLOW); + setRemoteAllowHf(allow); + } } - if(onRxReqStatus(req) && hdl) + if (onRxReqStatus(req) && hdl) hdl->onSipRequest(req); } @@ -584,7 +595,8 @@ int AmBasicSipDialog::reply(const AmSipRequest& req, int flags) { TransMap::const_iterator t_it = uas_trans.find(req.cseq); - if(t_it == uas_trans.end()){ + + if (t_it == uas_trans.end()) { ERROR("could not find any transaction matching request cseq\n"); ERROR("request cseq=%i; reply code=%i; callid=%s; local_tag=%s; " "remote_tag=%s\n", @@ -593,29 +605,41 @@ int AmBasicSipDialog::reply(const AmSipRequest& req, log_stacktrace(L_ERR); return -1; } + DBG("reply: transaction found!\n"); - + AmSipReply reply; reply.code = code; reply.reason = reason; reply.tt = req.tt; - if((code > 100) && !(flags & SIP_FLAGS_NOTAG)) - reply.to_tag = ext_local_tag.empty() ? local_tag : ext_local_tag; + if((code > 100) && !(flags & SIP_FLAGS_NOTAG)) { + reply.to_tag = ext_local_tag.empty() ? local_tag : ext_local_tag; + } reply.hdrs = hdrs; reply.cseq = req.cseq; reply.cseq_method = req.method; - if(body != NULL) + /* add/update Allow header in 200OK, if wasn't empty in previously received request */ + if (reply.code == 200 && !allow_hf.empty()) { + /* make sure to remove if already added into hdrs */ + string allow = getHeader(reply.hdrs, SIP_HDR_ALLOW); + if (!allow.empty()) removeHeader(reply.hdrs, SIP_HDR_ALLOW); + + allow = allow_hf; /* must be added, when receiving request in AmBasicSipDialog::onRxRequest() */ + reply.hdrs += SIP_HDR_COLSP(SIP_HDR_ALLOW) + allow + CRLF; + } + + if (body != NULL) reply.body = *body; - if(onTxReply(req,reply,flags)){ + if (onTxReply(req,reply,flags)) { DBG("onTxReply failed\n"); return -1; } if (!(flags & SIP_FLAGS_VERBATIM)) { - // add Signature + /* add Signature */ if (AmConfig::Signature.length()) reply.hdrs += SIP_HDR_COLSP(SIP_HDR_SERVER) + AmConfig::Signature + CRLF; } @@ -626,15 +650,15 @@ int AmBasicSipDialog::reply(const AmSipRequest& req, } int ret = SipCtrlInterface::send(reply,local_tag,logger); - if(ret){ - ERROR("Could not send reply: code=%i; reason='%s'; method=%s;" - " call-id=%s; cseq=%i\n", - reply.code,reply.reason.c_str(),reply.cseq_method.c_str(), - callid.c_str(),reply.cseq); + if (ret) { + ERROR("Could not send reply: code=%i; reason='%s'; method=%s; call-id=%s; cseq=%i\n", + reply.code,reply.reason.c_str(), + reply.cseq_method.c_str(), + callid.c_str(), + reply.cseq); return ret; - } - else { + } else { onReplyTxed(req,reply); } diff --git a/core/AmBasicSipDialog.h b/core/AmBasicSipDialog.h index 03d84f23..f4f4e2b1 100644 --- a/core/AmBasicSipDialog.h +++ b/core/AmBasicSipDialog.h @@ -112,6 +112,8 @@ protected: string route; + string allow_hf; + string next_hop; bool next_hop_1st_req; bool patch_ruri_next_hop; @@ -292,6 +294,10 @@ public: virtual void setRemoteUA(const string& new_remote_ua) { remote_ua = new_remote_ua; } + const string& getRemoteAllowHf() const { return allow_hf; } + virtual void setRemoteAllowHf(const string& new_allow_hf) + { allow_hf = new_allow_hf; } + const string& getRouteSet() const { return route; } virtual void setRouteSet(const string& new_rs) { route = new_rs; }