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
* 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: */

View File

@ -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

View File

@ -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;

View File

@ -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;
}
}