You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
sems/apps/dsm/mods/mod_sbc/ModSbc.cpp

676 lines
22 KiB

/*
* Copyright (C) 2013 Stefan Sayer
*
* This file is part of SEMS, a free SIP media server.
*
* SEMS is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version. This program is released under
* the GPL with the additional exemption that compiling, linking,
* and/or using OpenSSL is allowed.
*
* For a license to use the SEMS software under conditions
* other than those described here, or to purchase support for this
* software, please contact iptel.org by e-mail at the following addresses:
* info@iptel.org
*
* SEMS 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. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "ModSbc.h"
#include "log.h"
#include "AmUtils.h"
#include "DSMCoreModule.h"
#include "SBCCallProfile.h"
#include "SBCDSMParams.h"
#include "SBCCallLeg.h"
SC_EXPORT(MOD_CLS_NAME);
int MOD_CLS_NAME::preload() {
DBG("initializing mod_sbc...\n");
return 0;
}
MOD_ACTIONEXPORT_BEGIN(MOD_CLS_NAME) {
DEF_CMD("sbc.profileSet", MODSBCActionProfileSet);
DEF_CMD("sbc.stopCall", MODSBCActionStopCall);
DEF_CMD("sbc.disconnect", MODSBCActionDisconnect);
DEF_CMD("sbc.putOnHold", MODSBCActionPutOnHold);
DEF_CMD("sbc.resumeHeld", MODSBCActionResumeHeld);
DEF_CMD("sbc.sendDisconnectEvent", MODSBCActionSendDisconnectEvent);
DEF_CMD("sbc.getCallStatus", MODSBCActionGetCallStatus);
DEF_CMD("sbc.relayReliableEvent", MODSBCActionB2BRelayReliable);
DEF_CMD("sbc.addCallee", MODSBCActionAddCallee);
DEF_CMD("sbc.enableRelayDTMFReceiving", MODSBCEnableRelayDTMFReceiving);
DEF_CMD("sbc.addToMediaProcessor", MODSBCAddToMediaProcessor);
DEF_CMD("sbc.removeFromMediaProcessor", MODSBCRemoveFromMediaProcessor);
DEF_CMD("sbc.streamsSetReceiving", MODSBCRtpStreamsSetReceiving);
DEF_CMD("sbc.clearExtLocalTag", MODSBCClearExtLocalTag);
DEF_CMD("sbc.setExtLocalTag", MODSBCSetExtLocalTag);
DEF_CMD("sbc.setLastReq", MODSBCSetLastReq);
DEF_CMD("sbc.testSDPConnectionAddress", MODSBCtestSDPConnectionAddress);
} MOD_ACTIONEXPORT_END;
MOD_CONDITIONEXPORT_BEGIN(MOD_CLS_NAME) {
if (cmd == "legStateChange")
return new TestDSMCondition(params, DSMCondition::LegStateChange);
if (cmd == "bLegRefused")
return new TestDSMCondition(params, DSMCondition::BLegRefused);
// HOLD related
if (cmd == "PutOnHold")
return new TestDSMCondition(params, DSMCondition::PutOnHold);
if (cmd == "ResumeHeld")
return new TestDSMCondition(params, DSMCondition::ResumeHeld);
if (cmd == "CreateHoldRequest")
return new TestDSMCondition(params, DSMCondition::CreateHoldRequest);
if (cmd == "HandleHoldReply")
return new TestDSMCondition(params, DSMCondition::HandleHoldReply);
// simple relay related
if (cmd == "RelayInit")
return new TestDSMCondition(params, DSMCondition::RelayInit);
if (cmd == "RelayInitUAC")
return new TestDSMCondition(params, DSMCondition::RelayInitUAC);
if (cmd == "RelayInitUAS")
return new TestDSMCondition(params, DSMCondition::RelayInitUAS);
if (cmd == "RelayFinalize")
return new TestDSMCondition(params, DSMCondition::RelayFinalize);
if (cmd == "RelayOnSipRequest")
return new TestDSMCondition(params, DSMCondition::RelayOnSipRequest);
if (cmd == "RelayOnSipReply")
return new TestDSMCondition(params, DSMCondition::RelayOnSipReply);
if (cmd == "RelayOnB2BRequest")
return new TestDSMCondition(params, DSMCondition::RelayOnB2BRequest);
if (cmd == "RelayOnB2BReply")
return new TestDSMCondition(params, DSMCondition::RelayOnB2BReply);
if (cmd == "RelayOnB2BReply")
return new TestDSMCondition(params, DSMCondition::RelayOnB2BReply);
if (cmd == "sbc.isALeg")
return new SBCIsALegCondition(params, false);
if (cmd == "sbc.isOnHold")
return new SBCIsOnHoldCondition(params, false);
if (cmd == "sbc.isDisconnected")
return new SBCIsDisconnectedCondition(params, false);
if (cmd == "sbc.isNoReply")
return new SBCIsNoReplyCondition(params, false);
if (cmd == "sbc.isRinging")
return new SBCIsRingingCondition(params, false);
if (cmd == "sbc.isConnected")
return new SBCIsConnectedCondition(params, false);
if (cmd == "sbc.isDisconnecting")
return new SBCIsDisconnectingCondition(params, false);
} MOD_CONDITIONEXPORT_END
MATCH_CONDITION_START(SBCIsALegCondition) {
SBCCallLeg* call_leg = dynamic_cast<SBCCallLeg*>(sess);
if (NULL == call_leg) {
DBG("script writer error: DSM condition sbc.isALeg"
" used without call leg\n");
return false;
}
bool b = call_leg->isALeg();
bool res = inv ^ b;
DBG("SBC: isALeg() == %s (res = %s)\n",
b ? "true":"false", res ? "true":"false");
return res;
} MATCH_CONDITION_END;
MATCH_CONDITION_START(SBCIsOnHoldCondition) {
SBCCallLeg* call_leg = dynamic_cast<SBCCallLeg*>(sess);
if (NULL == call_leg) {
DBG("script writer error: DSM condition sbc.isOnHold"
" used without call leg\n");
return false;
}
bool b = call_leg->isOnHold();
bool res = inv ^ b;
DBG("SBC: isOnHold() == %s (res = %s)\n",
b ? "true":"false", res ? "true":"false");
return res;
} MATCH_CONDITION_END;
#define DEF_CALLSTATUS_COND(cond_name, cond_desc, call_status) \
\
MATCH_CONDITION_START(cond_name) { \
SBCCallLeg* call_leg = dynamic_cast<SBCCallLeg*>(sess); \
if (NULL == call_leg) { \
DBG("script writer error: DSM condition used without call leg\n"); \
return false; \
} \
\
bool b = call_leg->getCallStatus() == call_status; \
bool res = inv ^ b; \
DBG("SBC: " cond_desc " == %s (res = %s)\n", \
b ? "true":"false", res ? "true":"false"); \
return res; \
} MATCH_CONDITION_END
DEF_CALLSTATUS_COND(SBCIsDisconnectedCondition, "sbc.isDisconnected", CallLeg::Disconnected);
DEF_CALLSTATUS_COND(SBCIsNoReplyCondition, "sbc.isNoReply", CallLeg::NoReply);
DEF_CALLSTATUS_COND(SBCIsRingingCondition, "sbc.isRinging", CallLeg::Ringing);
DEF_CALLSTATUS_COND(SBCIsConnectedCondition, "sbc.isConnected", CallLeg::Connected);
DEF_CALLSTATUS_COND(SBCIsDisconnectingCondition, "sbc.isDisconnecting", CallLeg::Disconnecting);
#define ACTION_GET_PROFILE \
SBCCallProfile* profile = NULL; \
AVarMapT::iterator it = sc_sess->avar.find(DSM_SBC_AVAR_PROFILE); \
if (it != sc_sess->avar.end()) { \
profile = dynamic_cast<SBCCallProfile*>(it->second.asObject()); \
} \
if (NULL == profile) { \
SBCCallLeg* call = dynamic_cast<SBCCallLeg*>(sess); \
if (NULL != call) \
profile = &call->getCallProfile(); \
} \
\
if (NULL == profile) { \
ERROR("internal: Call profile object not found\n"); \
EXEC_ACTION_STOP; \
}
CONST_ACTION_2P(MODSBCActionProfileSet, ',', false);
EXEC_ACTION_START(MODSBCActionProfileSet) {
string profile_param = resolveVars(par1, sess, sc_sess, event_params);
string value = resolveVars(par2, sess, sc_sess, event_params);
FilterEntry mf;
ACTION_GET_PROFILE;
#define SET_TO_CALL_PROFILE(cfgparam, member) \
if (profile_param == cfgparam) { \
profile->member=value; \
DBG(cfgparam " set to '%s'\n", value.c_str()); \
EXEC_ACTION_STOP; \
}
#define SET_TO_CALL_PROFILE_OPTION(cfgparam, member) \
if (profile_param == cfgparam) { \
profile->member=(value == "true"); \
DBG(cfgparam " set to '%s'\n", profile->member?"true":"false"); \
EXEC_ACTION_STOP; \
}
switch (profile_param.length()) {
case 2:
SET_TO_CALL_PROFILE("To", to);
break;
case 4:
SET_TO_CALL_PROFILE("RURI", ruri);
SET_TO_CALL_PROFILE("From", from);
break;
case 7:
SET_TO_CALL_PROFILE("Call-ID", callid);
break;
case 8:
SET_TO_CALL_PROFILE("next_hop", next_hop);
break;
case 9:
SET_TO_CALL_PROFILE("RURI_host", ruri_host);
break;
case 11:
SET_TO_CALL_PROFILE("refuse_with", refuse_with);
break;
default:
SET_TO_CALL_PROFILE("outbound_proxy", outbound_proxy);
SET_TO_CALL_PROFILE_OPTION("force_outbound_proxy", force_outbound_proxy);
SET_TO_CALL_PROFILE("aleg_outbound_proxy", aleg_outbound_proxy);
SET_TO_CALL_PROFILE_OPTION("aleg_force_outbound_proxy", aleg_force_outbound_proxy);
SET_TO_CALL_PROFILE_OPTION("next_hop_1st_req", next_hop_1st_req);
SET_TO_CALL_PROFILE_OPTION("patch_ruri_next_hop", patch_ruri_next_hop);
SET_TO_CALL_PROFILE("aleg_next_hop", aleg_next_hop);
// TODO: header_filter
// TODO: sdp_filter
// TODO: auth
// TODO: aleg_auth
SET_TO_CALL_PROFILE("append_headers", append_headers);
SET_TO_CALL_PROFILE("append_headers_req", append_headers_req);
SET_TO_CALL_PROFILE("aleg_append_headers_req", aleg_append_headers_req);
SET_TO_CALL_PROFILE("rtprelay_enabled", rtprelay_enabled);
SET_TO_CALL_PROFILE_OPTION("force_symmetric_rtp", force_symmetric_rtp_value);
SET_TO_CALL_PROFILE_OPTION("aleg_force_symmetric_rtp", aleg_force_symmetric_rtp_value);
SET_TO_CALL_PROFILE_OPTION("msgflags_symmetric_rtp", msgflags_symmetric_rtp);
SET_TO_CALL_PROFILE_OPTION("rtprelay_transparent_seqno", rtprelay_transparent_seqno);
SET_TO_CALL_PROFILE_OPTION("rtprelay_transparent_ssrc", rtprelay_transparent_ssrc);
SET_TO_CALL_PROFILE_OPTION("rtprelay_dtmf_filtering", rtprelay_dtmf_filtering);
SET_TO_CALL_PROFILE_OPTION("rtprelay_dtmf_detection", rtprelay_dtmf_detection);
if (profile_param == "rtprelay_interface") {
profile->rtprelay_interface=value;
if (!profile->evaluateRTPRelayInterface()) {
sc_sess->SET_ERRNO(DSM_ERRNO_UNKNOWN_ARG);
sc_sess->SET_STRERROR("rtprelay_interface '"+value+"' not present");
} else {
DBG("rtprelay_interface set to '%s'\n", value.c_str());
}
EXEC_ACTION_STOP;
}
else if (profile_param == "aleg_rtprelay_interface") {
profile->aleg_rtprelay_interface=value;
if (!profile->evaluateRTPRelayAlegInterface()) {
sc_sess->SET_ERRNO(DSM_ERRNO_UNKNOWN_ARG);
sc_sess->SET_STRERROR("aleg_rtprelay_interface '"+value+"' not present");
} else {
DBG("aleg_rtprelay_interface set to '%s'\n", value.c_str());
}
EXEC_ACTION_STOP;
}
else if (profile_param == "message_filter") {
mf.filter_type = String2FilterType(value.c_str());
DBG("message_filter set to '%s'\n", value.c_str());
EXEC_ACTION_STOP;
}
else if (profile_param == "message_list") {
vector<string> elems = explode(value, ",");
for (vector<string>::iterator it=elems.begin(); it != elems.end(); it++)
{
mf.filter_list.insert(*it);
}
mf.filter_type = Undefined;
profile->messagefilter.push_back(std::move(mf));
DBG("message_list set to '%s'\n", value.c_str());
EXEC_ACTION_STOP;
}
}
// TODO: Transcoder Settings
// TODO: CODEC Prefs
// TODO: contact hiding
// TODO: reg_caching
DBG("script writer: Call profile property '%s' not known\n", profile_param.c_str());
sc_sess->SET_ERRNO(DSM_ERRNO_UNKNOWN_ARG);
sc_sess->SET_STRERROR("Call profile property '"+profile_param+"' not known");
} EXEC_ACTION_END;
#define GET_CALL_LEG(action) \
CallLeg* call_leg = dynamic_cast<CallLeg*>(sess); \
if (NULL == call_leg) { \
DBG("script writer error: DSM action " #action \
" used without call leg\n"); \
throw DSMException("sbc", "type", "param", "cause", \
"script writer error: DSM action " #action \
" used without call leg"); \
}
#define GET_SBC_CALL_LEG(action) \
SBCCallLeg* sbc_call_leg = dynamic_cast<SBCCallLeg*>(sess); \
if (NULL == sbc_call_leg) { \
DBG("script writer error: DSM action " #action \
" used without sbc call leg\n"); \
throw DSMException("sbc", "type", "param", "cause", \
"script writer error: DSM action " #action \
" used without sbc call leg"); \
}
#define GET_B2B_MEDIA \
AmB2BMedia* b2b_media = sbc_call_leg->getMediaSession(); \
DBG("session: %p, media: %p\n", sbc_call_leg, b2b_media); \
if (NULL == b2b_media) { \
DBG("No B2BMedia in current SBC call leg, sorry\n"); \
sc_sess->SET_ERRNO(DSM_ERRNO_UNKNOWN_ARG); \
sc_sess->SET_STRERROR("No B2BMedia in current SBC call leg, sorry"); \
EXEC_ACTION_STOP; \
}
EXEC_ACTION_START(MODSBCActionStopCall) {
GET_CALL_LEG(StopCall);
string cause = resolveVars(arg, sess, sc_sess, event_params);
call_leg->stopCall(cause.c_str());
} EXEC_ACTION_END;
CONST_ACTION_2P(MODSBCActionDisconnect, ',', true);
EXEC_ACTION_START(MODSBCActionDisconnect) {
GET_CALL_LEG(Disconnect);
string hold_remote = resolveVars(par1, sess, sc_sess, event_params);
string preserve_media_session = resolveVars(par2, sess, sc_sess, event_params);
call_leg->disconnect(hold_remote == DSM_TRUE, preserve_media_session == DSM_TRUE);
} EXEC_ACTION_END;
EXEC_ACTION_START(MODSBCActionSendDisconnectEvent) {
GET_CALL_LEG(SendDisconnectEvent);
string hold_remote = resolveVars(arg, sess, sc_sess, event_params);
if (!AmSessionContainer::instance()->postEvent(call_leg->getLocalTag(),
new DisconnectLegEvent(hold_remote == DSM_TRUE))) {
ERROR("couldn't self-post event\n");
}
} EXEC_ACTION_END;
EXEC_ACTION_START(MODSBCActionPutOnHold) {
GET_CALL_LEG(PutOnHold);
call_leg->putOnHold();
} EXEC_ACTION_END;
EXEC_ACTION_START(MODSBCActionResumeHeld) {
GET_CALL_LEG(ResumeHeld);
call_leg->resumeHeld();
} EXEC_ACTION_END;
EXEC_ACTION_START(MODSBCActionGetCallStatus) {
GET_CALL_LEG(GetCallStatus);
string varname = arg;
if (varname.size() && varname[0] == '$')
varname.erase(0, 1);
sc_sess->var[varname] = call_leg->getCallStatusStr();
DBG("set $%s='%s'\n", varname.c_str(), sc_sess->var[varname].c_str());
} EXEC_ACTION_END;
void setReliableEventParameters(const DSMSession* sc_sess, const string& var, VarMapT& params) {
vector<string> vars = explode(var, ";");
for (vector<string>::iterator it = vars.begin(); it != vars.end(); it++) {
string varname = *it;
if (varname.length() && varname[varname.length()-1]=='.') {
DBG("adding postEvent param %s (struct)\n", varname.c_str());
map<string, string>::const_iterator lb = sc_sess->var.lower_bound(varname);
while (lb != sc_sess->var.end()) {
if ((lb->first.length() < varname.length()) ||
strncmp(lb->first.c_str(), varname.c_str(), varname.length()))
break;
params[lb->first] = lb->second;
lb++;
}
} else {
VarMapT::const_iterator v_it = sc_sess->var.find(varname);
if (v_it != sc_sess->var.end()) {
DBG("adding reliableEvent param %s=%s\n",
it->c_str(), v_it->second.c_str());
params[varname] = v_it->second;
}
}
}
}
CONST_ACTION_2P(MODSBCActionB2BRelayReliable, ',', false);
EXEC_ACTION_START(MODSBCActionB2BRelayReliable) {
GET_CALL_LEG(B2BRelayReliable);
string ev_params = par1;
vector<string> success_params = explode(par2, ","); // q&d...
B2BEvent* processed = new B2BEvent(E_B2B_APP, B2BEvent::B2BApplication);
if (success_params.size()) {
setReliableEventParameters(sc_sess, trim(success_params[0], " "), processed->params);
}
B2BEvent* unprocessed = new B2BEvent(E_B2B_APP, B2BEvent::B2BApplication);
if (success_params.size() > 1) {
DBG("p='%s'\n", success_params[1].c_str());
setReliableEventParameters(sc_sess, trim(success_params[1], " "), unprocessed->params);
}
ReliableB2BEvent* rel_b2b_ev = new ReliableB2BEvent(E_B2B_APP, B2BEvent::B2BApplication, processed, unprocessed);
setReliableEventParameters(sc_sess, ev_params, rel_b2b_ev->params);
rel_b2b_ev->setSender(call_leg->getLocalTag());
call_leg->relayEvent(rel_b2b_ev);
} EXEC_ACTION_END;
CONST_ACTION_2P(MODSBCActionAddCallee, ',', false);
EXEC_ACTION_START(MODSBCActionAddCallee) {
GET_SBC_CALL_LEG(sbc.addCallee);
string mode = resolveVars(par1, sess, sc_sess, event_params);
string varname = par2;
if (mode == DSM_SBC_PARAM_ADDCALLEE_MODE_STR) {
string hdrs;
VarMapT::iterator it = sc_sess->var.find(varname+"." DSM_SBC_PARAM_ADDCALLEE_TRANSPARENT_DLG_ID);
if (it != sc_sess->var.end()) {
sbc_call_leg->getCallProfile().transparent_dlg_id = it->second == DSM_TRUE;
} else {
// default to false
sbc_call_leg->getCallProfile().transparent_dlg_id = false;
}
DBG("Using %stransparent dialog IDs for new call leg\n",
sbc_call_leg->getCallProfile().transparent_dlg_id ? "":"non-");
SBCCallLeg* peer = new SBCCallLeg(sbc_call_leg);
SBCCallProfile &p = peer->getCallProfile();
AmB2BSession::RTPRelayMode rtp_mode = sbc_call_leg->getRtpRelayMode();
it = sc_sess->var.find(varname+"." DSM_SBC_PARAM_ADDCALLEE_LOCAL_PARTY);
if (it != sc_sess->var.end())
peer->setLocalParty(it->second, it->second);
it = sc_sess->var.find(varname+"." DSM_SBC_PARAM_ADDCALLEE_REMOTE_PARTY);
if (it != sc_sess->var.end())
peer->setRemoteParty(it->second, it->second);
it = sc_sess->var.find(varname+"." DSM_SBC_PARAM_ADDCALLEE_HDRS);
if (it != sc_sess->var.end())
hdrs = it->second;
it = sc_sess->var.find(varname+"." DSM_SBC_PARAM_ADDCALLEE_OUTBOUND_PROXY);
if (it != sc_sess->var.end())
p.outbound_proxy = it->second;
it = sc_sess->var.find(varname+"." DSM_SBC_PARAM_ADDCALLEE_NEXT_HOP);
if (it != sc_sess->var.end())
p.next_hop = it->second;
it = sc_sess->var.find(varname+"." DSM_SBC_PARAM_ADDCALLEE_NEXT_HOP_1ST_REQ);
if (it != sc_sess->var.end())
p.next_hop_1st_req = (it->second == DSM_TRUE);
it = sc_sess->var.find(varname+"." DSM_SBC_PARAM_ADDCALLEE_NEXT_HOP_PATCH_RURI);
if (it != sc_sess->var.end())
p.patch_ruri_next_hop = (it->second == DSM_TRUE);
it = sc_sess->var.find(varname+"." DSM_SBC_PARAM_ADDCALLEE_NEXT_HOP_FIXED);
if (it != sc_sess->var.end())
p.next_hop_fixed = (it->second == DSM_TRUE);
it = sc_sess->var.find(varname+"." DSM_SBC_PARAM_ADDCALLEE_OUTBOUND_INTERFACE);
if (it != sc_sess->var.end()) {
p.outbound_interface = it->second;
p.evaluateOutboundInterface();
}
it = sc_sess->var.find(varname+"." DSM_SBC_PARAM_ADDCALLEE_RTP_INTERFACE);
if (it != sc_sess->var.end()) {
p.rtprelay_interface = it->second;
p.evaluateRTPRelayInterface();
}
sbc_call_leg->addCallee(peer, hdrs);
} else if (mode == DSM_SBC_PARAM_ADDCALLEE_MODE_LTAG) {
string ltag;
string hdrs;
VarMapT::iterator it = sc_sess->var.find(varname+"." DSM_SBC_PARAM_ADDCALLEE_LTAG);
if (it != sc_sess->var.end())
ltag = it->second;
it = sc_sess->var.find(varname+"." DSM_SBC_PARAM_ADDCALLEE_HDRS);
if (it != sc_sess->var.end())
hdrs = it->second;
sbc_call_leg->addCallee(ltag, hdrs);
}
} EXEC_ACTION_END;
EXEC_ACTION_START(MODSBCEnableRelayDTMFReceiving) {
bool enable = (resolveVars(arg, sess, sc_sess, event_params)==DSM_TRUE);
GET_SBC_CALL_LEG(AddCallee);
GET_B2B_MEDIA;
b2b_media->setRelayDTMFReceiving(enable);
} EXEC_ACTION_END;
EXEC_ACTION_START(MODSBCAddToMediaProcessor) {
GET_CALL_LEG(AddToMediaProcessor);
AmMediaProcessor::instance()->addSession(call_leg, call_leg->getCallgroup());
} EXEC_ACTION_END;
EXEC_ACTION_START(MODSBCRemoveFromMediaProcessor) {
GET_CALL_LEG(RemoveFromMediaProcessor);
AmMediaProcessor::instance()->removeSession(call_leg);
} EXEC_ACTION_END;
CONST_ACTION_2P(MODSBCRtpStreamsSetReceiving, ',', false);
EXEC_ACTION_START(MODSBCRtpStreamsSetReceiving) {
bool p_a = (resolveVars(par1, sess, sc_sess, event_params)==DSM_TRUE);
bool p_b = (resolveVars(par2, sess, sc_sess, event_params)==DSM_TRUE);
GET_SBC_CALL_LEG(RtpStreamsSetReceiving);
GET_B2B_MEDIA;
b2b_media->setReceiving(p_a, p_b);
} EXEC_ACTION_END;
EXEC_ACTION_START(MODSBCClearExtLocalTag) {
DBG("clearing externally used local tag for call leg [%s/%p]\n",
sess->getLocalTag().c_str(), sess);
sess->dlg->setExtLocalTag("");
} EXEC_ACTION_END;
EXEC_ACTION_START(MODSBCSetExtLocalTag) {
string new_tag = resolveVars(arg, sess, sc_sess, event_params);
DBG("setting externally used local tag for call leg [%s/%p] to '%s'\n",
sess->getLocalTag().c_str(), sess, new_tag.c_str());
sess->dlg->setExtLocalTag(new_tag);
} EXEC_ACTION_END;
EXEC_ACTION_START(MODSBCSetLastReq) {
AVarMapT::iterator it = sc_sess->avar.find(DSM_AVAR_REQUEST);
if (it == sc_sess->avar.end()) {
ERROR("Could not find " DSM_AVAR_REQUEST " avar for request");
EXEC_ACTION_STOP;
}
if (NULL == it->second.asObject()) {
ERROR("Could not find " DSM_AVAR_REQUEST " avar as pointer");
EXEC_ACTION_STOP;
}
AmSipRequest* r = dynamic_cast<AmSipRequest*>(it->second.asObject());
if (NULL == r) {
ERROR("Could not find " DSM_AVAR_REQUEST " avar as request");
EXEC_ACTION_STOP;
}
sc_sess->last_req.reset(new AmSipRequest(*r));
} EXEC_ACTION_END;
EXEC_ACTION_START(MODSBCtestSDPConnectionAddress) {
vector<string> check_adrs = explode(resolveVars(arg, sess, sc_sess, event_params), ",");
AVarMapT::iterator it = sc_sess->avar.find(DSM_AVAR_REPLY);
if (it == sc_sess->avar.end()) {
ERROR("Could not find " DSM_AVAR_REPLY " avar for reply");
EXEC_ACTION_STOP;
}
if (NULL == it->second.asObject()) {
ERROR("Could not find " DSM_AVAR_REPLY " avar as pointer");
EXEC_ACTION_STOP;
}
DSMSipReply* r = dynamic_cast<DSMSipReply*>(it->second.asObject());
if (NULL == r) {
ERROR("Could not find " DSM_AVAR_REPLY " avar as reply");
EXEC_ACTION_STOP;
}
const AmMimeBody* sdp_body = r->reply->body.hasContentType(SIP_APPLICATION_SDP);
if (!sdp_body) {
ERROR("No SDP in reply\n");
EXEC_ACTION_STOP;
}
AmSdp parser_sdp;
if (!parser_sdp.parse(sdp_body->getPayload())) {
ERROR("error parsing SDP '%s'\n", sdp_body->getPayload().c_str());
EXEC_ACTION_STOP;
}
bool found = false;
for (vector<string>::iterator it = check_adrs.begin(); it != check_adrs.end(); it++) {
if (*it == parser_sdp.conn.address) {
DBG("found address!\n");
found = true;
break;
}
}
sc_sess->var["match_connection_addr"] = found ? "true":"false";
DBG("set: match_connection_addr = '%s'\n", sc_sess->var["match_connection_addr"].c_str());
} EXEC_ACTION_END;