Module: sems Branch: master Commit: 9d35567fca2866b24cece3413797801624850c93 URL: http://git.sip-router.org/cgi-bin/gitweb.cgi/sems/?a=commit;h=9d35567fca2866b24cece3413797801624850c93
Author: Stefan Sayer <[email protected]> Committer: Stefan Sayer <[email protected]> Date: Mon Nov 15 20:38:51 2010 +0100 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(-) diff --git a/apps/sbc/SBC.cpp b/apps/sbc/SBC.cpp index fad0310..588ffe2 100644 --- a/apps/sbc/SBC.cpp +++ b/apps/sbc/SBC.cpp @@ -159,6 +159,42 @@ bool SBCCallProfile::readFromConfiguration(const string& name, return false; } + vector<string> reply_translations_v = + explode(cfg.getParameter("reply_translations"), "|"); + for (vector<string>::iterator it = + reply_translations_v.begin(); it != reply_translations_v.end(); it++) { + // expected: "603=>488 Not acceptable here" + vector<string> 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<unsigned int, pair<unsigned int, string> >::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<B2BSipRequestEvent*>(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<B2BSipReplyEvent*>(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<B2BSipRequestEvent*>(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<B2BSipReplyEvent*>(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<unsigned int, pair<unsigned int, string> >::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<B2BSipRequestEvent*>(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<B2BSipReplyEvent*>(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<B2BSipRequestEvent*>(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<B2BSipReplyEvent*>(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<unsigned int, pair<unsigned int, string> >::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 babbc47..54b7d2a 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<unsigned int, pair<unsigned int, string> > 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 0000000..bfdba45 --- /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 e6c1a7e..3d96b7f 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 9e92380..925ce31 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 _______________________________________________ Semsdev mailing list [email protected] http://lists.iptel.org/mailman/listinfo/semsdev
