/**@file Declarations for common-use control-layer functions. */ /* * Copyright 2013 Range Networks, Inc. * * This software is distributed under multiple licenses; * see the COPYING file in the main directory for licensing * information for this specific distribution. * * This use of this software may be subject to additional restrictions. * See the LEGAL file in the main directory for details. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. */ #define LOG_GROUP LogGroup::Control #include // For snprintf #include #include #include #include #include namespace Control { using std::string; using namespace GSM; // The default SIP <-> L3-CC-Cause mapping an be overridden with config options. // For this purpose the GSM Layer3 causes are identified by using the names of the causes // as defined in GSM 4.08 with space replaced by underbar and any other special chars removed. See file L3Enums.h // Config option Control.Termination.CauseToSIP. specifies the SIP code, and optionally, the SIP reason phrase, // to be sent to the SIP peer when this L3 Cause occurs. // Config option Control.Termination.SIPToCause. specifies the name of the layer3 cause to be used for a specific SIP code. // The Layer3 cause is passed to the handset to indicate the message to display, and also may be saved in the CDR. // To make this easier for the user we will use the L3 cause as the SIP reason phrase, so the reason phrase can // be placed in the config option to control it. static int cause2SipCodeFromConfig(AnyCause acause, string &reason) { // User is allowed to over-ride default sipcode for each cause in configuration options: const char *causeName = L3Cause::AnyCause2Str(acause); char configOptionName[100]; snprintf(configOptionName,100,"Control.Termination.CauseToSIP.%s",causeName); if (gConfig.defines(configOptionName)) { string value = gConfig.getStr(configOptionName); // Value must begin with a positive number; ignore leading space. const char *vp = value.c_str(); while (isspace(*vp)) { vp++; } if (!isdigit(*vp)) { LOG(ERR) << "Invalid config value for '"< commap)) return 0; causep += strlen("cause"); int result; if (1 != sscanf(causep," = %d",&result)) return 0; return result; } // Search for a cause in the SIP message. TermCause dialog2TermCause(SIP::SipDialog *dialog) { if (! dialog) { // Be ultra-cautious. // This is not supposed to happen. return TermCause::Remote(AnyCause(L3Cause::No_User_Responding),480,"No_User_Responding"); } string sipreason; int sipcode = dialog->getLastResponseCode(sipreason); // Does the reason phrase look like one that was created on a peer OpenBTS? int l3cause = CauseName2Cause(sipreason); if (! l3cause) { string reasonHeader = dialog->getLastResponseReasonHeader(); // Was a Q.850 reason included? int q850 = parseReasonHeaderQ850(reasonHeader.c_str()); if (q850) { l3cause = (q850 == 8) ? L3Cause::Preemption : (CCCause) q850; } else { bool alerted = dialog->mReceived180; l3cause = sipCode2AnyCause(sipcode,alerted); } } return TermCause::Remote(AnyCause(l3cause),sipcode,sipreason); } std::ostream& operator<<(std::ostream& os, TermCause &cause) { os <