From 9d35567fca2866b24cece3413797801624850c93 Mon Sep 17 00:00:00 2001 From: Stefan Sayer Date: Mon, 15 Nov 2010 20:38:51 +0100 Subject: [PATCH] sbc: support for translating response codes --- apps/sbc/SBC.cpp | 130 ++++++++++++++++---- apps/sbc/SBC.h | 2 + apps/sbc/etc/replytranslate.sbcprofile.conf | 2 + apps/sbc/etc/transparent.sbcprofile.conf | 4 + doc/Readme.sbc.txt | 21 ++++ 5 files changed, 136 insertions(+), 23 deletions(-) create mode 100644 apps/sbc/etc/replytranslate.sbcprofile.conf diff --git a/apps/sbc/SBC.cpp b/apps/sbc/SBC.cpp index fad03107..588ffe28 100644 --- a/apps/sbc/SBC.cpp +++ b/apps/sbc/SBC.cpp @@ -159,6 +159,42 @@ bool SBCCallProfile::readFromConfiguration(const string& name, return false; } + vector reply_translations_v = + explode(cfg.getParameter("reply_translations"), "|"); + for (vector::iterator it = + reply_translations_v.begin(); it != reply_translations_v.end(); it++) { + // expected: "603=>488 Not acceptable here" + vector trans_components = explode(*it, "=>"); + if (trans_components.size() != 2) { + ERROR("%s: entry '%s' in reply_translations could not be understood.\n", + name.c_str(), it->c_str()); + ERROR("expected 'from_code=>to_code reason'\n"); + return false; + } + + unsigned int from_code, to_code; + if (str2i(trans_components[0], from_code)) { + ERROR("%s: code '%s' in reply_translations not understood.\n", + name.c_str(), trans_components[0].c_str()); + return false; + } + unsigned int s_pos = 0; + string to_reply = trans_components[1]; + while (s_pos < to_reply.length() && to_reply[s_pos] != ' ') + s_pos++; + if (str2i(to_reply.substr(0, s_pos), to_code)) { + ERROR("%s: code '%s' in reply_translations not understood.\n", + name.c_str(), to_reply.substr(0, s_pos).c_str()); + return false; + } + + if (s_pos < to_reply.length()) + s_pos++; + // DBG("got translation %u => %u %s\n", + // from_code, to_code, to_reply.substr(s_pos).c_str()); + reply_translations[from_code] = make_pair(to_code, to_reply.substr(s_pos)); + } + INFO("SBC: loaded SBC profile '%s':\n", name.c_str()); INFO("SBC: RURI = '%s'\n", ruri.c_str()); @@ -191,6 +227,14 @@ bool SBCCallProfile::readFromConfiguration(const string& name, INFO("SBC: uuid = '%s'\n", prepaid_uuid.c_str()); INFO("SBC: acc_dest = '%s'\n", prepaid_acc_dest.c_str()); } + if (reply_translations.size()) { + string reply_trans_codes; + for(map >::iterator it= + reply_translations.begin(); it != reply_translations.end(); it++) + reply_trans_codes += int2str(it->first)+", "; + reply_trans_codes.erase(reply_trans_codes.length()-2); + INFO("SBC: reply translation for %s\n", reply_trans_codes.c_str()); + } return true; } @@ -367,7 +411,7 @@ void SBCDialog::onInvite(const AmSipRequest& req) removeHeader(invite_req.hdrs,SIP_HDR_MIN_SE); } - inplaceHeaderFilter(invite_req.hdrs, + inplaceHeaderFilter(invite_req.hdrs, call_profile.headerfilter_list, call_profile.headerfilter); if (call_profile.auth_enabled) { @@ -483,17 +527,37 @@ void SBCDialog::process(AmEvent* ev) } void SBCDialog::relayEvent(AmEvent* ev) { - if (call_profile.headerfilter != Transparent) { - if (ev->event_id == B2BSipRequest) { - B2BSipRequestEvent* req_ev = dynamic_cast(ev); - assert(req_ev); - inplaceHeaderFilter(req_ev->req.hdrs, - call_profile.headerfilter_list, call_profile.headerfilter); - } else if (ev->event_id == B2BSipReply) { - B2BSipReplyEvent* reply_ev = dynamic_cast(ev); - assert(reply_ev); - inplaceHeaderFilter(reply_ev->reply.hdrs, - call_profile.headerfilter_list, call_profile.headerfilter); + if ((call_profile.headerfilter != Transparent) && + (ev->event_id == B2BSipRequest)) { + // header filter + B2BSipRequestEvent* req_ev = dynamic_cast(ev); + assert(req_ev); + inplaceHeaderFilter(req_ev->req.hdrs, + call_profile.headerfilter_list, call_profile.headerfilter); + } else { + if (ev->event_id == B2BSipReply) { + if ((call_profile.headerfilter != Transparent) || + (call_profile.reply_translations.size())) { + B2BSipReplyEvent* reply_ev = dynamic_cast(ev); + assert(reply_ev); + // header filter + if (call_profile.headerfilter != Transparent) { + inplaceHeaderFilter(reply_ev->reply.hdrs, + call_profile.headerfilter_list, + call_profile.headerfilter); + } + + // reply translations + map >::iterator it = + call_profile.reply_translations.find(reply_ev->reply.code); + if (it != call_profile.reply_translations.end()) { + DBG("translating reply %u %s => %u %s\n", + reply_ev->reply.code, reply_ev->reply.reason.c_str(), + it->second.first, it->second.second.c_str()); + reply_ev->reply.code = it->second.first; + reply_ev->reply.reason = it->second.second; + } + } } } @@ -800,17 +864,37 @@ inline UACAuthCred* SBCCalleeSession::getCredentials() { } void SBCCalleeSession::relayEvent(AmEvent* ev) { - if (call_profile.headerfilter != Transparent) { - if (ev->event_id == B2BSipRequest) { - B2BSipRequestEvent* req_ev = dynamic_cast(ev); - assert(req_ev); - inplaceHeaderFilter(req_ev->req.hdrs, - call_profile.headerfilter_list, call_profile.headerfilter); - } else if (ev->event_id == B2BSipReply) { - B2BSipReplyEvent* reply_ev = dynamic_cast(ev); - assert(reply_ev); - inplaceHeaderFilter(reply_ev->reply.hdrs, - call_profile.headerfilter_list, call_profile.headerfilter); + if ((call_profile.headerfilter != Transparent) && + (ev->event_id == B2BSipRequest)) { + // header filter + B2BSipRequestEvent* req_ev = dynamic_cast(ev); + assert(req_ev); + inplaceHeaderFilter(req_ev->req.hdrs, + call_profile.headerfilter_list, call_profile.headerfilter); + } else { + if (ev->event_id == B2BSipReply) { + if ((call_profile.headerfilter != Transparent) || + (call_profile.reply_translations.size())) { + B2BSipReplyEvent* reply_ev = dynamic_cast(ev); + assert(reply_ev); + + // header filter + if (call_profile.headerfilter != Transparent) { + inplaceHeaderFilter(reply_ev->reply.hdrs, + call_profile.headerfilter_list, + call_profile.headerfilter); + } + // reply translations + map >::iterator it = + call_profile.reply_translations.find(reply_ev->reply.code); + if (it != call_profile.reply_translations.end()) { + DBG("translating reply %u %s => %u %s\n", + reply_ev->reply.code, reply_ev->reply.reason.c_str(), + it->second.first, it->second.second.c_str()); + reply_ev->reply.code = it->second.first; + reply_ev->reply.reason = it->second.second; + } + } } } diff --git a/apps/sbc/SBC.h b/apps/sbc/SBC.h index babbc474..54b7d2a9 100644 --- a/apps/sbc/SBC.h +++ b/apps/sbc/SBC.h @@ -79,6 +79,8 @@ struct SBCCallProfile { string prepaid_uuid; string prepaid_acc_dest; + map > reply_translations; + // todo: RTP forwarding mode // todo: RTP transcoding mode diff --git a/apps/sbc/etc/replytranslate.sbcprofile.conf b/apps/sbc/etc/replytranslate.sbcprofile.conf new file mode 100644 index 00000000..bfdba450 --- /dev/null +++ b/apps/sbc/etc/replytranslate.sbcprofile.conf @@ -0,0 +1,2 @@ +# swap 603 and 488 replies: +reply_translations="603=>488 Not acceptable here|488=>603 Decline" \ No newline at end of file diff --git a/apps/sbc/etc/transparent.sbcprofile.conf b/apps/sbc/etc/transparent.sbcprofile.conf index e6c1a7e1..3d96b7fc 100644 --- a/apps/sbc/etc/transparent.sbcprofile.conf +++ b/apps/sbc/etc/transparent.sbcprofile.conf @@ -24,6 +24,10 @@ #sdp_filter=whitelist #sdpfilter_list=g729,g723,ilbc,speex,gsm,amr +## reply translations +# translate some 6xx class replies to 4xx class: +#reply_translations="603=>488 Not acceptable here|600=>406 Not Acceptable" + ## authentication: #enable_auth=yes #auth_user=$P(u) diff --git a/doc/Readme.sbc.txt b/doc/Readme.sbc.txt index 9e92380d..925ce319 100644 --- a/doc/Readme.sbc.txt +++ b/doc/Readme.sbc.txt @@ -16,6 +16,7 @@ Features o flexible call profile based configuration o From, To, RURI update o Header and message filter + o reply code translation o SIP authentication o SIP Session Timers o call timer @@ -156,6 +157,26 @@ set to transparent, the SDP is parsed and reconstructed (SDP sanity check). Codecs may be filtered out by their payload names in whitelist or blacklist modes. The payload names in the list are case-insensitive (PCMU==pcmu). +Reply code translations +----------------------- +Response codes and reasons may be translated, e.g. if some 6xx class replies need +to be changed to 4xx class replies. + +Example: + reply_translations="603=>488 Not acceptable here" + +Here, all 603 replies received on one leg will be sent out as 488 reply with +the reason string "Not acceptable here". + +Entries are separated in the reply_translations list with a pipe symbol (|). + +Example: + reply_translations="603=>488 Not acceptable here|600=>406 Not acceptable" + +Warning: Changing response codes, especially between different response + code classes, can seriously mess up everything. Use with caution + and only if you know what you are doing! + Session Timer configuration --------------------------- If SIP Session Timers are enabled for a profile, the session timers values