Marian's changes.
git-svn-id: http://yate.null.ro/svn/yate/trunk@900 acf43c95-373e-0410-b603-e72c3f656dc1
This commit is contained in:
parent
2a5a670687
commit
1236b2e154
|
@ -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
|
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
* engine.cpp
|
||||
* 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
|
||||
* Copyright (C) 2004-2006 Null Team
|
||||
|
@ -30,31 +30,40 @@
|
|||
|
||||
using namespace TelEngine;
|
||||
|
||||
IAXEngine::IAXEngine(int transCount, int retransCount, int retransInterval, int maxFullFrameDataLen, u_int32_t transTimeout,
|
||||
u_int32_t format, u_int32_t capab)
|
||||
: Mutex(true), m_transList(0), m_transListCount(0), m_retransCount(retransCount),
|
||||
m_retransInterval(retransInterval), m_maxFullFrameDataLen(maxFullFrameDataLen), m_transactionTimeout(transTimeout),
|
||||
m_format(format), m_capability(capab)
|
||||
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)
|
||||
: Mutex(true),
|
||||
m_lastGetEvIndex(0),
|
||||
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");
|
||||
if (transCount < 4)
|
||||
transCount = 4;
|
||||
else if (transCount > 256)
|
||||
transCount = 256;
|
||||
m_transList = new ObjList*[transCount];
|
||||
if ((port <= 0) || port > 65535)
|
||||
port = 4569;
|
||||
if (transListCount < 4)
|
||||
transListCount = 4;
|
||||
else if (transListCount > 256)
|
||||
transListCount = 256;
|
||||
m_transList = new ObjList*[transListCount];
|
||||
int i;
|
||||
for (i = 0; i < transCount; i++)
|
||||
for (i = 0; i < transListCount; i++)
|
||||
m_transList[i] = new ObjList;
|
||||
m_transListCount = transCount;
|
||||
m_transListCount = transListCount;
|
||||
for(i = 0; i <= IAX2_MAX_CALLNO; i++)
|
||||
m_lUsedCallNo[i] = false;
|
||||
m_lastGetEvIndex = 0;
|
||||
m_socket.create(AF_INET,SOCK_DGRAM);
|
||||
SocketAddr addr(AF_INET);
|
||||
addr.port(4569);
|
||||
addr.port(port);
|
||||
m_socket.setBlocking(false);
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -85,7 +94,7 @@ IAXTransaction* IAXEngine::addFrame(const SocketAddr& addr, IAXFrame* frame)
|
|||
tr->m_rCallNo = frame->sourceCallNo();
|
||||
m_incompleteTransList.remove(tr,false);
|
||||
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());
|
||||
return tr;
|
||||
}
|
||||
|
@ -134,7 +143,10 @@ IAXTransaction* IAXEngine::addFrame(const SocketAddr& addr, IAXFrame* frame)
|
|||
return 0;
|
||||
// Create and add transaction
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -232,7 +244,6 @@ void IAXEngine::removeTransaction(IAXTransaction* transaction)
|
|||
u_int32_t IAXEngine::transactionCount()
|
||||
{
|
||||
u_int32_t n = 0;
|
||||
ObjList* l;
|
||||
|
||||
Lock lock(this);
|
||||
// Incomplete transactions
|
||||
|
@ -240,7 +251,7 @@ u_int32_t IAXEngine::transactionCount()
|
|||
// Complete transactions
|
||||
for (int i = 0; i < m_transListCount; i++)
|
||||
n += m_transList[i]->count();
|
||||
return n;
|
||||
return n;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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);
|
||||
u_int16_t lcn = generateCallNo();
|
||||
if (!lcn)
|
||||
return 0;
|
||||
IAXTransaction* tr = IAXTransaction::factoryOut(this,type,lcn,addr,ieList);
|
||||
if (tr->type() == IAXTransaction::Incorrect) {
|
||||
Debug(this,DebugWarn,"Error initializing transaction");
|
||||
delete tr;
|
||||
return 0;
|
||||
}
|
||||
m_incompleteTransList.append(tr);
|
||||
if (tr)
|
||||
m_incompleteTransList.append(tr);
|
||||
else
|
||||
releaseCallNo(lcn);
|
||||
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)
|
||||
{
|
||||
MD5 md5;
|
||||
|
@ -356,16 +403,16 @@ bool IAXEngine::isMD5ChallengeCorrect(const String& md5data, const String& chall
|
|||
/*
|
||||
* IAXEvent
|
||||
*/
|
||||
IAXEvent::IAXEvent(Type type, 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)
|
||||
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_local(local), m_final(final), m_transaction(0)
|
||||
|
||||
{
|
||||
if (transaction && transaction->ref())
|
||||
m_transaction = transaction;
|
||||
}
|
||||
|
||||
IAXEvent::IAXEvent(Type type, 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)
|
||||
IAXEvent::IAXEvent(Type type, bool local, bool final, IAXTransaction* transaction, const IAXFullFrame* 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())
|
||||
|
@ -381,8 +428,10 @@ IAXEvent::~IAXEvent()
|
|||
if (m_final && m_transaction && m_transaction->state() == IAXTransaction::Terminated) {
|
||||
m_transaction->getEngine()->removeTransaction(m_transaction);
|
||||
}
|
||||
if (m_transaction)
|
||||
if (m_transaction) {
|
||||
m_transaction->eventTerminated(this);
|
||||
m_transaction->deref();
|
||||
}
|
||||
}
|
||||
|
||||
/* vi: set ts=8 sw=4 sts=4 noet: */
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
* frame.cpp
|
||||
* 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
|
||||
* Copyright (C) 2004-2006 Null Team
|
||||
|
@ -124,7 +124,7 @@ IAXInfoElementNumeric::IAXInfoElementNumeric(Type type, u_int32_t val, u_int8_t
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void IAXInfoElementNumeric::toBuffer(DataBlock& buf)
|
||||
{
|
||||
unsigned char d[6] = {m_type,m_length};
|
||||
|
@ -158,10 +158,8 @@ void IAXInfoElementBinary::toBuffer(DataBlock& buf)
|
|||
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());
|
||||
}
|
||||
|
||||
|
@ -177,7 +175,6 @@ bool IAXInfoElementBinary::unpackIP(SocketAddr& addr, IAXInfoElementBinary* ie)
|
|||
/**
|
||||
* IAXIEList
|
||||
*/
|
||||
|
||||
void IAXIEList::insertVersion()
|
||||
{
|
||||
if (!getIE(IAXInfoElement::VERSION))
|
||||
|
@ -225,7 +222,7 @@ bool IAXIEList::createFromFrame(const IAXFullFrame* frame)
|
|||
case IAXInfoElement::RSA_RESULT:
|
||||
case IAXInfoElement::CAUSE:
|
||||
case IAXInfoElement::MUSICONHOLD: // Optional
|
||||
case IAXInfoElement::RDNIS:
|
||||
case IAXInfoElement::RDNIS:
|
||||
case IAXInfoElement::DEVICETYPE:
|
||||
if (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::FWBLOCKDATA: // Length can be 0
|
||||
case IAXInfoElement::ENKEY:
|
||||
if (data[i-1] != IAXInfoElement::FWBLOCKDATA && !data[i]) {
|
||||
i = 0xFFFF;
|
||||
break;
|
||||
}
|
||||
if (data[i-1] == IAXInfoElement::SERVICEIDENT && data[i] != 6) {
|
||||
i = 0xFFFF;
|
||||
break;
|
||||
|
@ -285,7 +278,7 @@ bool IAXIEList::createFromFrame(const IAXFullFrame* frame)
|
|||
case IAXInfoElement::AUTHMETHODS:
|
||||
case IAXInfoElement::REFRESH:
|
||||
case IAXInfoElement::DPSTATUS:
|
||||
case IAXInfoElement::CALLNO:
|
||||
case IAXInfoElement::CALLNO:
|
||||
case IAXInfoElement::MSGCOUNT:
|
||||
case IAXInfoElement::CALLINGTNS:
|
||||
case IAXInfoElement::FIRMWAREVER:
|
||||
|
@ -295,10 +288,6 @@ bool IAXIEList::createFromFrame(const IAXFullFrame* frame)
|
|||
break;
|
||||
}
|
||||
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);
|
||||
i += 3;
|
||||
break;
|
||||
|
@ -424,18 +413,12 @@ TokenDict IAXFormat::videoData[] = {
|
|||
|
||||
const char* IAXFormat::audioText(u_int8_t audio)
|
||||
{
|
||||
for (int i = 0; audioData[i].value; i++)
|
||||
if (audioData[i].value == audio)
|
||||
return audioData[i].token;
|
||||
return 0;
|
||||
return lookup(audio,audioData);
|
||||
}
|
||||
|
||||
const char* IAXFormat::videoText(u_int8_t video)
|
||||
{
|
||||
for (int i = 0; videoData[i].value; i++)
|
||||
if (videoData[i].value == video)
|
||||
return videoData[i].token;
|
||||
return 0;
|
||||
return lookup(video,videoData);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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_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()
|
||||
|
@ -454,15 +437,6 @@ IAXFrame::~IAXFrame()
|
|||
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)
|
||||
{
|
||||
if (len < 4)
|
||||
|
@ -577,7 +551,7 @@ u_int8_t IAXFrame::packSubclass(u_int32_t value)
|
|||
return 0;
|
||||
}
|
||||
|
||||
u_int32_t IAXFrame::unpackSubclass(u_int8_t value)
|
||||
u_int32_t IAXFrame::unpackSubclass(u_int8_t value)
|
||||
{
|
||||
if (value > 0x9f) {
|
||||
DDebug(DebugMild,"IAXFrame nonstandard unpack %u",value);
|
||||
|
@ -659,4 +633,29 @@ const IAXFullFrame* IAXFullFrame::fullFrame() const
|
|||
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: */
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
* yateiax.h
|
||||
* Yet Another IAX2 Stack
|
||||
* This file is part of the YATE Project http://YATE.null.ro
|
||||
|
@ -42,7 +42,7 @@
|
|||
#define YIAX_API
|
||||
#endif
|
||||
|
||||
/**
|
||||
/**
|
||||
* Holds all Telephony Engine related classes.
|
||||
*/
|
||||
namespace TelEngine {
|
||||
|
@ -174,7 +174,7 @@ public:
|
|||
inline int length() const
|
||||
{ return m_strData.length(); }
|
||||
|
||||
inline String& data()
|
||||
inline String& data()
|
||||
{ return m_strData; }
|
||||
|
||||
virtual void toBuffer(DataBlock& buf);
|
||||
|
@ -190,8 +190,8 @@ class IAXInfoElementNumeric : public IAXInfoElement
|
|||
{
|
||||
public:
|
||||
IAXInfoElementNumeric(Type type, u_int32_t val, u_int8_t len);
|
||||
|
||||
virtual ~IAXInfoElementNumeric() {}
|
||||
|
||||
virtual ~IAXInfoElementNumeric() {}
|
||||
|
||||
inline int length() const
|
||||
{ return m_length; }
|
||||
|
@ -225,7 +225,7 @@ public:
|
|||
|
||||
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);
|
||||
|
||||
|
@ -314,7 +314,7 @@ public:
|
|||
* This class holds the enumeration values for audio and video formats
|
||||
* @short Wrapper class for audio and video formats
|
||||
*/
|
||||
class YIAX_API IAXFormat
|
||||
class YIAX_API IAXFormat
|
||||
{
|
||||
public:
|
||||
enum Audio {
|
||||
|
@ -348,7 +348,7 @@ public:
|
|||
/**
|
||||
* This class holds the enumeration values for IAX control (subclass)
|
||||
*/
|
||||
class YIAX_API IAXControl
|
||||
class YIAX_API IAXControl
|
||||
{
|
||||
public:
|
||||
enum Type {
|
||||
|
@ -425,8 +425,6 @@ public:
|
|||
inline bool retrans() const
|
||||
{ return m_retrans; }
|
||||
|
||||
bool setRetrans();
|
||||
|
||||
inline u_int16_t sourceCallNo() const
|
||||
{ return m_sCallNo; }
|
||||
|
||||
|
@ -451,7 +449,7 @@ public:
|
|||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
|
@ -535,21 +533,19 @@ public:
|
|||
|
||||
virtual ~IAXFrameOut()
|
||||
{}
|
||||
|
||||
|
||||
inline bool timeout() const
|
||||
{ return !(bool)m_retransCount; }
|
||||
|
||||
inline bool needRetrans(u_int64_t time)
|
||||
{ return !ack() && time > m_nextTransTime; }
|
||||
|
||||
inline void transmitted() {
|
||||
if (m_retransCount) {
|
||||
m_retransCount--;
|
||||
m_retransTimeInterval *= 2;
|
||||
m_nextTransTime += m_retransTimeInterval;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
inline bool timeForRetrans(u_int64_t time)
|
||||
{ return time > m_nextTransTime; }
|
||||
|
||||
void transmitted();
|
||||
|
||||
inline void hurryTransmission(u_int64_t time = Time::msecNow())
|
||||
{ m_nextTransTime = time; }
|
||||
|
||||
inline bool ack()
|
||||
{ return m_ack; }
|
||||
|
||||
|
@ -559,6 +555,12 @@ public:
|
|||
inline bool 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:
|
||||
bool m_ack; /* Acknoledge flag */
|
||||
bool m_ackOnly; /* frame need only Ack as response */
|
||||
|
@ -567,35 +569,12 @@ protected:
|
|||
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
|
||||
*/
|
||||
class YIAX_API IAXTransaction : public RefObject, public Mutex
|
||||
{
|
||||
friend class IAXEvent;
|
||||
friend class IAXEngine;
|
||||
public:
|
||||
enum Type {
|
||||
|
@ -611,62 +590,62 @@ public:
|
|||
/* *** New */
|
||||
Connected, /* Call leg established (Accepted). */
|
||||
/* Outgoing */
|
||||
NewLocalInvite, /* Sent: New, RegReq/RegRel */
|
||||
NewLocalInvite, /* Sent: New, RegReq/RegRel */
|
||||
/* New */
|
||||
/* *** Send: */
|
||||
/* *** Send: */
|
||||
/* Hangup --> Terminating */
|
||||
/* *** Receive: */
|
||||
/* *** Receive: */
|
||||
/* AuthReq --> NewLocalInvite_AuthRecv */
|
||||
/* Accept --> Connected */
|
||||
/* Reject, Hangup --> Terminating */
|
||||
/* RegReq/RegRel */
|
||||
/* *** Send: */
|
||||
/* *** Send: */
|
||||
/* RegRej --> Terminating */
|
||||
/* *** Receive: */
|
||||
/* *** Receive: */
|
||||
/* RegAuth --> NewLocalInvite_AuthRecv */
|
||||
/* RegAck (if RegReq) --> Terminating */
|
||||
/* RegRej --> Terminating */
|
||||
NewLocalInvite_AuthRecv, /* Received: AuthReq, RegReq/RegRel */
|
||||
/* New */
|
||||
/* *** Send: */
|
||||
/* *** Send: */
|
||||
/* AuthRep --> NewLocalInvite_RepSent */
|
||||
/* Hangup, Reject --> Terminating */
|
||||
/* *** Receive: */
|
||||
/* *** Receive: */
|
||||
/* Reject, Hangup --> Terminating */
|
||||
/* RegReq/RegRel */
|
||||
/* *** Send: */
|
||||
/* *** Send: */
|
||||
/* RegReq/RegRel --> NewLocalInvite_RepSent */
|
||||
/* RegRej --> Terminating */
|
||||
/* *** Receive: */
|
||||
/* *** Receive: */
|
||||
/* RegRej --> Terminating */
|
||||
NewLocalInvite_RepSent, /* Sent: AuthRep, RegReq/RegRel */
|
||||
/* New */
|
||||
/* *** Send: */
|
||||
/* *** Send: */
|
||||
/* Hangup --> Terminating */
|
||||
/* *** Receive: */
|
||||
/* *** Receive: */
|
||||
/* Accept --> Connected */
|
||||
/* Reject, Hangup --> Terminating */
|
||||
/* RegReq/RegRel */
|
||||
/* *** Send: */
|
||||
/* *** Send: */
|
||||
/* RegRej --> Terminating */
|
||||
/* *** Receive: */
|
||||
/* *** Receive: */
|
||||
/* RegAck --> Terminating */
|
||||
/* RegRej --> Terminating */
|
||||
/* Incoming */
|
||||
NewRemoteInvite, /* Received: New, RegReq/RegRel*/
|
||||
/* New */
|
||||
/* *** Send: */
|
||||
/* *** Send: */
|
||||
/* AuthReq --> NewRemoteInvite_AuthSent */
|
||||
/* Accept --> Connected */
|
||||
/* Hangup --> Terminating */
|
||||
/* *** Receive: */
|
||||
/* *** Receive: */
|
||||
/* Reject, Hangup --> Terminating */
|
||||
/* RegReq/RegRel */
|
||||
/* *** Send: */
|
||||
/* *** Send: */
|
||||
/* RegAuth --> NewRemoteInvite_AuthSent */
|
||||
/* RegAck (if RegReq) --> Terminated */
|
||||
/* RegRej --> Terminating */
|
||||
/* *** Receive: */
|
||||
/* *** Receive: */
|
||||
/* RegRej --> Terminating */
|
||||
NewRemoteInvite_AuthSent, /* Sent: AuthReq, RegAuth */
|
||||
/* New */
|
||||
|
@ -676,28 +655,28 @@ public:
|
|||
/* AuthRep --> NewRemoteInvite_RepRecv */
|
||||
/* Reject, Hangup --> Terminating */
|
||||
/* RegReq/RegRel */
|
||||
/* *** Send: */
|
||||
/* *** Send: */
|
||||
/* RegRej --> Terminating */
|
||||
/* *** Receive: */
|
||||
/* *** Receive: */
|
||||
/* RegReq/RegRel --> NewRemoteInvite_RepRecv */
|
||||
/* RegRej --> Terminating */
|
||||
NewRemoteInvite_RepRecv, /* Received: AuthRep, RegReq/RegRel*/
|
||||
/* New */
|
||||
/* *** Send: */
|
||||
/* *** Send: */
|
||||
/* Accept --> Connected */
|
||||
/* Hangup --> Terminating */
|
||||
/* *** Receive: */
|
||||
/* *** Receive: */
|
||||
/* Reject, Hangup --> Terminating */
|
||||
/* RegReq/RegRel */
|
||||
/* *** Send: */
|
||||
/* *** Send: */
|
||||
/* RegAck, RegRej --> Terminating */
|
||||
/* *** Receive: */
|
||||
/* *** Receive: */
|
||||
/* RegRej --> Terminating */
|
||||
/* Not initialized or terminated */
|
||||
Unknown, /* Initial state. */
|
||||
Terminated, /* Terminated. No more frames accepted. */
|
||||
Terminating, /* Terminating. Wait for ACK or timeout to terminate. */
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
|
@ -725,7 +704,7 @@ public:
|
|||
* @param ieList Starting IE list
|
||||
* @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);
|
||||
|
||||
/**
|
||||
|
@ -820,6 +799,12 @@ public:
|
|||
inline u_int32_t 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()
|
||||
{ return m_capability; }
|
||||
|
||||
|
@ -841,7 +826,7 @@ public:
|
|||
/**
|
||||
* Process received mini frame 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
|
||||
* @return 'this' if successful or 0
|
||||
*/
|
||||
|
@ -918,7 +903,7 @@ public:
|
|||
* @param pwd Required password
|
||||
* @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.
|
||||
|
@ -953,10 +938,22 @@ public:
|
|||
inline bool sendNoise(u_int8_t noise)
|
||||
{ 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();
|
||||
|
||||
/**
|
||||
* Print transaction data on stdin.
|
||||
*/
|
||||
void print();
|
||||
|
||||
static String s_iax_modNoAuthMethod;
|
||||
static String s_iax_modNoMediaFormat;
|
||||
static String s_iax_modInvalidAuth;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Constructor: constructs an incoming transaction from a received full frame with an IAX
|
||||
|
@ -1011,19 +1008,21 @@ protected:
|
|||
/**
|
||||
* Terminate the transaction.
|
||||
* @param evType IAXEvent type to generate.
|
||||
* @param local If true it is a locally generated event.
|
||||
* @param frame Frame to build event from.
|
||||
* @param createIEList If true create IE list in the generated event.
|
||||
* @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 local If true it is a locally generated event.
|
||||
* @param frame Frame to build event from.
|
||||
* @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
|
||||
|
@ -1035,30 +1034,34 @@ protected:
|
|||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
bool sendFrame(IAXFrameOut* frame);
|
||||
bool sendFrame(IAXFrameOut* frame, bool vnak = false);
|
||||
|
||||
/**
|
||||
* Create an event from a frame.
|
||||
* @param evType Event type
|
||||
* @param local If true it is a locally generated event.
|
||||
* @param frameOut Frame to create from
|
||||
* @param newState The transaction new state
|
||||
* @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.
|
||||
* @param frame Frame to create response for
|
||||
* @param findType Frame type to find
|
||||
* @param findSubclass Frame subclass to find
|
||||
* @param evType Event type to generate
|
||||
* @param local local flag for the generated event.
|
||||
* @param newState New transaction state if an event was generated
|
||||
* @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.
|
||||
|
@ -1112,7 +1115,14 @@ protected:
|
|||
* @param subclass Frame subclass to find
|
||||
* @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.
|
||||
|
@ -1133,6 +1143,11 @@ protected:
|
|||
*/
|
||||
void sendInval();
|
||||
|
||||
/**
|
||||
* Send an VNAK frame.
|
||||
*/
|
||||
void sendVNAK();
|
||||
|
||||
/**
|
||||
* Internal protocol outgoing frames processing (e.g. IAX PING, LAGRQ).
|
||||
* @param frame Frame to process
|
||||
|
@ -1175,10 +1190,54 @@ protected:
|
|||
|
||||
/**
|
||||
* Terminate the transaction if state is Terminating and timeout.
|
||||
* @param time Current time
|
||||
* @return A valid IAXEvent or 0.
|
||||
*/
|
||||
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:
|
||||
/* Params */
|
||||
bool m_localInitTrans; /* True: local initiated transaction */
|
||||
|
@ -1194,9 +1253,11 @@ private:
|
|||
unsigned char m_iSeqNo; /* Incoming frame sequence number */
|
||||
IAXEngine* m_engine; /* Engine that owns this transaction */
|
||||
void* m_userdata; /* User data */
|
||||
u_int16_t m_lastMiniFrameOut; /* Last transmitted mini frame timestamp */
|
||||
u_int32_t m_lastMiniFrameIn; /* Last received mini frame timestamp */
|
||||
u_int16_t m_lastMiniFrameOut; /* Last transmitted mini frame timestamp */
|
||||
u_int32_t m_lastMiniFrameIn; /* Last received mini frame timestamp */
|
||||
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 */
|
||||
ObjList m_outFrames; /* Transaction & protocol control outgoing frames */
|
||||
u_int16_t m_retransCount; /* Retransmission counter. 0 --> Timeout */
|
||||
|
@ -1221,9 +1282,11 @@ private:
|
|||
String m_calledContext; /* Called context */
|
||||
String m_challenge; /* Challenge */
|
||||
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_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
|
||||
|
@ -1236,17 +1299,16 @@ public:
|
|||
*/
|
||||
enum Type {
|
||||
Invalid = 0,
|
||||
Unexpected,
|
||||
Terminated,
|
||||
Timeout,
|
||||
NotImplemented,
|
||||
New, /* New remote transaction. Need Auth. */
|
||||
AuthRep, /* Auth reply. Need Auth for password. */
|
||||
New, /* New remote transaction. */
|
||||
AuthReq, /* Auth request. Internally processed. */
|
||||
AuthRep, /* Auth reply. */
|
||||
Accept,
|
||||
Hangup,
|
||||
Reject,
|
||||
Busy,
|
||||
Voice,
|
||||
Text,
|
||||
Dtmf,
|
||||
Noise,
|
||||
|
@ -1271,6 +1333,13 @@ public:
|
|||
inline Type type() const
|
||||
{ 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.
|
||||
* @return True if the transaction has finalized and will be destroyed
|
||||
|
@ -1328,14 +1397,15 @@ protected:
|
|||
* Constructor
|
||||
* @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:
|
||||
Type m_type; /* Event type */
|
||||
u_int8_t m_frameType; /* Frame type */
|
||||
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 */
|
||||
IAXTransaction* m_transaction; /* Transaction that generated this event */
|
||||
IAXIEList m_ieList; /* IAXInfoElement list */
|
||||
|
@ -1346,16 +1416,18 @@ class YIAX_API IAXEngine : public DebugEnabler, public Mutex
|
|||
public:
|
||||
/**
|
||||
* Constructor
|
||||
* @param transCount Number of entries in the transaction hash table
|
||||
* @param retransCount Number of frame retransmission before timeout
|
||||
* @param retransTime Default retransmission time
|
||||
* @param port UDP port to run the protocol on
|
||||
* @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
|
||||
* @param transTimeout Timeout (in seconds) of transactions belonging to this engine
|
||||
* @param format Default media format
|
||||
* @param capab Media capabilities of this engine
|
||||
*/
|
||||
IAXEngine(int transCount, int retransCount, int retransInterval, int maxFullFrameDataLen, u_int32_t transTimeout,
|
||||
u_int32_t format, u_int32_t capab);
|
||||
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);
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
|
@ -1382,10 +1454,10 @@ public:
|
|||
/**
|
||||
* Process media from remote peer. Descendents must override this method.
|
||||
* @param transaction IAXTransaction that owns the call leg
|
||||
* @param data Media data.
|
||||
* @param tStamp Media timestamp.
|
||||
* @param data Media data.
|
||||
* @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()
|
||||
{ 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.
|
||||
* @return Timeout (in seconds) of transactions belonging to this engine
|
||||
*/
|
||||
inline u_int32_t transactionTimeout()
|
||||
{ return m_transactionTimeout; }
|
||||
{ return m_transTimeout; }
|
||||
|
||||
inline int maxFullFrameDataLen()
|
||||
inline u_int16_t maxFullFrameDataLen()
|
||||
{ return m_maxFullFrameDataLen; }
|
||||
|
||||
inline u_int32_t format()
|
||||
|
@ -1426,7 +1505,7 @@ public:
|
|||
{ return m_capability; }
|
||||
|
||||
/**
|
||||
* Read data from socket
|
||||
* Read data from socket
|
||||
*/
|
||||
void readSocket(SocketAddr& addr);
|
||||
|
||||
|
@ -1456,11 +1535,40 @@ public:
|
|||
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.
|
||||
*/
|
||||
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 bool isMD5ChallengeCorrect(const String& md5data, const String& challenge, const String& password);
|
||||
|
@ -1505,15 +1613,16 @@ private:
|
|||
Socket m_socket; /* Socket */
|
||||
ObjList** m_transList; /* Full transactions */
|
||||
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 */
|
||||
int m_lastGetEvIndex; /* getEvent: keep last array entry */
|
||||
/* Parameters */
|
||||
int m_maxFullFrameDataLen; /* Max full frame data (IE list) length */
|
||||
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 */
|
||||
u_int32_t m_format;
|
||||
u_int32_t m_capability;
|
||||
|
|
|
@ -23,7 +23,6 @@
|
|||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
|
||||
#include <yatephone.h>
|
||||
#include <yateversn.h>
|
||||
|
||||
|
@ -35,11 +34,17 @@
|
|||
|
||||
#include <yateiax.h>
|
||||
|
||||
extern TelEngine::String s_iax_modInvalidAuth;
|
||||
|
||||
using namespace TelEngine;
|
||||
namespace { // anonymous
|
||||
|
||||
static TokenDict dict_tos[] = {
|
||||
{ "lowdelay", Socket::LowDelay },
|
||||
{ "throughput", Socket::MaxThroughput },
|
||||
{ "reliability", Socket::MaxReliability },
|
||||
{ "mincost", Socket::MinCost },
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
static Configuration s_cfg;
|
||||
|
||||
class YIAXLineContainer;
|
||||
|
@ -111,7 +116,7 @@ public:
|
|||
inline ~YIAXLineContainer() {}
|
||||
|
||||
/**
|
||||
* logout and remove all lines
|
||||
* Logout and remove all lines
|
||||
*/
|
||||
void clear();
|
||||
|
||||
|
@ -200,8 +205,22 @@ protected:
|
|||
class YIAXEngine : public IAXEngine
|
||||
{
|
||||
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()
|
||||
{}
|
||||
|
||||
|
@ -238,9 +257,10 @@ public:
|
|||
|
||||
/**
|
||||
* 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:
|
||||
|
||||
|
@ -249,6 +269,9 @@ protected:
|
|||
*/
|
||||
virtual void processEvent(IAXEvent* event);
|
||||
|
||||
/**
|
||||
* Event handler for incoming registration transactions.
|
||||
*/
|
||||
void processRemoteReg(IAXEvent* event);
|
||||
|
||||
/**
|
||||
|
@ -315,12 +338,13 @@ class YIAXConnection;
|
|||
class YIAXConsumer : public DataConsumer
|
||||
{
|
||||
public:
|
||||
YIAXConsumer(YIAXConnection* conn, const char* format);
|
||||
YIAXConsumer(YIAXConnection* conn, u_int32_t format, const char* formatText);
|
||||
~YIAXConsumer();
|
||||
virtual void Consume(const DataBlock &data, unsigned long tStamp);
|
||||
private:
|
||||
YIAXConnection* m_connection;
|
||||
unsigned m_total;
|
||||
u_int32_t m_format;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -329,12 +353,13 @@ private:
|
|||
class YIAXSource : public DataSource
|
||||
{
|
||||
public:
|
||||
YIAXSource(YIAXConnection* conn, const char* format);
|
||||
YIAXSource(YIAXConnection* conn, u_int32_t format, const char* formatText);
|
||||
~YIAXSource();
|
||||
void Forward(const DataBlock &data, unsigned long tStamp = 0);
|
||||
private:
|
||||
YIAXConnection* m_connection;
|
||||
unsigned m_total;
|
||||
u_int32_t m_format;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -364,9 +389,6 @@ public:
|
|||
inline bool mutedOut() const
|
||||
{ return m_mutedOut; }
|
||||
|
||||
inline u_int32_t format()
|
||||
{ return m_format; }
|
||||
|
||||
void handleEvent(IAXEvent* event);
|
||||
|
||||
/* Start router */
|
||||
|
@ -388,20 +410,19 @@ protected:
|
|||
void evAuthRep(IAXEvent* event);
|
||||
|
||||
void safeDeref();
|
||||
bool safeGetRefIncreased();
|
||||
|
||||
bool safeRefIncrease();
|
||||
|
||||
private:
|
||||
YIAXEngine* m_iaxEngine; /* IAX engine owning the transaction */
|
||||
IAXTransaction* m_transaction; /* IAX transaction */
|
||||
bool m_mutedIn; /* No remote media accepted */
|
||||
bool m_mutedOut; /* No local media accepted */
|
||||
u_int32_t m_format; /* Current media format */
|
||||
u_int32_t m_capability; /* Supported formats */
|
||||
String m_reason; /* */
|
||||
bool m_hangup; /* Need to send chan.hangup message */
|
||||
/* */
|
||||
Mutex m_mutexRefIncreased;
|
||||
bool m_refIncreased;
|
||||
YIAXEngine* m_iaxEngine; // IAX engine owning the transaction
|
||||
IAXTransaction* m_transaction; // IAX transaction
|
||||
String m_password; // Password for client authentication
|
||||
bool m_mutedIn; // No remote media accepted
|
||||
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_mutexRefIncreased; // Safe ref/deref connection
|
||||
bool m_refIncreased; // If true, the reference counter was increased
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -462,12 +483,10 @@ YIAXLine::YIAXLine(const String& name)
|
|||
m_registered(false),
|
||||
m_register(true)
|
||||
{
|
||||
// yiax_line_allocated++;
|
||||
}
|
||||
|
||||
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_callingNo = trans->callingNo();
|
||||
line->m_callingName = trans->callingName();
|
||||
Debug(&iplugin,DebugAll,"YIAXLineContainer::regTerminate[%s] - Ack for '%s'.",
|
||||
line->c_str(),line->state() == YIAXLine::Registering?"Register":"Unregister");
|
||||
Debug(&iplugin,DebugAll,"YIAXLineContainer::regTerminate[%s] - Ack for '%s'. Next: %u",
|
||||
line->c_str(),line->state() == YIAXLine::Registering?"Register":"Unregister",line->m_nextReg);
|
||||
line->m_registered = true;
|
||||
break;
|
||||
case IAXEvent::Reject:
|
||||
// retry at 25% of the expire time
|
||||
line->m_nextReg = Time::secNow() + (line->expire() / 4);
|
||||
Debug(&iplugin,DebugAll,"YIAXLineContainer::regTerminate[%s] - Reject for '%s'.",
|
||||
line->c_str(),line->state() == YIAXLine::Registering?"Register":"Unregister");
|
||||
line->m_nextReg = Time::secNow() + (line->expire() / 2);
|
||||
Debug(&iplugin,DebugAll,"YIAXLineContainer::regTerminate[%s] - Reject for '%s'. Next: %u",
|
||||
line->c_str(),line->state() == YIAXLine::Registering?"Register":"Unregister",line->m_nextReg);
|
||||
line->m_registered = false;
|
||||
break;
|
||||
case IAXEvent::Timeout:
|
||||
// retry at 50% of the expire time
|
||||
line->m_nextReg = Time::secNow() + (line->expire() / 2);
|
||||
Debug(&iplugin,DebugAll,"YIAXLineContainer::regTerminate[%s] - Timeout for '%s'.",
|
||||
line->c_str(),line->state() == YIAXLine::Registering?"Register":"Unregister");
|
||||
Debug(&iplugin,DebugAll,"YIAXLineContainer::regTerminate[%s] - Timeout for '%s'. Next: %u",
|
||||
line->c_str(),line->state() == YIAXLine::Registering?"Register":"Unregister",line->m_nextReg);
|
||||
line->m_registered = false;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
|
@ -538,8 +558,7 @@ void YIAXLineContainer::handleEvent(IAXEvent* event)
|
|||
regTerminate(event);
|
||||
break;
|
||||
default:
|
||||
Debug(&iplugin,DebugAll,"YIAXLineContainer::handleEvent. Unexpected event: %u",event->type());
|
||||
break;
|
||||
iplugin.getEngine()->defaultEventHandler(event);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -716,9 +735,11 @@ void YIAXGetEvent::run()
|
|||
/**
|
||||
* YIAXEngine
|
||||
*/
|
||||
YIAXEngine::YIAXEngine(int transCount, int retransCount, int retransTime, int maxFullFrameDataLen, u_int32_t transTimeout)
|
||||
: IAXEngine(transCount,retransCount,retransTime,maxFullFrameDataLen,transTimeout,iplugin.defaultCodec(),iplugin.codecs()),
|
||||
m_threadsCreated(false)
|
||||
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)
|
||||
: 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 ((static_cast<YIAXConnection*>(transaction->getUserData()))->getSource())
|
||||
(static_cast<YIAXSource*>((static_cast<YIAXConnection*>(transaction->getUserData()))->getSource()))->Forward(data,tStamp);
|
||||
else
|
||||
; //Debug(this,DebugAll,"YIAXEngine - processMedia. No media source");
|
||||
else {
|
||||
XDebug(this,DebugAll,"YIAXEngine - processMedia. No media source");
|
||||
}
|
||||
else
|
||||
Debug(this,DebugAll,"YIAXEngine - processMedia. Transaction doesn't have a connection");
|
||||
else
|
||||
|
@ -745,14 +767,14 @@ IAXTransaction* YIAXEngine::reg(YIAXLine* line, bool regreq)
|
|||
addr.port(line->remotePort());
|
||||
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());
|
||||
/* Create IE list */
|
||||
// Create IE list
|
||||
IAXIEList ieList;
|
||||
ieList.appendString(IAXInfoElement::USERNAME,line->username());
|
||||
ieList.appendString(IAXInfoElement::PASSWORD,line->password());
|
||||
ieList.appendString(IAXInfoElement::CALLING_NUMBER,line->callingNo());
|
||||
ieList.appendString(IAXInfoElement::CALLING_NAME,line->callingName());
|
||||
ieList.appendNumeric(IAXInfoElement::REFRESH,line->expire(),2);
|
||||
/* Make it ! */
|
||||
// Make it !
|
||||
IAXTransaction* tr = startLocalTransaction(regreq ? IAXTransaction::RegReq : IAXTransaction::RegRel,addr,ieList);
|
||||
if (tr)
|
||||
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",
|
||||
params.getValue("username"),addr.host().c_str(),addr.port(),params.getValue("called"),params.getValue("calledname"));
|
||||
/* Create IE list */
|
||||
// Create IE list
|
||||
IAXIEList ieList;
|
||||
ieList.appendString(IAXInfoElement::USERNAME,params.getValue("username"));
|
||||
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.appendNumeric(IAXInfoElement::FORMAT,iplugin.defaultCodec(),4);
|
||||
ieList.appendNumeric(IAXInfoElement::CAPABILITY,iplugin.codecs(),4);
|
||||
/* Make the call ! */
|
||||
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());
|
||||
IAXIEList ieList;
|
||||
/* Poke */
|
||||
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)
|
||||
return;
|
||||
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--)
|
||||
(new YIAXListener(this,"YIAXListener thread"))->startup();
|
||||
(new YIAXGetEvent(this,"YIAXGetEvent thread"))->startup();
|
||||
for (; eventThreadCount; eventThreadCount--)
|
||||
(new YIAXGetEvent(this,"YIAXGetEvent 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:
|
||||
|
@ -808,14 +834,29 @@ void YIAXEngine::processEvent(IAXEvent* event)
|
|||
// We already have a channel for this call
|
||||
connection->handleEvent(event);
|
||||
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);
|
||||
connection->disconnect();
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (event->type() == IAXEvent::New) {
|
||||
/* Incoming request for a new call */
|
||||
// Incoming request for a new call
|
||||
connection = new YIAXConnection(this,event->getTransaction());
|
||||
event->getTransaction()->setUserData(connection);
|
||||
if (!connection->route())
|
||||
|
@ -825,13 +866,11 @@ void YIAXEngine::processEvent(IAXEvent* event)
|
|||
break;
|
||||
case IAXTransaction::RegReq:
|
||||
case IAXTransaction::RegRel:
|
||||
if (event->getTransaction()->getUserData()) {
|
||||
// Existing line
|
||||
s_lines.handleEvent(event);
|
||||
break;
|
||||
}
|
||||
if (event->type() == IAXEvent::New)
|
||||
processRemoteReg(event);
|
||||
else
|
||||
if (event->getTransaction()->getUserData())
|
||||
s_lines.handleEvent(event);
|
||||
break;
|
||||
default: ;
|
||||
}
|
||||
|
@ -847,26 +886,26 @@ void YIAXEngine::processRemoteReg(IAXEvent* event)
|
|||
Message msg("user.auth");
|
||||
msg.addParam("username",tr->username());
|
||||
if (!Engine::dispatch(msg)) {
|
||||
/* Not authenticated */
|
||||
Debug(this,DebugAll,"evNewRegistration. Not authenticated. Reject");
|
||||
// Not authenticated
|
||||
Debug(this,DebugAll,"processRemoteReg. Not authenticated. Reject");
|
||||
tr->sendReject();
|
||||
return;
|
||||
}
|
||||
String password = msg.retValue();
|
||||
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)) {
|
||||
Debug(this,DebugAll,"evNewRegistration. Authenticated and (un)registered. Ack");
|
||||
Debug(this,DebugAll,"processRemoteReg. Authenticated and (un)registered. Ack");
|
||||
tr->sendAccept();
|
||||
}
|
||||
else {
|
||||
Debug(this,DebugAll,"evNewRegistration. Authenticated but not (un)registered. Reject");
|
||||
Debug(this,DebugAll,"processRemoteReg. Authenticated but not (un)registered. Reject");
|
||||
tr->sendReject();
|
||||
}
|
||||
return;
|
||||
}
|
||||
/* Authenticated, password required */
|
||||
Debug(this,DebugAll,"evNewRegistration. Request authentication");
|
||||
// Authenticated, password required
|
||||
Debug(this,DebugAll,"processRemoteReg. Request authentication");
|
||||
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());
|
||||
Message msg(regrel ? "user.unregister" : "user.register");
|
||||
msg.addParam("username",username);
|
||||
msg.setParam("driver","iax");
|
||||
if (!regrel)
|
||||
msg.addParam("expires",(String(refresh)).c_str());
|
||||
return Engine::dispatch(msg);
|
||||
|
@ -917,10 +957,10 @@ void YIAXDriver::initialize()
|
|||
{
|
||||
Output("Initializing module YIAX");
|
||||
lock();
|
||||
// Load configuration
|
||||
s_cfg = Engine::configFile("yiaxchan");
|
||||
s_cfg.load();
|
||||
/* Load configuration */
|
||||
/* Codec capability */
|
||||
// Codec capabilities
|
||||
m_defaultCodec = 0;
|
||||
m_codecs = 0;
|
||||
u_int32_t fallback = 0;
|
||||
|
@ -931,36 +971,43 @@ void YIAXDriver::initialize()
|
|||
def && DataTranslator::canConvert(IAXFormat::audioData[i].token))) {
|
||||
m_codecs |= IAXFormat::audioData[i].value;
|
||||
fallback = IAXFormat::audioData[i].value;
|
||||
/* Set default (desired) codec */
|
||||
// Set default (desired) codec
|
||||
if (preferred == IAXFormat::audioData[i].token)
|
||||
m_defaultCodec = fallback;
|
||||
}
|
||||
}
|
||||
if (!m_codecs)
|
||||
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)
|
||||
m_defaultCodec = fallback;
|
||||
/* Port */
|
||||
if (s_cfg.getIntValue("general","port"))
|
||||
m_port = s_cfg.getIntValue("general","port");
|
||||
// Port
|
||||
m_port = s_cfg.getIntValue("general","port",4569);
|
||||
unlock();
|
||||
setup();
|
||||
/* We need channels to be dropped on shutdown */
|
||||
// We need channels to be dropped on shutdown
|
||||
installRelay(Halt);
|
||||
installRelay(Route);
|
||||
/* Init IAX engine */
|
||||
int transCount = 16;
|
||||
int retransCount = 5;
|
||||
int retransTime = 500;
|
||||
int maxFullFrameDataLen = 1400;
|
||||
u_int32_t transTimeout = 10;
|
||||
int readThreadCount = 3;
|
||||
// Init IAX engine
|
||||
u_int16_t transListCount = 16;
|
||||
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;
|
||||
if (!m_iaxEngine) {
|
||||
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)
|
||||
|
@ -1046,8 +1093,8 @@ bool YIAXDriver::received(Message& msg, int id)
|
|||
/**
|
||||
* IAXConsumer
|
||||
*/
|
||||
YIAXConsumer::YIAXConsumer(YIAXConnection* conn, const char* format)
|
||||
: DataConsumer(format), m_connection(conn), m_total(0)
|
||||
YIAXConsumer::YIAXConsumer(YIAXConnection* conn, u_int32_t format, const char* formatText)
|
||||
: 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()) {
|
||||
m_total += data.length();
|
||||
if (m_connection->transaction())
|
||||
m_connection->transaction()->sendMedia(data,m_connection->format());
|
||||
m_connection->transaction()->sendMedia(data,m_format);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* YIAXSource
|
||||
*/
|
||||
YIAXSource::YIAXSource(YIAXConnection* conn, const char* format)
|
||||
: DataSource(format), m_connection(conn), m_total(0)
|
||||
YIAXSource::YIAXSource(YIAXConnection* conn, u_int32_t format, const char* formatText)
|
||||
: 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)
|
||||
: Channel(&iplugin,0,transaction->outgoing()),
|
||||
m_iaxEngine(iaxEngine), m_transaction(transaction), m_mutedIn(false), m_mutedOut(false),
|
||||
m_format(iplugin.defaultCodec()), m_capability(iplugin.codecs()), m_hangup(true),
|
||||
m_mutexRefIncreased(true), m_refIncreased(false)
|
||||
m_hangup(true), m_mutexRefIncreased(true), m_refIncreased(false)
|
||||
{
|
||||
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);
|
||||
Message* m = message("chan.startup");
|
||||
m->setParam("direction",status());
|
||||
if (msg) {
|
||||
m_targetid = msg->getValue("id");
|
||||
m_password = msg->getValue("password");
|
||||
m->setParam("caller",msg->getValue("caller"));
|
||||
m->setParam("called",msg->getValue("called"));
|
||||
m->setParam("billid",msg->getValue("billid"));
|
||||
|
@ -1113,11 +1155,11 @@ YIAXConnection::YIAXConnection(YIAXEngine* iaxEngine, IAXTransaction* transactio
|
|||
|
||||
YIAXConnection::~YIAXConnection()
|
||||
{
|
||||
DDebug(this,DebugAll,"YIAXConnection::~YIAXConnection [%p]",this);
|
||||
status("destroyed");
|
||||
setConsumer();
|
||||
setSource();
|
||||
hangup();
|
||||
DDebug(this,DebugAll,"YIAXConnection::~YIAXConnection [%p]",this);
|
||||
}
|
||||
|
||||
void YIAXConnection::callAccept(Message& msg)
|
||||
|
@ -1138,14 +1180,9 @@ 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);
|
||||
if (s == "noauth" && m_transaction && !safeGetRefIncreased()) {
|
||||
Debug(this,DebugAll,"callRejected [%p]. Request authentication",this);
|
||||
String pwd;
|
||||
m_transaction->sendAuth(pwd);
|
||||
if (ref()) {
|
||||
m_refIncreased = true;
|
||||
DDebug(this,DebugInfo,"callRejected [%p]. Authentication requested. Increased references counter",this);
|
||||
}
|
||||
if (m_transaction && (s == "noauth") && safeRefIncrease()) {
|
||||
Debug(this,DebugAll,"callRejected [%p]. Requesting authentication",this);
|
||||
m_transaction->sendAuth(m_password);
|
||||
return;
|
||||
}
|
||||
hangup(reason,true);
|
||||
|
@ -1233,6 +1270,7 @@ void YIAXConnection::handleEvent(IAXEvent* event)
|
|||
case IAXEvent::Dtmf: {
|
||||
Debug(this,DebugAll,"YIAXConnection - DTMF: %c",(char)event->subclass());
|
||||
String dtmf((char)event->subclass());
|
||||
dtmf.toUpper();
|
||||
Message* m = message("chan.dtmf");
|
||||
m->addParam("text",dtmf);
|
||||
Engine::enqueue(m);
|
||||
|
@ -1276,7 +1314,8 @@ void YIAXConnection::handleEvent(IAXEvent* event)
|
|||
Debug(this,DebugAll,"YIAXConnection - REJECT/HANGUP: '%s'",m_reason.c_str());
|
||||
break;
|
||||
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";
|
||||
break;
|
||||
case IAXEvent::Busy:
|
||||
|
@ -1287,13 +1326,11 @@ void YIAXConnection::handleEvent(IAXEvent* event)
|
|||
evAuthRep(event);
|
||||
break;
|
||||
default:
|
||||
// Debug(DebugWarn,"YIAXConnection::handleEvent - Unhandled IAX event. Event type: %u. Frame - Type: %u Subclass: %u",
|
||||
// event->type(),event->frameType(),event->subClass());
|
||||
iplugin.getEngine()->defaultEventHandler(event);
|
||||
if (!m_transaction)
|
||||
event->setFinal();
|
||||
}
|
||||
if (event->final()) {
|
||||
//Debug(DebugWarn,"YIAXConnection::handleEvent - Final event: need deref ?");
|
||||
safeDeref();
|
||||
m_transaction = 0;
|
||||
}
|
||||
|
@ -1302,7 +1339,7 @@ void YIAXConnection::handleEvent(IAXEvent* event)
|
|||
void YIAXConnection::hangup(const char *reason, bool reject)
|
||||
{
|
||||
if (!m_hangup)
|
||||
/* Already done */
|
||||
// Already done
|
||||
return;
|
||||
m_hangup = false;
|
||||
if (!reason)
|
||||
|
@ -1336,6 +1373,10 @@ bool YIAXConnection::route(bool authenticated)
|
|||
}
|
||||
else {
|
||||
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
|
||||
if (m_transaction->username())
|
||||
m->addParam("authname",m_transaction->username());
|
||||
|
@ -1349,47 +1390,53 @@ void YIAXConnection::startAudioIn()
|
|||
{
|
||||
if (getSource())
|
||||
return;
|
||||
const char* formatText = IAXFormat::audioText(m_format);
|
||||
setSource(new YIAXSource(this,formatText));
|
||||
u_int32_t format = 0;
|
||||
if (m_transaction)
|
||||
format = m_transaction->formatIn();
|
||||
const char* formatText = IAXFormat::audioText(format);
|
||||
setSource(new YIAXSource(this,format,formatText));
|
||||
getSource()->deref();
|
||||
DDebug(this,DebugAll,"startAudioIn - Format %u: '%s'",m_format,formatText);
|
||||
DDebug(this,DebugAll,"startAudioIn - Format %u: '%s'",format,formatText);
|
||||
}
|
||||
|
||||
void YIAXConnection::startAudioOut()
|
||||
{
|
||||
if (getConsumer())
|
||||
return;
|
||||
const char* formatText = (char*)IAXFormat::audioText(m_format);
|
||||
setConsumer(new YIAXConsumer(this,formatText));
|
||||
u_int32_t format = 0;
|
||||
if (m_transaction)
|
||||
format = m_transaction->formatOut();
|
||||
const char* formatText = (char*)IAXFormat::audioText(format);
|
||||
setConsumer(new YIAXConsumer(this,format,formatText));
|
||||
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)
|
||||
{
|
||||
DDebug(this,DebugAll,"YIAXConnection - AUTHREP");
|
||||
IAXTransaction* tr = event->getTransaction();
|
||||
/* Try to obtain a password from Engine */
|
||||
// Try to obtain a password from Engine
|
||||
Message msg("user.auth");
|
||||
msg.addParam("username",tr->username());
|
||||
if (!Engine::dispatch(msg)) {
|
||||
/* NOT Authenticated */
|
||||
// NOT Authenticated
|
||||
hangup(event,"",true);
|
||||
return;
|
||||
}
|
||||
String pwd = msg.retValue();
|
||||
if (!pwd.length()) {
|
||||
/* Authenticated */
|
||||
if (pwd.null()) {
|
||||
// Authenticated
|
||||
tr->sendAccept();
|
||||
return;
|
||||
}
|
||||
if (!IAXEngine::isMD5ChallengeCorrect(tr->authdata(),tr->challenge(),pwd)) {
|
||||
/* Incorrect data received */
|
||||
// Incorrect data received
|
||||
DDebug(this,DebugAll,"AUTHREP - Incorrect MD5 answer. Reject.");
|
||||
hangup(event,s_iax_modInvalidAuth,true);
|
||||
hangup(event,IAXTransaction::s_iax_modInvalidAuth,true);
|
||||
return;
|
||||
}
|
||||
/* Password is correct. Route the user. */
|
||||
// Password is correct. Route the user.
|
||||
route(true);
|
||||
}
|
||||
|
||||
|
@ -1403,33 +1450,37 @@ void YIAXConnection::safeDeref()
|
|||
deref();
|
||||
}
|
||||
|
||||
bool YIAXConnection::safeGetRefIncreased()
|
||||
bool YIAXConnection::safeRefIncrease()
|
||||
{
|
||||
Lock lock(&m_mutexRefIncreased);
|
||||
return m_refIncreased;
|
||||
bool ok = false;
|
||||
m_mutexRefIncreased.lock();
|
||||
if (!m_refIncreased && ref())
|
||||
m_refIncreased = ok = true;
|
||||
m_mutexRefIncreased.unlock();
|
||||
return ok;
|
||||
}
|
||||
|
||||
/**
|
||||
* IAXURI
|
||||
*/
|
||||
IAXURI::IAXURI(const char* user, const char* host, const char* calledNo, const char* calledContext, int port)
|
||||
: m_username(user),
|
||||
m_host(host),
|
||||
m_port(port),
|
||||
m_calledNo(calledNo),
|
||||
m_calledContext(calledContext),
|
||||
m_parsed(true)
|
||||
: m_username(user),
|
||||
m_host(host),
|
||||
m_port(port),
|
||||
m_calledNo(calledNo),
|
||||
m_calledContext(calledContext),
|
||||
m_parsed(true)
|
||||
|
||||
{
|
||||
*this << "iax:";
|
||||
if (m_username.length())
|
||||
if (m_username)
|
||||
*this << m_username << "@";
|
||||
*this << m_host;
|
||||
if (m_port)
|
||||
*this << ":" << m_port;
|
||||
if (m_calledNo.length()) {
|
||||
if (m_calledNo) {
|
||||
*this << "/" << m_calledNo;
|
||||
if (m_calledContext.length())
|
||||
if (m_calledContext)
|
||||
*this << "@" << m_calledContext;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue