mirror of https://github.com/sipwise/sems.git
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.
286 lines
9.2 KiB
286 lines
9.2 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 "log.h"
|
|
#include "CCDSM.h"
|
|
|
|
static const string data_var_name(MOD_NAME "::data");
|
|
|
|
EXPORT_PLUGIN_CLASS_FACTORY(CCDSMFactory, MOD_NAME);
|
|
|
|
CCDSMModule* CCDSMModule::_instance = 0;
|
|
|
|
CCDSMModule* CCDSMModule::instance()
|
|
{
|
|
if (!_instance) _instance = new CCDSMModule();
|
|
return _instance;
|
|
}
|
|
|
|
void CCDSMModule::invoke(const string& method, const AmArg& args, AmArg& ret)
|
|
{
|
|
DBG(MOD_NAME " %s(%s)\n", method.c_str(), AmArg::print(args).c_str());
|
|
|
|
if ((method == "start") || (method == "connect") || (method == "end")) {
|
|
return; // FIXME: advertise that the interface shouldn't be used
|
|
}
|
|
else if(method == "_list"){
|
|
ret.push("start");
|
|
ret.push("connect");
|
|
ret.push("end");
|
|
}
|
|
else if (method == "getExtendedInterfaceHandler") {
|
|
ret.push((AmObject*)this);
|
|
}
|
|
else
|
|
throw AmDynInvoke::NotImplemented(method);
|
|
}
|
|
|
|
SBCDSMInstance* CCDSMModule::getDSMInstance(SBCCallProfile &profile)
|
|
{
|
|
SBCVarMapIteratorT i = profile.cc_vars.find(data_var_name);
|
|
if (i != profile.cc_vars.end())
|
|
return dynamic_cast<SBCDSMInstance*>(i->second.asObject());
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void CCDSMModule::deleteDSMInstance(SBCCallProfile &profile)
|
|
{
|
|
SBCVarMapIteratorT i = profile.cc_vars.find(data_var_name);
|
|
if (i != profile.cc_vars.end()) {
|
|
SBCDSMInstance* h = dynamic_cast<SBCDSMInstance*>(i->second.asObject());
|
|
if (h) delete h;
|
|
profile.cc_vars.erase(i);
|
|
}
|
|
}
|
|
|
|
void CCDSMModule::resetDSMInstance(SBCCallProfile &profile)
|
|
{
|
|
SBCVarMapIteratorT i = profile.cc_vars.find(data_var_name);
|
|
if (i != profile.cc_vars.end()) {
|
|
profile.cc_vars.erase(i);
|
|
}
|
|
}
|
|
|
|
bool CCDSMModule::init(SBCCallLeg *call, const map<string, string> &values)
|
|
{
|
|
DBG("ExtCC: init - call instance: '%p' isAleg==%s\n", call, call->isALeg()?"true":"false");
|
|
|
|
SBCCallProfile &profile = call->getCallProfile();
|
|
resetDSMInstance(profile); // just forget the handler if already set
|
|
|
|
// if (!call->isALeg()) return;
|
|
|
|
// create DSM handler if necessary (with evaluated configuration)
|
|
try {
|
|
SBCDSMInstance* h = new SBCDSMInstance(call, values);
|
|
profile.cc_vars[data_var_name] = (AmObject*)h;
|
|
} catch (const string& e) {
|
|
ERROR("initializing DSM Call control module: '%s'\n", e.c_str());
|
|
return false;
|
|
} catch (...) {
|
|
ERROR("initializing DSM Call control module\n");
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
#define GET_DSM_INSTANCE \
|
|
SBCDSMInstance* h = getDSMInstance(call->getCallProfile()); \
|
|
if (NULL == h) \
|
|
return StopProcessing;
|
|
|
|
#define GET_DSM_INSTANCE_VOID \
|
|
SBCDSMInstance* h = getDSMInstance(call->getCallProfile()); \
|
|
if (NULL == h) { \
|
|
ERROR("DSM instance not found for call leg\n"); \
|
|
return;/* todo: throw exception? */ \
|
|
}
|
|
|
|
CCChainProcessing CCDSMModule::onInitialInvite(SBCCallLeg *call, InitialInviteHandlerParams ¶ms)
|
|
{
|
|
DBG("ExtCC: onInitialInvite - call instance: '%p' isAleg==%s\n", call, call->isALeg()?"true":"false");
|
|
GET_DSM_INSTANCE;
|
|
return h->onInitialInvite(call, params);
|
|
}
|
|
|
|
void CCDSMModule::onStateChange(SBCCallLeg *call, const CallLeg::StatusChangeCause &cause) {
|
|
DBG("ExtCC: onStateChange - call instance: '%p' isAleg==%s\n", call, call->isALeg()?"true":"false");
|
|
GET_DSM_INSTANCE_VOID;
|
|
h->onStateChange(call, cause);
|
|
};
|
|
|
|
CCChainProcessing CCDSMModule::onBLegRefused(SBCCallLeg *call, const AmSipReply& reply)
|
|
{
|
|
DBG("ExtCC: onBLegRefused - call instance: '%p' isAleg==%s\n", call, call->isALeg()?"true":"false");
|
|
GET_DSM_INSTANCE;
|
|
return h->onBLegRefused(call, reply);
|
|
}
|
|
void CCDSMModule::onDestroyLeg(SBCCallLeg *call) {
|
|
DBG("ExtCC: onDestroyLeg - call instance: '%p' isAleg==%s\n", call, call->isALeg()?"true":"false");
|
|
DBG("TODO: call DSM event?\n");
|
|
deleteDSMInstance(call->getCallProfile());
|
|
}
|
|
|
|
/** called from A/B leg when in-dialog request comes in */
|
|
CCChainProcessing CCDSMModule::onInDialogRequest(SBCCallLeg *call, const AmSipRequest &req) {
|
|
DBG("ExtCC: onInDialogRequest - call instance: '%p' isAleg==%s\n", call, call->isALeg()?"true":"false");
|
|
GET_DSM_INSTANCE;
|
|
return h->onInDialogRequest(call, req);
|
|
}
|
|
|
|
CCChainProcessing CCDSMModule::onInDialogReply(SBCCallLeg *call, const AmSipReply &reply) {
|
|
DBG("ExtCC: onInDialogReply - call instance: '%p' isAleg==%s\n", call, call->isALeg()?"true":"false");
|
|
GET_DSM_INSTANCE;
|
|
return h->onInDialogReply(call, reply);
|
|
}
|
|
|
|
/** called before any other processing for the event is done */
|
|
CCChainProcessing CCDSMModule::onEvent(SBCCallLeg *call, AmEvent *e) {
|
|
DBG("ExtCC: onEvent - call instance: '%p' isAleg==%s\n", call, call->isALeg()?"true":"false");
|
|
GET_DSM_INSTANCE;
|
|
return h->onEvent(call, e);
|
|
}
|
|
|
|
CCChainProcessing CCDSMModule::onDtmf(SBCCallLeg *call, int event, int duration) {
|
|
DBG("ExtCC: onDtmf(%i;%i) - call instance: '%p' isAleg==%s\n",
|
|
event, duration, call, call->isALeg()?"true":"false");
|
|
GET_DSM_INSTANCE;
|
|
return h->onDtmf(call, event, duration);
|
|
}
|
|
|
|
// hold related functionality
|
|
CCChainProcessing CCDSMModule::putOnHold(SBCCallLeg *call) {
|
|
DBG("ExtCC: putOnHold - call instance: '%p' isAleg==%s\n", call, call->isALeg()?"true":"false");
|
|
GET_DSM_INSTANCE;
|
|
return h->putOnHold(call);
|
|
}
|
|
|
|
CCChainProcessing CCDSMModule::resumeHeld(SBCCallLeg *call, bool send_reinvite) {
|
|
DBG("ExtCC: resumeHeld - call instance: '%p' isAleg==%s\n", call, call->isALeg()?"true":"false");
|
|
GET_DSM_INSTANCE;
|
|
return h->resumeHeld(call, send_reinvite);
|
|
}
|
|
|
|
CCChainProcessing CCDSMModule::createHoldRequest(SBCCallLeg *call, AmSdp &sdp) {
|
|
DBG("ExtCC: createHoldRequest - call instance: '%p' isAleg==%s\n", call, call->isALeg()?"true":"false");
|
|
GET_DSM_INSTANCE;
|
|
return h->createHoldRequest(call, sdp);
|
|
}
|
|
|
|
CCChainProcessing CCDSMModule::handleHoldReply(SBCCallLeg *call, bool succeeded) {
|
|
DBG("ExtCC: handleHoldReply - call instance: '%p' isAleg==%s\n", call, call->isALeg()?"true":"false");
|
|
GET_DSM_INSTANCE;
|
|
return h->handleHoldReply(call, succeeded);
|
|
}
|
|
|
|
/** Possibility to influence messages relayed to the B2B peer leg.
|
|
return value:
|
|
- lower than 0 means error (returned upstream, the one
|
|
returning error is responsible for destrying the event instance)
|
|
- greater than 0 means "stop processing and return 0 upstream"
|
|
- equal to 0 means "continue processing" */
|
|
int CCDSMModule::relayEvent(SBCCallLeg *call, AmEvent *e) {
|
|
// todo
|
|
return 0;
|
|
}
|
|
|
|
// using extended CC modules with simple relay
|
|
|
|
struct RelayUserData {
|
|
SimpleRelayDialog *relay;
|
|
SBCCallProfile& profile;
|
|
RelayUserData(SimpleRelayDialog *relay, SBCCallProfile& profile)
|
|
: relay(relay), profile(profile) { }
|
|
};
|
|
|
|
|
|
bool CCDSMModule::init(SBCCallProfile& profile, SimpleRelayDialog *relay, void *&user_data) {
|
|
SBCDSMInstance* h = getDSMInstance(profile);
|
|
if (NULL == h) {
|
|
user_data = NULL;
|
|
return false;
|
|
}
|
|
|
|
if (!h->init(profile, relay)) {
|
|
return false;
|
|
}
|
|
|
|
user_data = new RelayUserData(relay, profile);
|
|
return true;
|
|
}
|
|
|
|
#define GET_USER_DATA \
|
|
if (NULL == user_data) \
|
|
return; \
|
|
\
|
|
RelayUserData* ud= (RelayUserData*)user_data; \
|
|
SBCDSMInstance* h = getDSMInstance(ud->profile); \
|
|
if (NULL == h) { \
|
|
ERROR("SBC DSM instance disappeared, huh?\n"); \
|
|
return; \
|
|
}
|
|
|
|
void CCDSMModule::initUAC(const AmSipRequest &req, void *user_data) {
|
|
GET_USER_DATA;
|
|
h->initUAC(ud->profile, ud->relay, req);
|
|
}
|
|
|
|
void CCDSMModule::initUAS(const AmSipRequest &req, void *user_data) {
|
|
GET_USER_DATA;
|
|
h->initUAS(ud->profile, ud->relay, req);
|
|
}
|
|
|
|
void CCDSMModule::finalize(void *user_data) {
|
|
GET_USER_DATA;
|
|
h->finalize(ud->profile, ud->relay);
|
|
delete ud;
|
|
}
|
|
|
|
void CCDSMModule::onSipRequest(const AmSipRequest& req, void *user_data) {
|
|
GET_USER_DATA;
|
|
h->onSipRequest(ud->profile, ud->relay, req);
|
|
}
|
|
|
|
void CCDSMModule::onSipReply(const AmSipRequest& req,
|
|
const AmSipReply& reply,
|
|
AmBasicSipDialog::Status old_dlg_status,
|
|
void *user_data) {
|
|
GET_USER_DATA;
|
|
h->onSipReply(ud->profile, ud->relay, req, reply, old_dlg_status);
|
|
}
|
|
|
|
void CCDSMModule::onB2BRequest(const AmSipRequest& req, void *user_data) {
|
|
GET_USER_DATA;
|
|
h->onB2BRequest(ud->profile, ud->relay, req);
|
|
}
|
|
|
|
void CCDSMModule::onB2BReply(const AmSipReply& reply, void *user_data) {
|
|
GET_USER_DATA;
|
|
h->onB2BReply(ud->profile, ud->relay, reply);
|
|
}
|