2005-03-20 03:11:53 +00:00
|
|
|
/**
|
|
|
|
* Channel.cpp
|
|
|
|
* This file is part of the YATE Project http://YATE.null.ro
|
|
|
|
*
|
|
|
|
* Yet Another Telephony Engine - a fully featured software PBX and IVR
|
2014-02-05 11:42:17 +00:00
|
|
|
* Copyright (C) 2004-2014 Null Team
|
2005-03-20 03:11:53 +00:00
|
|
|
*
|
2013-08-06 13:38:10 +00:00
|
|
|
* 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.
|
2005-03-20 03:11:53 +00:00
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
2013-08-06 13:38:10 +00:00
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
2005-03-20 03:11:53 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include "yatephone.h"
|
|
|
|
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
|
|
|
using namespace TelEngine;
|
|
|
|
|
2006-06-10 17:35:56 +00:00
|
|
|
// Find if a string appears to be an E164 phone number
|
|
|
|
bool TelEngine::isE164(const char* str)
|
|
|
|
{
|
|
|
|
if (!str)
|
|
|
|
return false;
|
|
|
|
// an initial + character is ok, we skip it
|
|
|
|
if (*str == '+')
|
|
|
|
str++;
|
|
|
|
// at least one valid character is required
|
|
|
|
if (!*str)
|
|
|
|
return false;
|
|
|
|
for (;;) {
|
|
|
|
switch (*str++) {
|
|
|
|
case '0':
|
|
|
|
case '1':
|
|
|
|
case '2':
|
|
|
|
case '3':
|
|
|
|
case '4':
|
|
|
|
case '5':
|
|
|
|
case '6':
|
|
|
|
case '7':
|
|
|
|
case '8':
|
|
|
|
case '9':
|
|
|
|
case '*':
|
|
|
|
case '#':
|
|
|
|
break;
|
|
|
|
case '\0':
|
|
|
|
return true;
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-11-26 18:26:46 +00:00
|
|
|
static unsigned int s_callid = 0;
|
2009-05-05 12:25:31 +00:00
|
|
|
static Mutex s_callidMutex(false,"CallID");
|
2005-11-26 18:26:46 +00:00
|
|
|
|
2005-08-02 02:20:00 +00:00
|
|
|
// this is to protect against two threads trying to (dis)connect a pair
|
|
|
|
// of call endpoints at the same time
|
2009-05-05 12:25:31 +00:00
|
|
|
static Mutex s_mutex(true,"CallEndpoint");
|
2014-01-07 16:07:34 +00:00
|
|
|
static Mutex s_lastMutex(false,"CallEndpoint::last");
|
2012-06-01 11:52:50 +00:00
|
|
|
static const String s_audioType = "audio";
|
2012-07-02 15:30:52 +00:00
|
|
|
static const String s_copyParams = "copyparams";
|
|
|
|
|
2014-01-07 16:08:37 +00:00
|
|
|
// Check if a Lock taken on the common mutex succeeded, wait up to 55s more in congestion
|
|
|
|
static bool checkRetry(Lock& lock)
|
|
|
|
{
|
|
|
|
if (lock.locked())
|
|
|
|
return true;
|
|
|
|
Engine::setCongestion("Call endpoint mutex busy");
|
|
|
|
bool ok = lock.acquire(s_mutex,55000000);
|
|
|
|
Engine::setCongestion();
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
2005-08-02 02:20:00 +00:00
|
|
|
|
2005-04-25 22:19:54 +00:00
|
|
|
CallEndpoint::CallEndpoint(const char* id)
|
2014-01-07 16:07:34 +00:00
|
|
|
: m_peer(0), m_lastPeer(0), m_id(id), m_mutex(0)
|
2005-03-20 03:11:53 +00:00
|
|
|
{
|
2005-03-29 01:50:20 +00:00
|
|
|
}
|
|
|
|
|
2007-06-08 18:33:33 +00:00
|
|
|
void CallEndpoint::destroyed()
|
2005-03-29 01:50:20 +00:00
|
|
|
{
|
2005-04-11 21:20:12 +00:00
|
|
|
#ifdef DEBUG
|
|
|
|
ObjList* l = m_data.skipNull();
|
|
|
|
for (; l; l=l->skipNext()) {
|
|
|
|
DataEndpoint* e = static_cast<DataEndpoint*>(l->get());
|
|
|
|
Debug(DebugAll,"Endpoint at %p type '%s' refcount=%d",e,e->name().c_str(),e->refcount());
|
|
|
|
}
|
|
|
|
#endif
|
2009-03-29 18:11:54 +00:00
|
|
|
disconnect(true,0,true,0);
|
2009-05-20 12:30:57 +00:00
|
|
|
clearEndpoint();
|
2014-01-07 16:07:34 +00:00
|
|
|
m_lastPeer = 0;
|
2005-03-20 03:11:53 +00:00
|
|
|
}
|
|
|
|
|
2006-01-12 05:32:06 +00:00
|
|
|
Mutex& CallEndpoint::commonMutex()
|
|
|
|
{
|
|
|
|
return s_mutex;
|
|
|
|
}
|
|
|
|
|
2005-04-25 22:19:54 +00:00
|
|
|
void* CallEndpoint::getObject(const String& name) const
|
2005-04-14 03:14:20 +00:00
|
|
|
{
|
2013-04-12 13:19:14 +00:00
|
|
|
if (name == YATOM("CallEndpoint"))
|
2005-04-25 22:19:54 +00:00
|
|
|
return const_cast<CallEndpoint*>(this);
|
2005-04-14 03:14:20 +00:00
|
|
|
return RefObject::getObject(name);
|
|
|
|
}
|
|
|
|
|
2005-12-09 21:33:10 +00:00
|
|
|
void CallEndpoint::setId(const char* newId)
|
|
|
|
{
|
|
|
|
m_id = newId;
|
|
|
|
}
|
|
|
|
|
2006-03-28 22:10:35 +00:00
|
|
|
bool CallEndpoint::connect(CallEndpoint* peer, const char* reason, bool notify)
|
2005-03-20 03:11:53 +00:00
|
|
|
{
|
|
|
|
if (!peer) {
|
2006-03-28 22:10:35 +00:00
|
|
|
disconnect(reason,notify);
|
2005-03-20 03:11:53 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (peer == m_peer)
|
|
|
|
return true;
|
2006-05-16 16:49:34 +00:00
|
|
|
if (peer == this) {
|
|
|
|
Debug(DebugWarn,"CallEndpoint '%s' trying to connect to itself! [%p]",m_id.c_str(),this);
|
|
|
|
return false;
|
|
|
|
}
|
2005-07-01 22:35:06 +00:00
|
|
|
DDebug(DebugAll,"CallEndpoint '%s' connecting peer %p to [%p]",m_id.c_str(),peer,this);
|
2005-03-20 03:11:53 +00:00
|
|
|
|
2005-08-02 02:20:00 +00:00
|
|
|
#if 0
|
2010-01-16 21:04:08 +00:00
|
|
|
Lock lock(s_mutex,5000000);
|
2014-01-07 16:08:37 +00:00
|
|
|
if (!checkRetry(lock)) {
|
2013-07-05 12:49:44 +00:00
|
|
|
Alarm("engine","bug",DebugFail,"Call connect failed - timeout on call endpoint mutex owned by '%s'!",s_mutex.owner());
|
2005-08-02 02:20:00 +00:00
|
|
|
Engine::restart(0);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2006-01-18 16:06:05 +00:00
|
|
|
// are we already dead?
|
|
|
|
if (!ref())
|
|
|
|
return false;
|
2006-03-28 22:10:35 +00:00
|
|
|
disconnect(reason,notify);
|
2006-01-18 16:06:05 +00:00
|
|
|
// is our intended peer dead?
|
|
|
|
if (!peer->ref()) {
|
|
|
|
deref();
|
|
|
|
return false;
|
|
|
|
}
|
2006-03-28 22:10:35 +00:00
|
|
|
peer->disconnect(reason,notify);
|
2005-03-20 03:11:53 +00:00
|
|
|
|
2005-04-11 21:20:12 +00:00
|
|
|
ObjList* l = m_data.skipNull();
|
|
|
|
for (; l; l=l->skipNext()) {
|
|
|
|
DataEndpoint* e = static_cast<DataEndpoint*>(l->get());
|
|
|
|
e->connect(peer->getEndpoint(e->name()));
|
|
|
|
}
|
|
|
|
|
2005-03-20 03:11:53 +00:00
|
|
|
m_peer = peer;
|
2006-03-28 22:10:35 +00:00
|
|
|
peer->setPeer(this,reason,notify);
|
2009-03-29 18:11:54 +00:00
|
|
|
setDisconnect(0);
|
2005-08-02 02:20:00 +00:00
|
|
|
connected(reason);
|
|
|
|
|
2005-03-20 03:11:53 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2009-03-29 18:11:54 +00:00
|
|
|
bool CallEndpoint::disconnect(bool final, const char* reason, bool notify, const NamedList* params)
|
2005-03-20 03:11:53 +00:00
|
|
|
{
|
|
|
|
if (!m_peer)
|
2005-08-02 02:20:00 +00:00
|
|
|
return false;
|
2005-07-01 22:35:06 +00:00
|
|
|
DDebug(DebugAll,"CallEndpoint '%s' disconnecting peer %p from [%p]",m_id.c_str(),m_peer,this);
|
2005-03-20 03:11:53 +00:00
|
|
|
|
2005-08-02 02:20:00 +00:00
|
|
|
Lock lock(s_mutex,5000000);
|
2014-01-07 16:08:37 +00:00
|
|
|
if (!checkRetry(lock)) {
|
2013-07-05 12:49:44 +00:00
|
|
|
Alarm("engine","bug",DebugFail,"Call disconnect failed - timeout on call endpoint mutex owned by '%s'!",s_mutex.owner());
|
2005-08-02 02:20:00 +00:00
|
|
|
Engine::restart(0);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2005-04-25 22:19:54 +00:00
|
|
|
CallEndpoint *temp = m_peer;
|
2005-03-20 03:11:53 +00:00
|
|
|
m_peer = 0;
|
2014-04-04 09:14:04 +00:00
|
|
|
m_lastPeer = 0;
|
2005-08-02 02:20:00 +00:00
|
|
|
if (!temp)
|
|
|
|
return false;
|
2005-04-11 21:20:12 +00:00
|
|
|
|
|
|
|
ObjList* l = m_data.skipNull();
|
|
|
|
for (; l; l=l->skipNext()) {
|
|
|
|
DataEndpoint* e = static_cast<DataEndpoint*>(l->get());
|
|
|
|
DDebug(DebugAll,"Endpoint at %p type '%s' peer %p",e,e->name().c_str(),e->getPeer());
|
|
|
|
e->disconnect();
|
|
|
|
}
|
|
|
|
|
2009-03-29 18:11:54 +00:00
|
|
|
temp->setPeer(0,reason,notify,params);
|
2015-04-07 14:07:14 +00:00
|
|
|
bool dead = !alive();
|
|
|
|
if (dead)
|
|
|
|
Debug(DebugMild,"CallEndpoint '%s' disconnect called while dead [%p]",m_id.c_str(),this);
|
2005-08-02 02:20:00 +00:00
|
|
|
if (final)
|
|
|
|
disconnected(true,reason);
|
|
|
|
lock.drop();
|
2005-03-20 03:11:53 +00:00
|
|
|
temp->deref();
|
2015-04-07 14:07:14 +00:00
|
|
|
return dead || deref();
|
2005-03-20 03:11:53 +00:00
|
|
|
}
|
|
|
|
|
2009-03-29 18:11:54 +00:00
|
|
|
void CallEndpoint::setPeer(CallEndpoint* peer, const char* reason, bool notify, const NamedList* params)
|
2005-03-20 03:11:53 +00:00
|
|
|
{
|
|
|
|
m_peer = peer;
|
2009-03-29 18:11:54 +00:00
|
|
|
if (m_peer) {
|
|
|
|
setDisconnect(0);
|
2005-08-02 02:20:00 +00:00
|
|
|
connected(reason);
|
2009-03-29 18:11:54 +00:00
|
|
|
}
|
2014-04-04 09:14:04 +00:00
|
|
|
else {
|
|
|
|
m_lastPeer = 0;
|
|
|
|
if (notify) {
|
|
|
|
setDisconnect(params);
|
|
|
|
disconnected(false,reason);
|
|
|
|
}
|
2009-03-29 18:11:54 +00:00
|
|
|
}
|
2005-03-20 03:11:53 +00:00
|
|
|
}
|
|
|
|
|
2010-01-14 00:01:38 +00:00
|
|
|
bool CallEndpoint::getPeerId(String& id) const
|
|
|
|
{
|
2010-01-16 21:04:08 +00:00
|
|
|
id.clear();
|
|
|
|
if (!m_peer)
|
|
|
|
return false;
|
2014-01-07 16:07:34 +00:00
|
|
|
if (m_peer == m_lastPeer) {
|
|
|
|
Lock mylock(s_lastMutex);
|
|
|
|
if (m_peer == m_lastPeer) {
|
|
|
|
id = m_lastPeerId;
|
|
|
|
return !id.null();
|
|
|
|
}
|
|
|
|
}
|
2010-01-14 00:01:38 +00:00
|
|
|
Lock lock(s_mutex,5000000);
|
2014-01-07 16:08:37 +00:00
|
|
|
if (!checkRetry(lock)) {
|
2013-07-05 12:49:44 +00:00
|
|
|
Alarm("engine","bug",DebugFail,"Peer ID failed - timeout on call endpoint mutex owned by '%s'!",s_mutex.owner());
|
2010-01-14 00:01:38 +00:00
|
|
|
Engine::restart(0);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (m_peer) {
|
|
|
|
id = m_peer->id();
|
|
|
|
return true;
|
|
|
|
}
|
2010-01-16 21:04:08 +00:00
|
|
|
else
|
2010-01-14 00:01:38 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
String CallEndpoint::getPeerId() const
|
|
|
|
{
|
|
|
|
String id;
|
|
|
|
getPeerId(id);
|
|
|
|
return id;
|
|
|
|
}
|
|
|
|
|
2014-01-07 16:07:34 +00:00
|
|
|
bool CallEndpoint::getLastPeerId(String& id) const
|
|
|
|
{
|
|
|
|
id.clear();
|
2014-04-04 09:14:04 +00:00
|
|
|
if (m_lastPeerId.null())
|
2014-01-07 16:07:34 +00:00
|
|
|
return false;
|
|
|
|
s_lastMutex.lock();
|
|
|
|
id = m_lastPeerId;
|
|
|
|
s_lastMutex.unlock();
|
|
|
|
return !id.null();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CallEndpoint::setLastPeerId()
|
|
|
|
{
|
|
|
|
if (!m_peer)
|
|
|
|
return;
|
|
|
|
if (m_peer == m_lastPeer)
|
|
|
|
return;
|
|
|
|
Lock lock(s_mutex,5000000);
|
2014-01-07 16:08:37 +00:00
|
|
|
if (!checkRetry(lock)) {
|
2014-01-07 16:07:34 +00:00
|
|
|
Alarm("engine","bug",DebugGoOn,"Set last peer ID failed - timeout on call endpoint mutex owned by '%s'!",s_mutex.owner());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (m_peer) {
|
|
|
|
s_lastMutex.lock();
|
|
|
|
m_lastPeer = m_peer;
|
|
|
|
m_lastPeerId = m_peer->id();
|
|
|
|
s_lastMutex.unlock();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-06-01 11:52:50 +00:00
|
|
|
DataEndpoint* CallEndpoint::getEndpoint(const String& type) const
|
2005-04-25 22:19:54 +00:00
|
|
|
{
|
2012-06-01 11:52:50 +00:00
|
|
|
if (type.null())
|
2005-04-25 22:19:54 +00:00
|
|
|
return 0;
|
|
|
|
const ObjList* pos = m_data.find(type);
|
|
|
|
return pos ? static_cast<DataEndpoint*>(pos->get()) : 0;
|
|
|
|
}
|
|
|
|
|
2012-06-01 11:52:50 +00:00
|
|
|
DataEndpoint* CallEndpoint::setEndpoint(const String& type)
|
2005-04-25 22:19:54 +00:00
|
|
|
{
|
2012-06-01 11:52:50 +00:00
|
|
|
if (type.null())
|
2005-04-25 22:19:54 +00:00
|
|
|
return 0;
|
|
|
|
DataEndpoint* dat = getEndpoint(type);
|
|
|
|
if (!dat) {
|
|
|
|
dat = new DataEndpoint(this,type);
|
|
|
|
if (m_peer)
|
|
|
|
dat->connect(m_peer->getEndpoint(type));
|
|
|
|
}
|
|
|
|
return dat;
|
|
|
|
}
|
|
|
|
|
2006-12-22 16:48:51 +00:00
|
|
|
void CallEndpoint::setEndpoint(DataEndpoint* endPoint)
|
|
|
|
{
|
|
|
|
if (!(endPoint && endPoint->ref()))
|
|
|
|
return;
|
|
|
|
if (m_data.find(endPoint)) {
|
|
|
|
endPoint->deref();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
clearEndpoint(endPoint->toString());
|
|
|
|
endPoint->disconnect();
|
|
|
|
m_data.append(endPoint);
|
|
|
|
if (m_peer)
|
|
|
|
endPoint->connect(m_peer->getEndpoint(endPoint->toString()));
|
|
|
|
}
|
|
|
|
|
2012-06-01 11:52:50 +00:00
|
|
|
void CallEndpoint::clearEndpoint(const String& type)
|
2005-09-06 02:51:09 +00:00
|
|
|
{
|
2012-06-01 11:52:50 +00:00
|
|
|
if (type.null()) {
|
2005-09-06 02:51:09 +00:00
|
|
|
ObjList* l = m_data.skipNull();
|
|
|
|
for (; l; l=l->skipNext()) {
|
|
|
|
DataEndpoint* e = static_cast<DataEndpoint*>(l->get());
|
|
|
|
DDebug(DebugAll,"Endpoint at %p type '%s' peer %p",e,e->name().c_str(),e->getPeer());
|
|
|
|
e->disconnect();
|
2009-05-20 12:30:57 +00:00
|
|
|
e->clearCall(this);
|
2005-09-06 02:51:09 +00:00
|
|
|
}
|
|
|
|
m_data.clear();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
DataEndpoint* dat = getEndpoint(type);
|
|
|
|
if (dat) {
|
|
|
|
m_data.remove(dat,false);
|
|
|
|
dat->disconnect();
|
2009-05-20 12:30:57 +00:00
|
|
|
dat->clearCall(this);
|
2005-09-06 02:51:09 +00:00
|
|
|
dat->destruct();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-06-01 11:52:50 +00:00
|
|
|
void CallEndpoint::setSource(DataSource* source, const String& type)
|
2005-04-25 22:19:54 +00:00
|
|
|
{
|
|
|
|
DataEndpoint* dat = source ? setEndpoint(type) : getEndpoint(type);
|
|
|
|
if (dat)
|
|
|
|
dat->setSource(source);
|
|
|
|
}
|
|
|
|
|
2012-06-01 11:52:50 +00:00
|
|
|
DataSource* CallEndpoint::getSource(const String& type) const
|
2005-04-25 22:19:54 +00:00
|
|
|
{
|
|
|
|
DataEndpoint* dat = getEndpoint(type);
|
|
|
|
return dat ? dat->getSource() : 0;
|
|
|
|
}
|
|
|
|
|
2012-06-01 11:52:50 +00:00
|
|
|
void CallEndpoint::setConsumer(DataConsumer* consumer, const String& type)
|
2005-04-25 22:19:54 +00:00
|
|
|
{
|
|
|
|
DataEndpoint* dat = consumer ? setEndpoint(type) : getEndpoint(type);
|
|
|
|
if (dat)
|
|
|
|
dat->setConsumer(consumer);
|
|
|
|
}
|
|
|
|
|
2012-06-01 11:52:50 +00:00
|
|
|
DataConsumer* CallEndpoint::getConsumer(const String& type) const
|
2005-04-25 22:19:54 +00:00
|
|
|
{
|
|
|
|
DataEndpoint* dat = getEndpoint(type);
|
|
|
|
return dat ? dat->getConsumer() : 0;
|
|
|
|
}
|
|
|
|
|
2012-06-01 11:52:50 +00:00
|
|
|
bool CallEndpoint::clearData(DataNode* node, const String& type)
|
2009-09-07 23:49:12 +00:00
|
|
|
{
|
2012-06-01 11:52:50 +00:00
|
|
|
if (type.null() || !node)
|
2009-09-07 23:49:12 +00:00
|
|
|
return false;
|
|
|
|
Lock mylock(DataEndpoint::commonMutex());
|
|
|
|
RefPointer<DataEndpoint> dat = getEndpoint(type);
|
|
|
|
return dat && dat->clearData(node);
|
|
|
|
}
|
|
|
|
|
2012-06-01 11:52:50 +00:00
|
|
|
const String& CallEndpoint::audioType()
|
|
|
|
{
|
|
|
|
return s_audioType;
|
|
|
|
}
|
|
|
|
|
2009-09-07 23:49:12 +00:00
|
|
|
|
2011-03-17 20:57:34 +00:00
|
|
|
static const String s_disconnected("chan.disconnected");
|
|
|
|
|
2011-10-28 18:23:26 +00:00
|
|
|
// Mutex used to lock disconnect parameters during access
|
|
|
|
static Mutex s_paramMutex(true,"ChannelParams");
|
|
|
|
|
2005-04-25 22:19:54 +00:00
|
|
|
Channel::Channel(Driver* driver, const char* id, bool outgoing)
|
|
|
|
: CallEndpoint(id),
|
2009-03-29 18:11:54 +00:00
|
|
|
m_parameters(""), m_driver(driver), m_outgoing(outgoing),
|
2013-10-11 12:46:20 +00:00
|
|
|
m_timeout(0), m_maxcall(0), m_maxPDD(0), m_dtmfTime(0),
|
2012-09-25 09:39:49 +00:00
|
|
|
m_toutAns(0), m_dtmfSeq(0), m_answered(false)
|
2005-04-25 22:19:54 +00:00
|
|
|
{
|
|
|
|
init();
|
|
|
|
}
|
|
|
|
|
|
|
|
Channel::Channel(Driver& driver, const char* id, bool outgoing)
|
|
|
|
: CallEndpoint(id),
|
2009-03-29 18:11:54 +00:00
|
|
|
m_parameters(""), m_driver(&driver), m_outgoing(outgoing),
|
2013-10-11 12:46:20 +00:00
|
|
|
m_timeout(0), m_maxcall(0), m_maxPDD(0), m_dtmfTime(0),
|
2012-09-25 09:39:49 +00:00
|
|
|
m_toutAns(0), m_dtmfSeq(0), m_answered(false)
|
2005-04-25 22:19:54 +00:00
|
|
|
{
|
|
|
|
init();
|
|
|
|
}
|
|
|
|
|
|
|
|
Channel::~Channel()
|
|
|
|
{
|
|
|
|
#ifdef DEBUG
|
2005-12-13 18:28:11 +00:00
|
|
|
Debugger debug(DebugAll,"Channel::~Channel()"," '%s' [%p]",id().c_str(),this);
|
2005-04-25 22:19:54 +00:00
|
|
|
#endif
|
2005-08-02 02:20:00 +00:00
|
|
|
cleanup();
|
2005-04-25 22:19:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void* Channel::getObject(const String& name) const
|
|
|
|
{
|
2013-04-12 13:19:14 +00:00
|
|
|
if (name == YATOM("Channel"))
|
2005-04-25 22:19:54 +00:00
|
|
|
return const_cast<Channel*>(this);
|
2013-04-12 13:19:14 +00:00
|
|
|
if (name == YATOM("MessageNotifier"))
|
2011-03-17 20:57:34 +00:00
|
|
|
return static_cast<MessageNotifier*>(const_cast<Channel*>(this));
|
2005-04-25 22:19:54 +00:00
|
|
|
return CallEndpoint::getObject(name);
|
|
|
|
}
|
|
|
|
|
2011-10-28 18:23:26 +00:00
|
|
|
Mutex& Channel::paramMutex()
|
|
|
|
{
|
|
|
|
return s_paramMutex;
|
|
|
|
}
|
|
|
|
|
2005-04-25 22:19:54 +00:00
|
|
|
void Channel::init()
|
|
|
|
{
|
|
|
|
status(direction());
|
2005-07-28 01:37:19 +00:00
|
|
|
m_mutex = m_driver;
|
2005-04-25 22:19:54 +00:00
|
|
|
if (m_driver) {
|
2005-08-02 02:20:00 +00:00
|
|
|
m_driver->lock();
|
2005-06-20 20:51:17 +00:00
|
|
|
debugName(m_driver->debugName());
|
2005-04-25 22:19:54 +00:00
|
|
|
debugChain(m_driver);
|
2005-12-09 21:33:10 +00:00
|
|
|
if (id().null()) {
|
|
|
|
String tmp(m_driver->prefix());
|
|
|
|
tmp << m_driver->nextid();
|
|
|
|
setId(tmp);
|
|
|
|
}
|
2005-08-02 02:20:00 +00:00
|
|
|
m_driver->unlock();
|
2005-04-25 22:19:54 +00:00
|
|
|
}
|
2005-11-26 18:26:46 +00:00
|
|
|
// assign a new billid only to incoming calls
|
|
|
|
if (m_billid.null() && !m_outgoing)
|
|
|
|
m_billid << Engine::runId() << "-" << allocId();
|
2005-12-09 21:33:10 +00:00
|
|
|
DDebug(this,DebugInfo,"Channel::init() '%s' [%p]",id().c_str(),this);
|
2005-04-25 22:19:54 +00:00
|
|
|
}
|
|
|
|
|
2005-08-02 02:20:00 +00:00
|
|
|
void Channel::cleanup()
|
|
|
|
{
|
|
|
|
m_timeout = 0;
|
2005-11-04 19:30:47 +00:00
|
|
|
m_maxcall = 0;
|
2013-10-11 12:46:20 +00:00
|
|
|
m_maxPDD = 0;
|
2005-08-02 02:20:00 +00:00
|
|
|
status("deleted");
|
|
|
|
m_targetid.clear();
|
|
|
|
dropChan();
|
|
|
|
m_driver = 0;
|
|
|
|
m_mutex = 0;
|
|
|
|
}
|
|
|
|
|
2005-12-09 21:33:10 +00:00
|
|
|
void Channel::filterDebug(const String& item)
|
|
|
|
{
|
|
|
|
if (m_driver) {
|
|
|
|
if (m_driver->filterInstalled())
|
|
|
|
debugEnabled(m_driver->filterDebug(item));
|
|
|
|
else
|
|
|
|
debugChain(m_driver);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-01-26 10:31:32 +00:00
|
|
|
void Channel::initChan()
|
|
|
|
{
|
|
|
|
if (!m_driver)
|
|
|
|
return;
|
|
|
|
Lock mylock(m_driver);
|
|
|
|
#ifndef NDEBUG
|
|
|
|
if (m_driver->channels().find(this)) {
|
|
|
|
Debug(DebugGoOn,"Channel '%s' already in list of '%s' driver [%p]",
|
|
|
|
id().c_str(),m_driver->name().c_str(),this);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
m_driver->m_total++;
|
2012-08-15 12:36:53 +00:00
|
|
|
m_driver->m_chanCount++;
|
2010-01-26 10:31:32 +00:00
|
|
|
m_driver->channels().append(this);
|
|
|
|
m_driver->changed();
|
|
|
|
}
|
|
|
|
|
2005-07-18 21:47:18 +00:00
|
|
|
void Channel::dropChan()
|
2005-06-14 20:53:20 +00:00
|
|
|
{
|
|
|
|
if (!m_driver)
|
|
|
|
return;
|
2005-08-02 02:20:00 +00:00
|
|
|
m_driver->lock();
|
2006-01-12 05:32:06 +00:00
|
|
|
if (!m_driver)
|
|
|
|
Debug(DebugFail,"Driver lost in dropChan! [%p]",this);
|
2012-08-15 12:36:53 +00:00
|
|
|
if (m_driver->channels().remove(this,false)) {
|
|
|
|
if (m_driver->m_chanCount > 0)
|
|
|
|
m_driver->m_chanCount--;
|
2005-07-18 21:47:18 +00:00
|
|
|
m_driver->changed();
|
2012-08-15 12:36:53 +00:00
|
|
|
}
|
2005-08-02 02:20:00 +00:00
|
|
|
m_driver->unlock();
|
2005-07-18 21:47:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Channel::zeroRefs()
|
|
|
|
{
|
|
|
|
// remove us from driver's list before calling the destructor
|
|
|
|
dropChan();
|
|
|
|
CallEndpoint::zeroRefs();
|
2005-06-14 20:53:20 +00:00
|
|
|
}
|
|
|
|
|
2005-11-26 18:26:46 +00:00
|
|
|
void Channel::connected(const char* reason)
|
|
|
|
{
|
2008-07-04 07:51:44 +00:00
|
|
|
CallEndpoint::connected(reason);
|
2010-10-26 15:48:36 +00:00
|
|
|
if (m_billid.null()) {
|
|
|
|
Channel* peer = YOBJECT(Channel,getPeer());
|
|
|
|
if (peer && peer->billid())
|
|
|
|
m_billid = peer->billid();
|
|
|
|
}
|
|
|
|
Message* m = message("chan.connected",false,true);
|
2014-04-04 09:14:04 +00:00
|
|
|
setLastPeerId();
|
2010-10-26 15:48:36 +00:00
|
|
|
if (reason)
|
|
|
|
m->setParam("reason",reason);
|
|
|
|
if (!Engine::enqueue(m))
|
|
|
|
TelEngine::destruct(m);
|
2005-11-26 18:26:46 +00:00
|
|
|
}
|
|
|
|
|
2005-04-28 22:46:59 +00:00
|
|
|
void Channel::disconnected(bool final, const char* reason)
|
|
|
|
{
|
2005-07-20 00:42:10 +00:00
|
|
|
if (final || Engine::exiting())
|
2005-04-28 22:46:59 +00:00
|
|
|
return;
|
|
|
|
// last chance to get reconnected to something
|
2009-03-29 18:11:54 +00:00
|
|
|
Message* m = getDisconnect(reason);
|
2011-10-28 18:23:26 +00:00
|
|
|
s_paramMutex.lock();
|
2005-04-28 22:46:59 +00:00
|
|
|
m_targetid.clear();
|
2011-03-01 16:06:22 +00:00
|
|
|
m_parameters.clearParams();
|
2011-10-28 18:23:26 +00:00
|
|
|
s_paramMutex.unlock();
|
2005-04-28 22:46:59 +00:00
|
|
|
Engine::enqueue(m);
|
|
|
|
}
|
|
|
|
|
2009-03-29 18:11:54 +00:00
|
|
|
void Channel::setDisconnect(const NamedList* params)
|
|
|
|
{
|
|
|
|
DDebug(this,DebugInfo,"setDisconnect(%p) [%p]",params,this);
|
2011-10-28 18:23:26 +00:00
|
|
|
s_paramMutex.lock();
|
2009-03-29 18:11:54 +00:00
|
|
|
m_parameters.clearParams();
|
|
|
|
if (params)
|
|
|
|
m_parameters.copyParams(*params);
|
2011-10-28 18:23:26 +00:00
|
|
|
s_paramMutex.unlock();
|
2009-03-29 18:11:54 +00:00
|
|
|
}
|
|
|
|
|
2011-03-17 20:57:34 +00:00
|
|
|
void Channel::endDisconnect(const Message& msg, bool handled)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void Channel::dispatched(const Message& msg, bool handled)
|
|
|
|
{
|
|
|
|
if (s_disconnected == msg)
|
|
|
|
endDisconnect(msg,handled);
|
|
|
|
}
|
|
|
|
|
2005-12-09 21:33:10 +00:00
|
|
|
void Channel::setId(const char* newId)
|
|
|
|
{
|
|
|
|
debugName(0);
|
|
|
|
CallEndpoint::setId(newId);
|
|
|
|
debugName(id());
|
|
|
|
}
|
|
|
|
|
2009-03-29 18:11:54 +00:00
|
|
|
Message* Channel::getDisconnect(const char* reason)
|
|
|
|
{
|
2011-03-17 20:57:34 +00:00
|
|
|
Message* msg = new Message(s_disconnected);
|
2011-10-28 18:23:26 +00:00
|
|
|
s_paramMutex.lock();
|
2009-03-29 18:11:54 +00:00
|
|
|
msg->copyParams(m_parameters);
|
2011-10-28 18:23:26 +00:00
|
|
|
s_paramMutex.unlock();
|
2009-03-29 18:11:54 +00:00
|
|
|
complete(*msg);
|
|
|
|
if (reason)
|
|
|
|
msg->setParam("reason",reason);
|
2011-02-09 11:16:43 +00:00
|
|
|
// we will remain referenced until the message is destroyed
|
|
|
|
msg->userData(this);
|
2011-03-17 20:57:34 +00:00
|
|
|
msg->setNotify();
|
2009-03-29 18:11:54 +00:00
|
|
|
return msg;
|
|
|
|
}
|
|
|
|
|
2006-01-05 21:33:15 +00:00
|
|
|
void Channel::status(const char* newstat)
|
|
|
|
{
|
2011-05-13 13:26:07 +00:00
|
|
|
Lock lock(mutex());
|
2006-01-05 21:33:15 +00:00
|
|
|
m_status = newstat;
|
2011-06-03 12:26:53 +00:00
|
|
|
if (!m_answered && (m_status == YSTRING("answered"))) {
|
2009-12-18 19:08:41 +00:00
|
|
|
m_answered = true;
|
2012-09-25 09:39:49 +00:00
|
|
|
// stop pre-answer timeout, restart answered timeout
|
|
|
|
m_maxcall = 0;
|
2013-10-11 12:46:20 +00:00
|
|
|
maxPDD(0);
|
2012-09-25 09:39:49 +00:00
|
|
|
if (m_toutAns)
|
|
|
|
timeout(Time::now() + m_toutAns*(u_int64_t)1000);
|
2009-12-18 19:08:41 +00:00
|
|
|
}
|
2013-10-11 12:46:20 +00:00
|
|
|
else if (m_status == YSTRING("ringing") || m_status == YSTRING("progressing"))
|
|
|
|
maxPDD(0);
|
2006-01-05 21:33:15 +00:00
|
|
|
}
|
|
|
|
|
2005-04-25 22:19:54 +00:00
|
|
|
const char* Channel::direction() const
|
|
|
|
{
|
|
|
|
return m_outgoing ? "outgoing" : "incoming";
|
|
|
|
}
|
|
|
|
|
2012-09-25 09:39:49 +00:00
|
|
|
void Channel::setMaxcall(const Message* msg, int defTout)
|
2005-11-04 19:30:47 +00:00
|
|
|
{
|
2012-09-25 09:39:49 +00:00
|
|
|
int tout = msg ? msg->getIntValue(YSTRING("timeout"),defTout) : defTout;
|
|
|
|
if (tout > 0) {
|
|
|
|
m_toutAns = tout;
|
|
|
|
timeout(Time::now() + tout*(u_int64_t)1000);
|
|
|
|
}
|
|
|
|
else if (tout == 0) {
|
|
|
|
m_toutAns = 0;
|
|
|
|
timeout(0);
|
|
|
|
}
|
|
|
|
if (m_answered)
|
2005-11-04 19:30:47 +00:00
|
|
|
maxcall(0);
|
2012-09-25 09:39:49 +00:00
|
|
|
else if (msg) {
|
|
|
|
tout = msg->getIntValue(YSTRING("maxcall"),-1);
|
|
|
|
if (tout > 0) {
|
2008-04-14 09:40:48 +00:00
|
|
|
timeout(0);
|
2012-09-25 09:39:49 +00:00
|
|
|
maxcall(Time::now() + tout*(u_int64_t)1000);
|
|
|
|
}
|
|
|
|
else if (tout == 0)
|
|
|
|
maxcall(0);
|
2008-04-14 09:40:48 +00:00
|
|
|
}
|
2005-11-04 19:30:47 +00:00
|
|
|
}
|
|
|
|
|
2013-10-11 12:46:20 +00:00
|
|
|
void Channel::setMaxPDD(const Message& msg)
|
|
|
|
{
|
|
|
|
if (m_answered) {
|
|
|
|
maxPDD(0);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
int tout = msg.getIntValue(YSTRING("maxpdd"),-1);
|
|
|
|
if (tout > 0)
|
|
|
|
maxPDD(Time::now() + tout * (u_int64_t)1000);
|
|
|
|
else if (tout == 0)
|
|
|
|
maxPDD(0);
|
|
|
|
}
|
|
|
|
|
2005-03-28 22:27:26 +00:00
|
|
|
void Channel::complete(Message& msg, bool minimal) const
|
2005-03-20 03:11:53 +00:00
|
|
|
{
|
2011-01-21 10:21:01 +00:00
|
|
|
static const String s_hangup("chan.hangup");
|
|
|
|
|
2005-12-09 21:33:10 +00:00
|
|
|
msg.setParam("id",id());
|
2005-03-25 01:05:44 +00:00
|
|
|
if (m_driver)
|
2005-03-28 22:27:26 +00:00
|
|
|
msg.setParam("module",m_driver->name());
|
2011-10-28 18:23:26 +00:00
|
|
|
if (s_hangup == msg) {
|
|
|
|
s_paramMutex.lock();
|
2011-01-21 10:21:01 +00:00
|
|
|
msg.copyParams(parameters());
|
2011-10-28 18:23:26 +00:00
|
|
|
s_paramMutex.unlock();
|
|
|
|
}
|
2005-03-28 22:27:26 +00:00
|
|
|
|
|
|
|
if (minimal)
|
|
|
|
return;
|
|
|
|
|
2005-03-25 01:05:44 +00:00
|
|
|
if (m_status)
|
|
|
|
msg.setParam("status",m_status);
|
2005-03-28 22:27:26 +00:00
|
|
|
if (m_address)
|
|
|
|
msg.setParam("address",m_address);
|
2005-03-20 03:11:53 +00:00
|
|
|
if (m_targetid)
|
|
|
|
msg.setParam("targetid",m_targetid);
|
|
|
|
if (m_billid)
|
|
|
|
msg.setParam("billid",m_billid);
|
2010-01-14 00:01:38 +00:00
|
|
|
String peer;
|
|
|
|
if (getPeerId(peer))
|
|
|
|
msg.setParam("peerid",peer);
|
2014-01-07 16:07:34 +00:00
|
|
|
if (getLastPeerId(peer))
|
|
|
|
msg.setParam("lastpeerid",peer);
|
2006-01-05 21:33:15 +00:00
|
|
|
msg.setParam("answered",String::boolText(m_answered));
|
2012-06-15 10:52:12 +00:00
|
|
|
msg.setParam("direction",direction());
|
2005-03-28 22:27:26 +00:00
|
|
|
}
|
|
|
|
|
2005-06-14 20:53:20 +00:00
|
|
|
Message* Channel::message(const char* name, bool minimal, bool data)
|
2005-03-28 22:27:26 +00:00
|
|
|
{
|
|
|
|
Message* msg = new Message(name);
|
2005-06-14 20:53:20 +00:00
|
|
|
if (data)
|
|
|
|
msg->userData(this);
|
2005-03-28 22:27:26 +00:00
|
|
|
complete(*msg,minimal);
|
|
|
|
return msg;
|
2005-03-20 03:11:53 +00:00
|
|
|
}
|
|
|
|
|
2007-01-23 00:17:11 +00:00
|
|
|
Message* Channel::message(const char* name, const NamedList* original, const char* params, bool minimal, bool data)
|
|
|
|
{
|
|
|
|
Message* msg = message(name,minimal,data);
|
|
|
|
if (original) {
|
|
|
|
if (!params)
|
2012-07-02 15:30:52 +00:00
|
|
|
params = original->getValue(s_copyParams);
|
2007-05-12 13:27:44 +00:00
|
|
|
if (!null(params))
|
|
|
|
msg->copyParams(*original,params);
|
2007-01-23 00:17:11 +00:00
|
|
|
}
|
|
|
|
return msg;
|
|
|
|
}
|
|
|
|
|
2005-04-23 23:52:08 +00:00
|
|
|
bool Channel::startRouter(Message* msg)
|
2005-04-09 22:10:00 +00:00
|
|
|
{
|
|
|
|
if (!msg)
|
|
|
|
return false;
|
|
|
|
if (m_driver) {
|
2005-12-09 21:33:10 +00:00
|
|
|
Router* r = new Router(m_driver,id(),msg);
|
2005-04-09 22:10:00 +00:00
|
|
|
if (r->startup())
|
|
|
|
return true;
|
|
|
|
delete r;
|
|
|
|
}
|
|
|
|
else
|
2007-05-15 15:40:50 +00:00
|
|
|
TelEngine::destruct(msg);
|
2005-07-12 16:05:29 +00:00
|
|
|
callRejected("failure","Internal server error");
|
2005-04-23 23:52:08 +00:00
|
|
|
// dereference and die if the channel is dynamic
|
|
|
|
if (m_driver && m_driver->varchan())
|
|
|
|
deref();
|
2005-04-09 22:10:00 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2005-07-12 16:05:29 +00:00
|
|
|
bool Channel::msgProgress(Message& msg)
|
|
|
|
{
|
|
|
|
status("progressing");
|
|
|
|
if (m_billid.null())
|
2011-06-03 12:26:53 +00:00
|
|
|
m_billid = msg.getValue(YSTRING("billid"));
|
2005-07-12 16:05:29 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2005-03-20 03:11:53 +00:00
|
|
|
bool Channel::msgRinging(Message& msg)
|
|
|
|
{
|
|
|
|
status("ringing");
|
2005-05-10 14:54:04 +00:00
|
|
|
if (m_billid.null())
|
2011-06-03 12:26:53 +00:00
|
|
|
m_billid = msg.getValue(YSTRING("billid"));
|
2005-04-29 21:07:41 +00:00
|
|
|
return true;
|
2005-03-20 03:11:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool Channel::msgAnswered(Message& msg)
|
|
|
|
{
|
2005-11-04 19:30:47 +00:00
|
|
|
m_maxcall = 0;
|
2012-09-25 09:39:49 +00:00
|
|
|
int tout = msg.getIntValue(YSTRING("timeout"),m_toutAns);
|
|
|
|
m_toutAns = (tout > 0) ? tout : 0;
|
2005-03-20 03:11:53 +00:00
|
|
|
status("answered");
|
2012-09-25 09:39:49 +00:00
|
|
|
m_answered = true;
|
2005-05-10 14:54:04 +00:00
|
|
|
if (m_billid.null())
|
2011-06-03 12:26:53 +00:00
|
|
|
m_billid = msg.getValue(YSTRING("billid"));
|
2005-04-29 21:07:41 +00:00
|
|
|
return true;
|
2005-03-20 03:11:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool Channel::msgTone(Message& msg, const char* tone)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Channel::msgText(Message& msg, const char* text)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2005-04-09 22:10:00 +00:00
|
|
|
bool Channel::msgDrop(Message& msg, const char* reason)
|
|
|
|
{
|
2013-10-11 12:46:20 +00:00
|
|
|
m_timeout = m_maxcall = m_maxPDD = 0;
|
2005-11-04 19:30:47 +00:00
|
|
|
status(null(reason) ? "dropped" : reason);
|
2013-05-14 09:28:14 +00:00
|
|
|
disconnect(reason,msg);
|
2005-04-29 21:07:41 +00:00
|
|
|
return true;
|
2005-04-09 22:10:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool Channel::msgTransfer(Message& msg)
|
2005-03-20 03:11:53 +00:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2006-01-23 15:57:47 +00:00
|
|
|
bool Channel::msgUpdate(Message& msg)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2006-12-19 17:48:57 +00:00
|
|
|
bool Channel::msgMasquerade(Message& msg)
|
|
|
|
{
|
|
|
|
if (m_billid.null())
|
2011-06-03 12:26:53 +00:00
|
|
|
m_billid = msg.getValue(YSTRING("billid"));
|
|
|
|
if (msg == YSTRING("call.answered")) {
|
2006-12-19 17:48:57 +00:00
|
|
|
Debug(this,DebugInfo,"Masquerading answer operation [%p]",this);
|
|
|
|
m_maxcall = 0;
|
2013-10-11 12:46:20 +00:00
|
|
|
maxPDD(0);
|
2009-08-12 15:31:05 +00:00
|
|
|
m_status = "answered";
|
2006-12-19 17:48:57 +00:00
|
|
|
}
|
2011-06-03 12:26:53 +00:00
|
|
|
else if (msg == YSTRING("call.progress")) {
|
2006-12-19 17:48:57 +00:00
|
|
|
Debug(this,DebugInfo,"Masquerading progress operation [%p]",this);
|
|
|
|
status("progressing");
|
|
|
|
}
|
2011-06-03 12:26:53 +00:00
|
|
|
else if (msg == YSTRING("call.ringing")) {
|
2006-12-19 17:48:57 +00:00
|
|
|
Debug(this,DebugInfo,"Masquerading ringing operation [%p]",this);
|
|
|
|
status("ringing");
|
|
|
|
}
|
2011-06-03 12:26:53 +00:00
|
|
|
else if (msg == YSTRING("chan.dtmf")) {
|
2008-04-25 13:11:49 +00:00
|
|
|
// add sequence, stop the message if it was a disallowed DTMF duplicate
|
|
|
|
if (dtmfSequence(msg) && m_driver && !m_driver->m_dtmfDups) {
|
2008-04-25 13:23:43 +00:00
|
|
|
Debug(this,DebugNote,"Stopping duplicate '%s' DTMF '%s' [%p]",
|
|
|
|
msg.getValue("detected"),msg.getValue("text"),this);
|
2008-04-25 13:11:49 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
2006-12-19 17:48:57 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2006-02-17 15:39:36 +00:00
|
|
|
void Channel::msgStatus(Message& msg)
|
|
|
|
{
|
|
|
|
String par;
|
|
|
|
Lock lock(mutex());
|
|
|
|
complete(msg);
|
|
|
|
statusParams(par);
|
|
|
|
lock.drop();
|
|
|
|
msg.retValue().clear();
|
2006-10-17 20:40:01 +00:00
|
|
|
msg.retValue() << "name=" << id() << ",type=channel;" << par << "\r\n";
|
2006-02-17 15:39:36 +00:00
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// Control message handler that is invoked only for messages to this channel
|
|
|
|
// Find a data endpoint to process it
|
|
|
|
bool Channel::msgControl(Message& msg)
|
|
|
|
{
|
2009-12-20 15:17:37 +00:00
|
|
|
setMaxcall(msg);
|
2013-10-11 12:46:20 +00:00
|
|
|
setMaxPDD(msg);
|
2008-08-04 02:06:00 +00:00
|
|
|
for (ObjList* o = m_data.skipNull(); o; o = o->skipNext()) {
|
|
|
|
DataEndpoint* dep = static_cast<DataEndpoint*>(o->get());
|
|
|
|
if (dep->control(msg))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2006-02-17 15:39:36 +00:00
|
|
|
void Channel::statusParams(String& str)
|
|
|
|
{
|
|
|
|
if (m_driver)
|
|
|
|
str.append("module=",",") << m_driver->name();
|
2010-01-14 00:01:38 +00:00
|
|
|
String peer;
|
|
|
|
if (getPeerId(peer))
|
|
|
|
str.append("peerid=",",") << peer;
|
2006-02-17 15:39:36 +00:00
|
|
|
str.append("status=",",") << m_status;
|
|
|
|
str << ",direction=" << direction();
|
|
|
|
str << ",answered=" << m_answered;
|
|
|
|
str << ",targetid=" << m_targetid;
|
|
|
|
str << ",address=" << m_address;
|
|
|
|
str << ",billid=" << m_billid;
|
2013-10-11 12:46:20 +00:00
|
|
|
if (m_timeout || m_maxcall || m_maxPDD) {
|
2006-02-17 15:39:36 +00:00
|
|
|
u_int64_t t = Time::now();
|
|
|
|
if (m_timeout) {
|
|
|
|
str << ",timeout=";
|
|
|
|
if (m_timeout > t)
|
2012-09-25 09:39:49 +00:00
|
|
|
str << (unsigned int)((m_timeout - t + 500) / 1000);
|
2006-02-17 15:39:36 +00:00
|
|
|
else
|
|
|
|
str << "expired";
|
|
|
|
}
|
|
|
|
if (m_maxcall) {
|
|
|
|
str << ",maxcall=";
|
|
|
|
if (m_maxcall > t)
|
2012-09-25 09:39:49 +00:00
|
|
|
str << (unsigned int)((m_maxcall - t + 500) / 1000);
|
2006-02-17 15:39:36 +00:00
|
|
|
else
|
|
|
|
str << "expired";
|
|
|
|
}
|
2013-10-11 12:46:20 +00:00
|
|
|
if (m_maxPDD) {
|
|
|
|
str << ",maxpdd=";
|
|
|
|
if (m_maxPDD > t)
|
|
|
|
str << (unsigned int)((m_maxPDD - t + 500) / 1000);
|
|
|
|
else
|
|
|
|
str << "expired";
|
|
|
|
}
|
2006-02-17 15:39:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-02-28 15:12:12 +00:00
|
|
|
void Channel::checkTimers(Message& msg, const Time& tmr)
|
|
|
|
{
|
|
|
|
if (timeout() && (timeout() < tmr))
|
|
|
|
msgDrop(msg,"timeout");
|
|
|
|
else if (maxcall() && (maxcall() < tmr))
|
|
|
|
msgDrop(msg,"noanswer");
|
2013-10-11 12:46:20 +00:00
|
|
|
else if (maxPDD() && (maxPDD() < tmr))
|
|
|
|
msgDrop(msg,"postdialdelay");
|
2006-02-28 15:12:12 +00:00
|
|
|
}
|
|
|
|
|
2006-01-30 20:44:03 +00:00
|
|
|
bool Channel::callPrerouted(Message& msg, bool handled)
|
|
|
|
{
|
|
|
|
status("prerouted");
|
|
|
|
// accept a new billid at this stage
|
2011-06-03 12:26:53 +00:00
|
|
|
String* str = msg.getParam(YSTRING("billid"));
|
2006-01-30 20:44:03 +00:00
|
|
|
if (str)
|
|
|
|
m_billid = *str;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2005-05-14 20:03:38 +00:00
|
|
|
bool Channel::callRouted(Message& msg)
|
2005-04-29 21:07:41 +00:00
|
|
|
{
|
|
|
|
status("routed");
|
2005-05-10 14:54:04 +00:00
|
|
|
if (m_billid.null())
|
2011-06-03 12:26:53 +00:00
|
|
|
m_billid = msg.getValue(YSTRING("billid"));
|
2005-05-14 20:03:38 +00:00
|
|
|
return true;
|
2005-04-29 21:07:41 +00:00
|
|
|
}
|
|
|
|
|
2005-03-28 22:27:26 +00:00
|
|
|
void Channel::callAccept(Message& msg)
|
|
|
|
{
|
|
|
|
status("accepted");
|
2013-04-15 12:46:48 +00:00
|
|
|
int defTout = m_driver ? m_driver->timeout() : -1;
|
|
|
|
if (defTout <= 0)
|
|
|
|
defTout = -1;
|
|
|
|
setMaxcall(msg,defTout);
|
2005-05-10 14:54:04 +00:00
|
|
|
if (m_billid.null())
|
2011-06-03 12:26:53 +00:00
|
|
|
m_billid = msg.getValue(YSTRING("billid"));
|
|
|
|
m_targetid = msg.getValue(YSTRING("targetid"));
|
|
|
|
String detect = msg.getValue(YSTRING("tonedetect_in"));
|
2006-09-08 09:50:19 +00:00
|
|
|
if (detect && detect.toBoolean(true)) {
|
|
|
|
if (detect.toBoolean(false))
|
|
|
|
detect = "tone/*";
|
|
|
|
toneDetect(detect);
|
|
|
|
}
|
2011-06-03 12:26:53 +00:00
|
|
|
if (msg.getBoolValue(YSTRING("autoanswer")))
|
2005-09-02 16:39:00 +00:00
|
|
|
msgAnswered(msg);
|
2011-06-03 12:26:53 +00:00
|
|
|
else if (msg.getBoolValue(YSTRING("autoring")))
|
2005-09-02 16:39:00 +00:00
|
|
|
msgRinging(msg);
|
2011-06-03 12:26:53 +00:00
|
|
|
else if (msg.getBoolValue(YSTRING("autoprogress")))
|
2005-11-21 22:07:58 +00:00
|
|
|
msgProgress(msg);
|
2011-06-03 12:26:53 +00:00
|
|
|
else if (m_targetid.null() && msg.getBoolValue(YSTRING("autoanswer"),true)) {
|
2005-09-02 16:39:00 +00:00
|
|
|
// no preference exists in the message so issue a notice
|
|
|
|
Debug(this,DebugNote,"Answering now call %s because we have no targetid [%p]",
|
2005-12-09 21:33:10 +00:00
|
|
|
id().c_str(),this);
|
2005-04-09 22:10:00 +00:00
|
|
|
msgAnswered(msg);
|
|
|
|
}
|
2005-03-28 22:27:26 +00:00
|
|
|
}
|
|
|
|
|
2006-09-08 09:50:19 +00:00
|
|
|
void Channel::callConnect(Message& msg)
|
|
|
|
{
|
2011-06-03 12:26:53 +00:00
|
|
|
String detect = msg.getValue(YSTRING("tonedetect_out"));
|
2006-09-08 09:50:19 +00:00
|
|
|
if (detect && detect.toBoolean(true)) {
|
|
|
|
if (detect.toBoolean(false))
|
|
|
|
detect = "tone/*";
|
|
|
|
toneDetect(detect);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-07-12 16:05:29 +00:00
|
|
|
void Channel::callRejected(const char* error, const char* reason, const Message* msg)
|
2005-03-28 22:27:26 +00:00
|
|
|
{
|
2005-07-20 04:42:29 +00:00
|
|
|
Debug(this,DebugMild,"Call rejected error='%s' reason='%s' [%p]",error,reason,this);
|
2012-07-01 20:47:55 +00:00
|
|
|
if (msg) {
|
2012-07-02 15:30:52 +00:00
|
|
|
const String* cp = msg->getParam(s_copyParams);
|
2012-07-01 20:47:55 +00:00
|
|
|
if (!TelEngine::null(cp)) {
|
|
|
|
s_paramMutex.lock();
|
|
|
|
parameters().copyParams(*msg,*cp);
|
|
|
|
s_paramMutex.unlock();
|
|
|
|
}
|
|
|
|
}
|
2005-03-28 22:27:26 +00:00
|
|
|
status("rejected");
|
|
|
|
}
|
|
|
|
|
2008-04-25 13:11:49 +00:00
|
|
|
bool Channel::dtmfSequence(Message& msg)
|
|
|
|
{
|
2011-06-03 12:26:53 +00:00
|
|
|
if ((msg != YSTRING("chan.dtmf")) || msg.getParam(YSTRING("sequence")))
|
2008-04-25 13:11:49 +00:00
|
|
|
return false;
|
|
|
|
bool duplicate = false;
|
2011-06-03 12:26:53 +00:00
|
|
|
const String* detected = msg.getParam(YSTRING("detected"));
|
|
|
|
const String* text = msg.getParam(YSTRING("text"));
|
2008-04-25 13:11:49 +00:00
|
|
|
Lock lock(mutex());
|
|
|
|
unsigned int seq = m_dtmfSeq;
|
2008-04-28 16:54:03 +00:00
|
|
|
if (text && detected &&
|
|
|
|
(*text == m_dtmfText) && (*detected != m_dtmfDetected) &&
|
|
|
|
(msg.msgTime() < m_dtmfTime))
|
2008-04-25 13:11:49 +00:00
|
|
|
duplicate = true;
|
|
|
|
else {
|
|
|
|
seq = ++m_dtmfSeq;
|
2008-04-28 16:54:03 +00:00
|
|
|
m_dtmfTime = msg.msgTime() + 4000000;
|
2008-04-25 13:11:49 +00:00
|
|
|
m_dtmfText = text;
|
|
|
|
m_dtmfDetected = detected;
|
|
|
|
}
|
|
|
|
// need to add sequence number used to detect reorders
|
|
|
|
msg.addParam("sequence",String(seq));
|
|
|
|
msg.addParam("duplicate",String::boolText(duplicate));
|
|
|
|
return duplicate;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Channel::dtmfEnqueue(Message* msg)
|
|
|
|
{
|
|
|
|
if (!msg)
|
|
|
|
return false;
|
|
|
|
if (dtmfSequence(*msg) && m_driver && !m_driver->m_dtmfDups) {
|
2008-04-25 13:23:43 +00:00
|
|
|
Debug(this,DebugNote,"Dropping duplicate '%s' DTMF '%s' [%p]",
|
|
|
|
msg->getValue("detected"),msg->getValue("text"),this);
|
2008-04-25 13:11:49 +00:00
|
|
|
TelEngine::destruct(msg);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return Engine::enqueue(msg);
|
|
|
|
}
|
|
|
|
|
2005-11-09 22:12:28 +00:00
|
|
|
bool Channel::dtmfInband(const char* tone)
|
|
|
|
{
|
|
|
|
if (null(tone))
|
|
|
|
return false;
|
|
|
|
Message m("chan.attach");
|
|
|
|
complete(m,true);
|
|
|
|
m.userData(this);
|
|
|
|
String tmp("tone/dtmfstr/");
|
|
|
|
tmp += tone;
|
|
|
|
m.setParam("override",tmp);
|
|
|
|
m.setParam("single","yes");
|
|
|
|
return Engine::dispatch(m);
|
|
|
|
}
|
|
|
|
|
2006-09-08 09:50:19 +00:00
|
|
|
bool Channel::toneDetect(const char* sniffer)
|
|
|
|
{
|
|
|
|
if (null(sniffer))
|
2006-10-17 20:40:01 +00:00
|
|
|
sniffer = "tone/*";
|
2006-09-08 09:50:19 +00:00
|
|
|
Message m("chan.attach");
|
|
|
|
complete(m,true);
|
|
|
|
m.userData(this);
|
|
|
|
m.setParam("sniffer",sniffer);
|
|
|
|
m.setParam("single","yes");
|
|
|
|
return Engine::dispatch(m);
|
|
|
|
}
|
|
|
|
|
2005-03-28 22:27:26 +00:00
|
|
|
bool Channel::setDebug(Message& msg)
|
|
|
|
{
|
|
|
|
String str = msg.getValue("line");
|
|
|
|
if (str.startSkip("level")) {
|
|
|
|
int dbg = debugLevel();
|
|
|
|
str >> dbg;
|
|
|
|
debugLevel(dbg);
|
|
|
|
}
|
|
|
|
else if (str == "reset")
|
|
|
|
debugChain(m_driver);
|
2005-06-20 20:51:17 +00:00
|
|
|
else if (str == "engine")
|
|
|
|
debugCopy();
|
|
|
|
else if (str.isBoolean())
|
|
|
|
debugEnabled(str.toBoolean(debugEnabled()));
|
2005-12-09 21:33:10 +00:00
|
|
|
msg.retValue() << "Channel " << id()
|
2005-03-28 22:27:26 +00:00
|
|
|
<< " debug " << (debugEnabled() ? "on" : "off")
|
2006-10-17 20:40:01 +00:00
|
|
|
<< " level " << debugLevel() << (debugChained() ? " chained" : "") << "\r\n";
|
2005-03-28 22:27:26 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2005-11-26 18:26:46 +00:00
|
|
|
unsigned int Channel::allocId()
|
|
|
|
{
|
|
|
|
s_callidMutex.lock();
|
|
|
|
unsigned int id = ++s_callid;
|
|
|
|
s_callidMutex.unlock();
|
|
|
|
return id;
|
|
|
|
}
|
2005-03-28 22:27:26 +00:00
|
|
|
|
2005-04-07 20:31:22 +00:00
|
|
|
TokenDict Module::s_messages[] = {
|
|
|
|
{ "engine.status", Module::Status },
|
|
|
|
{ "engine.timer", Module::Timer },
|
2005-05-06 18:13:33 +00:00
|
|
|
{ "engine.debug", Module::Level },
|
2005-04-07 20:31:22 +00:00
|
|
|
{ "engine.command", Module::Command },
|
|
|
|
{ "engine.help", Module::Help },
|
2005-04-19 00:45:40 +00:00
|
|
|
{ "engine.halt", Module::Halt },
|
2006-01-23 15:57:47 +00:00
|
|
|
{ "call.route", Module::Route },
|
2005-04-07 20:31:22 +00:00
|
|
|
{ "call.execute", Module::Execute },
|
|
|
|
{ "call.drop", Module::Drop },
|
2005-07-12 16:05:29 +00:00
|
|
|
{ "call.progress", Module::Progress },
|
2005-04-07 20:31:22 +00:00
|
|
|
{ "call.ringing", Module::Ringing },
|
|
|
|
{ "call.answered", Module::Answered },
|
2006-01-23 15:57:47 +00:00
|
|
|
{ "call.update", Module::Update },
|
2005-04-07 20:31:22 +00:00
|
|
|
{ "chan.dtmf", Module::Tone },
|
|
|
|
{ "chan.text", Module::Text },
|
|
|
|
{ "chan.masquerade", Module::Masquerade },
|
|
|
|
{ "chan.locate", Module::Locate },
|
2005-04-09 22:10:00 +00:00
|
|
|
{ "chan.transfer", Module::Transfer },
|
2008-08-04 02:06:00 +00:00
|
|
|
{ "chan.control", Module::Control },
|
2013-08-13 07:54:00 +00:00
|
|
|
{ "msg.execute", Module::MsgExecute },
|
2005-04-07 20:31:22 +00:00
|
|
|
{ 0, 0 }
|
|
|
|
};
|
|
|
|
|
2005-04-23 23:52:08 +00:00
|
|
|
unsigned int Module::s_delay = 5;
|
2005-03-28 22:27:26 +00:00
|
|
|
|
2005-04-07 20:31:22 +00:00
|
|
|
const char* Module::messageName(int id)
|
|
|
|
{
|
|
|
|
if ((id <= 0) || (id >PubLast))
|
|
|
|
return 0;
|
|
|
|
return lookup(id,s_messages);
|
|
|
|
}
|
|
|
|
|
2007-11-26 23:56:37 +00:00
|
|
|
Module::Module(const char* name, const char* type, bool earlyInit)
|
2009-05-05 12:25:31 +00:00
|
|
|
: Plugin(name,earlyInit), Mutex(true,"Module"),
|
2011-03-23 16:26:25 +00:00
|
|
|
m_init(false), m_relays(0), m_type(type), m_changed(0)
|
2005-04-07 20:31:22 +00:00
|
|
|
{
|
2005-06-20 20:51:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Module::~Module()
|
|
|
|
{
|
2005-04-07 20:31:22 +00:00
|
|
|
}
|
|
|
|
|
2005-04-14 03:14:20 +00:00
|
|
|
void* Module::getObject(const String& name) const
|
|
|
|
{
|
2013-04-12 13:19:14 +00:00
|
|
|
if (name == YATOM("Module"))
|
2005-04-14 03:14:20 +00:00
|
|
|
return const_cast<Module*>(this);
|
|
|
|
return Plugin::getObject(name);
|
|
|
|
}
|
|
|
|
|
2008-01-28 17:24:55 +00:00
|
|
|
bool Module::installRelay(int id, const char* name, unsigned priority)
|
2005-04-07 20:31:22 +00:00
|
|
|
{
|
2008-04-23 12:54:20 +00:00
|
|
|
if (!(id && name && priority))
|
2005-04-07 20:31:22 +00:00
|
|
|
return false;
|
|
|
|
|
2014-02-04 16:36:23 +00:00
|
|
|
TempObjectCounter cnt(objectsCounter(),true);
|
2005-04-07 20:31:22 +00:00
|
|
|
Lock lock(this);
|
|
|
|
if (m_relays & id)
|
|
|
|
return true;
|
|
|
|
m_relays |= id;
|
|
|
|
|
2012-06-12 23:47:01 +00:00
|
|
|
MessageRelay* relay = new MessageRelay(name,this,id,priority,Module::name());
|
2008-01-26 20:43:05 +00:00
|
|
|
m_relayList.append(relay)->setDelete(false);
|
|
|
|
Engine::install(relay);
|
2005-04-07 20:31:22 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Module::installRelay(int id, unsigned priority)
|
|
|
|
{
|
2008-01-28 17:24:55 +00:00
|
|
|
return installRelay(id,messageName(id),priority);
|
2005-04-07 20:31:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool Module::installRelay(const char* name, unsigned priority)
|
2005-03-28 22:27:26 +00:00
|
|
|
{
|
2008-01-28 17:24:55 +00:00
|
|
|
return installRelay(lookup(name,s_messages),name,priority);
|
2005-03-28 22:27:26 +00:00
|
|
|
}
|
|
|
|
|
2008-01-26 20:43:05 +00:00
|
|
|
bool Module::installRelay(MessageRelay* relay)
|
|
|
|
{
|
|
|
|
if (!relay || ((relay->id() & m_relays) != 0) || m_relayList.find(relay))
|
|
|
|
return false;
|
|
|
|
m_relays |= relay->id();
|
|
|
|
m_relayList.append(relay)->setDelete(false);
|
|
|
|
Engine::install(relay);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2008-01-27 10:04:42 +00:00
|
|
|
bool Module::uninstallRelay(MessageRelay* relay, bool delRelay)
|
|
|
|
{
|
|
|
|
if (!relay || ((relay->id() & m_relays) == 0) || !m_relayList.remove(relay,false))
|
|
|
|
return false;
|
|
|
|
Engine::uninstall(relay);
|
|
|
|
m_relays &= ~relay->id();
|
|
|
|
if (delRelay)
|
|
|
|
TelEngine::destruct(relay);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Module::uninstallRelay(int id, bool delRelay)
|
|
|
|
{
|
|
|
|
if ((id & m_relays) == 0)
|
|
|
|
return false;
|
|
|
|
for (ObjList* l = m_relayList.skipNull(); l; l = l->skipNext()) {
|
|
|
|
MessageRelay* r = static_cast<MessageRelay*>(l->get());
|
|
|
|
if (r->id() != id)
|
|
|
|
continue;
|
|
|
|
Engine::uninstall(r);
|
|
|
|
m_relays &= ~id;
|
2012-11-13 11:30:30 +00:00
|
|
|
l->remove(delRelay);
|
|
|
|
break;
|
2008-01-27 10:04:42 +00:00
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-01-26 20:43:05 +00:00
|
|
|
bool Module::uninstallRelays()
|
|
|
|
{
|
|
|
|
while (MessageRelay* relay = static_cast<MessageRelay*>(m_relayList.remove(false))) {
|
|
|
|
Engine::uninstall(relay);
|
|
|
|
m_relays &= ~relay->id();
|
|
|
|
relay->destruct();
|
|
|
|
}
|
2008-01-27 10:04:42 +00:00
|
|
|
return (0 == m_relays) && (0 == m_relayList.count());
|
2008-01-26 20:43:05 +00:00
|
|
|
}
|
|
|
|
|
2005-03-29 01:50:20 +00:00
|
|
|
void Module::initialize()
|
|
|
|
{
|
|
|
|
setup();
|
|
|
|
}
|
|
|
|
|
2005-03-28 22:27:26 +00:00
|
|
|
void Module::setup()
|
|
|
|
{
|
2005-07-01 22:35:06 +00:00
|
|
|
DDebug(this,DebugAll,"Module::setup()");
|
2005-03-28 22:27:26 +00:00
|
|
|
if (m_init)
|
|
|
|
return;
|
|
|
|
m_init = true;
|
2005-05-06 18:13:33 +00:00
|
|
|
installRelay(Timer,90);
|
|
|
|
installRelay(Status,110);
|
|
|
|
installRelay(Level,120);
|
2006-10-17 20:40:01 +00:00
|
|
|
installRelay(Command,120);
|
2005-03-28 22:27:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Module::changed()
|
|
|
|
{
|
|
|
|
if (s_delay && !m_changed)
|
2005-04-11 21:20:12 +00:00
|
|
|
m_changed = Time::now() + s_delay*(u_int64_t)1000000;
|
2005-03-28 22:27:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Module::msgTimer(Message& msg)
|
|
|
|
{
|
|
|
|
if (m_changed && (msg.msgTime() > m_changed)) {
|
|
|
|
Message* m = new Message("module.update");
|
2011-03-23 16:26:25 +00:00
|
|
|
m->addParam("module",name());
|
2005-03-28 22:27:26 +00:00
|
|
|
m_changed = 0;
|
|
|
|
genUpdate(*m);
|
|
|
|
Engine::enqueue(m);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-01-23 15:57:47 +00:00
|
|
|
bool Module::msgRoute(Message& msg)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2006-10-17 20:40:01 +00:00
|
|
|
bool Module::msgCommand(Message& msg)
|
|
|
|
{
|
2011-06-03 12:26:53 +00:00
|
|
|
const NamedString* line = msg.getParam(YSTRING("line"));
|
2006-10-17 20:40:01 +00:00
|
|
|
if (line)
|
|
|
|
return commandExecute(msg.retValue(),*line);
|
2011-06-03 12:26:53 +00:00
|
|
|
if (msg.getParam(YSTRING("partline")) || msg.getParam(YSTRING("partword")))
|
|
|
|
return commandComplete(msg,msg.getValue(YSTRING("partline")),msg.getValue(YSTRING("partword")));
|
2006-10-17 20:40:01 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Module::commandExecute(String& retVal, const String& line)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Module::commandComplete(Message& msg, const String& partLine, const String& partWord)
|
|
|
|
{
|
2011-06-03 12:26:53 +00:00
|
|
|
if ((partLine == YSTRING("debug")) || (partLine == YSTRING("status")))
|
2008-09-16 13:30:04 +00:00
|
|
|
itemComplete(msg.retValue(),name(),partWord);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Module::itemComplete(String& itemList, const String& item, const String& partWord)
|
|
|
|
{
|
|
|
|
if (partWord.null() || item.startsWith(partWord)) {
|
|
|
|
itemList.append(item,"\t");
|
|
|
|
return true;
|
2006-10-17 20:40:01 +00:00
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2005-03-28 22:27:26 +00:00
|
|
|
void Module::msgStatus(Message& msg)
|
|
|
|
{
|
2006-09-26 09:54:11 +00:00
|
|
|
String mod, par, det;
|
2011-06-03 12:26:53 +00:00
|
|
|
bool details = msg.getBoolValue(YSTRING("details"),true);
|
2005-03-28 22:27:26 +00:00
|
|
|
lock();
|
|
|
|
statusModule(mod);
|
|
|
|
statusParams(par);
|
2006-09-26 09:54:11 +00:00
|
|
|
if (details)
|
|
|
|
statusDetail(det);
|
2005-03-28 22:27:26 +00:00
|
|
|
unlock();
|
2006-09-26 09:54:11 +00:00
|
|
|
msg.retValue() << mod << ";" << par;
|
|
|
|
if (det)
|
|
|
|
msg.retValue() << ";" << det;
|
2006-10-17 20:40:01 +00:00
|
|
|
msg.retValue() << "\r\n";
|
2005-03-28 22:27:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Module::statusModule(String& str)
|
|
|
|
{
|
2011-03-23 16:26:25 +00:00
|
|
|
str.append("name=",",") << name();
|
2005-03-28 22:27:26 +00:00
|
|
|
if (m_type)
|
|
|
|
str << ",type=" << m_type;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Module::statusParams(String& str)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2006-09-26 09:54:11 +00:00
|
|
|
void Module::statusDetail(String& str)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2005-03-28 22:27:26 +00:00
|
|
|
void Module::genUpdate(Message& msg)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Module::received(Message &msg, int id)
|
|
|
|
{
|
2011-03-23 16:26:25 +00:00
|
|
|
if (name().null())
|
2005-03-28 22:27:26 +00:00
|
|
|
return false;
|
|
|
|
|
2006-01-23 15:57:47 +00:00
|
|
|
switch (id) {
|
|
|
|
case Timer:
|
|
|
|
lock();
|
|
|
|
msgTimer(msg);
|
|
|
|
unlock();
|
|
|
|
return false;
|
|
|
|
case Route:
|
|
|
|
return msgRoute(msg);
|
2005-03-28 22:27:26 +00:00
|
|
|
}
|
|
|
|
|
2011-06-03 12:26:53 +00:00
|
|
|
String dest = msg.getValue(YSTRING("module"));
|
2005-03-28 22:27:26 +00:00
|
|
|
|
|
|
|
if (id == Status) {
|
2011-03-23 16:26:25 +00:00
|
|
|
if (dest == name()) {
|
2005-03-28 22:27:26 +00:00
|
|
|
msgStatus(msg);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (dest.null() || (dest == m_type))
|
|
|
|
msgStatus(msg);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
else if (id == Level)
|
|
|
|
return setDebug(msg,dest);
|
2006-10-17 20:40:01 +00:00
|
|
|
else if (id == Command)
|
|
|
|
return msgCommand(msg);
|
2005-03-28 22:27:26 +00:00
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Module::setDebug(Message& msg, const String& target)
|
|
|
|
{
|
2011-03-23 16:26:25 +00:00
|
|
|
if (target != name())
|
2005-03-28 22:27:26 +00:00
|
|
|
return false;
|
|
|
|
|
2014-02-04 16:36:23 +00:00
|
|
|
NamedCounter* counter = objectsCounter();
|
2005-03-28 22:27:26 +00:00
|
|
|
String str = msg.getValue("line");
|
|
|
|
if (str.startSkip("level")) {
|
|
|
|
int dbg = debugLevel();
|
|
|
|
str >> dbg;
|
|
|
|
debugLevel(dbg);
|
|
|
|
}
|
|
|
|
else if (str == "reset") {
|
|
|
|
debugLevel(TelEngine::debugLevel());
|
|
|
|
debugEnabled(true);
|
2014-02-04 16:36:23 +00:00
|
|
|
if (counter)
|
|
|
|
counter->enable(getObjCounting());
|
|
|
|
}
|
|
|
|
else if (str.startSkip("objects")) {
|
|
|
|
bool dbg = (str == "reset") ? getObjCounting() : (counter && counter->enabled());
|
|
|
|
str >> dbg;
|
|
|
|
if (counter)
|
|
|
|
counter->enable(dbg);
|
2005-03-28 22:27:26 +00:00
|
|
|
}
|
2005-12-09 21:33:10 +00:00
|
|
|
else if (str.startSkip("filter"))
|
|
|
|
m_filter = str;
|
2005-03-28 22:27:26 +00:00
|
|
|
else {
|
|
|
|
bool dbg = debugEnabled();
|
|
|
|
str >> dbg;
|
|
|
|
debugEnabled(dbg);
|
|
|
|
}
|
2011-03-23 16:26:25 +00:00
|
|
|
msg.retValue() << "Module " << name()
|
2005-03-28 22:27:26 +00:00
|
|
|
<< " debug " << (debugEnabled() ? "on" : "off")
|
2014-02-04 16:36:23 +00:00
|
|
|
<< " level " << debugLevel()
|
|
|
|
<< " objects " << ((counter && counter->enabled()) ? "on" : "off");
|
2005-12-09 21:33:10 +00:00
|
|
|
if (m_filter)
|
|
|
|
msg.retValue() << " filter: " << m_filter;
|
2006-10-17 20:40:01 +00:00
|
|
|
msg.retValue() << "\r\n";
|
2005-03-28 22:27:26 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2005-12-09 21:33:10 +00:00
|
|
|
bool Module::filterDebug(const String& item) const
|
|
|
|
{
|
|
|
|
return m_filter.null() ? debugEnabled() : m_filter.matches(item);
|
|
|
|
}
|
|
|
|
|
2005-03-28 22:27:26 +00:00
|
|
|
|
2005-03-28 00:58:26 +00:00
|
|
|
Driver::Driver(const char* name, const char* type)
|
2005-04-23 23:52:08 +00:00
|
|
|
: Module(name,type),
|
|
|
|
m_init(false), m_varchan(true),
|
2005-06-14 20:53:20 +00:00
|
|
|
m_routing(0), m_routed(0), m_total(0),
|
2005-04-29 21:07:41 +00:00
|
|
|
m_nextid(0), m_timeout(0),
|
2012-08-15 12:36:53 +00:00
|
|
|
m_maxroute(0), m_maxchans(0), m_chanCount(0), m_dtmfDups(false)
|
2005-03-20 03:11:53 +00:00
|
|
|
{
|
2005-04-20 12:37:59 +00:00
|
|
|
m_prefix << name << "/";
|
2005-03-20 03:11:53 +00:00
|
|
|
}
|
|
|
|
|
2005-04-14 03:14:20 +00:00
|
|
|
void* Driver::getObject(const String& name) const
|
|
|
|
{
|
2013-04-12 13:19:14 +00:00
|
|
|
if (name == YATOM("Driver"))
|
2005-04-14 03:14:20 +00:00
|
|
|
return const_cast<Driver*>(this);
|
|
|
|
return Module::getObject(name);
|
|
|
|
}
|
|
|
|
|
2005-04-09 22:10:00 +00:00
|
|
|
void Driver::initialize()
|
|
|
|
{
|
|
|
|
setup();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Driver::setup(const char* prefix, bool minimal)
|
2005-03-20 03:11:53 +00:00
|
|
|
{
|
2005-06-20 20:51:17 +00:00
|
|
|
DDebug(this,DebugAll,"Driver::setup('%s',%d)",prefix,minimal);
|
2005-03-28 22:27:26 +00:00
|
|
|
Module::setup();
|
2006-01-19 21:45:30 +00:00
|
|
|
loadLimits();
|
2005-03-20 03:11:53 +00:00
|
|
|
if (m_init)
|
|
|
|
return;
|
|
|
|
m_init = true;
|
2005-03-28 22:27:26 +00:00
|
|
|
m_prefix = prefix ? prefix : name().c_str();
|
|
|
|
if (m_prefix && !m_prefix.endsWith("/"))
|
|
|
|
m_prefix += "/";
|
2005-05-03 18:27:14 +00:00
|
|
|
XDebug(DebugAll,"setup name='%s' prefix='%s'",name().c_str(),m_prefix.c_str());
|
2005-04-07 20:31:22 +00:00
|
|
|
installRelay(Masquerade,10);
|
2005-04-28 22:46:59 +00:00
|
|
|
installRelay(Locate,40);
|
|
|
|
installRelay(Drop,60);
|
|
|
|
installRelay(Execute,90);
|
2008-08-04 02:06:00 +00:00
|
|
|
installRelay(Control,90);
|
2005-04-09 22:10:00 +00:00
|
|
|
if (minimal)
|
|
|
|
return;
|
|
|
|
installRelay(Tone);
|
|
|
|
installRelay(Text);
|
|
|
|
installRelay(Ringing);
|
|
|
|
installRelay(Answered);
|
2005-03-28 00:58:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool Driver::isBusy() const
|
|
|
|
{
|
2012-08-15 12:36:53 +00:00
|
|
|
return (m_routing || m_chanCount);
|
2005-03-28 22:27:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Channel* Driver::find(const String& id) const
|
|
|
|
{
|
|
|
|
const ObjList* pos = m_chans.find(id);
|
|
|
|
return pos ? static_cast<Channel*>(pos->get()) : 0;
|
2005-03-20 03:11:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool Driver::received(Message &msg, int id)
|
|
|
|
{
|
2005-03-25 01:05:44 +00:00
|
|
|
if (!m_prefix)
|
|
|
|
return false;
|
|
|
|
// pick destination depending on message type
|
2005-03-20 03:11:53 +00:00
|
|
|
String dest;
|
|
|
|
switch (id) {
|
2005-03-28 22:27:26 +00:00
|
|
|
case Timer:
|
2005-04-28 22:46:59 +00:00
|
|
|
{
|
|
|
|
// check each channel for timeouts
|
|
|
|
lock();
|
2006-01-12 05:32:06 +00:00
|
|
|
ListIterator iter(m_chans);
|
2005-04-28 22:46:59 +00:00
|
|
|
Time t;
|
2006-01-12 05:32:06 +00:00
|
|
|
for (;;) {
|
|
|
|
RefPointer<Channel> c = static_cast<Channel*>(iter.get());
|
|
|
|
unlock();
|
|
|
|
if (!c)
|
|
|
|
break;
|
2006-02-28 15:12:12 +00:00
|
|
|
c->checkTimers(msg,t);
|
2011-06-22 11:38:57 +00:00
|
|
|
c = 0;
|
2006-01-12 05:32:06 +00:00
|
|
|
lock();
|
2005-04-28 22:46:59 +00:00
|
|
|
}
|
|
|
|
}
|
2014-02-04 16:36:23 +00:00
|
|
|
return Module::received(msg,id);
|
2005-04-28 22:46:59 +00:00
|
|
|
case Status:
|
2006-02-17 15:39:36 +00:00
|
|
|
// check if it's a channel status request
|
2011-06-03 12:26:53 +00:00
|
|
|
dest = msg.getValue(YSTRING("module"));
|
2006-02-17 15:39:36 +00:00
|
|
|
if (dest.startsWith(m_prefix))
|
|
|
|
break;
|
2014-02-04 16:36:23 +00:00
|
|
|
// fall through
|
2005-03-28 22:27:26 +00:00
|
|
|
case Level:
|
2006-01-23 15:57:47 +00:00
|
|
|
case Route:
|
2006-10-17 20:40:01 +00:00
|
|
|
case Command:
|
2005-03-28 22:27:26 +00:00
|
|
|
return Module::received(msg,id);
|
2005-04-28 22:46:59 +00:00
|
|
|
case Halt:
|
2005-04-29 21:07:41 +00:00
|
|
|
dropAll(msg);
|
|
|
|
return false;
|
2005-03-20 03:11:53 +00:00
|
|
|
case Execute:
|
2011-06-03 12:26:53 +00:00
|
|
|
dest = msg.getValue(YSTRING("callto"));
|
2005-03-20 03:11:53 +00:00
|
|
|
break;
|
|
|
|
case Drop:
|
|
|
|
case Masquerade:
|
2005-03-28 22:27:26 +00:00
|
|
|
case Locate:
|
2011-06-03 12:26:53 +00:00
|
|
|
dest = msg.getValue(YSTRING("id"));
|
2005-03-20 03:11:53 +00:00
|
|
|
break;
|
|
|
|
default:
|
2011-06-03 12:26:53 +00:00
|
|
|
dest = msg.getValue(YSTRING("peerid"));
|
2007-07-05 11:39:43 +00:00
|
|
|
// if this channel is not the peer, try to match it as target
|
2006-11-08 23:16:28 +00:00
|
|
|
if (!dest.startsWith(m_prefix))
|
2011-06-03 12:26:53 +00:00
|
|
|
dest = msg.getValue(YSTRING("targetid"));
|
2005-03-20 03:11:53 +00:00
|
|
|
break;
|
|
|
|
}
|
2005-05-03 18:27:14 +00:00
|
|
|
XDebug(DebugAll,"id=%d prefix='%s' dest='%s'",id,m_prefix.c_str(),dest.c_str());
|
2005-03-28 00:58:26 +00:00
|
|
|
|
2005-05-05 21:16:14 +00:00
|
|
|
if (id == Drop) {
|
|
|
|
bool exact = (dest == name());
|
|
|
|
if (exact || dest.null() || (dest == type())) {
|
|
|
|
dropAll(msg);
|
|
|
|
return exact;
|
|
|
|
}
|
2005-03-20 03:11:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// handle call.execute which should start a new channel
|
2005-04-09 22:10:00 +00:00
|
|
|
if (id == Execute) {
|
2005-08-03 02:02:50 +00:00
|
|
|
if (!canAccept(false))
|
2005-04-29 21:07:41 +00:00
|
|
|
return false;
|
2008-07-16 09:48:49 +00:00
|
|
|
if (dest.startSkip(m_prefix,false) ||
|
2011-06-03 12:26:53 +00:00
|
|
|
(dest.startSkip("line/",false) && hasLine(msg.getValue(YSTRING("line")))))
|
2008-07-16 09:48:49 +00:00
|
|
|
return msgExecute(msg,dest);
|
|
|
|
return false;
|
2005-04-09 22:10:00 +00:00
|
|
|
}
|
2005-03-20 03:11:53 +00:00
|
|
|
|
2008-07-16 09:48:49 +00:00
|
|
|
// check if the message was for this driver
|
|
|
|
if (!dest.startsWith(m_prefix))
|
|
|
|
return false;
|
|
|
|
|
2006-01-12 05:32:06 +00:00
|
|
|
lock();
|
|
|
|
RefPointer<Channel> chan = find(dest);
|
|
|
|
unlock();
|
2005-03-20 03:11:53 +00:00
|
|
|
if (!chan) {
|
2005-06-20 20:51:17 +00:00
|
|
|
DDebug(this,DebugMild,"Could not find channel '%s'",dest.c_str());
|
2005-03-20 03:11:53 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (id) {
|
2006-02-17 15:39:36 +00:00
|
|
|
case Status:
|
|
|
|
chan->msgStatus(msg);
|
|
|
|
return true;
|
2005-07-12 16:05:29 +00:00
|
|
|
case Progress:
|
2009-04-02 15:52:21 +00:00
|
|
|
return chan->isIncoming() && !chan->isAnswered() && chan->msgProgress(msg);
|
2005-03-20 03:11:53 +00:00
|
|
|
case Ringing:
|
2009-04-02 15:52:21 +00:00
|
|
|
return chan->isIncoming() && !chan->isAnswered() && chan->msgRinging(msg);
|
2005-03-20 03:11:53 +00:00
|
|
|
case Answered:
|
2009-04-02 15:52:21 +00:00
|
|
|
return chan->isIncoming() && !chan->isAnswered() && chan->msgAnswered(msg);
|
2005-03-20 03:11:53 +00:00
|
|
|
case Tone:
|
|
|
|
return chan->msgTone(msg,msg.getValue("text"));
|
|
|
|
case Text:
|
|
|
|
return chan->msgText(msg,msg.getValue("text"));
|
|
|
|
case Drop:
|
2005-04-09 22:10:00 +00:00
|
|
|
return chan->msgDrop(msg,msg.getValue("reason"));
|
|
|
|
case Transfer:
|
|
|
|
return chan->msgTransfer(msg);
|
2006-01-23 15:57:47 +00:00
|
|
|
case Update:
|
|
|
|
return chan->msgUpdate(msg);
|
2005-03-20 03:11:53 +00:00
|
|
|
case Masquerade:
|
2011-06-03 12:26:53 +00:00
|
|
|
msg = msg.getValue(YSTRING("message"));
|
|
|
|
msg.clearParam(YSTRING("message"));
|
2005-03-20 03:11:53 +00:00
|
|
|
msg.userData(chan);
|
2007-07-05 11:39:43 +00:00
|
|
|
if (chan->msgMasquerade(msg))
|
|
|
|
return true;
|
2012-05-29 08:48:54 +00:00
|
|
|
chan->complete(msg,msg.getBoolValue(YSTRING("complete_minimal"),false));
|
2007-07-05 11:39:43 +00:00
|
|
|
return false;
|
2005-03-28 22:27:26 +00:00
|
|
|
case Locate:
|
|
|
|
msg.userData(chan);
|
|
|
|
return true;
|
2008-08-04 02:06:00 +00:00
|
|
|
case Control:
|
|
|
|
return chan->msgControl(msg);
|
2005-03-20 03:11:53 +00:00
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2005-04-28 22:46:59 +00:00
|
|
|
void Driver::dropAll(Message &msg)
|
2005-03-20 03:11:53 +00:00
|
|
|
{
|
2011-06-03 12:26:53 +00:00
|
|
|
const char* reason = msg.getValue(YSTRING("reason"));
|
2006-01-12 05:32:06 +00:00
|
|
|
lock();
|
|
|
|
ListIterator iter(m_chans);
|
|
|
|
for (;;) {
|
|
|
|
RefPointer<Channel> c = static_cast<Channel*>(iter.get());
|
|
|
|
unlock();
|
|
|
|
if (!c)
|
|
|
|
break;
|
2006-01-12 22:41:37 +00:00
|
|
|
DDebug(this,DebugAll,"Dropping %s channel '%s' @%p [%p]",
|
|
|
|
name().c_str(),c->id().c_str(),static_cast<Channel*>(c),this);
|
2006-01-12 05:32:06 +00:00
|
|
|
c->msgDrop(msg,reason);
|
2006-01-12 19:06:25 +00:00
|
|
|
c = 0;
|
2006-01-12 05:32:06 +00:00
|
|
|
lock();
|
2005-04-28 22:46:59 +00:00
|
|
|
}
|
2005-03-20 03:11:53 +00:00
|
|
|
}
|
2005-03-28 00:58:26 +00:00
|
|
|
|
2005-08-03 02:02:50 +00:00
|
|
|
bool Driver::canAccept(bool routers)
|
2005-04-29 21:07:41 +00:00
|
|
|
{
|
|
|
|
if (Engine::exiting())
|
|
|
|
return false;
|
2005-08-03 02:02:50 +00:00
|
|
|
if (routers && !canRoute())
|
2005-04-29 21:07:41 +00:00
|
|
|
return false;
|
2012-08-15 12:36:53 +00:00
|
|
|
if (m_maxchans)
|
|
|
|
return (m_chanCount < m_maxchans);
|
2005-04-29 21:07:41 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2005-08-03 02:02:50 +00:00
|
|
|
bool Driver::canRoute()
|
|
|
|
{
|
2014-01-07 16:08:09 +00:00
|
|
|
if (Engine::exiting() || (Engine::accept() >= Engine::Congestion))
|
2005-08-03 02:02:50 +00:00
|
|
|
return false;
|
|
|
|
if (m_maxroute && (m_routing >= m_maxroute))
|
|
|
|
return false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2008-07-16 09:48:49 +00:00
|
|
|
bool Driver::hasLine(const String& line) const
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Driver::msgRoute(Message& msg)
|
|
|
|
{
|
2011-06-03 12:26:53 +00:00
|
|
|
String called = msg.getValue(YSTRING("called"));
|
2008-07-16 09:48:49 +00:00
|
|
|
if (called.null())
|
|
|
|
return false;
|
2011-06-03 12:26:53 +00:00
|
|
|
String line = msg.getValue(YSTRING("line"));
|
2008-07-16 09:48:49 +00:00
|
|
|
if (line.null())
|
2011-06-03 12:26:53 +00:00
|
|
|
line = msg.getValue(YSTRING("account"));
|
2008-07-16 09:48:49 +00:00
|
|
|
if (line && hasLine(line)) {
|
|
|
|
// asked to route to a line we have locally
|
|
|
|
msg.setParam("line",line);
|
|
|
|
msg.retValue() = prefix() + called;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return Module::msgRoute(msg);
|
|
|
|
}
|
|
|
|
|
2005-03-28 22:27:26 +00:00
|
|
|
void Driver::genUpdate(Message& msg)
|
|
|
|
{
|
|
|
|
msg.addParam("routed",String(m_routed));
|
|
|
|
msg.addParam("routing",String(m_routing));
|
2005-06-14 20:53:20 +00:00
|
|
|
msg.addParam("total",String(m_total));
|
2012-08-15 12:36:53 +00:00
|
|
|
msg.addParam("chans",String(m_chanCount));
|
2005-03-28 22:27:26 +00:00
|
|
|
}
|
|
|
|
|
2005-03-28 00:58:26 +00:00
|
|
|
void Driver::statusModule(String& str)
|
|
|
|
{
|
2005-03-28 22:27:26 +00:00
|
|
|
Module::statusModule(str);
|
2005-06-17 18:34:16 +00:00
|
|
|
str.append("format=Status|Address|Peer",",");
|
2005-03-28 00:58:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Driver::statusParams(String& str)
|
|
|
|
{
|
2005-03-28 22:27:26 +00:00
|
|
|
Module::statusParams(str);
|
|
|
|
str.append("routed=",",") << m_routed;
|
|
|
|
str << ",routing=" << m_routing;
|
2005-06-14 20:53:20 +00:00
|
|
|
str << ",total=" << m_total;
|
2012-08-15 12:36:53 +00:00
|
|
|
str << ",chans=" << m_chanCount;
|
2005-03-28 00:58:26 +00:00
|
|
|
}
|
|
|
|
|
2006-09-26 09:54:11 +00:00
|
|
|
void Driver::statusDetail(String& str)
|
2005-03-28 00:58:26 +00:00
|
|
|
{
|
2005-04-08 12:45:19 +00:00
|
|
|
ObjList* l = m_chans.skipNull();
|
|
|
|
for (; l; l=l->skipNext()) {
|
2005-03-28 00:58:26 +00:00
|
|
|
Channel* c = static_cast<Channel*>(l->get());
|
2005-06-17 18:34:16 +00:00
|
|
|
str.append(c->id(),",") << "=" << c->status() << "|" << c->address() << "|" << c->getPeerId();
|
2005-03-28 00:58:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-10-17 20:40:01 +00:00
|
|
|
bool Driver::commandComplete(Message& msg, const String& partLine, const String& partWord)
|
|
|
|
{
|
|
|
|
bool ok = false;
|
2011-06-03 12:26:53 +00:00
|
|
|
bool listChans = String(msg.getValue(YSTRING("complete"))) == YSTRING("channels");
|
2006-10-17 20:40:01 +00:00
|
|
|
if (listChans && (partWord.null() || name().startsWith(partWord)))
|
|
|
|
msg.retValue().append(name(),"\t");
|
|
|
|
else
|
|
|
|
ok = Module::commandComplete(msg,partLine,partWord);
|
|
|
|
lock();
|
|
|
|
unsigned int nchans = m_chans.count();
|
|
|
|
unlock();
|
|
|
|
if (nchans && listChans) {
|
|
|
|
if (name().startsWith(partWord)) {
|
|
|
|
msg.retValue().append(prefix(),"\t");
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
if (partWord.startsWith(prefix()))
|
|
|
|
ok = true;
|
|
|
|
lock();
|
|
|
|
ObjList* l = m_chans.skipNull();
|
|
|
|
for (; l; l=l->skipNext()) {
|
|
|
|
Channel* c = static_cast<Channel*>(l->get());
|
|
|
|
if (c->id().startsWith(partWord))
|
|
|
|
msg.retValue().append(c->id(),"\t");
|
|
|
|
}
|
|
|
|
unlock();
|
|
|
|
}
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
2005-03-28 22:27:26 +00:00
|
|
|
bool Driver::setDebug(Message& msg, const String& target)
|
|
|
|
{
|
|
|
|
if (!target.startsWith(m_prefix))
|
|
|
|
return Module::setDebug(msg,target);
|
|
|
|
|
|
|
|
Lock lock(this);
|
|
|
|
Channel* chan = find(target);
|
|
|
|
if (chan)
|
|
|
|
return chan->setDebug(msg);
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2006-01-09 23:19:36 +00:00
|
|
|
void Driver::loadLimits()
|
|
|
|
{
|
2011-06-03 12:26:53 +00:00
|
|
|
timeout(Engine::config().getIntValue(YSTRING("telephony"),"timeout"));
|
|
|
|
maxRoute(Engine::config().getIntValue(YSTRING("telephony"),"maxroute"));
|
|
|
|
maxChans(Engine::config().getIntValue(YSTRING("telephony"),"maxchans"));
|
|
|
|
dtmfDups(Engine::config().getBoolValue(YSTRING("telephony"),"dtmfdups"));
|
2006-01-09 23:19:36 +00:00
|
|
|
}
|
|
|
|
|
2005-03-29 01:50:20 +00:00
|
|
|
unsigned int Driver::nextid()
|
|
|
|
{
|
|
|
|
Lock lock(this);
|
|
|
|
return ++m_nextid;
|
|
|
|
}
|
|
|
|
|
2005-03-28 22:27:26 +00:00
|
|
|
|
|
|
|
Router::Router(Driver* driver, const char* id, Message* msg)
|
2005-04-10 21:42:49 +00:00
|
|
|
: Thread("Call Router"), m_driver(driver), m_id(id), m_msg(msg)
|
2005-03-28 22:27:26 +00:00
|
|
|
{
|
2014-02-04 16:36:23 +00:00
|
|
|
if (driver)
|
|
|
|
setObjCounter(driver->objectsCounter());
|
2005-03-28 22:27:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Router::run()
|
|
|
|
{
|
|
|
|
if (!(m_driver && m_msg))
|
|
|
|
return;
|
|
|
|
m_driver->lock();
|
|
|
|
m_driver->m_routing++;
|
|
|
|
m_driver->changed();
|
|
|
|
m_driver->unlock();
|
|
|
|
bool ok = route();
|
|
|
|
m_driver->lock();
|
|
|
|
m_driver->m_routing--;
|
|
|
|
if (ok)
|
|
|
|
m_driver->m_routed++;
|
|
|
|
m_driver->changed();
|
|
|
|
m_driver->unlock();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Router::route()
|
|
|
|
{
|
2005-07-01 22:35:06 +00:00
|
|
|
DDebug(m_driver,DebugAll,"Routing thread for '%s' [%p]",m_id.c_str(),this);
|
2005-07-01 21:12:16 +00:00
|
|
|
|
2006-01-30 20:44:03 +00:00
|
|
|
RefPointer<Channel> chan;
|
2011-06-03 12:26:53 +00:00
|
|
|
String tmp(m_msg->getValue(YSTRING("callto")));
|
2005-07-03 10:51:19 +00:00
|
|
|
bool ok = !tmp.null();
|
2005-07-01 21:12:16 +00:00
|
|
|
if (ok)
|
|
|
|
m_msg->retValue() = tmp;
|
2005-11-28 00:07:24 +00:00
|
|
|
else {
|
2011-06-03 12:26:53 +00:00
|
|
|
if (*m_msg == YSTRING("call.preroute")) {
|
2006-01-30 20:44:03 +00:00
|
|
|
ok = Engine::dispatch(m_msg);
|
|
|
|
m_driver->lock();
|
|
|
|
chan = m_driver->find(m_id);
|
|
|
|
m_driver->unlock();
|
|
|
|
if (!chan) {
|
|
|
|
Debug(m_driver,DebugInfo,"Connection '%s' vanished while prerouting!",m_id.c_str());
|
|
|
|
return false;
|
|
|
|
}
|
2012-07-02 15:30:52 +00:00
|
|
|
const String* cp = m_msg->getParam(s_copyParams);
|
|
|
|
if (!TelEngine::null(cp)) {
|
|
|
|
Channel::paramMutex().lock();
|
|
|
|
chan->parameters().copyParams(*m_msg,*cp);
|
|
|
|
Channel::paramMutex().unlock();
|
|
|
|
}
|
2011-06-03 12:26:53 +00:00
|
|
|
bool dropCall = ok && ((m_msg->retValue() == YSTRING("-")) || (m_msg->retValue() == YSTRING("error")));
|
2006-01-30 20:44:03 +00:00
|
|
|
if (dropCall)
|
2011-06-03 12:26:53 +00:00
|
|
|
chan->callRejected(m_msg->getValue(YSTRING("error"),"unknown"),
|
|
|
|
m_msg->getValue(YSTRING("reason")),m_msg);
|
2006-01-30 20:44:03 +00:00
|
|
|
else
|
|
|
|
dropCall = !chan->callPrerouted(*m_msg,ok);
|
|
|
|
if (dropCall) {
|
|
|
|
// get rid of the dynamic chans
|
|
|
|
if (m_driver->varchan())
|
|
|
|
chan->deref();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
chan = 0;
|
2005-11-28 00:07:24 +00:00
|
|
|
*m_msg = "call.route";
|
2006-01-30 20:44:03 +00:00
|
|
|
m_msg->retValue().clear();
|
2005-11-28 00:07:24 +00:00
|
|
|
}
|
2005-07-01 21:12:16 +00:00
|
|
|
ok = Engine::dispatch(m_msg);
|
2005-11-28 00:07:24 +00:00
|
|
|
}
|
2005-03-28 22:27:26 +00:00
|
|
|
|
|
|
|
m_driver->lock();
|
2006-01-30 20:44:03 +00:00
|
|
|
chan = m_driver->find(m_id);
|
2005-03-28 22:27:26 +00:00
|
|
|
m_driver->unlock();
|
|
|
|
|
|
|
|
if (!chan) {
|
2005-07-01 22:35:06 +00:00
|
|
|
Debug(m_driver,DebugInfo,"Connection '%s' vanished while routing!",m_id.c_str());
|
2005-03-28 22:27:26 +00:00
|
|
|
return false;
|
|
|
|
}
|
2006-01-30 20:44:03 +00:00
|
|
|
// chan will keep it referenced even if message user data is changed
|
|
|
|
m_msg->userData(chan);
|
2005-03-28 22:27:26 +00:00
|
|
|
|
2012-05-31 17:40:33 +00:00
|
|
|
static const char s_noroute[] = "noroute";
|
|
|
|
static const char s_looping[] = "looping";
|
|
|
|
static const char s_noconn[] = "noconn";
|
|
|
|
|
2011-12-22 13:46:09 +00:00
|
|
|
if (ok && m_msg->retValue().trimSpaces()) {
|
2011-06-03 12:26:53 +00:00
|
|
|
if ((m_msg->retValue() == YSTRING("-")) || (m_msg->retValue() == YSTRING("error")))
|
|
|
|
chan->callRejected(m_msg->getValue(YSTRING("error"),"unknown"),
|
2005-07-12 16:05:29 +00:00
|
|
|
m_msg->getValue("reason"),m_msg);
|
2012-05-31 17:40:33 +00:00
|
|
|
else if (m_msg->getIntValue(YSTRING("antiloop"),1) <= 0) {
|
|
|
|
const char* error = m_msg->getValue(YSTRING("error"),s_looping);
|
|
|
|
chan->callRejected(error,m_msg->getValue(YSTRING("reason"),
|
|
|
|
((s_looping == error) ? "Call is looping" : (const char*)0)),m_msg);
|
|
|
|
}
|
2005-05-14 21:59:07 +00:00
|
|
|
else if (chan->callRouted(*m_msg)) {
|
2005-05-14 20:03:38 +00:00
|
|
|
*m_msg = "call.execute";
|
|
|
|
m_msg->setParam("callto",m_msg->retValue());
|
2011-06-03 12:26:53 +00:00
|
|
|
m_msg->clearParam(YSTRING("error"));
|
2005-05-14 20:03:38 +00:00
|
|
|
m_msg->retValue().clear();
|
|
|
|
ok = Engine::dispatch(m_msg);
|
|
|
|
if (ok)
|
|
|
|
chan->callAccept(*m_msg);
|
2006-01-06 00:39:06 +00:00
|
|
|
else {
|
2012-05-31 17:40:33 +00:00
|
|
|
const char* error = m_msg->getValue(YSTRING("error"),s_noconn);
|
|
|
|
const char* reason = m_msg->getValue(YSTRING("reason"),
|
|
|
|
((s_noconn == error) ? "Could not connect to target" : (const char*)0));
|
2011-03-17 20:57:34 +00:00
|
|
|
Message m(s_disconnected);
|
2012-07-02 15:30:52 +00:00
|
|
|
const String* cp = m_msg->getParam(s_copyParams);
|
2012-07-01 20:47:55 +00:00
|
|
|
if (!TelEngine::null(cp))
|
|
|
|
m.copyParams(*m_msg,*cp);
|
2006-01-06 00:39:06 +00:00
|
|
|
chan->complete(m);
|
|
|
|
m.setParam("error",error);
|
|
|
|
m.setParam("reason",reason);
|
|
|
|
m.setParam("reroute",String::boolText(true));
|
|
|
|
m.userData(chan);
|
2011-03-17 20:57:34 +00:00
|
|
|
m.setNotify();
|
2006-01-06 00:39:06 +00:00
|
|
|
if (!Engine::dispatch(m))
|
|
|
|
chan->callRejected(error,reason,m_msg);
|
|
|
|
}
|
2005-05-14 20:03:38 +00:00
|
|
|
}
|
2005-03-28 22:27:26 +00:00
|
|
|
}
|
2012-05-31 17:40:33 +00:00
|
|
|
else {
|
|
|
|
const char* error = m_msg->getValue(YSTRING("error"),s_noroute);
|
|
|
|
chan->callRejected(error,m_msg->getValue(YSTRING("reason"),
|
|
|
|
((s_noroute == error) ? "No route to call target" : (const char*)0)),m_msg);
|
|
|
|
}
|
2005-03-28 22:27:26 +00:00
|
|
|
|
2005-04-23 23:52:08 +00:00
|
|
|
// dereference again if the channel is dynamic
|
|
|
|
if (m_driver->varchan())
|
|
|
|
chan->deref();
|
2005-03-28 22:27:26 +00:00
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Router::cleanup()
|
|
|
|
{
|
2007-05-15 15:40:50 +00:00
|
|
|
destruct(m_msg);
|
2005-03-28 22:27:26 +00:00
|
|
|
}
|
|
|
|
|
2005-03-28 00:58:26 +00:00
|
|
|
/* vi: set ts=8 sw=4 sts=4 noet: */
|