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/examples/b2b_connect/b2b_connect.cpp

266 lines
7.1 KiB

/*
* Copyright (C) 2008 Greger Viken Teigre
* Based on auth_b2b, Copyright (C) 2008 Iptego Gmbh
* Based on the concept of mycc, Copyright (C) 2007 Sipwise GmbH
* Based on the concept of sw_prepaid_sip, Copyright (C) 2002-2003 Fhg Fokus
*
* 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.
*
* 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 "b2b_connect.h"
#include "log.h"
#include "AmUtils.h"
#include "AmAudio.h"
#include "AmPlugIn.h"
#include "AmMediaProcessor.h"
#include "AmConfigReader.h"
#include "AmSessionContainer.h"
bool b2b_connectFactory::TransparentHeaders = true; // default
bool b2b_connectFactory::TransparentDestination = false; // default
EXPORT_SESSION_FACTORY(b2b_connectFactory,MOD_NAME);
b2b_connectFactory::b2b_connectFactory(const string& _app_name)
: AmSessionFactory(_app_name)
{
}
int b2b_connectFactory::onLoad()
{
AmConfigReader cfg;
if(cfg.loadFile(AmConfig::ModConfigPath + string(MOD_NAME ".conf"))) {
INFO("configuration file '%s' not found. using defaults.\n",
(AmConfig::ModConfigPath + string(MOD_NAME ".conf")).c_str());
return 0;
}
if (cfg.getParameter("transparent_headers")=="false")
TransparentHeaders = false;
if (cfg.getParameter("transparent_ruri")=="true")
TransparentDestination = true;
return 0;
}
AmSession* b2b_connectFactory::onInvite(const AmSipRequest& req, const string& app_name,
const map<string,string>& app_params)
{
if (!app_params.size()) {
throw AmSession::Exception(500, "b2b_connect: parameters not found");
}
return new b2b_connectDialog();
}
b2b_connectDialog::b2b_connectDialog()
: AmB2ABCallerSession()
{
RTPStream()->setPlayoutType(ADAPTIVE_PLAYOUT);
}
b2b_connectDialog::~b2b_connectDialog()
{
}
void b2b_connectDialog::onInvite(const AmSipRequest& req)
{
if (dlg->getStatus() == AmSipDialog::Connected) {
// reinvites
AmB2ABCallerSession::onInvite(req);
return;
}
string remote_party, remote_uri;
domain = getAppParam("d");
user = getAppParam("u");
password = getAppParam("p");
if (domain.empty() || user.empty()) {
throw AmSession::Exception(500, "b2b_connect: domain parameters not found");
}
from = "sip:"+user+"@"+domain;
if (b2b_connectFactory::TransparentDestination) {
remote_uri = req.r_uri;
remote_party = to = req.to;
} else {
remote_uri = to = "sip:"+req.user+"@"+domain;
remote_party = "<" + to + ">";
}
if(dlg->reply(req, 100, "Connecting") != 0) {
throw AmSession::Exception(500,"Failed to reply 100");
}
invite_req = req;
if (b2b_connectFactory::TransparentHeaders) {
removeHeader(invite_req.hdrs, PARAM_HDR);
removeHeader(invite_req.hdrs, "P-App-Name");
removeHeader(invite_req.hdrs, "User-Agent");
removeHeader(invite_req.hdrs, "Max-Forwards");
}
recvd_req.insert(std::make_pair(req.cseq,req));
connectCallee(remote_party, remote_uri, from, from,
b2b_connectFactory::TransparentHeaders ? invite_req.hdrs : "");
MONITORING_LOG(other_id.c_str(),
"app", MOD_NAME);
}
void b2b_connectDialog::onSessionStart()
{
AmB2ABCallerSession::onSessionStart();
}
void b2b_connectDialog::onB2ABEvent(B2ABEvent* ev)
{
if (ev->event_id == B2ABConnectOtherLegException) {
B2ABConnectOtherLegExceptionEvent* ex_ev =
dynamic_cast<B2ABConnectOtherLegExceptionEvent*>(ev);
if (ex_ev && dlg->getStatus() < AmSipDialog::Connected) {
DBG("callee leg creation failed with exception '%d %s'\n",
ex_ev->code, ex_ev->reason.c_str());
dlg->reply(invite_req, ex_ev->code, ex_ev->reason);
setStopped();
return;
}
}
if (ev->event_id == B2ABConnectOtherLegFailed) {
B2ABConnectOtherLegFailedEvent* f_ev =
dynamic_cast<B2ABConnectOtherLegFailedEvent*>(ev);
if (f_ev && dlg->getStatus() < AmSipDialog::Connected) {
DBG("callee leg creation failed with reply '%d %s'\n",
f_ev->code, f_ev->reason.c_str());
dlg->reply(invite_req, f_ev->code, f_ev->reason);
setStopped();
return;
}
}
if (ev->event_id == B2ABConnectAudio) {
// delayed processing of first INVITE request
AmSession::onInvite(invite_req);
}
AmB2ABCallerSession::onB2ABEvent(ev);
}
void b2b_connectDialog::process(AmEvent* ev)
{
// AmPluginEvent* plugin_event = dynamic_cast<AmPluginEvent*>(ev);
// if(plugin_event && plugin_event->name == "timer_timeout") {
// int timer_id = plugin_event->data.get(0).asInt();
// if (timer_id == TIMERID_CREDIT_TIMEOUT) {
// DBG("timer timeout, no more credit\n");
// stopAccounting();
// terminateOtherLeg();
// terminateLeg();
// ev->processed = true;
// return;
// }
// }
AmAudioEvent* audio_event = dynamic_cast<AmAudioEvent*>(ev);
if(audio_event && (audio_event->event_id == AmAudioEvent::cleared)){
DBG("ignoring end of prompt.\n");
return;
}
AmB2ABCallerSession::process(ev);
}
void b2b_connectDialog::onDtmf(int event, int duration)
{
DBG("DTMF event %d duration %d\n", event, duration);
return;
}
void b2b_connectDialog::onBye(const AmSipRequest& req)
{
terminateOtherLeg();
setStopped();
}
void b2b_connectDialog::onCancel(const AmSipRequest& req)
{
if(dlg->getStatus() < AmSipDialog::Connected) {
DBG("Wait for leg B to terminate");
}
else {
DBG("Canceling leg A on CANCEL since dialog is not pending");
dlg->reply(invite_req, 487, "Request terminated");
setStopped();
}
}
AmB2ABCalleeSession* b2b_connectDialog::createCalleeSession()
{
b2b_connectCalleeSession* sess =
new b2b_connectCalleeSession(getLocalTag(), connector, user, password);
AmUACAuth::enable(sess);
return sess;
}
b2b_connectCalleeSession::b2b_connectCalleeSession(const string& other_tag,
AmSessionAudioConnector* connector,
const string& user, const string& pwd)
: credentials("", user, pwd), // domain (realm) is unused in credentials
AmB2ABCalleeSession(other_tag, connector)
{
RTPStream()->setPlayoutType(ADAPTIVE_PLAYOUT);
setDtmfDetectionEnabled(false);
}
b2b_connectCalleeSession::~b2b_connectCalleeSession() {
}
inline UACAuthCred* b2b_connectCalleeSession::getCredentials() {
return &credentials;
}
void b2b_connectCalleeSession::onSipReply(const AmSipRequest& req,
const AmSipReply& reply,
AmSipDialog::Status old_dlg_status) {
AmB2ABCalleeSession::onSipReply(req, reply, old_dlg_status);
if ((old_dlg_status < AmSipDialog::Connected) &&
(dlg->getStatus() == AmSipDialog::Disconnected)) {
DBG("status change Pending -> Disconnected. Stopping session.\n");
setStopped();
}
}