Marian's changes.

git-svn-id: http://yate.null.ro/svn/yate/trunk@900 acf43c95-373e-0410-b603-e72c3f656dc1
This commit is contained in:
paulc 2006-06-26 05:19:52 +00:00
parent 2a5a670687
commit 1236b2e154
6 changed files with 894 additions and 555 deletions

View File

@ -0,0 +1,34 @@
[general]
; This section sets global variables of the implementation
; port: int: UDP port for incoming connections
;port=4569
; tos: keyword: Type Of Service to set in outgoing UDP packets
; numeric TOS value or: lowdelay, throughput, reliability, mincost
;tos=0
[formats]
; This section allows to individually enable or disable the codecs
; default: bool: Default enabling state for codecs
;default=enable
; preferred: string: Preferred format to use
;preferred=
; slin: bool: Uncompressed 16-bit signed linear
;slin=enable
; mulaw: bool: Companded-only G711 mu-law
;mulaw=enable
; alaw: bool: Companded-only G711 a-law
;alaw=enable
; gsm: bool: European GSM 06.10
;gsm=enable
; lpc10: bool: LPC 10
;lpc10=enable

View File

@ -1,7 +1,7 @@
/** /**
* engine.cpp * engine.cpp
* Yet Another IAX2 Stack * Yet Another IAX2 Stack
* This file is part of the YATE Project http://YATE.null.ro * This file is part of the YATE Project http://YATE.null.ro
* *
* Yet Another Telephony Engine - a fully featured software PBX and IVR * Yet Another Telephony Engine - a fully featured software PBX and IVR
* Copyright (C) 2004-2006 Null Team * Copyright (C) 2004-2006 Null Team
@ -30,31 +30,40 @@
using namespace TelEngine; using namespace TelEngine;
IAXEngine::IAXEngine(int transCount, int retransCount, int retransInterval, int maxFullFrameDataLen, u_int32_t transTimeout, IAXEngine::IAXEngine(int port, u_int16_t transListCount, u_int16_t retransCount, u_int16_t retransInterval,
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)
: Mutex(true), m_transList(0), m_transListCount(0), m_retransCount(retransCount), : Mutex(true),
m_retransInterval(retransInterval), m_maxFullFrameDataLen(maxFullFrameDataLen), m_transactionTimeout(transTimeout), m_lastGetEvIndex(0),
m_format(format), m_capability(capab) m_maxFullFrameDataLen(maxFullFrameDataLen),
m_startLocalCallNo(0),
m_transListCount(0),
m_retransCount(retransCount),
m_retransInterval(retransInterval),
m_authTimeout(authTimeout),
m_transTimeout(transTimeout),
m_format(format),
m_capability(capab)
{ {
debugName("iaxengine"); debugName("iaxengine");
if (transCount < 4) if ((port <= 0) || port > 65535)
transCount = 4; port = 4569;
else if (transCount > 256) if (transListCount < 4)
transCount = 256; transListCount = 4;
m_transList = new ObjList*[transCount]; else if (transListCount > 256)
transListCount = 256;
m_transList = new ObjList*[transListCount];
int i; int i;
for (i = 0; i < transCount; i++) for (i = 0; i < transListCount; i++)
m_transList[i] = new ObjList; m_transList[i] = new ObjList;
m_transListCount = transCount; m_transListCount = transListCount;
for(i = 0; i <= IAX2_MAX_CALLNO; i++) for(i = 0; i <= IAX2_MAX_CALLNO; i++)
m_lUsedCallNo[i] = false; m_lUsedCallNo[i] = false;
m_lastGetEvIndex = 0;
m_socket.create(AF_INET,SOCK_DGRAM); m_socket.create(AF_INET,SOCK_DGRAM);
SocketAddr addr(AF_INET); SocketAddr addr(AF_INET);
addr.port(4569); addr.port(port);
m_socket.setBlocking(false); m_socket.setBlocking(false);
if (!m_socket.bind(addr)) if (!m_socket.bind(addr))
Debug(this,DebugWarn,"Failed to bind socket!"); Debug(this,DebugWarn,"Failed to bind socket on port %d",port);
m_startLocalCallNo = 1 + (u_int16_t)(random() % IAX2_MAX_CALLNO); m_startLocalCallNo = 1 + (u_int16_t)(random() % IAX2_MAX_CALLNO);
} }
@ -85,7 +94,7 @@ IAXTransaction* IAXEngine::addFrame(const SocketAddr& addr, IAXFrame* frame)
tr->m_rCallNo = frame->sourceCallNo(); tr->m_rCallNo = frame->sourceCallNo();
m_incompleteTransList.remove(tr,false); m_incompleteTransList.remove(tr,false);
m_transList[frame->sourceCallNo() % m_transListCount]->append(tr); m_transList[frame->sourceCallNo() % m_transListCount]->append(tr);
XDebug(this,DebugAll,"New remote transaction completed (%u,%u)", XDebug(this,DebugAll,"New incomplete outgoing transaction completed (%u,%u)",
tr->localCallNo(),tr->remoteCallNo()); tr->localCallNo(),tr->remoteCallNo());
return tr; return tr;
} }
@ -134,7 +143,10 @@ IAXTransaction* IAXEngine::addFrame(const SocketAddr& addr, IAXFrame* frame)
return 0; return 0;
// Create and add transaction // Create and add transaction
tr = IAXTransaction::factoryIn(this,(IAXFullFrame*)frame->fullFrame(),lcn,addr); tr = IAXTransaction::factoryIn(this,(IAXFullFrame*)frame->fullFrame(),lcn,addr);
m_transList[frame->sourceCallNo() % m_transListCount]->append(tr); if (tr)
m_transList[frame->sourceCallNo() % m_transListCount]->append(tr);
else
releaseCallNo(lcn);
return tr; return tr;
} }
@ -232,7 +244,6 @@ void IAXEngine::removeTransaction(IAXTransaction* transaction)
u_int32_t IAXEngine::transactionCount() u_int32_t IAXEngine::transactionCount()
{ {
u_int32_t n = 0; u_int32_t n = 0;
ObjList* l;
Lock lock(this); Lock lock(this);
// Incomplete transactions // Incomplete transactions
@ -240,7 +251,7 @@ u_int32_t IAXEngine::transactionCount()
// Complete transactions // Complete transactions
for (int i = 0; i < m_transListCount; i++) for (int i = 0; i < m_transListCount; i++)
n += m_transList[i]->count(); n += m_transList[i]->count();
return n; return n;
} }
void IAXEngine::keepAlive(SocketAddr& addr) void IAXEngine::keepAlive(SocketAddr& addr)
@ -314,31 +325,67 @@ void IAXEngine::releaseCallNo(u_int16_t lcallno)
IAXTransaction* IAXEngine::startLocalTransaction(IAXTransaction::Type type, const SocketAddr& addr, IAXIEList& ieList) IAXTransaction* IAXEngine::startLocalTransaction(IAXTransaction::Type type, const SocketAddr& addr, IAXIEList& ieList)
{ {
switch (type) {
case IAXTransaction::New:
case IAXTransaction::RegReq:
case IAXTransaction::RegRel:
case IAXTransaction::Poke:
break;
case IAXTransaction::FwDownl:
default:
Debug(this,DebugWarn,"Unsupported new transaction type %u requested",type);
return 0;
}
Lock lock(this); Lock lock(this);
u_int16_t lcn = generateCallNo(); u_int16_t lcn = generateCallNo();
if (!lcn) if (!lcn)
return 0; return 0;
IAXTransaction* tr = IAXTransaction::factoryOut(this,type,lcn,addr,ieList); IAXTransaction* tr = IAXTransaction::factoryOut(this,type,lcn,addr,ieList);
if (tr->type() == IAXTransaction::Incorrect) { if (tr)
Debug(this,DebugWarn,"Error initializing transaction"); m_incompleteTransList.append(tr);
delete tr; else
return 0; releaseCallNo(lcn);
}
m_incompleteTransList.append(tr);
return tr; return tr;
} }
bool IAXEngine::acceptFormatAndCapability(IAXTransaction* trans)
{
if (!trans)
return false;
u_int32_t format = trans->format();
u_int32_t capability = m_capability & trans->capability();
// Valid capability ?
if (!capability)
return false;
for (;;) {
// Received format is valid ?
if (0 != (format & capability) && IAXFormat::audioText(format))
break;
// Local format is valid ?
format = m_format;
if (0 != (m_format & capability) && IAXFormat::audioText(format))
break;
// No valid format: choose one from capability
format = 0;
u_int32_t i = 0;
for (; IAXFormat::audioData[i].value; i++)
if (0 != (capability & IAXFormat::audioData[i].value))
break;
if (IAXFormat::audioData[i].value) {
format = IAXFormat::audioData[i].value;
break;
}
return false;
}
trans->m_format = format;
trans->m_formatIn = format;
trans->m_formatOut = format;
trans->m_capability = capability;
return true;
}
void IAXEngine::defaultEventHandler(IAXEvent* event)
{
DDebug(this,DebugAll,"defaultEventHandler - Event type: %u. Frame - Type: %u Subclass: %u",
event->type(),event->frameType(),event->subclass());
IAXTransaction* tr = event->getTransaction();
switch (event->type()) {
case IAXEvent::New:
tr->sendReject("Feature not implemented or unsupported");
break;
default: ;
}
}
void IAXEngine::getMD5FromChallenge(String& md5data, const String& challenge, const String& password) void IAXEngine::getMD5FromChallenge(String& md5data, const String& challenge, const String& password)
{ {
MD5 md5; MD5 md5;
@ -356,16 +403,16 @@ bool IAXEngine::isMD5ChallengeCorrect(const String& md5data, const String& chall
/* /*
* IAXEvent * IAXEvent
*/ */
IAXEvent::IAXEvent(Type type, bool final, IAXTransaction* transaction, u_int8_t frameType, u_int8_t subclass) IAXEvent::IAXEvent(Type type, bool local, bool final, IAXTransaction* transaction, u_int8_t frameType, u_int8_t subclass)
: m_type(type), m_frameType(frameType), m_subClass(subclass), m_final(final), m_transaction(0) : m_type(type), m_frameType(frameType), m_subClass(subclass), m_local(local), m_final(final), m_transaction(0)
{ {
if (transaction && transaction->ref()) if (transaction && transaction->ref())
m_transaction = transaction; m_transaction = transaction;
} }
IAXEvent::IAXEvent(Type type, bool final, IAXTransaction* transaction, const IAXFullFrame* frame) IAXEvent::IAXEvent(Type type, bool local, bool final, IAXTransaction* transaction, const IAXFullFrame* frame)
: m_type(type), m_frameType(0), m_subClass(0), m_final(final), m_transaction(0), m_ieList(frame) : m_type(type), m_frameType(0), m_subClass(0), m_local(local), m_final(final), m_transaction(0), m_ieList(frame)
{ {
if (transaction && transaction->ref()) if (transaction && transaction->ref())
@ -381,8 +428,10 @@ IAXEvent::~IAXEvent()
if (m_final && m_transaction && m_transaction->state() == IAXTransaction::Terminated) { if (m_final && m_transaction && m_transaction->state() == IAXTransaction::Terminated) {
m_transaction->getEngine()->removeTransaction(m_transaction); m_transaction->getEngine()->removeTransaction(m_transaction);
} }
if (m_transaction) if (m_transaction) {
m_transaction->eventTerminated(this);
m_transaction->deref(); m_transaction->deref();
}
} }
/* vi: set ts=8 sw=4 sts=4 noet: */ /* vi: set ts=8 sw=4 sts=4 noet: */

View File

@ -1,7 +1,7 @@
/** /**
* frame.cpp * frame.cpp
* Yet Another IAX2 Stack * Yet Another IAX2 Stack
* This file is part of the YATE Project http://YATE.null.ro * This file is part of the YATE Project http://YATE.null.ro
* *
* Yet Another Telephony Engine - a fully featured software PBX and IVR * Yet Another Telephony Engine - a fully featured software PBX and IVR
* Copyright (C) 2004-2006 Null Team * Copyright (C) 2004-2006 Null Team
@ -124,7 +124,7 @@ IAXInfoElementNumeric::IAXInfoElementNumeric(Type type, u_int32_t val, u_int8_t
break; break;
} }
} }
void IAXInfoElementNumeric::toBuffer(DataBlock& buf) void IAXInfoElementNumeric::toBuffer(DataBlock& buf)
{ {
unsigned char d[6] = {m_type,m_length}; unsigned char d[6] = {m_type,m_length};
@ -158,10 +158,8 @@ void IAXInfoElementBinary::toBuffer(DataBlock& buf)
buf += m_data; buf += m_data;
} }
IAXInfoElementBinary* IAXInfoElementBinary::packIP(const SocketAddr& addr, bool ipv4) IAXInfoElementBinary* IAXInfoElementBinary::packIP(const SocketAddr& addr)
{ {
if (!ipv4)
return 0;
return new IAXInfoElementBinary(IAXInfoElement::APPARENT_ADDR,(unsigned char*)(addr.address()),addr.length()); return new IAXInfoElementBinary(IAXInfoElement::APPARENT_ADDR,(unsigned char*)(addr.address()),addr.length());
} }
@ -177,7 +175,6 @@ bool IAXInfoElementBinary::unpackIP(SocketAddr& addr, IAXInfoElementBinary* ie)
/** /**
* IAXIEList * IAXIEList
*/ */
void IAXIEList::insertVersion() void IAXIEList::insertVersion()
{ {
if (!getIE(IAXInfoElement::VERSION)) if (!getIE(IAXInfoElement::VERSION))
@ -225,7 +222,7 @@ bool IAXIEList::createFromFrame(const IAXFullFrame* frame)
case IAXInfoElement::RSA_RESULT: case IAXInfoElement::RSA_RESULT:
case IAXInfoElement::CAUSE: case IAXInfoElement::CAUSE:
case IAXInfoElement::MUSICONHOLD: // Optional case IAXInfoElement::MUSICONHOLD: // Optional
case IAXInfoElement::RDNIS: case IAXInfoElement::RDNIS:
case IAXInfoElement::DEVICETYPE: case IAXInfoElement::DEVICETYPE:
if (data[i]) if (data[i])
appendString((IAXInfoElement::Type)data[i-1],data+i+1,data[i]); appendString((IAXInfoElement::Type)data[i-1],data+i+1,data[i]);
@ -247,10 +244,6 @@ bool IAXIEList::createFromFrame(const IAXFullFrame* frame)
case IAXInfoElement::SERVICEIDENT: // Length must be 6 case IAXInfoElement::SERVICEIDENT: // Length must be 6
case IAXInfoElement::FWBLOCKDATA: // Length can be 0 case IAXInfoElement::FWBLOCKDATA: // Length can be 0
case IAXInfoElement::ENKEY: case IAXInfoElement::ENKEY:
if (data[i-1] != IAXInfoElement::FWBLOCKDATA && !data[i]) {
i = 0xFFFF;
break;
}
if (data[i-1] == IAXInfoElement::SERVICEIDENT && data[i] != 6) { if (data[i-1] == IAXInfoElement::SERVICEIDENT && data[i] != 6) {
i = 0xFFFF; i = 0xFFFF;
break; break;
@ -285,7 +278,7 @@ bool IAXIEList::createFromFrame(const IAXFullFrame* frame)
case IAXInfoElement::AUTHMETHODS: case IAXInfoElement::AUTHMETHODS:
case IAXInfoElement::REFRESH: case IAXInfoElement::REFRESH:
case IAXInfoElement::DPSTATUS: case IAXInfoElement::DPSTATUS:
case IAXInfoElement::CALLNO: case IAXInfoElement::CALLNO:
case IAXInfoElement::MSGCOUNT: case IAXInfoElement::MSGCOUNT:
case IAXInfoElement::CALLINGTNS: case IAXInfoElement::CALLINGTNS:
case IAXInfoElement::FIRMWAREVER: case IAXInfoElement::FIRMWAREVER:
@ -295,10 +288,6 @@ bool IAXIEList::createFromFrame(const IAXFullFrame* frame)
break; break;
} }
value = (data[i+1] << 8) | data[i+2]; value = (data[i+1] << 8) | data[i+2];
if (data[i-1] == IAXInfoElement::VERSION && value != IAX_PROTOCOL_VERSION) {
i = 0xFFFF;
break;
}
appendNumeric((IAXInfoElement::Type)data[i-1],value,2); appendNumeric((IAXInfoElement::Type)data[i-1],value,2);
i += 3; i += 3;
break; break;
@ -424,18 +413,12 @@ TokenDict IAXFormat::videoData[] = {
const char* IAXFormat::audioText(u_int8_t audio) const char* IAXFormat::audioText(u_int8_t audio)
{ {
for (int i = 0; audioData[i].value; i++) return lookup(audio,audioData);
if (audioData[i].value == audio)
return audioData[i].token;
return 0;
} }
const char* IAXFormat::videoText(u_int8_t video) const char* IAXFormat::videoText(u_int8_t video)
{ {
for (int i = 0; videoData[i].value; i++) return lookup(video,videoData);
if (videoData[i].value == video)
return videoData[i].token;
return 0;
} }
/** /**
@ -446,7 +429,7 @@ IAXFrame::IAXFrame(Type type, u_int16_t sCallNo, u_int32_t tStamp, bool retrans,
: m_type(type), m_data((char*)buf,len,true), m_retrans(retrans), : 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), m_subclass(0)
{ {
XDebug(DebugAll,"IAXFrame::IAXFrame(%u,%u) [%p]",type,this); XDebug(DebugAll,"IAXFrame::IAXFrame(%u) [%p]",type,this);
} }
IAXFrame::~IAXFrame() IAXFrame::~IAXFrame()
@ -454,15 +437,6 @@ IAXFrame::~IAXFrame()
XDebug(DebugAll,"IAXFrame::~IAXFrame() [%p]",this); XDebug(DebugAll,"IAXFrame::~IAXFrame() [%p]",this);
} }
bool IAXFrame::setRetrans()
{
if (!m_retrans) {
m_retrans = true;
((unsigned char*)m_data.data())[2] |= 0x80;
}
return true;
}
IAXFrame* IAXFrame::parse(const unsigned char* buf, unsigned int len, IAXEngine* engine, const SocketAddr* addr) IAXFrame* IAXFrame::parse(const unsigned char* buf, unsigned int len, IAXEngine* engine, const SocketAddr* addr)
{ {
if (len < 4) if (len < 4)
@ -577,7 +551,7 @@ u_int8_t IAXFrame::packSubclass(u_int32_t value)
return 0; return 0;
} }
u_int32_t IAXFrame::unpackSubclass(u_int8_t value) u_int32_t IAXFrame::unpackSubclass(u_int8_t value)
{ {
if (value > 0x9f) { if (value > 0x9f) {
DDebug(DebugMild,"IAXFrame nonstandard unpack %u",value); DDebug(DebugMild,"IAXFrame nonstandard unpack %u",value);
@ -659,4 +633,29 @@ const IAXFullFrame* IAXFullFrame::fullFrame() const
return this; return this;
} }
/**
* IAXFrameOut
*/
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;
}
}
}
void IAXFrameOut::adjustAuthTimeout(u_int64_t nextTransTime)
{
if (!(type() == IAXFrame::IAX && (subclass() == IAXControl::AuthReq || subclass() ==IAXControl::RegAuth)))
return;
m_retransCount = 1;
m_nextTransTime = nextTransTime;
}
/* vi: set ts=8 sw=4 sts=4 noet: */ /* vi: set ts=8 sw=4 sts=4 noet: */

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
/** /*
* yateiax.h * yateiax.h
* Yet Another IAX2 Stack * Yet Another IAX2 Stack
* This file is part of the YATE Project http://YATE.null.ro * This file is part of the YATE Project http://YATE.null.ro
@ -42,7 +42,7 @@
#define YIAX_API #define YIAX_API
#endif #endif
/** /**
* Holds all Telephony Engine related classes. * Holds all Telephony Engine related classes.
*/ */
namespace TelEngine { namespace TelEngine {
@ -174,7 +174,7 @@ public:
inline int length() const inline int length() const
{ return m_strData.length(); } { return m_strData.length(); }
inline String& data() inline String& data()
{ return m_strData; } { return m_strData; }
virtual void toBuffer(DataBlock& buf); virtual void toBuffer(DataBlock& buf);
@ -190,8 +190,8 @@ class IAXInfoElementNumeric : public IAXInfoElement
{ {
public: public:
IAXInfoElementNumeric(Type type, u_int32_t val, u_int8_t len); IAXInfoElementNumeric(Type type, u_int32_t val, u_int8_t len);
virtual ~IAXInfoElementNumeric() {} virtual ~IAXInfoElementNumeric() {}
inline int length() const inline int length() const
{ return m_length; } { return m_length; }
@ -225,7 +225,7 @@ public:
virtual void toBuffer(DataBlock& buf); virtual void toBuffer(DataBlock& buf);
static IAXInfoElementBinary* packIP(const SocketAddr& addr, bool ipv4 = true); static IAXInfoElementBinary* packIP(const SocketAddr& addr);
static bool unpackIP(SocketAddr& addr, IAXInfoElementBinary* ie); static bool unpackIP(SocketAddr& addr, IAXInfoElementBinary* ie);
@ -314,7 +314,7 @@ public:
* This class holds the enumeration values for audio and video formats * This class holds the enumeration values for audio and video formats
* @short Wrapper class for audio and video formats * @short Wrapper class for audio and video formats
*/ */
class YIAX_API IAXFormat class YIAX_API IAXFormat
{ {
public: public:
enum Audio { enum Audio {
@ -348,7 +348,7 @@ public:
/** /**
* This class holds the enumeration values for IAX control (subclass) * This class holds the enumeration values for IAX control (subclass)
*/ */
class YIAX_API IAXControl class YIAX_API IAXControl
{ {
public: public:
enum Type { enum Type {
@ -425,8 +425,6 @@ public:
inline bool retrans() const inline bool retrans() const
{ return m_retrans; } { return m_retrans; }
bool setRetrans();
inline u_int16_t sourceCallNo() const inline u_int16_t sourceCallNo() const
{ return m_sCallNo; } { return m_sCallNo; }
@ -451,7 +449,7 @@ public:
/** /**
* Unpack the the value received according to IAX protocol * Unpack the the value received according to IAX protocol
* @return The unpacked subclass * @return The unpacked subclass
*/ */
static u_int32_t IAXFrame::unpackSubclass(u_int8_t value); static u_int32_t IAXFrame::unpackSubclass(u_int8_t value);
@ -535,21 +533,19 @@ public:
virtual ~IAXFrameOut() virtual ~IAXFrameOut()
{} {}
inline bool timeout() const inline bool timeout() const
{ return !(bool)m_retransCount; } { return !(bool)m_retransCount; }
inline bool needRetrans(u_int64_t time)
{ return !ack() && time > m_nextTransTime; }
inline void transmitted() {
if (m_retransCount) { inline bool timeForRetrans(u_int64_t time)
m_retransCount--; { return time > m_nextTransTime; }
m_retransTimeInterval *= 2;
m_nextTransTime += m_retransTimeInterval; void transmitted();
}
} inline void hurryTransmission(u_int64_t time = Time::msecNow())
{ m_nextTransTime = time; }
inline bool ack() inline bool ack()
{ return m_ack; } { return m_ack; }
@ -559,6 +555,12 @@ public:
inline bool ackOnly() inline bool ackOnly()
{ return m_ackOnly; } { return m_ackOnly; }
/**
* Increase the timeout for acknoledged authentication frames sent and set the counter to 1
* @param nextTransTime Next transmission time
*/
void adjustAuthTimeout(u_int64_t nextTransTime);
protected: protected:
bool m_ack; /* Acknoledge flag */ bool m_ack; /* Acknoledge flag */
bool m_ackOnly; /* frame need only Ack as response */ bool m_ackOnly; /* frame need only Ack as response */
@ -567,35 +569,12 @@ protected:
u_int64_t m_nextTransTime; /* Next transmission time */ u_int64_t m_nextTransTime; /* Next transmission time */
}; };
class IAXConnectionlessTransaction;
/**
* Keep registration data
*/
class YIAX_API IAXRegData
{
public:
inline IAXRegData() : m_expire(60), m_userdata(0)
{}
inline IAXRegData(const String& username, const String& password, const String& callingNo, const String& callingName,
u_int16_t expire, void* userdata = 0)
: m_username(username), m_password(password), m_callingNo(callingNo), m_callingName(callingName),
m_expire(expire), m_userdata(userdata)
{}
String m_username; /* Username */
String m_password; /* Password */
String m_callingNo; /* Calling number */
String m_callingName; /* Calling name */
u_int32_t m_expire; /* Expire time */
void* m_userdata; /* */
};
/** /**
* Handle transactions of type New * Handle transactions of type New
*/ */
class YIAX_API IAXTransaction : public RefObject, public Mutex class YIAX_API IAXTransaction : public RefObject, public Mutex
{ {
friend class IAXEvent;
friend class IAXEngine; friend class IAXEngine;
public: public:
enum Type { enum Type {
@ -611,62 +590,62 @@ public:
/* *** New */ /* *** New */
Connected, /* Call leg established (Accepted). */ Connected, /* Call leg established (Accepted). */
/* Outgoing */ /* Outgoing */
NewLocalInvite, /* Sent: New, RegReq/RegRel */ NewLocalInvite, /* Sent: New, RegReq/RegRel */
/* New */ /* New */
/* *** Send: */ /* *** Send: */
/* Hangup --> Terminating */ /* Hangup --> Terminating */
/* *** Receive: */ /* *** Receive: */
/* AuthReq --> NewLocalInvite_AuthRecv */ /* AuthReq --> NewLocalInvite_AuthRecv */
/* Accept --> Connected */ /* Accept --> Connected */
/* Reject, Hangup --> Terminating */ /* Reject, Hangup --> Terminating */
/* RegReq/RegRel */ /* RegReq/RegRel */
/* *** Send: */ /* *** Send: */
/* RegRej --> Terminating */ /* RegRej --> Terminating */
/* *** Receive: */ /* *** Receive: */
/* RegAuth --> NewLocalInvite_AuthRecv */ /* RegAuth --> NewLocalInvite_AuthRecv */
/* RegAck (if RegReq) --> Terminating */ /* RegAck (if RegReq) --> Terminating */
/* RegRej --> Terminating */ /* RegRej --> Terminating */
NewLocalInvite_AuthRecv, /* Received: AuthReq, RegReq/RegRel */ NewLocalInvite_AuthRecv, /* Received: AuthReq, RegReq/RegRel */
/* New */ /* New */
/* *** Send: */ /* *** Send: */
/* AuthRep --> NewLocalInvite_RepSent */ /* AuthRep --> NewLocalInvite_RepSent */
/* Hangup, Reject --> Terminating */ /* Hangup, Reject --> Terminating */
/* *** Receive: */ /* *** Receive: */
/* Reject, Hangup --> Terminating */ /* Reject, Hangup --> Terminating */
/* RegReq/RegRel */ /* RegReq/RegRel */
/* *** Send: */ /* *** Send: */
/* RegReq/RegRel --> NewLocalInvite_RepSent */ /* RegReq/RegRel --> NewLocalInvite_RepSent */
/* RegRej --> Terminating */ /* RegRej --> Terminating */
/* *** Receive: */ /* *** Receive: */
/* RegRej --> Terminating */ /* RegRej --> Terminating */
NewLocalInvite_RepSent, /* Sent: AuthRep, RegReq/RegRel */ NewLocalInvite_RepSent, /* Sent: AuthRep, RegReq/RegRel */
/* New */ /* New */
/* *** Send: */ /* *** Send: */
/* Hangup --> Terminating */ /* Hangup --> Terminating */
/* *** Receive: */ /* *** Receive: */
/* Accept --> Connected */ /* Accept --> Connected */
/* Reject, Hangup --> Terminating */ /* Reject, Hangup --> Terminating */
/* RegReq/RegRel */ /* RegReq/RegRel */
/* *** Send: */ /* *** Send: */
/* RegRej --> Terminating */ /* RegRej --> Terminating */
/* *** Receive: */ /* *** Receive: */
/* RegAck --> Terminating */ /* RegAck --> Terminating */
/* RegRej --> Terminating */ /* RegRej --> Terminating */
/* Incoming */ /* Incoming */
NewRemoteInvite, /* Received: New, RegReq/RegRel*/ NewRemoteInvite, /* Received: New, RegReq/RegRel*/
/* New */ /* New */
/* *** Send: */ /* *** Send: */
/* AuthReq --> NewRemoteInvite_AuthSent */ /* AuthReq --> NewRemoteInvite_AuthSent */
/* Accept --> Connected */ /* Accept --> Connected */
/* Hangup --> Terminating */ /* Hangup --> Terminating */
/* *** Receive: */ /* *** Receive: */
/* Reject, Hangup --> Terminating */ /* Reject, Hangup --> Terminating */
/* RegReq/RegRel */ /* RegReq/RegRel */
/* *** Send: */ /* *** Send: */
/* RegAuth --> NewRemoteInvite_AuthSent */ /* RegAuth --> NewRemoteInvite_AuthSent */
/* RegAck (if RegReq) --> Terminated */ /* RegAck (if RegReq) --> Terminated */
/* RegRej --> Terminating */ /* RegRej --> Terminating */
/* *** Receive: */ /* *** Receive: */
/* RegRej --> Terminating */ /* RegRej --> Terminating */
NewRemoteInvite_AuthSent, /* Sent: AuthReq, RegAuth */ NewRemoteInvite_AuthSent, /* Sent: AuthReq, RegAuth */
/* New */ /* New */
@ -676,28 +655,28 @@ public:
/* AuthRep --> NewRemoteInvite_RepRecv */ /* AuthRep --> NewRemoteInvite_RepRecv */
/* Reject, Hangup --> Terminating */ /* Reject, Hangup --> Terminating */
/* RegReq/RegRel */ /* RegReq/RegRel */
/* *** Send: */ /* *** Send: */
/* RegRej --> Terminating */ /* RegRej --> Terminating */
/* *** Receive: */ /* *** Receive: */
/* RegReq/RegRel --> NewRemoteInvite_RepRecv */ /* RegReq/RegRel --> NewRemoteInvite_RepRecv */
/* RegRej --> Terminating */ /* RegRej --> Terminating */
NewRemoteInvite_RepRecv, /* Received: AuthRep, RegReq/RegRel*/ NewRemoteInvite_RepRecv, /* Received: AuthRep, RegReq/RegRel*/
/* New */ /* New */
/* *** Send: */ /* *** Send: */
/* Accept --> Connected */ /* Accept --> Connected */
/* Hangup --> Terminating */ /* Hangup --> Terminating */
/* *** Receive: */ /* *** Receive: */
/* Reject, Hangup --> Terminating */ /* Reject, Hangup --> Terminating */
/* RegReq/RegRel */ /* RegReq/RegRel */
/* *** Send: */ /* *** Send: */
/* RegAck, RegRej --> Terminating */ /* RegAck, RegRej --> Terminating */
/* *** Receive: */ /* *** Receive: */
/* RegRej --> Terminating */ /* RegRej --> Terminating */
/* Not initialized or terminated */ /* Not initialized or terminated */
Unknown, /* Initial state. */ Unknown, /* Initial state. */
Terminated, /* Terminated. No more frames accepted. */ Terminated, /* Terminated. No more frames accepted. */
Terminating, /* Terminating. Wait for ACK or timeout to terminate. */ Terminating, /* Terminating. Wait for ACK or timeout to terminate. */
}; };
/** /**
* Destructor * Destructor
@ -725,7 +704,7 @@ public:
* @param ieList Starting IE list * @param ieList Starting IE list
* @param data Pointer to arbitrary user data * @param data Pointer to arbitrary user data
*/ */
static IAXTransaction* factoryOut(IAXEngine* engine, Type type, u_int16_t lcallno, const SocketAddr& addr, static IAXTransaction* factoryOut(IAXEngine* engine, Type type, u_int16_t lcallno, const SocketAddr& addr,
IAXIEList& ieList, void* data = 0); IAXIEList& ieList, void* data = 0);
/** /**
@ -820,6 +799,12 @@ public:
inline u_int32_t format() inline u_int32_t format()
{ return m_format; } { return m_format; }
inline u_int32_t formatIn()
{ return m_formatIn; }
inline u_int32_t formatOut()
{ return m_formatOut; }
inline u_int32_t capability() inline u_int32_t capability()
{ return m_capability; } { return m_capability; }
@ -841,7 +826,7 @@ public:
/** /**
* Process received mini frame data * Process received mini frame data
* @param data Received data * @param data Received data
* @param tStamp Mini frame timestamp * @param tStamp Mini frame timestamp
* @param voice True if received mini frame inside a Voice full frame * @param voice True if received mini frame inside a Voice full frame
* @return 'this' if successful or 0 * @return 'this' if successful or 0
*/ */
@ -918,7 +903,7 @@ public:
* @param pwd Required password * @param pwd Required password
* @return False if the current transaction state is not NewRemoteInvite. * @return False if the current transaction state is not NewRemoteInvite.
*/ */
bool sendAuth(String& pwd); bool sendAuth(const String& pwd);
/** /**
* Send an AUTHREP/REGREQ/REGREL frame to remote peer as a response to AUTHREQ/REGREQ/REGREL. * Send an AUTHREP/REGREQ/REGREL frame to remote peer as a response to AUTHREQ/REGREQ/REGREL.
@ -953,10 +938,22 @@ public:
inline bool sendNoise(u_int8_t noise) inline bool sendNoise(u_int8_t noise)
{ return noise <= 127 ? sendConnected((IAXFullFrame::ControlType)noise,IAXFrame::Noise) : false; } { return noise <= 127 ? sendConnected((IAXFullFrame::ControlType)noise,IAXFrame::Noise) : false; }
bool setFormatAndCapability(); /**
* Abort a registration transaction.
* This method is thread safe.
* @return False transaction is not a registration one or is already terminating.
*/
bool abortReg(); bool abortReg();
/**
* Print transaction data on stdin.
*/
void print();
static String s_iax_modNoAuthMethod;
static String s_iax_modNoMediaFormat;
static String s_iax_modInvalidAuth;
protected: protected:
/** /**
* Constructor: constructs an incoming transaction from a received full frame with an IAX * Constructor: constructs an incoming transaction from a received full frame with an IAX
@ -1011,19 +1008,21 @@ protected:
/** /**
* Terminate the transaction. * Terminate the transaction.
* @param evType IAXEvent type to generate. * @param evType IAXEvent type to generate.
* @param local If true it is a locally generated event.
* @param frame Frame to build event from. * @param frame Frame to build event from.
* @param createIEList If true create IE list in the generated event. * @param createIEList If true create IE list in the generated event.
* @return Pointer to a valid IAXEvent with the reason. * @return Pointer to a valid IAXEvent with the reason.
*/ */
IAXEvent* terminate(u_int8_t evType, const IAXFullFrame* frame = 0, bool createIEList = true); IAXEvent* terminate(u_int8_t evType, bool local, const IAXFullFrame* frame = 0, bool createIEList = true);
/** /**
* Terminate the transaction. Wait for ACK to terminate. No more events will be generated * Terminate the transaction. Wait for ACK to terminate. No more events will be generated
* @param evType IAXEvent type to generate. * @param evType IAXEvent type to generate.
* @param local If true it is a locally generated event.
* @param frame Frame to build event from. * @param frame Frame to build event from.
* @return Pointer to a valid IAXEvent with the reason. * @return Pointer to a valid IAXEvent with the reason.
*/ */
IAXEvent* waitForTerminate(u_int8_t evType, const IAXFullFrame* frame); IAXEvent* waitForTerminate(u_int8_t evType, bool local, const IAXFullFrame* frame);
/** /**
* Send a full frame to remote peer and put it in transmission list * Send a full frame to remote peer and put it in transmission list
@ -1035,30 +1034,34 @@ protected:
/** /**
* Send a full frame to remote peer. * Send a full frame to remote peer.
* @param frame Frame to send.
* @param vnak If true the transmission is a response to a VNAK frame.
* @return True on success. * @return True on success.
*/ */
bool sendFrame(IAXFrameOut* frame); bool sendFrame(IAXFrameOut* frame, bool vnak = false);
/** /**
* Create an event from a frame. * Create an event from a frame.
* @param evType Event type * @param evType Event type
* @param local If true it is a locally generated event.
* @param frameOut Frame to create from * @param frameOut Frame to create from
* @param newState The transaction new state * @param newState The transaction new state
* @return Pointer to an IAXEvent or 0 (Invalid IE list) * @return Pointer to an IAXEvent or 0 (Invalid IE list)
*/ */
IAXEvent* createEvent(u_int8_t evType, const IAXFullFrame* frame, State newState); IAXEvent* createEvent(u_int8_t evType, bool local, const IAXFullFrame* frame, State newState);
/** /**
* Create an event from a received frame that is a response to a sent frame and * Create an event from a received frame that is a response to a sent frame and
* change the transaction state to newState. Remove the response from incoming list. * change the transaction state to newState. Remove the response from incoming list.
* @param frame Frame to create response for * @param frame Frame to create response for
* @param findType Frame type to find * @param findType Frame type to find
* @param findSubclass Frame subclass to find * @param findSubclass Frame subclass to find
* @param evType Event type to generate * @param evType Event type to generate
* @param local local flag for the generated event.
* @param newState New transaction state if an event was generated * @param newState New transaction state if an event was generated
* @return Pointer to an IAXEvent or 0 (Invalid IE list) * @return Pointer to an IAXEvent or 0 (Invalid IE list)
*/ */
IAXEvent* createResponse(IAXFrameOut* frame, u_int8_t findType, u_int8_t findSubclass, u_int8_t evType, State newState); IAXEvent* createResponse(IAXFrameOut* frame, u_int8_t findType, u_int8_t findSubclass, u_int8_t evType, bool local, State newState);
/** /**
* Find a response for a previously sent frame. * Find a response for a previously sent frame.
@ -1112,7 +1115,14 @@ protected:
* @param subclass Frame subclass to find * @param subclass Frame subclass to find
* @return True if found. * @return True if found.
*/ */
bool findInFrameTimestamp(const IAXFullFrame* frameOut, IAXFrame::Type type = IAXFrame::IAX, u_int32_t subclass = IAXControl::Ack); bool findInFrameTimestamp(const IAXFullFrame* frameOut, IAXFrame::Type type, u_int32_t subclass);
/**
* Search in m_inFrames for an ACK frame which confirm @ref frame.
* @param frameOut Frame to find response for
* @return True if found.
*/
bool findInFrameAck(const IAXFullFrame* frameOut);
/** /**
* Send a frame to remote peer in state Connected. * Send a frame to remote peer in state Connected.
@ -1133,6 +1143,11 @@ protected:
*/ */
void sendInval(); void sendInval();
/**
* Send an VNAK frame.
*/
void sendVNAK();
/** /**
* Internal protocol outgoing frames processing (e.g. IAX PING, LAGRQ). * Internal protocol outgoing frames processing (e.g. IAX PING, LAGRQ).
* @param frame Frame to process * @param frame Frame to process
@ -1175,10 +1190,54 @@ protected:
/** /**
* Terminate the transaction if state is Terminating and timeout. * Terminate the transaction if state is Terminating and timeout.
* @param time Current time
* @return A valid IAXEvent or 0. * @return A valid IAXEvent or 0.
*/ */
IAXEvent* getEventTerminating(u_int64_t time); IAXEvent* getEventTerminating(u_int64_t time);
/**
* Send all frames from outgoing queue with
* outbound sequence number starting with @ref seqNo.
* @param seqNo Requested sequence number
* @return 0.
*/
IAXTransaction* IAXTransaction::retransmittOnVNAK(u_int16_t seqNo);
/**
* Generate an Accept event after internally accepting a transaction.
* @return A valid IAXEvent.
*/
IAXEvent* internalAccept();
/**
* Generate a Reject event after internally rejecting a transaction.
* @param reason The reason of rejecting
* @return A valid IAXEvent.
*/
IAXEvent* internalReject(String& reason);
/**
* Event terminated feedback.
* This method is thread safe.
* @param event The event notifying termination.
*/
inline void eventTerminated(IAXEvent* event) {
Lock lock(this);
if (event == m_currentEvent)
m_currentEvent = 0;
}
/**
* Set the current event.
* @param event The event notifying termination.
* @return @ref event.
*/
inline IAXEvent* keepEvent(IAXEvent* event) {
m_currentEvent = event;
return event;
}
private: private:
/* Params */ /* Params */
bool m_localInitTrans; /* True: local initiated transaction */ bool m_localInitTrans; /* True: local initiated transaction */
@ -1194,9 +1253,11 @@ private:
unsigned char m_iSeqNo; /* Incoming frame sequence number */ unsigned char m_iSeqNo; /* Incoming frame sequence number */
IAXEngine* m_engine; /* Engine that owns this transaction */ IAXEngine* m_engine; /* Engine that owns this transaction */
void* m_userdata; /* User data */ void* m_userdata; /* User data */
u_int16_t m_lastMiniFrameOut; /* Last transmitted mini frame timestamp */ u_int16_t m_lastMiniFrameOut; /* Last transmitted mini frame timestamp */
u_int32_t m_lastMiniFrameIn; /* Last received mini frame timestamp */ u_int32_t m_lastMiniFrameIn; /* Last received mini frame timestamp */
Mutex m_mutexInMedia; /* Keep received media thread safe */ Mutex m_mutexInMedia; /* Keep received media thread safe */
IAXEvent* m_pendingEvent; /* Pointer to a pending event or 0 */
IAXEvent* m_currentEvent; /* Pointer to last generated event or 0 */
/* Outgoing frames management */ /* Outgoing frames management */
ObjList m_outFrames; /* Transaction & protocol control outgoing frames */ ObjList m_outFrames; /* Transaction & protocol control outgoing frames */
u_int16_t m_retransCount; /* Retransmission counter. 0 --> Timeout */ u_int16_t m_retransCount; /* Retransmission counter. 0 --> Timeout */
@ -1221,9 +1282,11 @@ private:
String m_calledContext; /* Called context */ String m_calledContext; /* Called context */
String m_challenge; /* Challenge */ String m_challenge; /* Challenge */
String m_authdata; /* Auth data received with auth reply */ String m_authdata; /* Auth data received with auth reply */
u_int32_t m_format; /* Media format */
u_int32_t m_capability; /* Media format */
u_int32_t m_expire; /* Registration expiring time */ u_int32_t m_expire; /* Registration expiring time */
u_int32_t m_format; /* Media format used for initial negotiation */
u_int32_t m_formatIn; /* Incoming media format */
u_int32_t m_formatOut; /* Outgoing media format */
u_int32_t m_capability; /* Media capability of this transaction */
}; };
class YIAX_API IAXEvent class YIAX_API IAXEvent
@ -1236,17 +1299,16 @@ public:
*/ */
enum Type { enum Type {
Invalid = 0, Invalid = 0,
Unexpected,
Terminated, Terminated,
Timeout, Timeout,
NotImplemented, NotImplemented,
New, /* New remote transaction. Need Auth. */ New, /* New remote transaction. */
AuthRep, /* Auth reply. Need Auth for password. */ AuthReq, /* Auth request. Internally processed. */
AuthRep, /* Auth reply. */
Accept, Accept,
Hangup, Hangup,
Reject, Reject,
Busy, Busy,
Voice,
Text, Text,
Dtmf, Dtmf,
Noise, Noise,
@ -1271,6 +1333,13 @@ public:
inline Type type() const inline Type type() const
{ return m_type; } { return m_type; }
/**
* Check if this is a locally generated event
* @return True if it is a locally generated event
*/
inline bool local() const
{ return m_local; }
/** /**
* Check if this is a transaction finalization event. * Check if this is a transaction finalization event.
* @return True if the transaction has finalized and will be destroyed * @return True if the transaction has finalized and will be destroyed
@ -1328,14 +1397,15 @@ protected:
* Constructor * Constructor
* @param transaction IAX transaction that generated the event * @param transaction IAX transaction that generated the event
*/ */
IAXEvent(Type type, bool final, IAXTransaction* transaction, u_int8_t frameType = 0, u_int8_t subclass = 0); IAXEvent(Type type, bool local, bool final, IAXTransaction* transaction, u_int8_t frameType = 0, u_int8_t subclass = 0);
IAXEvent(Type type, bool final, IAXTransaction* transaction, const IAXFullFrame* frame = 0); IAXEvent(Type type, bool local, bool final, IAXTransaction* transaction, const IAXFullFrame* frame = 0);
private: private:
Type m_type; /* Event type */ Type m_type; /* Event type */
u_int8_t m_frameType; /* Frame type */ u_int8_t m_frameType; /* Frame type */
u_int8_t m_subClass; /* Frame subclass */ u_int8_t m_subClass; /* Frame subclass */
bool m_local; /* If true the event is generated locally, the receiver MUST not respond */
bool m_final; /* Final event flag */ bool m_final; /* Final event flag */
IAXTransaction* m_transaction; /* Transaction that generated this event */ IAXTransaction* m_transaction; /* Transaction that generated this event */
IAXIEList m_ieList; /* IAXInfoElement list */ IAXIEList m_ieList; /* IAXInfoElement list */
@ -1346,16 +1416,18 @@ class YIAX_API IAXEngine : public DebugEnabler, public Mutex
public: public:
/** /**
* Constructor * Constructor
* @param transCount Number of entries in the transaction hash table * @param port UDP port to run the protocol on
* @param retransCount Number of frame retransmission before timeout * @param transListCount Number of entries in the transaction hash table
* @param retransTime Default retransmission time * @param retransCount Retransmission counter for each transaction belonging to this engine
* @param retransInterval Retransmission interval default value in miliseconds
* @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 maxFullFrameDataLen Max full frame IE list (buffer) length
* @param transTimeout Timeout (in seconds) of transactions belonging to this engine
* @param format Default media format * @param format Default media format
* @param capab Media capabilities of this engine * @param capab Media capabilities of this engine
*/ */
IAXEngine(int transCount, int retransCount, int retransInterval, int maxFullFrameDataLen, u_int32_t transTimeout, IAXEngine(int port, u_int16_t transListCount, u_int16_t retransCount, u_int16_t retransInterval,
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);
/** /**
* Destructor * Destructor
@ -1382,10 +1454,10 @@ public:
/** /**
* Process media from remote peer. Descendents must override this method. * Process media from remote peer. Descendents must override this method.
* @param transaction IAXTransaction that owns the call leg * @param transaction IAXTransaction that owns the call leg
* @param data Media data. * @param data Media data.
* @param tStamp Media timestamp. * @param tStamp Media timestamp.
*/ */
virtual void processMedia(IAXTransaction* transaction, DataBlock& data, u_int32_t tStamp) virtual void processMedia(IAXTransaction* transaction, DataBlock& data, u_int32_t tStamp)
{} {}
/** /**
@ -1409,14 +1481,21 @@ public:
inline u_int16_t retransInterval() inline u_int16_t retransInterval()
{ return m_retransInterval; } { return m_retransInterval; }
/**
* Get the timeout (in seconds) of acknoledged auth frames sent.
* @return Auth timeout in seconds
*/
inline u_int16_t authTimeout()
{ return m_authTimeout; }
/** /**
* Get the timeout (in seconds) of transactions belonging to this engine. * Get the timeout (in seconds) of transactions belonging to this engine.
* @return Timeout (in seconds) of transactions belonging to this engine * @return Timeout (in seconds) of transactions belonging to this engine
*/ */
inline u_int32_t transactionTimeout() inline u_int32_t transactionTimeout()
{ return m_transactionTimeout; } { return m_transTimeout; }
inline int maxFullFrameDataLen() inline u_int16_t maxFullFrameDataLen()
{ return m_maxFullFrameDataLen; } { return m_maxFullFrameDataLen; }
inline u_int32_t format() inline u_int32_t format()
@ -1426,7 +1505,7 @@ public:
{ return m_capability; } { return m_capability; }
/** /**
* Read data from socket * Read data from socket
*/ */
void readSocket(SocketAddr& addr); void readSocket(SocketAddr& addr);
@ -1456,11 +1535,40 @@ public:
u_int32_t transactionCount(); u_int32_t transactionCount();
/** /**
* Send an Ack to a remote peer to keep alive. * Send an INVAL with call numbers set to 0 to a remote peer to keep alive.
* @param addr Address to send. * @param addr Address to send.
*/ */
void keepAlive(SocketAddr& addr); void keepAlive(SocketAddr& addr);
/**
* Process a new format received with a Voice frame.
* @param trans Transaction that received the new format.
* @param format The received format.
* @return True if accepted.
*/
virtual bool voiceFormatChanged(IAXTransaction* trans, u_int32_t format)
{ return false; }
/**
* Process the initial received format and capability. If accepted on exit will set the transaction format and capability.
* @param trans Transaction that received the new format.
* @return True if accepted.
*/
bool acceptFormatAndCapability(IAXTransaction* trans);
/**
* Default event handler. @ref event MUST NOT be deleted.
* @param event The event to handle.
*/
virtual void defaultEventHandler(IAXEvent* event);
/**
* Get the socket used for engine operation
* @return Reference to the UDP socket
*/
inline Socket& socket()
{ return m_socket; }
static void getMD5FromChallenge(String& md5data, const String& challenge, const String& password); static void getMD5FromChallenge(String& md5data, const String& challenge, const String& password);
static bool isMD5ChallengeCorrect(const String& md5data, const String& challenge, const String& password); static bool isMD5ChallengeCorrect(const String& md5data, const String& challenge, const String& password);
@ -1505,15 +1613,16 @@ private:
Socket m_socket; /* Socket */ Socket m_socket; /* Socket */
ObjList** m_transList; /* Full transactions */ ObjList** m_transList; /* Full transactions */
ObjList m_incompleteTransList; /* Incomplete transactions (no remote call number) */ ObjList m_incompleteTransList; /* Incomplete transactions (no remote call number) */
int m_transListCount; /* m_transList count */
u_int16_t m_retransCount; /* Retransmission counter for each transaction belonging to this engine */
u_int16_t m_retransInterval; /* Retransmission interval default value */
bool m_lUsedCallNo[IAX2_MAX_CALLNO + 1]; /* Used local call numnmbers flags */ bool m_lUsedCallNo[IAX2_MAX_CALLNO + 1]; /* Used local call numnmbers flags */
int m_lastGetEvIndex; /* getEvent: keep last array entry */ int m_lastGetEvIndex; /* getEvent: keep last array entry */
/* Parameters */ /* Parameters */
int m_maxFullFrameDataLen; /* Max full frame data (IE list) length */ int m_maxFullFrameDataLen; /* Max full frame data (IE list) length */
u_int16_t m_startLocalCallNo; /* Start index of local call number allocation */ u_int16_t m_startLocalCallNo; /* Start index of local call number allocation */
u_int32_t m_transactionTimeout; /* Timeout (in seconds) of transactions belonging to this engine */ u_int16_t m_transListCount; /* m_transList count */
u_int16_t m_retransCount; /* Retransmission counter for each transaction belonging to this engine */
u_int16_t m_retransInterval; /* Retransmission interval default value in miliseconds */
u_int16_t m_authTimeout; /* Timeout (in seconds) of acknoledged auth frames sent */
u_int32_t m_transTimeout; /* Timeout (in seconds) on remote request of transactions belonging to this engine */
/* Media */ /* Media */
u_int32_t m_format; u_int32_t m_format;
u_int32_t m_capability; u_int32_t m_capability;

View File

@ -23,7 +23,6 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
#include <yatephone.h> #include <yatephone.h>
#include <yateversn.h> #include <yateversn.h>
@ -35,11 +34,17 @@
#include <yateiax.h> #include <yateiax.h>
extern TelEngine::String s_iax_modInvalidAuth;
using namespace TelEngine; using namespace TelEngine;
namespace { // anonymous namespace { // anonymous
static TokenDict dict_tos[] = {
{ "lowdelay", Socket::LowDelay },
{ "throughput", Socket::MaxThroughput },
{ "reliability", Socket::MaxReliability },
{ "mincost", Socket::MinCost },
{ 0, 0 }
};
static Configuration s_cfg; static Configuration s_cfg;
class YIAXLineContainer; class YIAXLineContainer;
@ -111,7 +116,7 @@ public:
inline ~YIAXLineContainer() {} inline ~YIAXLineContainer() {}
/** /**
* logout and remove all lines * Logout and remove all lines
*/ */
void clear(); void clear();
@ -200,8 +205,22 @@ protected:
class YIAXEngine : public IAXEngine class YIAXEngine : public IAXEngine
{ {
public: public:
YIAXEngine(int transCount, int retransCount, int retransTime, int maxFullFrameDataLen, u_int32_t transTimeout); /**
* Constructor
* @param port UDP port to use
* @param transListCount Number of entries in the transaction hash table
* @param retransCount Retransmission counter for each transaction belonging to this engine
* @param retransInterval Retransmission interval default value in miliseconds
* @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
*/
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);
/**
* Destructor
*/
virtual ~YIAXEngine() virtual ~YIAXEngine()
{} {}
@ -238,9 +257,10 @@ public:
/** /**
* Start thread members * Start thread members
* @param listenThreadCount Reading thread count. * @param listenThreadCount Reading socket thread count.
* @param eventThreadCount Reading event thread count.
*/ */
void start(u_int16_t listenThreadCount = 1); void start(u_int16_t listenThreadCount, u_int16_t eventThreadCount);
protected: protected:
@ -249,6 +269,9 @@ protected:
*/ */
virtual void processEvent(IAXEvent* event); virtual void processEvent(IAXEvent* event);
/**
* Event handler for incoming registration transactions.
*/
void processRemoteReg(IAXEvent* event); void processRemoteReg(IAXEvent* event);
/** /**
@ -315,12 +338,13 @@ class YIAXConnection;
class YIAXConsumer : public DataConsumer class YIAXConsumer : public DataConsumer
{ {
public: public:
YIAXConsumer(YIAXConnection* conn, const char* format); YIAXConsumer(YIAXConnection* conn, u_int32_t format, const char* formatText);
~YIAXConsumer(); ~YIAXConsumer();
virtual void Consume(const DataBlock &data, unsigned long tStamp); virtual void Consume(const DataBlock &data, unsigned long tStamp);
private: private:
YIAXConnection* m_connection; YIAXConnection* m_connection;
unsigned m_total; unsigned m_total;
u_int32_t m_format;
}; };
/** /**
@ -329,12 +353,13 @@ private:
class YIAXSource : public DataSource class YIAXSource : public DataSource
{ {
public: public:
YIAXSource(YIAXConnection* conn, const char* format); YIAXSource(YIAXConnection* conn, u_int32_t format, const char* formatText);
~YIAXSource(); ~YIAXSource();
void Forward(const DataBlock &data, unsigned long tStamp = 0); void Forward(const DataBlock &data, unsigned long tStamp = 0);
private: private:
YIAXConnection* m_connection; YIAXConnection* m_connection;
unsigned m_total; unsigned m_total;
u_int32_t m_format;
}; };
/** /**
@ -364,9 +389,6 @@ public:
inline bool mutedOut() const inline bool mutedOut() const
{ return m_mutedOut; } { return m_mutedOut; }
inline u_int32_t format()
{ return m_format; }
void handleEvent(IAXEvent* event); void handleEvent(IAXEvent* event);
/* Start router */ /* Start router */
@ -388,20 +410,19 @@ protected:
void evAuthRep(IAXEvent* event); void evAuthRep(IAXEvent* event);
void safeDeref(); void safeDeref();
bool safeGetRefIncreased();
bool safeRefIncrease();
private: private:
YIAXEngine* m_iaxEngine; /* IAX engine owning the transaction */ YIAXEngine* m_iaxEngine; // IAX engine owning the transaction
IAXTransaction* m_transaction; /* IAX transaction */ IAXTransaction* m_transaction; // IAX transaction
bool m_mutedIn; /* No remote media accepted */ String m_password; // Password for client authentication
bool m_mutedOut; /* No local media accepted */ bool m_mutedIn; // No remote media accepted
u_int32_t m_format; /* Current media format */ bool m_mutedOut; // No local media accepted
u_int32_t m_capability; /* Supported formats */ String m_reason; // Call end reason text
String m_reason; /* */ bool m_hangup; // Need to send chan.hangup message
bool m_hangup; /* Need to send chan.hangup message */ Mutex m_mutexRefIncreased; // Safe ref/deref connection
/* */ bool m_refIncreased; // If true, the reference counter was increased
Mutex m_mutexRefIncreased;
bool m_refIncreased;
}; };
/** /**
@ -462,12 +483,10 @@ YIAXLine::YIAXLine(const String& name)
m_registered(false), m_registered(false),
m_register(true) m_register(true)
{ {
// yiax_line_allocated++;
} }
YIAXLine::~YIAXLine() YIAXLine::~YIAXLine()
{ {
// yiax_line_released++;
} }
/** /**
@ -500,22 +519,23 @@ void YIAXLineContainer::regTerminate(IAXEvent* event)
line->m_nextReg = Time::secNow() + (line->expire() * 3 / 4); line->m_nextReg = Time::secNow() + (line->expire() * 3 / 4);
line->m_callingNo = trans->callingNo(); line->m_callingNo = trans->callingNo();
line->m_callingName = trans->callingName(); line->m_callingName = trans->callingName();
Debug(&iplugin,DebugAll,"YIAXLineContainer::regTerminate[%s] - Ack for '%s'.", Debug(&iplugin,DebugAll,"YIAXLineContainer::regTerminate[%s] - Ack for '%s'. Next: %u",
line->c_str(),line->state() == YIAXLine::Registering?"Register":"Unregister"); line->c_str(),line->state() == YIAXLine::Registering?"Register":"Unregister",line->m_nextReg);
line->m_registered = true; line->m_registered = true;
break; break;
case IAXEvent::Reject: case IAXEvent::Reject:
// retry at 25% of the expire time // retry at 25% of the expire time
line->m_nextReg = Time::secNow() + (line->expire() / 4); line->m_nextReg = Time::secNow() + (line->expire() / 2);
Debug(&iplugin,DebugAll,"YIAXLineContainer::regTerminate[%s] - Reject for '%s'.", Debug(&iplugin,DebugAll,"YIAXLineContainer::regTerminate[%s] - Reject for '%s'. Next: %u",
line->c_str(),line->state() == YIAXLine::Registering?"Register":"Unregister"); line->c_str(),line->state() == YIAXLine::Registering?"Register":"Unregister",line->m_nextReg);
line->m_registered = false; line->m_registered = false;
break; break;
case IAXEvent::Timeout: case IAXEvent::Timeout:
// retry at 50% of the expire time // retry at 50% of the expire time
line->m_nextReg = Time::secNow() + (line->expire() / 2); line->m_nextReg = Time::secNow() + (line->expire() / 2);
Debug(&iplugin,DebugAll,"YIAXLineContainer::regTerminate[%s] - Timeout for '%s'.", Debug(&iplugin,DebugAll,"YIAXLineContainer::regTerminate[%s] - Timeout for '%s'. Next: %u",
line->c_str(),line->state() == YIAXLine::Registering?"Register":"Unregister"); line->c_str(),line->state() == YIAXLine::Registering?"Register":"Unregister",line->m_nextReg);
line->m_registered = false;
break; break;
default: default:
return; return;
@ -538,8 +558,7 @@ void YIAXLineContainer::handleEvent(IAXEvent* event)
regTerminate(event); regTerminate(event);
break; break;
default: default:
Debug(&iplugin,DebugAll,"YIAXLineContainer::handleEvent. Unexpected event: %u",event->type()); iplugin.getEngine()->defaultEventHandler(event);
break;
} }
} }
@ -716,9 +735,11 @@ void YIAXGetEvent::run()
/** /**
* YIAXEngine * YIAXEngine
*/ */
YIAXEngine::YIAXEngine(int transCount, int retransCount, int retransTime, int maxFullFrameDataLen, u_int32_t transTimeout) YIAXEngine::YIAXEngine(int port, u_int16_t transListCount, u_int16_t retransCount, u_int16_t retransInterval,
: IAXEngine(transCount,retransCount,retransTime,maxFullFrameDataLen,transTimeout,iplugin.defaultCodec(),iplugin.codecs()), u_int16_t authTimeout, u_int16_t transTimeout, u_int16_t maxFullFrameDataLen)
m_threadsCreated(false) : IAXEngine(port,transListCount,retransCount,retransInterval,authTimeout,transTimeout,
maxFullFrameDataLen,iplugin.defaultCodec(),iplugin.codecs()),
m_threadsCreated(false)
{ {
} }
@ -728,8 +749,9 @@ void YIAXEngine::processMedia(IAXTransaction* transaction, DataBlock& data, u_in
if (transaction->getUserData()) if (transaction->getUserData())
if ((static_cast<YIAXConnection*>(transaction->getUserData()))->getSource()) if ((static_cast<YIAXConnection*>(transaction->getUserData()))->getSource())
(static_cast<YIAXSource*>((static_cast<YIAXConnection*>(transaction->getUserData()))->getSource()))->Forward(data,tStamp); (static_cast<YIAXSource*>((static_cast<YIAXConnection*>(transaction->getUserData()))->getSource()))->Forward(data,tStamp);
else else {
; //Debug(this,DebugAll,"YIAXEngine - processMedia. No media source"); XDebug(this,DebugAll,"YIAXEngine - processMedia. No media source");
}
else else
Debug(this,DebugAll,"YIAXEngine - processMedia. Transaction doesn't have a connection"); Debug(this,DebugAll,"YIAXEngine - processMedia. Transaction doesn't have a connection");
else else
@ -745,14 +767,14 @@ IAXTransaction* YIAXEngine::reg(YIAXLine* line, bool regreq)
addr.port(line->remotePort()); addr.port(line->remotePort());
Debug(this,DebugAll,"Outgoing Registration[%s]:\nUsername: %s\nHost: %s\nPort: %d\nTime(sec): %u", Debug(this,DebugAll,"Outgoing Registration[%s]:\nUsername: %s\nHost: %s\nPort: %d\nTime(sec): %u",
line->c_str(),line->username().c_str(),addr.host().c_str(),addr.port(),Time::secNow()); line->c_str(),line->username().c_str(),addr.host().c_str(),addr.port(),Time::secNow());
/* Create IE list */ // Create IE list
IAXIEList ieList; IAXIEList ieList;
ieList.appendString(IAXInfoElement::USERNAME,line->username()); ieList.appendString(IAXInfoElement::USERNAME,line->username());
ieList.appendString(IAXInfoElement::PASSWORD,line->password()); ieList.appendString(IAXInfoElement::PASSWORD,line->password());
ieList.appendString(IAXInfoElement::CALLING_NUMBER,line->callingNo()); ieList.appendString(IAXInfoElement::CALLING_NUMBER,line->callingNo());
ieList.appendString(IAXInfoElement::CALLING_NAME,line->callingName()); ieList.appendString(IAXInfoElement::CALLING_NAME,line->callingName());
ieList.appendNumeric(IAXInfoElement::REFRESH,line->expire(),2); ieList.appendNumeric(IAXInfoElement::REFRESH,line->expire(),2);
/* Make it ! */ // Make it !
IAXTransaction* tr = startLocalTransaction(regreq ? IAXTransaction::RegReq : IAXTransaction::RegRel,addr,ieList); IAXTransaction* tr = startLocalTransaction(regreq ? IAXTransaction::RegReq : IAXTransaction::RegRel,addr,ieList);
if (tr) if (tr)
tr->setUserData(line); tr->setUserData(line);
@ -764,7 +786,7 @@ IAXTransaction* YIAXEngine::call(SocketAddr& addr, NamedList& params)
{ {
Debug(this,DebugAll,"Outgoing Call:\nUsername: %s\nHost: %s\nPort: %d\nCalled number: %s\nCalled context: %s", Debug(this,DebugAll,"Outgoing Call:\nUsername: %s\nHost: %s\nPort: %d\nCalled number: %s\nCalled context: %s",
params.getValue("username"),addr.host().c_str(),addr.port(),params.getValue("called"),params.getValue("calledname")); params.getValue("username"),addr.host().c_str(),addr.port(),params.getValue("called"),params.getValue("calledname"));
/* Create IE list */ // Create IE list
IAXIEList ieList; IAXIEList ieList;
ieList.appendString(IAXInfoElement::USERNAME,params.getValue("username")); ieList.appendString(IAXInfoElement::USERNAME,params.getValue("username"));
ieList.appendString(IAXInfoElement::PASSWORD,params.getValue("password")); ieList.appendString(IAXInfoElement::PASSWORD,params.getValue("password"));
@ -774,7 +796,6 @@ IAXTransaction* YIAXEngine::call(SocketAddr& addr, NamedList& params)
ieList.appendString(IAXInfoElement::CALLED_CONTEXT,params.getValue("calledname")); ieList.appendString(IAXInfoElement::CALLED_CONTEXT,params.getValue("calledname"));
ieList.appendNumeric(IAXInfoElement::FORMAT,iplugin.defaultCodec(),4); ieList.appendNumeric(IAXInfoElement::FORMAT,iplugin.defaultCodec(),4);
ieList.appendNumeric(IAXInfoElement::CAPABILITY,iplugin.codecs(),4); ieList.appendNumeric(IAXInfoElement::CAPABILITY,iplugin.codecs(),4);
/* Make the call ! */
return startLocalTransaction(IAXTransaction::New,addr,ieList); return startLocalTransaction(IAXTransaction::New,addr,ieList);
} }
@ -782,24 +803,29 @@ IAXTransaction* YIAXEngine::poke(SocketAddr& addr)
{ {
Debug(this,DebugAll,"Outgoing POKE: Host: %s Port: %d",addr.host().c_str(),addr.port()); Debug(this,DebugAll,"Outgoing POKE: Host: %s Port: %d",addr.host().c_str(),addr.port());
IAXIEList ieList; IAXIEList ieList;
/* Poke */
return startLocalTransaction(IAXTransaction::Poke,addr,ieList); return startLocalTransaction(IAXTransaction::Poke,addr,ieList);
} }
void YIAXEngine::start(u_int16_t listenThreadCount) void YIAXEngine::start(u_int16_t listenThreadCount, u_int16_t eventThreadCount)
{ {
if (m_threadsCreated) if (m_threadsCreated)
return; return;
if (!listenThreadCount) if (!listenThreadCount)
Debug(DebugWarn,"YIAXEngine - start. No reading threads(s)!."); Debug(DebugWarn,"YIAXEngine - start. No reading socket threads(s)!.");
if (!eventThreadCount)
Debug(DebugWarn,"YIAXEngine - start. No reading event threads(s)!.");
for (; listenThreadCount; listenThreadCount--) for (; listenThreadCount; listenThreadCount--)
(new YIAXListener(this,"YIAXListener thread"))->startup(); (new YIAXListener(this,"YIAXListener thread"))->startup();
(new YIAXGetEvent(this,"YIAXGetEvent thread"))->startup(); for (; eventThreadCount; eventThreadCount--)
(new YIAXGetEvent(this,"YIAXGetEvent thread"))->startup();
m_threadsCreated = true; m_threadsCreated = true;
} }
void YIAXEngine::processEvent(IAXEvent* event) void YIAXEngine::processEvent(IAXEvent* event)
{ {
#if 0
static u_int16_t hp = 0, rej = 0, final = 0;
#endif
YIAXConnection* connection = 0; YIAXConnection* connection = 0;
switch (event->getTransaction()->type()) { switch (event->getTransaction()->type()) {
case IAXTransaction::New: case IAXTransaction::New:
@ -808,14 +834,29 @@ void YIAXEngine::processEvent(IAXEvent* event)
// We already have a channel for this call // We already have a channel for this call
connection->handleEvent(event); connection->handleEvent(event);
if (event->final()) { if (event->final()) {
/* Final event: disconnect */ #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); Debug(this,DebugAll,"YIAXEngine::processEvent - Disconnect connection [%p]",connection);
connection->disconnect(); connection->disconnect();
} }
} }
else { else {
if (event->type() == IAXEvent::New) { if (event->type() == IAXEvent::New) {
/* Incoming request for a new call */ // Incoming request for a new call
connection = new YIAXConnection(this,event->getTransaction()); connection = new YIAXConnection(this,event->getTransaction());
event->getTransaction()->setUserData(connection); event->getTransaction()->setUserData(connection);
if (!connection->route()) if (!connection->route())
@ -825,13 +866,11 @@ void YIAXEngine::processEvent(IAXEvent* event)
break; break;
case IAXTransaction::RegReq: case IAXTransaction::RegReq:
case IAXTransaction::RegRel: case IAXTransaction::RegRel:
if (event->getTransaction()->getUserData()) {
// Existing line
s_lines.handleEvent(event);
break;
}
if (event->type() == IAXEvent::New) if (event->type() == IAXEvent::New)
processRemoteReg(event); processRemoteReg(event);
else
if (event->getTransaction()->getUserData())
s_lines.handleEvent(event);
break; break;
default: ; default: ;
} }
@ -847,26 +886,26 @@ void YIAXEngine::processRemoteReg(IAXEvent* event)
Message msg("user.auth"); Message msg("user.auth");
msg.addParam("username",tr->username()); msg.addParam("username",tr->username());
if (!Engine::dispatch(msg)) { if (!Engine::dispatch(msg)) {
/* Not authenticated */ // Not authenticated
Debug(this,DebugAll,"evNewRegistration. Not authenticated. Reject"); Debug(this,DebugAll,"processRemoteReg. Not authenticated. Reject");
tr->sendReject(); tr->sendReject();
return; return;
} }
String password = msg.retValue(); String password = msg.retValue();
if (!password.length()) { if (!password.length()) {
/* Authenticated, no password. Try to (un)register */ // Authenticated, no password. Try to (un)register
if (userreg(tr->username(),tr->expire(),event->subclass() == IAXControl::RegRel)) { if (userreg(tr->username(),tr->expire(),event->subclass() == IAXControl::RegRel)) {
Debug(this,DebugAll,"evNewRegistration. Authenticated and (un)registered. Ack"); Debug(this,DebugAll,"processRemoteReg. Authenticated and (un)registered. Ack");
tr->sendAccept(); tr->sendAccept();
} }
else { else {
Debug(this,DebugAll,"evNewRegistration. Authenticated but not (un)registered. Reject"); Debug(this,DebugAll,"processRemoteReg. Authenticated but not (un)registered. Reject");
tr->sendReject(); tr->sendReject();
} }
return; return;
} }
/* Authenticated, password required */ // Authenticated, password required
Debug(this,DebugAll,"evNewRegistration. Request authentication"); Debug(this,DebugAll,"processRemoteReg. Request authentication");
tr->sendAuth(password); tr->sendAuth(password);
} }
@ -875,6 +914,7 @@ bool YIAXEngine::userreg(const String& username, u_int16_t refresh, bool regrel)
Debug(this,DebugAll,"YIAXEngine - userreg. %s username: '%s'",regrel ? "Unregistering":"Registering",username.c_str()); Debug(this,DebugAll,"YIAXEngine - userreg. %s username: '%s'",regrel ? "Unregistering":"Registering",username.c_str());
Message msg(regrel ? "user.unregister" : "user.register"); Message msg(regrel ? "user.unregister" : "user.register");
msg.addParam("username",username); msg.addParam("username",username);
msg.setParam("driver","iax");
if (!regrel) if (!regrel)
msg.addParam("expires",(String(refresh)).c_str()); msg.addParam("expires",(String(refresh)).c_str());
return Engine::dispatch(msg); return Engine::dispatch(msg);
@ -917,10 +957,10 @@ void YIAXDriver::initialize()
{ {
Output("Initializing module YIAX"); Output("Initializing module YIAX");
lock(); lock();
// Load configuration
s_cfg = Engine::configFile("yiaxchan"); s_cfg = Engine::configFile("yiaxchan");
s_cfg.load(); s_cfg.load();
/* Load configuration */ // Codec capabilities
/* Codec capability */
m_defaultCodec = 0; m_defaultCodec = 0;
m_codecs = 0; m_codecs = 0;
u_int32_t fallback = 0; u_int32_t fallback = 0;
@ -931,36 +971,43 @@ void YIAXDriver::initialize()
def && DataTranslator::canConvert(IAXFormat::audioData[i].token))) { def && DataTranslator::canConvert(IAXFormat::audioData[i].token))) {
m_codecs |= IAXFormat::audioData[i].value; m_codecs |= IAXFormat::audioData[i].value;
fallback = IAXFormat::audioData[i].value; fallback = IAXFormat::audioData[i].value;
/* Set default (desired) codec */ // Set default (desired) codec
if (preferred == IAXFormat::audioData[i].token) if (preferred == IAXFormat::audioData[i].token)
m_defaultCodec = fallback; m_defaultCodec = fallback;
} }
} }
if (!m_codecs) if (!m_codecs)
Debug(DebugWarn,"YIAXDriver - initialize. No audio format(s) available."); Debug(DebugWarn,"YIAXDriver - initialize. No audio format(s) available.");
/* If desired codec is disabled fall back to last in list */ // If desired codec is disabled fall back to last in list
if (!m_defaultCodec) if (!m_defaultCodec)
m_defaultCodec = fallback; m_defaultCodec = fallback;
/* Port */ // Port
if (s_cfg.getIntValue("general","port")) m_port = s_cfg.getIntValue("general","port",4569);
m_port = s_cfg.getIntValue("general","port");
unlock(); unlock();
setup(); setup();
/* We need channels to be dropped on shutdown */ // We need channels to be dropped on shutdown
installRelay(Halt); installRelay(Halt);
installRelay(Route); installRelay(Route);
/* Init IAX engine */ // Init IAX engine
int transCount = 16; u_int16_t transListCount = 16;
int retransCount = 5; u_int16_t retransCount = 5;
int retransTime = 500; u_int16_t retransInterval = 500;
int maxFullFrameDataLen = 1400; u_int16_t authTimeout = 30;
u_int32_t transTimeout = 10; u_int16_t transTimeout = 10;
int readThreadCount = 3; u_int16_t maxFullFrameDataLen = 1400;
if (!m_iaxEngine) { if (!m_iaxEngine) {
Engine::install(new YIAXRegDataHandler); Engine::install(new YIAXRegDataHandler);
m_iaxEngine = new YIAXEngine(transCount,retransCount,retransTime,maxFullFrameDataLen,transTimeout); m_iaxEngine = new YIAXEngine(m_port,transListCount,retransCount,retransInterval,authTimeout,transTimeout,maxFullFrameDataLen);
m_iaxEngine->debugChain(this);
int tos = s_cfg.getIntValue("general","tos",dict_tos,0);
if (tos) {
if (!m_iaxEngine->socket().setTOS(tos))
Debug(this,DebugWarn,"Could not set IP TOS to 0x%02x",tos);
}
} }
m_iaxEngine->start(readThreadCount); int readThreadCount = 3;
int eventThreadCount = 3;
m_iaxEngine->start(readThreadCount,eventThreadCount);
} }
bool YIAXDriver::msgRoute(Message& msg) bool YIAXDriver::msgRoute(Message& msg)
@ -1046,8 +1093,8 @@ bool YIAXDriver::received(Message& msg, int id)
/** /**
* IAXConsumer * IAXConsumer
*/ */
YIAXConsumer::YIAXConsumer(YIAXConnection* conn, const char* format) YIAXConsumer::YIAXConsumer(YIAXConnection* conn, u_int32_t format, const char* formatText)
: DataConsumer(format), m_connection(conn), m_total(0) : DataConsumer(formatText), m_connection(conn), m_total(0), m_format(format)
{ {
} }
@ -1060,15 +1107,15 @@ void YIAXConsumer::Consume(const DataBlock& data, unsigned long tStamp)
if (m_connection && !m_connection->mutedOut()) { if (m_connection && !m_connection->mutedOut()) {
m_total += data.length(); m_total += data.length();
if (m_connection->transaction()) if (m_connection->transaction())
m_connection->transaction()->sendMedia(data,m_connection->format()); m_connection->transaction()->sendMedia(data,m_format);
} }
} }
/** /**
* YIAXSource * YIAXSource
*/ */
YIAXSource::YIAXSource(YIAXConnection* conn, const char* format) YIAXSource::YIAXSource(YIAXConnection* conn, u_int32_t format, const char* formatText)
: DataSource(format), m_connection(conn), m_total(0) : DataSource(formatText), m_connection(conn), m_total(0), m_format(format)
{ {
} }
@ -1090,20 +1137,15 @@ void YIAXSource::Forward(const DataBlock& data, unsigned long tStamp)
YIAXConnection::YIAXConnection(YIAXEngine* iaxEngine, IAXTransaction* transaction, Message* msg) YIAXConnection::YIAXConnection(YIAXEngine* iaxEngine, IAXTransaction* transaction, Message* msg)
: Channel(&iplugin,0,transaction->outgoing()), : Channel(&iplugin,0,transaction->outgoing()),
m_iaxEngine(iaxEngine), m_transaction(transaction), m_mutedIn(false), m_mutedOut(false), m_iaxEngine(iaxEngine), m_transaction(transaction), m_mutedIn(false), m_mutedOut(false),
m_format(iplugin.defaultCodec()), m_capability(iplugin.codecs()), m_hangup(true), m_hangup(true), m_mutexRefIncreased(true), m_refIncreased(false)
m_mutexRefIncreased(true), m_refIncreased(false)
{ {
DDebug(this,DebugAll,"YIAXConnection::YIAXConnection [%p]",this); DDebug(this,DebugAll,"YIAXConnection::YIAXConnection [%p]",this);
#if 0
if (username)
m_username = *username;
m_address << transaction->remoteAddr().host() << ":" << transaction->remoteAddr().port();
#endif
setMaxcall(msg); setMaxcall(msg);
Message* m = message("chan.startup"); Message* m = message("chan.startup");
m->setParam("direction",status()); m->setParam("direction",status());
if (msg) { if (msg) {
m_targetid = msg->getValue("id"); m_targetid = msg->getValue("id");
m_password = msg->getValue("password");
m->setParam("caller",msg->getValue("caller")); m->setParam("caller",msg->getValue("caller"));
m->setParam("called",msg->getValue("called")); m->setParam("called",msg->getValue("called"));
m->setParam("billid",msg->getValue("billid")); m->setParam("billid",msg->getValue("billid"));
@ -1113,11 +1155,11 @@ YIAXConnection::YIAXConnection(YIAXEngine* iaxEngine, IAXTransaction* transactio
YIAXConnection::~YIAXConnection() YIAXConnection::~YIAXConnection()
{ {
DDebug(this,DebugAll,"YIAXConnection::~YIAXConnection [%p]",this);
status("destroyed"); status("destroyed");
setConsumer(); setConsumer();
setSource(); setSource();
hangup(); hangup();
DDebug(this,DebugAll,"YIAXConnection::~YIAXConnection [%p]",this);
} }
void YIAXConnection::callAccept(Message& msg) void YIAXConnection::callAccept(Message& msg)
@ -1138,14 +1180,9 @@ void YIAXConnection::callRejected(const char* error, const char* reason, const M
reason = error; reason = error;
DDebug(this,DebugInfo,"callRejected [%p]. Error: '%s'",this,error); DDebug(this,DebugInfo,"callRejected [%p]. Error: '%s'",this,error);
String s(error); String s(error);
if (s == "noauth" && m_transaction && !safeGetRefIncreased()) { if (m_transaction && (s == "noauth") && safeRefIncrease()) {
Debug(this,DebugAll,"callRejected [%p]. Request authentication",this); Debug(this,DebugAll,"callRejected [%p]. Requesting authentication",this);
String pwd; m_transaction->sendAuth(m_password);
m_transaction->sendAuth(pwd);
if (ref()) {
m_refIncreased = true;
DDebug(this,DebugInfo,"callRejected [%p]. Authentication requested. Increased references counter",this);
}
return; return;
} }
hangup(reason,true); hangup(reason,true);
@ -1233,6 +1270,7 @@ void YIAXConnection::handleEvent(IAXEvent* event)
case IAXEvent::Dtmf: { case IAXEvent::Dtmf: {
Debug(this,DebugAll,"YIAXConnection - DTMF: %c",(char)event->subclass()); Debug(this,DebugAll,"YIAXConnection - DTMF: %c",(char)event->subclass());
String dtmf((char)event->subclass()); String dtmf((char)event->subclass());
dtmf.toUpper();
Message* m = message("chan.dtmf"); Message* m = message("chan.dtmf");
m->addParam("text",dtmf); m->addParam("text",dtmf);
Engine::enqueue(m); Engine::enqueue(m);
@ -1276,7 +1314,8 @@ void YIAXConnection::handleEvent(IAXEvent* event)
Debug(this,DebugAll,"YIAXConnection - REJECT/HANGUP: '%s'",m_reason.c_str()); Debug(this,DebugAll,"YIAXConnection - REJECT/HANGUP: '%s'",m_reason.c_str());
break; break;
case IAXEvent::Timeout: case IAXEvent::Timeout:
Debug(this,DebugAll,"YIAXConnection - TIMEOUT"); DDebug(this,DebugNote,"YIAXConnection - TIMEOUT. Transaction: %u,%u, Frame: %u,%u ",
m_transaction->localCallNo(),m_transaction->remoteCallNo(),event->frameType(),event->subclass());
m_reason = "Timeout"; m_reason = "Timeout";
break; break;
case IAXEvent::Busy: case IAXEvent::Busy:
@ -1287,13 +1326,11 @@ void YIAXConnection::handleEvent(IAXEvent* event)
evAuthRep(event); evAuthRep(event);
break; break;
default: default:
// Debug(DebugWarn,"YIAXConnection::handleEvent - Unhandled IAX event. Event type: %u. Frame - Type: %u Subclass: %u", iplugin.getEngine()->defaultEventHandler(event);
// event->type(),event->frameType(),event->subClass());
if (!m_transaction) if (!m_transaction)
event->setFinal(); event->setFinal();
} }
if (event->final()) { if (event->final()) {
//Debug(DebugWarn,"YIAXConnection::handleEvent - Final event: need deref ?");
safeDeref(); safeDeref();
m_transaction = 0; m_transaction = 0;
} }
@ -1302,7 +1339,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) if (!m_hangup)
/* Already done */ // Already done
return; return;
m_hangup = false; m_hangup = false;
if (!reason) if (!reason)
@ -1336,6 +1373,10 @@ bool YIAXConnection::route(bool authenticated)
} }
else { else {
DDebug(this,DebugAll,"Route pass 1: No username."); DDebug(this,DebugAll,"Route pass 1: No username.");
if (!iplugin.getEngine()->acceptFormatAndCapability(m_transaction)) {
hangup(IAXTransaction::s_iax_modNoMediaFormat,true);
return false;
}
// advertise the not yet authenticated username // advertise the not yet authenticated username
if (m_transaction->username()) if (m_transaction->username())
m->addParam("authname",m_transaction->username()); m->addParam("authname",m_transaction->username());
@ -1349,47 +1390,53 @@ void YIAXConnection::startAudioIn()
{ {
if (getSource()) if (getSource())
return; return;
const char* formatText = IAXFormat::audioText(m_format); u_int32_t format = 0;
setSource(new YIAXSource(this,formatText)); if (m_transaction)
format = m_transaction->formatIn();
const char* formatText = IAXFormat::audioText(format);
setSource(new YIAXSource(this,format,formatText));
getSource()->deref(); getSource()->deref();
DDebug(this,DebugAll,"startAudioIn - Format %u: '%s'",m_format,formatText); DDebug(this,DebugAll,"startAudioIn - Format %u: '%s'",format,formatText);
} }
void YIAXConnection::startAudioOut() void YIAXConnection::startAudioOut()
{ {
if (getConsumer()) if (getConsumer())
return; return;
const char* formatText = (char*)IAXFormat::audioText(m_format); u_int32_t format = 0;
setConsumer(new YIAXConsumer(this,formatText)); if (m_transaction)
format = m_transaction->formatOut();
const char* formatText = (char*)IAXFormat::audioText(format);
setConsumer(new YIAXConsumer(this,format,formatText));
getConsumer()->deref(); getConsumer()->deref();
DDebug(this,DebugAll,"startAudioOut - Format %u: '%s'",m_format,formatText); DDebug(this,DebugAll,"startAudioOut - Format %u: '%s'",format,formatText);
} }
void YIAXConnection::evAuthRep(IAXEvent* event) void YIAXConnection::evAuthRep(IAXEvent* event)
{ {
DDebug(this,DebugAll,"YIAXConnection - AUTHREP"); DDebug(this,DebugAll,"YIAXConnection - AUTHREP");
IAXTransaction* tr = event->getTransaction(); IAXTransaction* tr = event->getTransaction();
/* Try to obtain a password from Engine */ // Try to obtain a password from Engine
Message msg("user.auth"); Message msg("user.auth");
msg.addParam("username",tr->username()); msg.addParam("username",tr->username());
if (!Engine::dispatch(msg)) { if (!Engine::dispatch(msg)) {
/* NOT Authenticated */ // NOT Authenticated
hangup(event,"",true); hangup(event,"",true);
return; return;
} }
String pwd = msg.retValue(); String pwd = msg.retValue();
if (!pwd.length()) { if (pwd.null()) {
/* Authenticated */ // Authenticated
tr->sendAccept(); tr->sendAccept();
return; return;
} }
if (!IAXEngine::isMD5ChallengeCorrect(tr->authdata(),tr->challenge(),pwd)) { if (!IAXEngine::isMD5ChallengeCorrect(tr->authdata(),tr->challenge(),pwd)) {
/* Incorrect data received */ // Incorrect data received
DDebug(this,DebugAll,"AUTHREP - Incorrect MD5 answer. Reject."); DDebug(this,DebugAll,"AUTHREP - Incorrect MD5 answer. Reject.");
hangup(event,s_iax_modInvalidAuth,true); hangup(event,IAXTransaction::s_iax_modInvalidAuth,true);
return; return;
} }
/* Password is correct. Route the user. */ // Password is correct. Route the user.
route(true); route(true);
} }
@ -1403,33 +1450,37 @@ void YIAXConnection::safeDeref()
deref(); deref();
} }
bool YIAXConnection::safeGetRefIncreased() bool YIAXConnection::safeRefIncrease()
{ {
Lock lock(&m_mutexRefIncreased); bool ok = false;
return m_refIncreased; m_mutexRefIncreased.lock();
if (!m_refIncreased && ref())
m_refIncreased = ok = true;
m_mutexRefIncreased.unlock();
return ok;
} }
/** /**
* IAXURI * IAXURI
*/ */
IAXURI::IAXURI(const char* user, const char* host, const char* calledNo, const char* calledContext, int port) IAXURI::IAXURI(const char* user, const char* host, const char* calledNo, const char* calledContext, int port)
: m_username(user), : m_username(user),
m_host(host), m_host(host),
m_port(port), m_port(port),
m_calledNo(calledNo), m_calledNo(calledNo),
m_calledContext(calledContext), m_calledContext(calledContext),
m_parsed(true) m_parsed(true)
{ {
*this << "iax:"; *this << "iax:";
if (m_username.length()) if (m_username)
*this << m_username << "@"; *this << m_username << "@";
*this << m_host; *this << m_host;
if (m_port) if (m_port)
*this << ":" << m_port; *this << ":" << m_port;
if (m_calledNo.length()) { if (m_calledNo) {
*this << "/" << m_calledNo; *this << "/" << m_calledNo;
if (m_calledContext.length()) if (m_calledContext)
*this << "@" << m_calledContext; *this << "@" << m_calledContext;
} }
} }