Commited changes by Marian Podgoreanu.
git-svn-id: http://yate.null.ro/svn/yate/trunk@920 acf43c95-373e-0410-b603-e72c3f656dc1
This commit is contained in:
parent
3ab82e9ea2
commit
9dc980c5a9
|
@ -31,7 +31,8 @@
|
|||
using namespace TelEngine;
|
||||
|
||||
IAXEngine::IAXEngine(int port, u_int16_t transListCount, u_int16_t retransCount, u_int16_t retransInterval,
|
||||
u_int16_t authTimeout, u_int16_t transTimeout, u_int16_t maxFullFrameDataLen, u_int32_t format, u_int32_t capab)
|
||||
u_int16_t authTimeout, u_int16_t transTimeout, u_int16_t maxFullFrameDataLen,
|
||||
u_int32_t format, u_int32_t capab, u_int32_t trunkSendInterval)
|
||||
: Mutex(true),
|
||||
m_lastGetEvIndex(0),
|
||||
m_maxFullFrameDataLen(maxFullFrameDataLen),
|
||||
|
@ -42,7 +43,11 @@ IAXEngine::IAXEngine(int port, u_int16_t transListCount, u_int16_t retransCount,
|
|||
m_authTimeout(authTimeout),
|
||||
m_transTimeout(transTimeout),
|
||||
m_format(format),
|
||||
m_capability(capab)
|
||||
m_capability(capab),
|
||||
m_mutexTrunk(true),
|
||||
m_trunkSendInterval(trunkSendInterval),
|
||||
m_writeCommands(0),
|
||||
m_writeCommandsFail(0)
|
||||
{
|
||||
debugName("iaxengine");
|
||||
if ((port <= 0) || port > 65535)
|
||||
|
@ -72,6 +77,10 @@ IAXEngine::~IAXEngine()
|
|||
for (int i = 0; i < m_transListCount; i++)
|
||||
delete m_transList[i];
|
||||
delete[] m_transList;
|
||||
|
||||
|
||||
|
||||
print();
|
||||
}
|
||||
|
||||
IAXTransaction* IAXEngine::addFrame(const SocketAddr& addr, IAXFrame* frame)
|
||||
|
@ -91,7 +100,7 @@ IAXTransaction* IAXEngine::addFrame(const SocketAddr& addr, IAXFrame* frame)
|
|||
continue;
|
||||
// Complete transaction
|
||||
if (tr->processFrame(frame)) {
|
||||
tr->m_rCallNo = frame->sourceCallNo();
|
||||
tr->m_rCallNo = frame->sourceCallNo();
|
||||
m_incompleteTransList.remove(tr,false);
|
||||
m_transList[frame->sourceCallNo() % m_transListCount]->append(tr);
|
||||
XDebug(this,DebugAll,"New incomplete outgoing transaction completed (%u,%u)",
|
||||
|
@ -109,20 +118,28 @@ IAXTransaction* IAXEngine::addFrame(const SocketAddr& addr, IAXFrame* frame)
|
|||
continue;
|
||||
// Mini frame
|
||||
if (!frame->fullFrame()) {
|
||||
if (addr == tr->remoteAddr())
|
||||
return tr->processFrame(frame);
|
||||
if (addr == tr->remoteAddr()) {
|
||||
// keep transaction referenced but unlock the engine
|
||||
RefPointer<IAXTransaction> t = tr;
|
||||
lock.drop();
|
||||
return t ? t->processFrame(frame) : 0;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
// Full frame
|
||||
// Has a local number assigned? If not, test socket
|
||||
if ((frame->fullFrame())->destCallNo() || addr == tr->remoteAddr())
|
||||
return tr->processFrame(frame);
|
||||
if ((frame->fullFrame())->destCallNo() || addr == tr->remoteAddr()) {
|
||||
// keep transaction referenced but unlock the engine
|
||||
RefPointer<IAXTransaction> t = tr;
|
||||
lock.drop();
|
||||
return t ? t->processFrame(frame) : 0;
|
||||
}
|
||||
}
|
||||
// Frame doesn't belong to an existing transaction
|
||||
// Test if it is a full frame with an IAX control message that needs a new transaction
|
||||
if (!frame->fullFrame() || frame->type() != IAXFrame::IAX)
|
||||
return 0;
|
||||
switch (frame->subclass()) {
|
||||
switch (frame->fullFrame()->subclass()) {
|
||||
case IAXControl::New:
|
||||
case IAXControl::RegReq:
|
||||
case IAXControl::RegRel:
|
||||
|
@ -133,8 +150,14 @@ IAXTransaction* IAXEngine::addFrame(const SocketAddr& addr, IAXFrame* frame)
|
|||
return 0;
|
||||
case IAXControl::FwDownl:
|
||||
default:
|
||||
DDebug(this,DebugAll,"Unsupported incoming transaction Frame(%u,%u)",
|
||||
frame->type(),frame->subclass());
|
||||
if (frame->fullFrame()) {
|
||||
if (frame->fullFrame()->destCallNo())
|
||||
XDebug(this,DebugAll,"Unmatched Frame(%u,%u) for (%u,%u)",
|
||||
frame->type(),frame->subclass(),frame->fullFrame()->destCallNo(),frame->fullFrame()->sourceCallNo());
|
||||
else
|
||||
DDebug(this,DebugAll,"Unsupported incoming transaction Frame(%u,%u). Source call no: %u",
|
||||
frame->type(),frame->fullFrame()->subclass(),frame->fullFrame()->sourceCallNo());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
// Generate local number
|
||||
|
@ -200,10 +223,15 @@ void IAXEngine::readSocket(SocketAddr& addr)
|
|||
bool IAXEngine::writeSocket(const void* buf, int len, const SocketAddr& addr)
|
||||
{
|
||||
len = m_socket.sendTo(buf,len,addr);
|
||||
m_writeCommands++;
|
||||
if (len == Socket::socketError()) {
|
||||
m_writeCommandsFail++;
|
||||
if (!m_socket.canRetry())
|
||||
Debug(this,DebugWarn,"Socket write error: %s (%d)",
|
||||
::strerror(m_socket.error()),m_socket.error());
|
||||
else
|
||||
DDebug(this,DebugMild,"Socket temporary unavailable: %s (%d)",
|
||||
::strerror(m_socket.error()),m_socket.error());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -260,6 +288,25 @@ void IAXEngine::keepAlive(SocketAddr& addr)
|
|||
writeSocket(buf,sizeof(buf),addr);
|
||||
}
|
||||
|
||||
bool IAXEngine::processTrunkFrames(u_int32_t time)
|
||||
{
|
||||
Lock lock(&m_mutexTrunk);
|
||||
bool sent = false;
|
||||
for (ObjList* l = m_trunkList.skipNull(); l; l = l->next()) {
|
||||
IAXMetaTrunkFrame* frame = static_cast<IAXMetaTrunkFrame*>(l->get());
|
||||
// Frame has mini frame(s) ?
|
||||
if (!frame->timestamp())
|
||||
continue;
|
||||
int32_t interval = time - frame->timestamp();
|
||||
if (!interval || (interval && (u_int32_t)interval < m_trunkSendInterval))
|
||||
continue;
|
||||
// If the time wrapped around, send it. Worst case: we'll send an empty frame
|
||||
frame->send(time);
|
||||
sent = true;
|
||||
}
|
||||
return sent;
|
||||
}
|
||||
|
||||
void IAXEngine::processEvent(IAXEvent* event)
|
||||
{
|
||||
XDebug(this,DebugAll,"Default processing - deleting event %p Subclass %u",
|
||||
|
@ -273,26 +320,40 @@ IAXEvent* IAXEngine::getEvent(u_int64_t time)
|
|||
IAXEvent* ev;
|
||||
ObjList* l;
|
||||
|
||||
Lock lock(this);
|
||||
lock();
|
||||
// Find for incomplete transactions
|
||||
l = m_incompleteTransList.skipNull();
|
||||
for (; l; l = l->next()) {
|
||||
tr = static_cast<IAXTransaction*>(l->get());
|
||||
if (tr && 0 != (ev = tr->getEvent(time)))
|
||||
if (tr && 0 != (ev = tr->getEvent(time))) {
|
||||
unlock();
|
||||
return ev;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
// Find for complete transactions
|
||||
for (; m_lastGetEvIndex < m_transListCount; m_lastGetEvIndex++) {
|
||||
l = m_transList[m_lastGetEvIndex]->skipNull();
|
||||
for (; l; l = l->next()) {
|
||||
tr = static_cast<IAXTransaction*>(l->get());
|
||||
if (tr && 0 != (ev = tr->getEvent(time)))
|
||||
return ev;
|
||||
// Find for complete transactions, start with current index
|
||||
while (m_lastGetEvIndex < m_transListCount) {
|
||||
l = m_transList[m_lastGetEvIndex++]->skipNull();
|
||||
if (!l)
|
||||
continue;
|
||||
ListIterator iter(*l);
|
||||
for (;;) {
|
||||
tr = static_cast<IAXTransaction*>(iter.get());
|
||||
// end of iteration?
|
||||
if (!tr)
|
||||
break;
|
||||
RefPointer<IAXTransaction> t = tr;
|
||||
// dead pointer?
|
||||
if (!t)
|
||||
continue;
|
||||
unlock();
|
||||
if (0 != (ev = t->getEvent(time)))
|
||||
return ev;
|
||||
lock();
|
||||
}
|
||||
}
|
||||
m_lastGetEvIndex = 0;
|
||||
unlock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -323,15 +384,18 @@ void IAXEngine::releaseCallNo(u_int16_t lcallno)
|
|||
m_lUsedCallNo[lcallno] = false;
|
||||
}
|
||||
|
||||
IAXTransaction* IAXEngine::startLocalTransaction(IAXTransaction::Type type, const SocketAddr& addr, IAXIEList& ieList)
|
||||
IAXTransaction* IAXEngine::startLocalTransaction(IAXTransaction::Type type, const SocketAddr& addr, IAXIEList& ieList, bool trunking)
|
||||
{
|
||||
Lock lock(this);
|
||||
u_int16_t lcn = generateCallNo();
|
||||
if (!lcn)
|
||||
return 0;
|
||||
IAXTransaction* tr = IAXTransaction::factoryOut(this,type,lcn,addr,ieList);
|
||||
if (tr)
|
||||
if (tr) {
|
||||
m_incompleteTransList.append(tr);
|
||||
if (trunking)
|
||||
enableTrunking(tr);
|
||||
}
|
||||
else
|
||||
releaseCallNo(lcn);
|
||||
return tr;
|
||||
|
@ -386,6 +450,47 @@ void IAXEngine::defaultEventHandler(IAXEvent* event)
|
|||
}
|
||||
}
|
||||
|
||||
void IAXEngine::enableTrunking(IAXTransaction* trans)
|
||||
{
|
||||
Lock lock(&m_mutexTrunk);
|
||||
IAXMetaTrunkFrame* frame;
|
||||
// Already enabled ?
|
||||
for (ObjList* l = m_trunkList.skipNull(); l; l = l->next()) {
|
||||
frame = static_cast<IAXMetaTrunkFrame*>(l->get());
|
||||
if (frame && frame->addr() == trans->remoteAddr()) {
|
||||
trans->enableTrunking(frame);
|
||||
return;
|
||||
}
|
||||
}
|
||||
frame = new IAXMetaTrunkFrame(this,trans->remoteAddr());
|
||||
if (trans->enableTrunking(frame))
|
||||
m_trunkList.append(frame);
|
||||
// Deref frame: Only transactions are allowed to keep references for it
|
||||
frame->deref();
|
||||
}
|
||||
|
||||
void IAXEngine::removeTrunkFrame(IAXMetaTrunkFrame* trunkFrame)
|
||||
{
|
||||
Lock lock(&m_mutexTrunk);
|
||||
m_trunkList.remove(trunkFrame,false);
|
||||
}
|
||||
|
||||
void IAXEngine::runProcessTrunkFrames()
|
||||
{
|
||||
while (1) {
|
||||
processTrunkFrames();
|
||||
Thread::msleep(2,true);
|
||||
}
|
||||
}
|
||||
|
||||
void IAXEngine::print()
|
||||
{
|
||||
Debug(this,DebugInfo,"IAXEngine - START PRINT [%p]",this);
|
||||
Output("Write commands: " FMT64U,m_writeCommands);
|
||||
Output("Write commands failed: " FMT64U,m_writeCommandsFail);
|
||||
Debug(this,DebugInfo,"IAXEngine - END PRINT [%p]",this);
|
||||
}
|
||||
|
||||
void IAXEngine::getMD5FromChallenge(String& md5data, const String& challenge, const String& password)
|
||||
{
|
||||
MD5 md5;
|
||||
|
@ -425,9 +530,10 @@ IAXEvent::IAXEvent(Type type, bool local, bool final, IAXTransaction* transactio
|
|||
|
||||
IAXEvent::~IAXEvent()
|
||||
{
|
||||
if (m_final && m_transaction && m_transaction->state() == IAXTransaction::Terminated) {
|
||||
m_transaction->getEngine()->removeTransaction(m_transaction);
|
||||
}
|
||||
// Moved to transaction destructor
|
||||
// if (m_final && m_transaction && m_transaction->state() == IAXTransaction::Terminated) {
|
||||
// m_transaction->getEngine()->removeTransaction(m_transaction);
|
||||
// }
|
||||
if (m_transaction) {
|
||||
m_transaction->eventTerminated(this);
|
||||
m_transaction->deref();
|
||||
|
|
|
@ -24,6 +24,8 @@
|
|||
|
||||
#include <yateiax.h>
|
||||
|
||||
#include <string.h> // For memcpy()
|
||||
|
||||
using namespace TelEngine;
|
||||
|
||||
/**
|
||||
|
@ -421,13 +423,13 @@ const char* IAXFormat::videoText(u_int8_t video)
|
|||
return lookup(video,videoData);
|
||||
}
|
||||
|
||||
/**
|
||||
* IAXFrame
|
||||
*/
|
||||
/*
|
||||
* IAXFrame
|
||||
*/
|
||||
IAXFrame::IAXFrame(Type type, u_int16_t sCallNo, u_int32_t tStamp, bool retrans,
|
||||
const unsigned char* buf, unsigned int len)
|
||||
: m_type(type), m_data((char*)buf,len,true), m_retrans(retrans),
|
||||
m_sCallNo(sCallNo), m_tStamp(tStamp), m_subclass(0)
|
||||
m_sCallNo(sCallNo), m_tStamp(tStamp)
|
||||
{
|
||||
XDebug(DebugAll,"IAXFrame::IAXFrame(%u) [%p]",type,this);
|
||||
}
|
||||
|
@ -540,7 +542,7 @@ u_int8_t IAXFrame::packSubclass(u_int32_t value)
|
|||
DDebug(DebugMild,"IAXFrame nonstandard pack %u",value);
|
||||
return value;
|
||||
}
|
||||
// no need to start from zero, we already know it's >= 2^8
|
||||
// No need to start from zero, we already know it's >= 2^8
|
||||
u_int32_t v = 0x100;
|
||||
for (u_int8_t i = 8; i < 32; i++) {
|
||||
if (v == value)
|
||||
|
@ -570,32 +572,30 @@ const IAXFullFrame* IAXFrame::fullFrame() const
|
|||
/**
|
||||
* IAXFullFrame
|
||||
*/
|
||||
IAXFullFrame::IAXFullFrame(Type type, u_int32_t subClass, u_int16_t sCallNo, u_int16_t dCallNo,
|
||||
IAXFullFrame::IAXFullFrame(Type type, u_int32_t subclass, u_int16_t sCallNo, u_int16_t dCallNo,
|
||||
unsigned char oSeqNo, unsigned char iSeqNo,
|
||||
u_int32_t tStamp, bool retrans,
|
||||
const unsigned char* buf, unsigned int len)
|
||||
: IAXFrame(type,sCallNo,tStamp,retrans,buf,len),
|
||||
m_dCallNo(dCallNo), m_oSeqNo(oSeqNo), m_iSeqNo(iSeqNo)
|
||||
m_dCallNo(dCallNo), m_oSeqNo(oSeqNo), m_iSeqNo(iSeqNo), m_subclass(subclass)
|
||||
{
|
||||
DDebug(DebugAll,"IAXFullFrame::IAXFullFrame(%u,%u) [%p]",
|
||||
XDebug(DebugAll,"IAXFullFrame::IAXFullFrame(%u,%u) [%p]",
|
||||
type,subClass,this);
|
||||
m_subclass = subClass;
|
||||
}
|
||||
|
||||
IAXFullFrame::IAXFullFrame(Type type, u_int32_t subClass, u_int16_t sCallNo, u_int16_t dCallNo,
|
||||
IAXFullFrame::IAXFullFrame(Type type, u_int32_t subclass, u_int16_t sCallNo, u_int16_t dCallNo,
|
||||
unsigned char oSeqNo, unsigned char iSeqNo,
|
||||
u_int32_t tStamp,
|
||||
const unsigned char* buf, unsigned int len)
|
||||
: IAXFrame(type,sCallNo,tStamp,false,0,0),
|
||||
m_dCallNo(dCallNo), m_oSeqNo(oSeqNo), m_iSeqNo(iSeqNo)
|
||||
m_dCallNo(dCallNo), m_oSeqNo(oSeqNo), m_iSeqNo(iSeqNo), m_subclass(subclass)
|
||||
{
|
||||
DDebug(DebugAll,"IAXFullFrame::IAXFullFrame(%u,%u) [%p]",
|
||||
XDebug(DebugAll,"IAXFullFrame::IAXFullFrame(%u,%u) [%p]",
|
||||
type,subClass,this);
|
||||
|
||||
unsigned char header[12];
|
||||
DataBlock ie;
|
||||
|
||||
m_subclass = subClass;
|
||||
// Full frame flag + Source call number
|
||||
header[0] = 0x80 | (unsigned char)(m_sCallNo >> 8);
|
||||
header[1] = (unsigned char)(m_sCallNo);
|
||||
|
@ -624,7 +624,7 @@ IAXFullFrame::IAXFullFrame(Type type, u_int32_t subClass, u_int16_t sCallNo, u_i
|
|||
|
||||
IAXFullFrame::~IAXFullFrame()
|
||||
{
|
||||
DDebug(DebugAll,"IAXFullFrame::~IAXFullFrame(%u,%u) [%p]",
|
||||
XDebug(DebugAll,"IAXFullFrame::~IAXFullFrame(%u,%u) [%p]",
|
||||
m_type,m_subclass,this);
|
||||
}
|
||||
|
||||
|
@ -636,16 +636,20 @@ const IAXFullFrame* IAXFullFrame::fullFrame() const
|
|||
/**
|
||||
* IAXFrameOut
|
||||
*/
|
||||
void IAXFrameOut::setRetrans()
|
||||
{
|
||||
if (!m_retrans) {
|
||||
m_retrans = true;
|
||||
((unsigned char*)m_data.data())[2] |= 0x80;
|
||||
}
|
||||
}
|
||||
|
||||
void IAXFrameOut::transmitted()
|
||||
{
|
||||
if (m_retransCount) {
|
||||
m_retransCount--;
|
||||
m_retransTimeInterval *= 2;
|
||||
m_nextTransTime += m_retransTimeInterval;
|
||||
if (!m_retrans) {
|
||||
m_retrans = true;
|
||||
((unsigned char*)m_data.data())[2] |= 0x80;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -657,5 +661,74 @@ void IAXFrameOut::adjustAuthTimeout(u_int64_t nextTransTime)
|
|||
m_nextTransTime = nextTransTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* IAXFrameOut
|
||||
*/
|
||||
#define IAX2_METATRUNK_HEADERLENGTH 8
|
||||
#define IAX2_MINIFRAME_HEADERLENGTH 6
|
||||
|
||||
IAXMetaTrunkFrame::IAXMetaTrunkFrame(IAXEngine* engine, const SocketAddr& addr)
|
||||
: Mutex(true), m_data(0), m_dataAddIdx(IAX2_METATRUNK_HEADERLENGTH), m_engine(engine), m_addr(addr)
|
||||
{
|
||||
m_data = new u_int8_t[m_engine->maxFullFrameDataLen()];
|
||||
// Meta indicator
|
||||
*(u_int16_t*)m_data = 0;
|
||||
// Meta command & Command data (use timestamps)
|
||||
m_data[2] = 1;
|
||||
m_data[3] = 1;
|
||||
// Frame timestamp
|
||||
setTimestamp(Time::msecNow());
|
||||
}
|
||||
|
||||
IAXMetaTrunkFrame::~IAXMetaTrunkFrame()
|
||||
{
|
||||
m_engine->removeTrunkFrame(this);
|
||||
delete[] m_data;
|
||||
}
|
||||
|
||||
void IAXMetaTrunkFrame::setTimestamp(u_int32_t tStamp)
|
||||
{
|
||||
m_timestamp = tStamp;
|
||||
m_data[4] = tStamp >> 24;
|
||||
m_data[5] = tStamp >> 16;
|
||||
m_data[6] = tStamp >> 8;
|
||||
m_data[7] = tStamp;
|
||||
}
|
||||
|
||||
bool IAXMetaTrunkFrame::add(u_int16_t sCallNo, const DataBlock& data, u_int32_t tStamp)
|
||||
{
|
||||
Lock lock(this);
|
||||
bool b = true;
|
||||
// Do we have data ?
|
||||
if (!data.length())
|
||||
return b;
|
||||
// If no more room, send it
|
||||
if (m_dataAddIdx + data.length() + IAX2_MINIFRAME_HEADERLENGTH > m_engine->maxFullFrameDataLen())
|
||||
b = send(Time::msecNow());
|
||||
// Is the first mini frame ?
|
||||
if (m_dataAddIdx == IAX2_METATRUNK_HEADERLENGTH)
|
||||
m_timestamp = Time::msecNow();
|
||||
// Add the mini frame
|
||||
m_data[m_dataAddIdx++] = data.length() >> 8;
|
||||
m_data[m_dataAddIdx++] = data.length();
|
||||
m_data[m_dataAddIdx++] = sCallNo >> 8;
|
||||
m_data[m_dataAddIdx++] = sCallNo;
|
||||
m_data[m_dataAddIdx++] = tStamp >> 8;
|
||||
m_data[m_dataAddIdx++] = tStamp;
|
||||
memcpy(m_data + m_dataAddIdx,data.data(),data.length());
|
||||
m_dataAddIdx += data.length();
|
||||
return b;
|
||||
}
|
||||
|
||||
bool IAXMetaTrunkFrame::send(u_int32_t tStamp)
|
||||
{
|
||||
Lock lock(this);
|
||||
setTimestamp(tStamp);
|
||||
bool b = m_engine->writeSocket(m_data,m_dataAddIdx,m_addr);
|
||||
// Reset index & timestamp
|
||||
m_dataAddIdx = IAX2_METATRUNK_HEADERLENGTH;
|
||||
m_timestamp = 0;
|
||||
return b;
|
||||
}
|
||||
|
||||
/* vi: set ts=8 sw=4 sts=4 noet: */
|
||||
|
|
|
@ -33,8 +33,8 @@ String IAXTransaction::s_iax_modInvalidAuth("Invalid authentication request, res
|
|||
|
||||
unsigned char IAXTransaction::m_maxInFrames = 100;
|
||||
|
||||
IAXTransaction::IAXTransaction(IAXEngine* engine, IAXFullFrame* frame,
|
||||
u_int16_t lcallno, const SocketAddr& addr, void* data)
|
||||
IAXTransaction::IAXTransaction(IAXEngine* engine, IAXFullFrame* frame, u_int16_t lcallno,
|
||||
const SocketAddr& addr, void* data)
|
||||
: Mutex(true),
|
||||
m_localInitTrans(false),
|
||||
m_localReqEnd(false),
|
||||
|
@ -52,6 +52,7 @@ IAXTransaction::IAXTransaction(IAXEngine* engine, IAXFullFrame* frame,
|
|||
m_lastFullFrameOut(0),
|
||||
m_lastMiniFrameOut(0xFFFF),
|
||||
m_lastMiniFrameIn(0),
|
||||
m_lastAck(0xFFFF),
|
||||
m_mutexInMedia(true),
|
||||
m_pendingEvent(0),
|
||||
m_currentEvent(0),
|
||||
|
@ -67,7 +68,8 @@ IAXTransaction::IAXTransaction(IAXEngine* engine, IAXFullFrame* frame,
|
|||
m_format(0),
|
||||
m_formatIn(0),
|
||||
m_formatOut(0),
|
||||
m_capability(0)
|
||||
m_capability(0),
|
||||
m_trunkFrame(0)
|
||||
{
|
||||
XDebug(m_engine,DebugAll,"IAXTransaction::IAXTransaction(%u,%u) incoming [%p]",
|
||||
localCallNo(),remoteCallNo(),this);
|
||||
|
@ -88,7 +90,6 @@ IAXTransaction::IAXTransaction(IAXEngine* engine, IAXFullFrame* frame,
|
|||
case IAXControl::Poke:
|
||||
m_type = Poke;
|
||||
break;
|
||||
case IAXControl::FwDownl:
|
||||
default:
|
||||
XDebug(m_engine,DebugAll,"IAXTransaction::IAXTransaction(%u,%u) incoming [%p]. Unsupported type: %u",
|
||||
localCallNo(),remoteCallNo(),this,frame->subclass());
|
||||
|
@ -98,7 +99,6 @@ IAXTransaction::IAXTransaction(IAXEngine* engine, IAXFullFrame* frame,
|
|||
Lock lock(this);
|
||||
m_inFrames.append(frame);
|
||||
incrementSeqNo(frame,true);
|
||||
sendAck(frame->fullFrame());
|
||||
}
|
||||
|
||||
IAXTransaction::IAXTransaction(IAXEngine* engine, Type type, u_int16_t lcallno, const SocketAddr& addr,
|
||||
|
@ -120,6 +120,7 @@ IAXTransaction::IAXTransaction(IAXEngine* engine, Type type, u_int16_t lcallno,
|
|||
m_lastFullFrameOut(0),
|
||||
m_lastMiniFrameOut(0xFFFF),
|
||||
m_lastMiniFrameIn(0),
|
||||
m_lastAck(0xFFFF),
|
||||
m_mutexInMedia(true),
|
||||
m_pendingEvent(0),
|
||||
m_currentEvent(0),
|
||||
|
@ -135,7 +136,8 @@ IAXTransaction::IAXTransaction(IAXEngine* engine, Type type, u_int16_t lcallno,
|
|||
m_format(0),
|
||||
m_formatIn(0),
|
||||
m_formatOut(0),
|
||||
m_capability(0)
|
||||
m_capability(0),
|
||||
m_trunkFrame(0)
|
||||
{
|
||||
XDebug(m_engine,DebugAll,"IAXTransaction::IAXTransaction(%u,%u) outgoing [%p]",
|
||||
localCallNo(),remoteCallNo(),this);
|
||||
|
@ -190,12 +192,15 @@ IAXTransaction::~IAXTransaction()
|
|||
#ifdef XDEBUG
|
||||
print();
|
||||
#endif
|
||||
if (m_trunkFrame)
|
||||
m_trunkFrame->deref();
|
||||
m_engine->removeTransaction(this);
|
||||
if (state() != Terminating && state() != Terminated)
|
||||
sendReject("Server shutdown");
|
||||
}
|
||||
|
||||
IAXTransaction* IAXTransaction::factoryIn(IAXEngine* engine, IAXFullFrame* frame, u_int16_t lcallno, const SocketAddr& addr,
|
||||
void* data)
|
||||
IAXTransaction* IAXTransaction::factoryIn(IAXEngine* engine, IAXFullFrame* frame, u_int16_t lcallno,
|
||||
const SocketAddr& addr, void* data)
|
||||
{
|
||||
IAXTransaction* tr = new IAXTransaction(engine,frame,lcallno,addr,data);
|
||||
if (tr->type() != Incorrect)
|
||||
|
@ -204,8 +209,8 @@ IAXTransaction* IAXTransaction::factoryIn(IAXEngine* engine, IAXFullFrame* frame
|
|||
return 0;
|
||||
}
|
||||
|
||||
IAXTransaction* IAXTransaction::factoryOut(IAXEngine* engine, Type type, u_int16_t lcallno, const SocketAddr& addr,
|
||||
IAXIEList& ieList, void* data)
|
||||
IAXTransaction* IAXTransaction::factoryOut(IAXEngine* engine, Type type, u_int16_t lcallno,
|
||||
const SocketAddr& addr, IAXIEList& ieList, void* data)
|
||||
{
|
||||
IAXTransaction* tr = new IAXTransaction(engine,type,lcallno,addr,ieList,data);
|
||||
if (tr->type() != Incorrect)
|
||||
|
@ -218,79 +223,49 @@ IAXTransaction* IAXTransaction::processFrame(IAXFrame* frame)
|
|||
{
|
||||
if (!frame)
|
||||
return 0;
|
||||
|
||||
// if (frame->fullFrame())
|
||||
// Output("Transaction(%u,%u) received Frame(%u,%u) (%u,%u) stamp=%u",
|
||||
// localCallNo(),remoteCallNo(),frame->type(),frame->subclass(),frame->fullFrame()->destCallNo(),frame->sourceCallNo(),frame->timeStamp());
|
||||
|
||||
if (state() == Terminated) {
|
||||
// Output(" State is Terminated. DROP");
|
||||
sendInval();
|
||||
return 0;
|
||||
}
|
||||
if (state() == Terminating)
|
||||
// Local terminate: Accept only Ack. Remote terminate: Accept none.
|
||||
if (m_localReqEnd) {
|
||||
if (!(frame->type() == IAXFrame::IAX && frame->subclass() == IAXControl::Ack))
|
||||
{
|
||||
// if (frame->fullFrame())
|
||||
// Output(" State is Terminating and frame is not ACK. DROP");
|
||||
if (m_localReqEnd && frame->fullFrame()) {
|
||||
if (!(frame->type() == IAXFrame::IAX && frame->fullFrame()->subclass() == IAXControl::Ack))
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
// if (frame->fullFrame()) Output(" State is Terminating on remote request. DROP");
|
||||
return 0;
|
||||
}
|
||||
// Mini frame
|
||||
if (!frame->fullFrame())
|
||||
return processMedia(frame->data(),frame->timeStamp());
|
||||
Lock lock(this);
|
||||
m_inTotalFramesCount++;
|
||||
// Frame is VNAK ?
|
||||
if (frame->type() == IAXFrame::IAX && frame->subclass() == IAXControl::VNAK)
|
||||
if (frame->type() == IAXFrame::IAX && frame->fullFrame()->subclass() == IAXControl::VNAK)
|
||||
return retransmitOnVNAK(frame->fullFrame()->iSeqNo());
|
||||
// Do we have space?
|
||||
// Do we have enough space to keep this frame ?
|
||||
if (m_inFrames.count() == m_maxInFrames) {
|
||||
// Output(" Buffer overrun. DROP");
|
||||
Debug(DebugWarn,"IAXTransaction(%u,%u) - processFrame. Buffer overrun!",localCallNo(),remoteCallNo());
|
||||
Debug(DebugWarn,"Transaction(%u,%u) - processFrame. Buffer overrun!",localCallNo(),remoteCallNo());
|
||||
m_inDroppedFrames++;
|
||||
return 0;
|
||||
}
|
||||
bool fAck = frame->type() == IAXFrame::IAX && frame->subclass() == IAXControl::Ack;
|
||||
bool fAck = frame->type() == IAXFrame::IAX && frame->fullFrame()->subclass() == IAXControl::Ack;
|
||||
if (!fAck && !isFrameAcceptable(frame->fullFrame()))
|
||||
|
||||
{
|
||||
// Output(" Not acceptable. DROP");
|
||||
return 0;
|
||||
}
|
||||
incrementSeqNo(frame->fullFrame(),true);
|
||||
if (!fAck)
|
||||
sendAck(frame->fullFrame());
|
||||
// Voice full frame: process voice data & format
|
||||
if (frame->type() == IAXFrame::Voice && type() == New) {
|
||||
if (frame->fullFrame()->subclass() && frame->fullFrame()->subclass() != m_formatIn) {
|
||||
// Format changed.
|
||||
if (m_engine->voiceFormatChanged(this,frame->fullFrame()->subclass()))
|
||||
m_formatIn = frame->fullFrame()->subclass();
|
||||
else {
|
||||
// Output(" Media format change rejected. DROP");
|
||||
DDebug(m_engine,DebugAll,"IAXTransaction(%u,%u) - processFrame. Media format (%u) change rejected!",
|
||||
localCallNo(),remoteCallNo(),m_format);
|
||||
m_pendingEvent = internalReject(s_iax_modNoMediaFormat);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
processMedia(frame->data(),frame->timeStamp(),true);
|
||||
frame->data().clear();
|
||||
if (frame->type() == IAXFrame::Voice && type() == New)
|
||||
return processVoiceFrame(frame->fullFrame());
|
||||
// Process incoming Ping
|
||||
if (frame->type() == IAXFrame::IAX && frame->fullFrame()->subclass() == IAXControl::Ping) {
|
||||
postFrame(IAXFrame::IAX,IAXControl::Pong,0,0,frame->timeStamp(),true);
|
||||
return 0;
|
||||
}
|
||||
// Append frame to incoming frame list
|
||||
m_inFrames.append(frame);
|
||||
// Output("Transaction(%u,%u) enqueued Frame(%u,%u) stamp=%u",localCallNo(),remoteCallNo(),frame->type(),frame->subclass(),frame->timeStamp());
|
||||
DDebug(m_engine,DebugAll,"Transaction(%u,%u) enqueued Frame(%u,%u) stamp=%u [%p]",
|
||||
localCallNo(),remoteCallNo(),frame->type(),frame->subclass(),frame->timeStamp(),this);
|
||||
DDebug(m_engine,DebugAll,"Transaction(%u,%u) enqueued Frame(%u,%u) iseq=%u oseq=%u stamp=%u [%p]",
|
||||
localCallNo(),remoteCallNo(),frame->type(),frame->fullFrame()->subclass(),
|
||||
frame->fullFrame()->iSeqNo(),frame->fullFrame()->oSeqNo(),frame->timeStamp(),this);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -325,7 +300,7 @@ IAXTransaction* IAXTransaction::processMedia(DataBlock& data, u_int32_t tStamp,
|
|||
return 0;
|
||||
}
|
||||
|
||||
IAXTransaction* IAXTransaction::sendMedia(const DataBlock& data, u_int8_t format)
|
||||
IAXTransaction* IAXTransaction::sendMedia(const DataBlock& data, u_int32_t format)
|
||||
{
|
||||
if (!data.length())
|
||||
return 0;
|
||||
|
@ -346,25 +321,31 @@ IAXTransaction* IAXTransaction::sendMedia(const DataBlock& data, u_int8_t format
|
|||
}
|
||||
// Send mini frame
|
||||
m_lastMiniFrameOut = (u_int16_t)ts;
|
||||
unsigned char b[4] = {localCallNo() >> 8,localCallNo(),m_lastMiniFrameOut >> 8,m_lastMiniFrameOut};
|
||||
DataBlock buf(b,4);
|
||||
buf += data;
|
||||
m_engine->writeSocket(buf.data(),buf.length(),remoteAddr());
|
||||
if (m_trunkFrame)
|
||||
m_trunkFrame->add(localCallNo(),data,m_lastMiniFrameOut);
|
||||
else {
|
||||
unsigned char b[4] = {localCallNo() >> 8,localCallNo(),m_lastMiniFrameOut >> 8,m_lastMiniFrameOut};
|
||||
DataBlock buf(b,4);
|
||||
buf += data;
|
||||
m_engine->writeSocket(buf.data(),buf.length(),remoteAddr());
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
IAXEvent* IAXTransaction::getEvent(u_int64_t time)
|
||||
{
|
||||
IAXEvent* ev;
|
||||
IAXEvent* ev = 0;
|
||||
GenObject* obj;
|
||||
bool delFrame;
|
||||
|
||||
Lock lock(this);
|
||||
if (state() == Terminated)
|
||||
return 0;
|
||||
// Send ack for received frames
|
||||
ackInFrames();
|
||||
// Do we have a generated event ?
|
||||
if (m_currentEvent)
|
||||
return 0;
|
||||
Lock lock(this);
|
||||
// Waiting on remote cleanup ?
|
||||
if (state() == Terminating && !m_localReqEnd)
|
||||
return getEventTerminating(time);
|
||||
|
@ -382,22 +363,18 @@ IAXEvent* IAXTransaction::getEvent(u_int64_t time)
|
|||
}
|
||||
// Process outgoing frames
|
||||
ListIterator lout(m_outFrames);
|
||||
IAXFrameOut* lastFrameAck = 0;
|
||||
for (; (obj = lout.get());) {
|
||||
IAXFrameOut* frame = static_cast<IAXFrameOut*>(obj);
|
||||
ev = getEventResponse(frame,delFrame);
|
||||
if((frame->ack() && frame->ackOnly()) || delFrame) {
|
||||
|
||||
//if (frame->type() == IAXFrame::Voice)
|
||||
// Output("***********************Transaction(%u,%u) VOICE frame removed. ACK: %s",localCallNo(),remoteCallNo(),frame->ack()?"YES":"NO");
|
||||
|
||||
|
||||
m_outFrames.remove(frame,true);
|
||||
if (ev)
|
||||
return keepEvent(ev);
|
||||
continue;
|
||||
}
|
||||
if (delFrame)
|
||||
frame->setAck();
|
||||
if(frame->ack())
|
||||
lastFrameAck = frame;
|
||||
if (ev)
|
||||
return keepEvent(ev);
|
||||
break;
|
||||
if(frame->ack() && frame->ackOnly())
|
||||
continue;
|
||||
// Adjust timeout for acknoledged auth frames sent with no auth response
|
||||
if (state() == NewRemoteInvite_AuthSent && frame->ack())
|
||||
frame->adjustAuthTimeout(time + m_engine->authTimeout() * 1000);
|
||||
|
@ -405,24 +382,46 @@ IAXEvent* IAXTransaction::getEvent(u_int64_t time)
|
|||
if (frame->timeout()) {
|
||||
if (m_state == Terminating)
|
||||
// Client already notified: Terminate transaction
|
||||
return keepEvent(terminate(IAXEvent::Timeout,true));
|
||||
ev = terminate(IAXEvent::Timeout,true);
|
||||
else
|
||||
// Client not notified: Notify it and terminate transaction
|
||||
return keepEvent(terminate(IAXEvent::Timeout,true,frame,false));
|
||||
ev = terminate(IAXEvent::Timeout,true,frame,false);
|
||||
break;
|
||||
}
|
||||
// Retransmit ?
|
||||
if (frame->timeForRetrans(time)) {
|
||||
if (frame->ack())
|
||||
frame->transmitted(); // Frame acknoledged: just update retransmission info
|
||||
else {
|
||||
// Output("Transaction(%u,%u) resending Frame(%u,%u) oseq=%u iseq=%u stamp=%u [%p]",
|
||||
// localCallNo(),remoteCallNo(),frame->type(),frame->subclass(),frame->oSeqNo(),frame->iSeqNo(),frame->timeStamp(),this);
|
||||
Debug(m_engine,DebugNote,"Transaction(%u,%u) resending Frame(%u,%u) oseq=%u iseq=%u stamp=%u [%p]",
|
||||
localCallNo(),remoteCallNo(),frame->type(),frame->subclass(),frame->oSeqNo(),frame->iSeqNo(),frame->timeStamp(),this);
|
||||
sendFrame(frame); // Retransmission
|
||||
}
|
||||
}
|
||||
}
|
||||
// Set the ACK flag for each frame before lastFrameAck and delete it if it must
|
||||
if (lastFrameAck) {
|
||||
lout.reset();
|
||||
for (; (obj = lout.get());) {
|
||||
IAXFrameOut* frame = static_cast<IAXFrameOut*>(obj);
|
||||
if (frame == lastFrameAck) {
|
||||
DDebug(m_engine,DebugAll,"Transaction(%u,%u) removing outgoing frame(%u,%u) oseq=%u iseq=%u stamp=%u [%p]",
|
||||
localCallNo(),remoteCallNo(),frame->type(),frame->subclass(),frame->oSeqNo(),
|
||||
frame->iSeqNo(),frame->timeStamp(),this);
|
||||
m_outFrames.remove(frame,true);
|
||||
break;
|
||||
}
|
||||
frame->setAck();
|
||||
if (frame->ackOnly()) {
|
||||
DDebug(m_engine,DebugAll,"Transaction(%u,%u) removing outgoing frame(%u,%u) with implicit ACK(%u) oseq=%u iseq=%u stamp=%u [%p]",
|
||||
localCallNo(),remoteCallNo(),frame->type(),frame->subclass(),lastFrameAck->oSeqNo(),
|
||||
frame->oSeqNo(),frame->iSeqNo(),frame->timeStamp(),this);
|
||||
m_outFrames.remove(frame,true);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ev)
|
||||
return keepEvent(ev);
|
||||
// Process incoming frames
|
||||
ListIterator lin(m_inFrames);
|
||||
for (; (obj = lin.get());) {
|
||||
|
@ -519,7 +518,6 @@ bool IAXTransaction::sendReject(const char* cause, u_int8_t code)
|
|||
case RegRel:
|
||||
frametype = IAXControl::RegRej;
|
||||
break;
|
||||
case FwDownl:
|
||||
case Poke:
|
||||
default:
|
||||
return false;
|
||||
|
@ -648,9 +646,20 @@ bool IAXTransaction::abortReg()
|
|||
return true;
|
||||
}
|
||||
|
||||
bool IAXTransaction::enableTrunking(IAXMetaTrunkFrame* trunkFrame)
|
||||
{
|
||||
if (m_trunkFrame)
|
||||
return false;
|
||||
// Get a reference to the trunk frame
|
||||
if (!(trunkFrame && trunkFrame->ref()))
|
||||
return false;
|
||||
m_trunkFrame = trunkFrame;
|
||||
return true;
|
||||
}
|
||||
|
||||
void IAXTransaction::print()
|
||||
{
|
||||
Debug(m_engine,DebugAll,"IAXTransaction - START PRINT [%p]",this);
|
||||
Debug(m_engine,DebugInfo,"Transaction - START PRINT [%p]",this);
|
||||
Output("Local call no: %u\nRemote call no: %u\nType: %u\nState: %u\nTimestamp: %llu",
|
||||
localCallNo(),remoteCallNo(),type(),state(),(long unsigned long)timeStamp());
|
||||
Output("Queues:\nOutgoing: %u",m_outFrames.count());
|
||||
|
@ -669,7 +678,7 @@ void IAXTransaction::print()
|
|||
Output(" %5u Type: %3u Subclass: %3u Out: %5u In: %5u Timestamp: %5u",
|
||||
i+1,frame->type(),frame->subclass(),frame->oSeqNo(),frame->iSeqNo(), frame->timeStamp());
|
||||
}
|
||||
Debug(m_engine,DebugAll,"IAXTransaction - END PRINT [%p]",this);
|
||||
Debug(m_engine,DebugInfo,"Transaction - END PRINT [%p]",this);
|
||||
}
|
||||
|
||||
void IAXTransaction::init(IAXIEList& ieList)
|
||||
|
@ -693,7 +702,6 @@ void IAXTransaction::init(IAXIEList& ieList)
|
|||
ieList.getNumeric(IAXInfoElement::REFRESH,m_expire);
|
||||
break;
|
||||
case Poke:
|
||||
case FwDownl:
|
||||
default: ;
|
||||
}
|
||||
}
|
||||
|
@ -728,13 +736,15 @@ bool IAXTransaction::isFrameAcceptable(const IAXFullFrame* frame)
|
|||
return true;
|
||||
if (delta > 0) {
|
||||
// We missed some frames before this one: Send VNAK
|
||||
Debug(m_engine,DebugInfo,"IAXTransaction(%u,%u) - received frame out of order! oseq=%u expecting %u. Send VNAK",
|
||||
localCallNo(),remoteCallNo(),frame->oSeqNo(),m_iSeqNo);
|
||||
Debug(m_engine,DebugInfo,"Transaction(%u,%u) - received Frame(%u,%u) out of order! oseq=%u expecting %u. Send VNAK",
|
||||
localCallNo(),remoteCallNo(),frame->type(),frame->subclass(),frame->oSeqNo(),m_iSeqNo);
|
||||
sendVNAK();
|
||||
m_inOutOfOrderFrames++;
|
||||
return false;
|
||||
}
|
||||
DDebug(m_engine,DebugInfo,"IAXTransaction(%u,%u) - received late frame with oseq=%u expecting %u [%p]",
|
||||
localCallNo(),remoteCallNo(),frame->oSeqNo(),m_iSeqNo,this);
|
||||
DDebug(m_engine,DebugInfo,"Transaction(%u,%u) - received late Frame(%u,%u) with oseq=%u expecting %u [%p]",
|
||||
localCallNo(),remoteCallNo(),frame->type(),frame->subclass(),frame->oSeqNo(),m_iSeqNo,this);
|
||||
sendAck(frame);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -794,14 +804,14 @@ void IAXTransaction::postFrame(IAXFrame::Type type, u_int32_t subclass, void* da
|
|||
// adjust timestamp to be different from the last sent
|
||||
int32_t delta = tStamp - m_lastFullFrameOut;
|
||||
if (delta <= 0)
|
||||
tStamp = m_lastFullFrameOut+1;
|
||||
tStamp = m_lastFullFrameOut + 1;
|
||||
}
|
||||
m_lastFullFrameOut = tStamp;
|
||||
}
|
||||
IAXFrameOut* frame = new IAXFrameOut(type,subclass,m_lCallNo,m_rCallNo,m_oSeqNo,m_iSeqNo,tStamp,
|
||||
(unsigned char*)data,len,m_retransCount,m_retransInterval,ackOnly);
|
||||
DDebug(m_engine,DebugAll,"Transaction posting Frame(%u,%u) oseq=%u iseq=%u stamp=%u [%p]",
|
||||
type,subclass,m_oSeqNo,m_iSeqNo,tStamp,this);
|
||||
DDebug(m_engine,DebugAll,"Transaction(%u,%u) posting Frame(%u,%u) oseq=%u iseq=%u stamp=%u [%p]",
|
||||
localCallNo(),remoteCallNo(),type,subclass,m_oSeqNo,m_iSeqNo,tStamp,this);
|
||||
incrementSeqNo(frame,false);
|
||||
m_outFrames.append(frame);
|
||||
sendFrame(frame);
|
||||
|
@ -813,8 +823,12 @@ bool IAXTransaction::sendFrame(IAXFrameOut* frame, bool vnak)
|
|||
return false;
|
||||
bool b = m_engine->writeSocket(frame->data().data(),frame->data().length(),remoteAddr());
|
||||
// Don't modify timeout if transmitted as a response to a VNAK
|
||||
if (!vnak)
|
||||
frame->transmitted();
|
||||
if (!vnak) {
|
||||
if (frame->retrans()) // Retransmission
|
||||
frame->transmitted();
|
||||
else // First transmission
|
||||
frame->setRetrans();
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
|
@ -855,27 +869,18 @@ IAXEvent* IAXTransaction::createResponse(IAXFrameOut* frame, u_int8_t findType,
|
|||
|
||||
IAXEvent* IAXTransaction::getEventResponse(IAXFrameOut* frame, bool& delFrame)
|
||||
{
|
||||
delFrame = true;
|
||||
delFrame = false;
|
||||
if (findInFrameAck(frame)) {
|
||||
|
||||
//Output("************* Transaction(%u,%u) Found ACK for frame(%u,%u) stamp=%u",localCallNo(),remoteCallNo(),frame->type(),frame->subclass(),frame->timeStamp());
|
||||
|
||||
frame->setAck();
|
||||
// Terminating frame sent
|
||||
if (m_state == Terminating)
|
||||
return terminate(IAXEvent::Terminated,true);
|
||||
// Frame only need ACK
|
||||
if (frame->ackOnly())
|
||||
{
|
||||
|
||||
//Output(" ******* Frame only need ACK");
|
||||
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
}
|
||||
// Frame only need ACK. Didn't found it. Return
|
||||
delFrame = true;
|
||||
if (frame->ackOnly()) {
|
||||
delFrame = false;
|
||||
return 0;
|
||||
|
@ -1117,7 +1122,6 @@ IAXEvent* IAXTransaction::getEventRequest(IAXFullFrame* frame, bool& delFrame)
|
|||
postFrame(IAXFrame::IAX,IAXControl::Pong,0,0,frame->timeStamp());
|
||||
changeState(Terminating);
|
||||
return 0;
|
||||
case FwDownl:
|
||||
default: ;
|
||||
}
|
||||
delFrame = false;
|
||||
|
@ -1204,6 +1208,24 @@ bool IAXTransaction::findInFrameAck(const IAXFullFrame* frameOut)
|
|||
return false;
|
||||
}
|
||||
|
||||
void IAXTransaction::ackInFrames()
|
||||
{
|
||||
IAXFullFrame* ack = 0;
|
||||
for (ObjList* l = m_inFrames.skipNull(); l; l = l->next()) {
|
||||
IAXFullFrame* frame = static_cast<IAXFullFrame*>(l->get());
|
||||
if (frame && frame->type() == IAXFrame::IAX && frame->subclass() != IAXControl::Ack)
|
||||
ack = frame;
|
||||
}
|
||||
if (ack) {
|
||||
int32_t interval = (int32_t)ack->oSeqNo() - m_lastAck;
|
||||
if (interval > 32767 || (interval > -32767 && interval <= 0))
|
||||
// Frame is older then the last ack'd
|
||||
return;
|
||||
m_lastAck = ack->oSeqNo();
|
||||
sendAck(ack);
|
||||
}
|
||||
}
|
||||
|
||||
bool IAXTransaction::sendConnected(IAXFullFrame::ControlType subclass, IAXFrame::Type frametype)
|
||||
{
|
||||
if (state() != Connected)
|
||||
|
@ -1219,6 +1241,8 @@ void IAXTransaction::sendAck(const IAXFullFrame* frame)
|
|||
unsigned char buf[12] = {0x80 | localCallNo() >> 8,localCallNo(),remoteCallNo() >> 8,remoteCallNo(),
|
||||
frame->timeStamp() >> 24,frame->timeStamp() >> 16,frame->timeStamp() >> 8,frame->timeStamp(),
|
||||
frame->iSeqNo(),m_iSeqNo,IAXFrame::IAX,IAXControl::Ack};
|
||||
DDebug(m_engine,DebugInfo,"Transaction(%u,%u) - Send ACK for Frame(%u,%u) oseq: %u iseq: %u",
|
||||
localCallNo(),remoteCallNo(),frame->type(),frame->subclass(),frame->oSeqNo(),frame->iSeqNo());
|
||||
m_engine->writeSocket(buf,12,remoteAddr());
|
||||
}
|
||||
|
||||
|
@ -1242,6 +1266,7 @@ void IAXTransaction::sendVNAK()
|
|||
|
||||
IAXEvent* IAXTransaction::processInternalOutgoingRequest(IAXFrameOut* frame, bool& delFrame)
|
||||
{
|
||||
delFrame = false;
|
||||
if (frame->type() != IAXFrame::IAX)
|
||||
return 0;
|
||||
delFrame = true;
|
||||
|
@ -1266,19 +1291,13 @@ IAXEvent* IAXTransaction::processInternalOutgoingRequest(IAXFrameOut* frame, boo
|
|||
|
||||
IAXEvent* IAXTransaction::processInternalIncomingRequest(const IAXFullFrame* frame, bool& delFrame)
|
||||
{
|
||||
delFrame = false;
|
||||
if (frame->type() != IAXFrame::IAX)
|
||||
return 0;
|
||||
delFrame = true;
|
||||
switch (frame->subclass()) {
|
||||
case IAXControl::Ping:
|
||||
postFrame(IAXFrame::IAX,IAXControl::Pong,0,0,frame->timeStamp(),true);
|
||||
return 0;
|
||||
case IAXControl::LagRq:
|
||||
postFrame(IAXFrame::IAX,IAXControl::LagRp,0,0,frame->timeStamp(),true);
|
||||
return 0;
|
||||
default: ;
|
||||
if (frame->subclass() == IAXControl::LagRq) {
|
||||
postFrame(IAXFrame::IAX,IAXControl::LagRp,0,0,frame->timeStamp(),true);
|
||||
delFrame = true;
|
||||
}
|
||||
delFrame = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1374,6 +1393,29 @@ IAXEvent* IAXTransaction::getEventTerminating(u_int64_t time)
|
|||
return 0;
|
||||
}
|
||||
|
||||
IAXTransaction* IAXTransaction::processVoiceFrame(const IAXFullFrame* frame)
|
||||
{
|
||||
// Process format
|
||||
DDebug(m_engine,DebugAll,"Transaction(%u,%u) - Received Voice Frame(%u,%u) iseq=%u oseq=%u stamp=%u [%p]",
|
||||
localCallNo(),remoteCallNo(),frame->type(),frame->subclass(),
|
||||
frame->fullFrame()->iSeqNo(),frame->fullFrame()->oSeqNo(),frame->timeStamp(),this);
|
||||
sendAck(frame);
|
||||
if (frame->fullFrame()->subclass() && frame->fullFrame()->subclass() != m_formatIn) {
|
||||
// Format changed.
|
||||
if (m_engine->voiceFormatChanged(this,frame->fullFrame()->subclass()))
|
||||
m_formatIn = frame->fullFrame()->subclass();
|
||||
else {
|
||||
DDebug(m_engine,DebugAll,"IAXTransaction(%u,%u). Process Voice Frame. Media format (%u) change rejected!",
|
||||
localCallNo(),remoteCallNo(),m_format);
|
||||
m_pendingEvent = internalReject(s_iax_modNoMediaFormat);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
// Process voice data
|
||||
processMedia(((IAXFullFrame*)frame)->data(),frame->timeStamp(),true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
IAXTransaction* IAXTransaction::retransmitOnVNAK(u_int16_t seqNo)
|
||||
{
|
||||
int c = 0;
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -45,12 +45,13 @@ static TokenDict dict_tos[] = {
|
|||
{ 0, 0 }
|
||||
};
|
||||
|
||||
static Configuration s_cfg;
|
||||
|
||||
class YIAXLineContainer;
|
||||
class YIAXEngine;
|
||||
class IAXURI;
|
||||
|
||||
/*
|
||||
* Keep a single registration line
|
||||
*/
|
||||
class YIAXLine : public String
|
||||
{
|
||||
friend class YIAXLineContainer;
|
||||
|
@ -61,10 +62,8 @@ public:
|
|||
Registering,
|
||||
Unregistering,
|
||||
};
|
||||
|
||||
YIAXLine(const String& name);
|
||||
virtual ~YIAXLine();
|
||||
|
||||
inline State state() const
|
||||
{ return m_state; }
|
||||
inline bool registered() const
|
||||
|
@ -87,27 +86,26 @@ public:
|
|||
{ return m_localPort; }
|
||||
inline int remotePort() const
|
||||
{ return m_remotePort; }
|
||||
|
||||
private:
|
||||
State m_state;
|
||||
String m_username; /* Username */
|
||||
String m_password; /* Password */
|
||||
String m_callingNo; /* Calling number */
|
||||
String m_callingName; /* Calling name */
|
||||
u_int16_t m_expire; /* Expire time */
|
||||
String m_username; // Username
|
||||
String m_password; // Password
|
||||
String m_callingNo; // Calling number
|
||||
String m_callingName; // Calling name
|
||||
u_int16_t m_expire; // Expire time
|
||||
String m_localAddr;
|
||||
String m_remoteAddr;
|
||||
int m_localPort;
|
||||
int m_remotePort;
|
||||
u_int32_t m_nextReg; /* Time to next registration */
|
||||
u_int32_t m_nextKeepAlive; /* Time to next keep alive signal */
|
||||
bool m_registered;
|
||||
bool m_register; /* Operation flag: True - register */
|
||||
u_int32_t m_nextReg; // Time to next registration
|
||||
u_int32_t m_nextKeepAlive; // Time to next keep alive signal
|
||||
bool m_registered; // Registered flag. If true the line is registered
|
||||
bool m_register; // Operation flag: True - register
|
||||
IAXTransaction* m_transaction;
|
||||
};
|
||||
|
||||
/**
|
||||
* YIAXLineContainer
|
||||
/*
|
||||
* Line container: Add/Delete/Update/Register/Unregister lines
|
||||
*/
|
||||
class YIAXLineContainer : public Mutex
|
||||
{
|
||||
|
@ -115,12 +113,12 @@ public:
|
|||
inline YIAXLineContainer() : Mutex(true) {}
|
||||
inline ~YIAXLineContainer() {}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Logout and remove all lines
|
||||
*/
|
||||
void clear();
|
||||
|
||||
/**
|
||||
/*
|
||||
* Update a line from a message
|
||||
* This method is thread safe
|
||||
* @param msg Received message
|
||||
|
@ -128,33 +126,33 @@ public:
|
|||
*/
|
||||
bool updateLine(Message &msg);
|
||||
|
||||
/**
|
||||
/*
|
||||
* Event handler for a registration.
|
||||
* @param event The event.
|
||||
*/
|
||||
void handleEvent(IAXEvent* event);
|
||||
|
||||
/**
|
||||
/*
|
||||
* Terminate notification of a Register/Unregister operation
|
||||
* This method is thread safe
|
||||
* @param event The event (result)
|
||||
*/
|
||||
void regTerminate(IAXEvent* event);
|
||||
|
||||
/**
|
||||
/*
|
||||
* Timer notification
|
||||
* This method is thread safe
|
||||
* @param time Time
|
||||
*/
|
||||
void evTimer(Time& time);
|
||||
|
||||
/**
|
||||
/*
|
||||
* Fill a named list from a line
|
||||
* This method is thread safe
|
||||
*/
|
||||
bool fillList(String& name, NamedList& dest, SocketAddr& addr, bool& registered);
|
||||
|
||||
/**
|
||||
/*
|
||||
* Check if a line exists
|
||||
*/
|
||||
inline bool hasLine(const String& line)
|
||||
|
@ -171,7 +169,7 @@ private:
|
|||
ObjList m_lines;
|
||||
};
|
||||
|
||||
/**
|
||||
/*
|
||||
* Thread class for reading data from socket for the specified IAX engine
|
||||
*/
|
||||
class YIAX_API YIAXListener : public Thread
|
||||
|
@ -185,7 +183,7 @@ protected:
|
|||
YIAXEngine* m_engine;
|
||||
};
|
||||
|
||||
/**
|
||||
/*
|
||||
* Thread class for reading events for the specified IAX engine
|
||||
*/
|
||||
class YIAX_API YIAXGetEvent : public Thread
|
||||
|
@ -199,13 +197,27 @@ protected:
|
|||
YIAXEngine* m_engine;
|
||||
};
|
||||
|
||||
/**
|
||||
* YIAXEngine
|
||||
/*
|
||||
* Thread class for sending trunked mini frames for the specified IAX engine
|
||||
*/
|
||||
class YIAX_API YIAXTrunking : public Thread
|
||||
{
|
||||
public:
|
||||
inline YIAXTrunking(YIAXEngine* engine, const char* name = 0, Priority prio = Normal)
|
||||
: Thread(name,prio), m_engine(engine)
|
||||
{}
|
||||
virtual void run();
|
||||
protected:
|
||||
YIAXEngine* m_engine;
|
||||
};
|
||||
|
||||
/*
|
||||
* The IAX engine for this driver
|
||||
*/
|
||||
class YIAXEngine : public IAXEngine
|
||||
{
|
||||
public:
|
||||
/**
|
||||
/*
|
||||
* Constructor
|
||||
* @param port UDP port to use
|
||||
* @param transListCount Number of entries in the transaction hash table
|
||||
|
@ -214,17 +226,16 @@ public:
|
|||
* @param authTimeout Timeout (in seconds) of acknoledged auth frames sent
|
||||
* @param transTimeout Timeout (in seconds) on remote request of transactions belonging to this engine
|
||||
* @param maxFullFrameDataLen Max full frame IE list (buffer) length
|
||||
* @param trunkSendInterval Send trunk meta frame interval
|
||||
*/
|
||||
YIAXEngine(int port, u_int16_t transListCount, u_int16_t retransCount, u_int16_t retransInterval,
|
||||
u_int16_t authTimeout, u_int16_t transTimeout, u_int16_t maxFullFrameDataLen);
|
||||
u_int16_t authTimeout, u_int16_t transTimeout,
|
||||
u_int16_t maxFullFrameDataLen, u_int32_t trunkSendInterval);
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
virtual ~YIAXEngine()
|
||||
{}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Process media from remote peer.
|
||||
* @param transaction IAXTransaction that owns the call leg
|
||||
* @param data Media data.
|
||||
|
@ -232,7 +243,7 @@ public:
|
|||
*/
|
||||
virtual void processMedia(IAXTransaction* transaction, DataBlock& data, u_int32_t tStamp);
|
||||
|
||||
/**
|
||||
/*
|
||||
* Initiate an outgoing registration (release) request.
|
||||
* @param line YIAXLine pointer to use for registration.
|
||||
* @param regreq Registration request flag. If false a registration release will take place.
|
||||
|
@ -240,7 +251,7 @@ public:
|
|||
*/
|
||||
IAXTransaction* reg(YIAXLine* line, bool regreq = true);
|
||||
|
||||
/**
|
||||
/*
|
||||
* Initiate an aoutgoing call.
|
||||
* @param addr Address to poke.
|
||||
* @param params Call parameters.
|
||||
|
@ -248,42 +259,43 @@ public:
|
|||
*/
|
||||
IAXTransaction* call(SocketAddr& addr, NamedList& params);
|
||||
|
||||
/**
|
||||
/*
|
||||
* Initiate a test of existence of a remote IAX peer.
|
||||
* @param addr Address to poke.
|
||||
* @return IAXTransaction pointer on success.
|
||||
*/
|
||||
IAXTransaction* poke(SocketAddr& addr);
|
||||
|
||||
/**
|
||||
/*
|
||||
* Start thread members
|
||||
* @param listenThreadCount Reading socket thread count.
|
||||
* @param eventThreadCount Reading event thread count.
|
||||
* @param trunkingThreadCount Trunking thread count.
|
||||
*/
|
||||
void start(u_int16_t listenThreadCount, u_int16_t eventThreadCount);
|
||||
void start(u_int16_t listenThreadCount, u_int16_t eventThreadCount,u_int16_t trunkingThreadCount);
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
/*
|
||||
* Event handler for transaction with a connection.
|
||||
*/
|
||||
virtual void processEvent(IAXEvent* event);
|
||||
|
||||
/**
|
||||
/*
|
||||
* Event handler for incoming registration transactions.
|
||||
*/
|
||||
void processRemoteReg(IAXEvent* event);
|
||||
|
||||
/**
|
||||
/*
|
||||
* Send Register/Unregister messages to Engine
|
||||
*/
|
||||
bool userreg(IAXTransaction* tr, bool regrel = true);
|
||||
|
||||
private:
|
||||
bool m_threadsCreated; /* True if reading and get events threads were created */
|
||||
bool m_threadsCreated; // True if reading and get events threads were created
|
||||
};
|
||||
|
||||
/**
|
||||
/*
|
||||
* YIAXRegDataHandler
|
||||
*/
|
||||
class YIAXRegDataHandler : public MessageHandler
|
||||
|
@ -295,7 +307,7 @@ public:
|
|||
virtual bool received(Message &msg);
|
||||
};
|
||||
|
||||
/**
|
||||
/*
|
||||
* YIAXDriver
|
||||
*/
|
||||
class YIAXDriver : public Driver
|
||||
|
@ -304,11 +316,8 @@ public:
|
|||
YIAXDriver();
|
||||
virtual ~YIAXDriver();
|
||||
virtual void initialize();
|
||||
/* Create an outgoing call */
|
||||
virtual bool msgExecute(Message& msg, String& dest);
|
||||
|
||||
virtual bool msgRoute(Message& msg);
|
||||
|
||||
virtual bool received(Message& msg, int id);
|
||||
|
||||
inline u_int32_t defaultCodec() const
|
||||
|
@ -325,15 +334,15 @@ public:
|
|||
|
||||
protected:
|
||||
YIAXEngine* m_iaxEngine;
|
||||
u_int32_t m_defaultCodec; /* Default codec */
|
||||
u_int32_t m_codecs; /* Capability */
|
||||
int m_port; /* Default UDP port */
|
||||
u_int32_t m_defaultCodec;
|
||||
u_int32_t m_codecs;
|
||||
int m_port; // Default UDP port
|
||||
};
|
||||
|
||||
class YIAXConnection;
|
||||
|
||||
/**
|
||||
* YIAXConsumer
|
||||
/*
|
||||
* Connection's data consumer
|
||||
*/
|
||||
class YIAXConsumer : public DataConsumer
|
||||
{
|
||||
|
@ -347,8 +356,8 @@ private:
|
|||
u_int32_t m_format;
|
||||
};
|
||||
|
||||
/**
|
||||
* YIAXSource
|
||||
/*
|
||||
* Connection's data source
|
||||
*/
|
||||
class YIAXSource : public DataSource
|
||||
{
|
||||
|
@ -362,8 +371,8 @@ private:
|
|||
u_int32_t m_format;
|
||||
};
|
||||
|
||||
/**
|
||||
* YIAXConnection
|
||||
/*
|
||||
* The connection
|
||||
*/
|
||||
class YIAXConnection : public Channel
|
||||
{
|
||||
|
@ -391,28 +400,20 @@ public:
|
|||
|
||||
void handleEvent(IAXEvent* event);
|
||||
|
||||
/* Start router */
|
||||
bool route(bool authenticated = false);
|
||||
|
||||
protected:
|
||||
/* Hangup */
|
||||
void hangup(const char* reason = 0, bool reject = false);
|
||||
/* Hangup */
|
||||
inline void hangup(IAXEvent* event, const char* reason = 0, bool reject = false) {
|
||||
event->setFinal();
|
||||
hangup(reason,reject);
|
||||
}
|
||||
/* Start consumer */
|
||||
void startAudioIn();
|
||||
/* Start source */
|
||||
void startAudioOut();
|
||||
/* Events */
|
||||
void evAuthRep(IAXEvent* event);
|
||||
|
||||
// Safe deref the connection if the reference counter was increased during registration
|
||||
void safeDeref();
|
||||
|
||||
bool safeRefIncrease();
|
||||
|
||||
private:
|
||||
YIAXEngine* m_iaxEngine; // IAX engine owning the transaction
|
||||
IAXTransaction* m_transaction; // IAX transaction
|
||||
|
@ -421,11 +422,12 @@ private:
|
|||
bool m_mutedOut; // No local media accepted
|
||||
String m_reason; // Call end reason text
|
||||
bool m_hangup; // Need to send chan.hangup message
|
||||
Mutex m_mutexTrans; // Safe m_transaction operations
|
||||
Mutex m_mutexRefIncreased; // Safe ref/deref connection
|
||||
bool m_refIncreased; // If true, the reference counter was increased
|
||||
};
|
||||
|
||||
/**
|
||||
/*
|
||||
* IAXURI
|
||||
* [iax[2]:][username@]host[:port][/called_number[@called_context]]
|
||||
*/
|
||||
|
@ -461,19 +463,18 @@ private:
|
|||
};
|
||||
|
||||
|
||||
/**
|
||||
/*
|
||||
* Local data
|
||||
*/
|
||||
/* Init the driver */
|
||||
static YIAXDriver iplugin;
|
||||
/* Lines */
|
||||
static YIAXLineContainer s_lines;
|
||||
static Configuration s_cfg; // Configuration file
|
||||
static YIAXDriver iplugin; // Init the driver
|
||||
static YIAXLineContainer s_lines; // Lines
|
||||
|
||||
/**
|
||||
/*
|
||||
* Class definitions
|
||||
*/
|
||||
|
||||
/**
|
||||
/*
|
||||
* YIAXLine
|
||||
*/
|
||||
YIAXLine::YIAXLine(const String& name)
|
||||
|
@ -489,7 +490,7 @@ YIAXLine::~YIAXLine()
|
|||
{
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* YIAXLineContainer
|
||||
*/
|
||||
bool YIAXLineContainer::updateLine(Message& msg)
|
||||
|
@ -568,8 +569,10 @@ void YIAXLineContainer::evTimer(Time& time)
|
|||
Lock lock(this);
|
||||
for (ObjList* l = m_lines.skipNull(); l; l = l->next()) {
|
||||
YIAXLine* line = static_cast<YIAXLine*>(l->get());
|
||||
// Line exists and is idle ?
|
||||
if (!line || line->state() != YIAXLine::Idle)
|
||||
continue;
|
||||
// Time to keep alive
|
||||
if (sec > line->m_nextKeepAlive) {
|
||||
line->m_nextKeepAlive = sec + 25;
|
||||
SocketAddr addr(AF_INET);
|
||||
|
@ -577,6 +580,7 @@ void YIAXLineContainer::evTimer(Time& time)
|
|||
addr.port(line->remotePort());
|
||||
iplugin.getEngine()->keepAlive(addr);
|
||||
}
|
||||
// Time to reg/unreg
|
||||
if (sec > line->m_nextReg) {
|
||||
line->m_nextReg += line->expire();
|
||||
if (line->m_register)
|
||||
|
@ -732,13 +736,22 @@ void YIAXGetEvent::run()
|
|||
m_engine->runGetEvents();
|
||||
}
|
||||
|
||||
/**
|
||||
* YIAXTrunking
|
||||
*/
|
||||
void YIAXTrunking::run()
|
||||
{
|
||||
Debug(m_engine,DebugAll,"%s started",currentName());
|
||||
m_engine->runProcessTrunkFrames();
|
||||
}
|
||||
|
||||
/**
|
||||
* YIAXEngine
|
||||
*/
|
||||
YIAXEngine::YIAXEngine(int port, u_int16_t transListCount, u_int16_t retransCount, u_int16_t retransInterval,
|
||||
u_int16_t authTimeout, u_int16_t transTimeout, u_int16_t maxFullFrameDataLen)
|
||||
u_int16_t authTimeout, u_int16_t transTimeout, u_int16_t maxFullFrameDataLen, u_int32_t trunkSendInterval)
|
||||
: IAXEngine(port,transListCount,retransCount,retransInterval,authTimeout,transTimeout,
|
||||
maxFullFrameDataLen,iplugin.defaultCodec(),iplugin.codecs()),
|
||||
maxFullFrameDataLen,iplugin.defaultCodec(),iplugin.codecs(),trunkSendInterval),
|
||||
m_threadsCreated(false)
|
||||
{
|
||||
}
|
||||
|
@ -806,7 +819,7 @@ IAXTransaction* YIAXEngine::poke(SocketAddr& addr)
|
|||
return startLocalTransaction(IAXTransaction::Poke,addr,ieList);
|
||||
}
|
||||
|
||||
void YIAXEngine::start(u_int16_t listenThreadCount, u_int16_t eventThreadCount)
|
||||
void YIAXEngine::start(u_int16_t listenThreadCount, u_int16_t eventThreadCount, u_int16_t trunkThreadCount)
|
||||
{
|
||||
if (m_threadsCreated)
|
||||
return;
|
||||
|
@ -814,18 +827,19 @@ void YIAXEngine::start(u_int16_t listenThreadCount, u_int16_t eventThreadCount)
|
|||
Debug(DebugWarn,"YIAXEngine - start. No reading socket threads(s)!.");
|
||||
if (!eventThreadCount)
|
||||
Debug(DebugWarn,"YIAXEngine - start. No reading event threads(s)!.");
|
||||
if (!trunkThreadCount)
|
||||
Debug(DebugWarn,"YIAXEngine - start. No trunking threads(s)!.");
|
||||
for (; listenThreadCount; listenThreadCount--)
|
||||
(new YIAXListener(this,"YIAXListener thread"))->startup();
|
||||
for (; eventThreadCount; eventThreadCount--)
|
||||
(new YIAXGetEvent(this,"YIAXGetEvent thread"))->startup();
|
||||
for (; trunkThreadCount; trunkThreadCount--)
|
||||
(new YIAXTrunking(this,"YIAXTrunking thread"))->startup();
|
||||
m_threadsCreated = true;
|
||||
}
|
||||
|
||||
void YIAXEngine::processEvent(IAXEvent* event)
|
||||
{
|
||||
#if 0
|
||||
static u_int16_t hp = 0, rej = 0, final = 0;
|
||||
#endif
|
||||
YIAXConnection* connection = 0;
|
||||
switch (event->getTransaction()->type()) {
|
||||
case IAXTransaction::New:
|
||||
|
@ -834,21 +848,6 @@ static u_int16_t hp = 0, rej = 0, final = 0;
|
|||
// We already have a channel for this call
|
||||
connection->handleEvent(event);
|
||||
if (event->final()) {
|
||||
#if 0
|
||||
final++;
|
||||
switch (event->type()) {
|
||||
case IAXEvent::Hangup: hp++; break;
|
||||
case IAXEvent::Reject: rej++; break;
|
||||
case IAXEvent::Timeout:
|
||||
Output("**************************** Engine HALT: Channels: %u ****************************",iplugin.channels().count());
|
||||
Output("Final events: %u Hangup: %u, Reject: %u",final,hp,rej);
|
||||
event->getTransaction()->print();
|
||||
Engine::halt(0xFF);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
// Final event: disconnect
|
||||
Debug(this,DebugAll,"YIAXEngine::processEvent - Disconnect connection [%p]",connection);
|
||||
connection->disconnect();
|
||||
|
@ -861,6 +860,8 @@ switch (event->type()) {
|
|||
event->getTransaction()->setUserData(connection);
|
||||
if (!connection->route())
|
||||
event->getTransaction()->setUserData(0);
|
||||
else
|
||||
enableTrunking(event->getTransaction());
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -1001,15 +1002,17 @@ void YIAXDriver::initialize()
|
|||
installRelay(Halt);
|
||||
installRelay(Route);
|
||||
// Init IAX engine
|
||||
u_int16_t transListCount = 16;
|
||||
u_int16_t transListCount = 64;
|
||||
u_int16_t retransCount = 5;
|
||||
u_int16_t retransInterval = 500;
|
||||
u_int16_t authTimeout = 30;
|
||||
u_int16_t transTimeout = 10;
|
||||
u_int16_t maxFullFrameDataLen = 1400;
|
||||
u_int32_t trunkSendInterval = 10;
|
||||
if (!m_iaxEngine) {
|
||||
Engine::install(new YIAXRegDataHandler);
|
||||
m_iaxEngine = new YIAXEngine(m_port,transListCount,retransCount,retransInterval,authTimeout,transTimeout,maxFullFrameDataLen);
|
||||
m_iaxEngine = new YIAXEngine(m_port,transListCount,retransCount,retransInterval,authTimeout,
|
||||
transTimeout,maxFullFrameDataLen,trunkSendInterval);
|
||||
m_iaxEngine->debugChain(this);
|
||||
int tos = s_cfg.getIntValue("general","tos",dict_tos,0);
|
||||
if (tos) {
|
||||
|
@ -1019,7 +1022,8 @@ void YIAXDriver::initialize()
|
|||
}
|
||||
int readThreadCount = 3;
|
||||
int eventThreadCount = 3;
|
||||
m_iaxEngine->start(readThreadCount,eventThreadCount);
|
||||
int trunkingThreadCount = 1;
|
||||
m_iaxEngine->start(readThreadCount,eventThreadCount,trunkingThreadCount);
|
||||
}
|
||||
|
||||
bool YIAXDriver::msgRoute(Message& msg)
|
||||
|
@ -1149,7 +1153,7 @@ void YIAXSource::Forward(const DataBlock& data, unsigned long tStamp)
|
|||
YIAXConnection::YIAXConnection(YIAXEngine* iaxEngine, IAXTransaction* transaction, Message* msg)
|
||||
: Channel(&iplugin,0,transaction->outgoing()),
|
||||
m_iaxEngine(iaxEngine), m_transaction(transaction), m_mutedIn(false), m_mutedOut(false),
|
||||
m_hangup(true), m_mutexRefIncreased(true), m_refIncreased(false)
|
||||
m_hangup(true), m_mutexTrans(true), m_mutexRefIncreased(true), m_refIncreased(false)
|
||||
{
|
||||
DDebug(this,DebugAll,"YIAXConnection::YIAXConnection [%p]",this);
|
||||
setMaxcall(msg);
|
||||
|
@ -1179,8 +1183,10 @@ YIAXConnection::~YIAXConnection()
|
|||
void YIAXConnection::callAccept(Message& msg)
|
||||
{
|
||||
DDebug(this,DebugAll,"callAccept [%p]",this);
|
||||
m_mutexTrans.lock();
|
||||
if (m_transaction)
|
||||
m_transaction->sendAccept();
|
||||
m_mutexTrans.unlock();
|
||||
Channel::callAccept(msg);
|
||||
}
|
||||
|
||||
|
@ -1194,11 +1200,14 @@ void YIAXConnection::callRejected(const char* error, const char* reason, const M
|
|||
reason = error;
|
||||
DDebug(this,DebugInfo,"callRejected [%p]. Error: '%s'",this,error);
|
||||
String s(error);
|
||||
m_mutexTrans.lock();
|
||||
if (m_transaction && (s == "noauth") && safeRefIncrease()) {
|
||||
Debug(this,DebugAll,"callRejected [%p]. Requesting authentication",this);
|
||||
m_transaction->sendAuth(m_password);
|
||||
m_mutexTrans.unlock();
|
||||
return;
|
||||
}
|
||||
m_mutexTrans.unlock();
|
||||
hangup(reason,true);
|
||||
}
|
||||
|
||||
|
@ -1214,6 +1223,7 @@ bool YIAXConnection::callRouted(Message& msg)
|
|||
|
||||
bool YIAXConnection::msgRinging(Message& msg)
|
||||
{
|
||||
Lock lock(&m_mutexTrans);
|
||||
if (m_transaction) {
|
||||
m_transaction->sendRinging();
|
||||
startAudioOut();
|
||||
|
@ -1224,6 +1234,7 @@ bool YIAXConnection::msgRinging(Message& msg)
|
|||
|
||||
bool YIAXConnection::msgAnswered(Message& msg)
|
||||
{
|
||||
Lock lock(&m_mutexTrans);
|
||||
if (m_transaction) {
|
||||
m_transaction->sendAnswer();
|
||||
startAudioIn();
|
||||
|
@ -1235,6 +1246,7 @@ bool YIAXConnection::msgAnswered(Message& msg)
|
|||
|
||||
bool YIAXConnection::msgTone(Message& msg, const char* tone)
|
||||
{
|
||||
Lock lock(&m_mutexTrans);
|
||||
if (m_transaction) {
|
||||
while (tone && *tone)
|
||||
m_transaction->sendDtmf(*tone++);
|
||||
|
@ -1245,6 +1257,7 @@ bool YIAXConnection::msgTone(Message& msg, const char* tone)
|
|||
|
||||
bool YIAXConnection::msgText(Message& msg, const char* text)
|
||||
{
|
||||
Lock lock(&m_mutexTrans);
|
||||
if (m_transaction) {
|
||||
m_transaction->sendText(text);
|
||||
return true;
|
||||
|
@ -1329,7 +1342,7 @@ void YIAXConnection::handleEvent(IAXEvent* event)
|
|||
break;
|
||||
case IAXEvent::Timeout:
|
||||
DDebug(this,DebugNote,"YIAXConnection - TIMEOUT. Transaction: %u,%u, Frame: %u,%u ",
|
||||
m_transaction->localCallNo(),m_transaction->remoteCallNo(),event->frameType(),event->subclass());
|
||||
event->getTransaction()->localCallNo(),event->getTransaction()->remoteCallNo(),event->frameType(),event->subclass());
|
||||
m_reason = "Timeout";
|
||||
break;
|
||||
case IAXEvent::Busy:
|
||||
|
@ -1350,7 +1363,7 @@ void YIAXConnection::handleEvent(IAXEvent* event)
|
|||
}
|
||||
}
|
||||
|
||||
void YIAXConnection::hangup(const char *reason, bool reject)
|
||||
void YIAXConnection::hangup(const char* reason, bool reject)
|
||||
{
|
||||
if (!m_hangup)
|
||||
// Already done
|
||||
|
@ -1360,6 +1373,7 @@ void YIAXConnection::hangup(const char *reason, bool reject)
|
|||
reason = m_reason;
|
||||
if (!reason)
|
||||
reason = Engine::exiting() ? "Server shutdown" : "Unexpected problem";
|
||||
m_mutexTrans.lock();
|
||||
if (m_transaction) {
|
||||
m_transaction->setUserData(0);
|
||||
if (reject)
|
||||
|
@ -1368,6 +1382,7 @@ void YIAXConnection::hangup(const char *reason, bool reject)
|
|||
m_transaction->sendHangup(reason);
|
||||
m_transaction = 0;
|
||||
}
|
||||
m_mutexTrans.unlock();
|
||||
Message* m = message("chan.hangup",true);
|
||||
m->setParam("status","hangup");
|
||||
m->setParam("reason",reason);
|
||||
|
@ -1380,6 +1395,7 @@ bool YIAXConnection::route(bool authenticated)
|
|||
if (!m_transaction)
|
||||
return false;
|
||||
Message* m = message("call.preroute",false,true);
|
||||
Lock lock(&m_mutexTrans);
|
||||
if (authenticated) {
|
||||
DDebug(this,DebugAll,"Route pass 2: Password accepted.");
|
||||
m_refIncreased = false;
|
||||
|
@ -1407,8 +1423,10 @@ void YIAXConnection::startAudioIn()
|
|||
if (getSource())
|
||||
return;
|
||||
u_int32_t format = 0;
|
||||
m_mutexTrans.lock();
|
||||
if (m_transaction)
|
||||
format = m_transaction->formatIn();
|
||||
m_mutexTrans.unlock();
|
||||
const char* formatText = IAXFormat::audioText(format);
|
||||
setSource(new YIAXSource(this,format,formatText));
|
||||
getSource()->deref();
|
||||
|
@ -1420,8 +1438,10 @@ void YIAXConnection::startAudioOut()
|
|||
if (getConsumer())
|
||||
return;
|
||||
u_int32_t format = 0;
|
||||
m_mutexTrans.lock();
|
||||
if (m_transaction)
|
||||
format = m_transaction->formatOut();
|
||||
m_mutexTrans.unlock();
|
||||
const char* formatText = (char*)IAXFormat::audioText(format);
|
||||
setConsumer(new YIAXConsumer(this,format,formatText));
|
||||
getConsumer()->deref();
|
||||
|
|
Loading…
Reference in New Issue