Added support for multiple iax listeners.

git-svn-id: http://yate.null.ro/svn/yate/trunk@5550 acf43c95-373e-0410-b603-e72c3f656dc1
This commit is contained in:
marian 2013-06-20 13:50:39 +00:00
parent b3f76e22c0
commit 5f3ab731e3
7 changed files with 1701 additions and 830 deletions

View File

@ -57,6 +57,11 @@
; server: Registrar address or domain. A port can be specified here (e.g. 1.2.3.4:7999)
; port: Registrar port if not specified in 'server' parameter
; If not set the port defaults to 4569
; connection_id: The name of the iax listener to use for registration
; ip_transport_localip: This parameter is used in conjuction ip_transport_localport
; to identify the listener to use for registration and outgoing calls
; ip_transport_localport: Local port. This parameter is used to identify the listener
; to use for registration and outgoing calls
; trunking: Enable trunking for outgoing calls sent on this line
; The following parameters can also be set (see yiaxchan.conf.sample for more info):
; trunk_timestamps: Configure how trunked audio data is sent, enable it for

View File

@ -15,9 +15,19 @@
; is another call using trunking with the same remote ip/port.
; TAKE CARE WHEN SETTING TRUNKING PARAMETERS IN MORE THEN 1 PLACE FOR THE SAME
; REMOTE IP/PORT !!!
; When routing a call to iax module a specific listener can be specfied:
; 1: Its name can be set in 'oconnection_id' parameter.
; The name of the listener created from 'general' section is 'iaxengine'
; 2: Local ip/port can be specified in 'oip_transport_localip' and
; 'oip_transport_localport'. The port defaults to 4569 if missing.
; If a non empty connection id or local address is specified and a valid listener
; is not found the call will fail
[general]
; This section sets global variables of the implementation
; It also sets the default listener named 'iaxengine'
; Unless specified all parameters are listener specific
; port: int: UDP port for incoming connections
;port=4569
@ -29,6 +39,10 @@
; Defaults to yes
;force_bind=yes
; default: boolean: Specifiy if this is the default transport to use when none specified
; Defaults to yes (unlike the other listeners)
;default=yes
; numtype: string: Default calling number type for outgoing calls
; This parameter is applied on reload
; It can be overridden from routing by 'callernumtype' parameter
@ -126,6 +140,7 @@
;calltoken_in=no
; calltoken_out: boolean: Offer call token ip address authentication on outgoing calls
; This is not a listener specific parameter, it will be applied for all listeners
; This parameter is applied on reload and can be overridden from routing
; Defaults to yes
;calltoken_out=yes
@ -214,6 +229,7 @@
;thread=normal
; maxchans: int: Maximum number of channels running at once
; This is not a listener specific parameter, it will be applied for all listeners
; A value of 0 specifies that there is no limit enforced.
; Defaults to the value set by the maxchans setting from yate.conf
;maxchans=
@ -270,3 +286,29 @@
; lpc10: bool: LPC 10
;lpc10=enable
;[listener listener_name]
; This section configures an extra listener to use
; 'iaxengine' can't be used as listener name
; Listed parameters can't use the default value from 'general' section
; All other parameters from 'general' section who are listener specific can be overriden
; for this listener
; enable: boolean: Enable or disable this listener
; This parameter is applied on reload and defaults to yes
;enable=yes
; port: int: UDP port for incoming connections
;port=4569
; addr: ipaddress: IP address to bind to
;addr=0.0.0.0
; force_bind: boolean: Try to use a random port if failed to bind on configured one
; Defaults to yes
;force_bind=yes
; default: boolean: Specifiy if this is the default transport to use when none specified
; Defaults to no
;default=no

View File

@ -55,15 +55,16 @@ static void buildSecretDigest(String& buf, const String& secret, unsigned int t,
}
IAXEngine::IAXEngine(const char* iface, int port, u_int16_t transListCount,
u_int16_t maxFullFrameDataLen,
u_int32_t format, u_int32_t capab, bool authRequired, NamedList* params)
IAXEngine::IAXEngine(const char* iface, int port, u_int32_t format, u_int32_t capab,
const NamedList* params, const char* name)
: Mutex(true,"IAXEngine"),
m_trunking(0),
m_name(name),
m_lastGetEvIndex(0),
m_authRequired(authRequired),
m_maxFullFrameDataLen(maxFullFrameDataLen),
m_exiting(false),
m_maxFullFrameDataLen(1400),
m_startLocalCallNo(0),
m_transListCount(0),
m_transListCount(64),
m_challengeTout(IAX2_CHALLENGETOUT_DEF),
m_callToken(false),
m_callTokenAge(10),
@ -80,59 +81,29 @@ IAXEngine::IAXEngine(const char* iface, int port, u_int16_t transListCount,
m_mutexTrunk(false,"IAXEngine::Trunk"),
m_trunkInfoMutex(false,"IAXEngine::TrunkInfo")
{
debugName("iaxengine");
debugName(m_name);
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 < transListCount; i++)
m_transList[i] = new ObjList;
m_transListCount = transListCount;
for(i = 0; i <= IAX2_MAX_CALLNO; i++)
m_lUsedCallNo[i] = false;
if (params)
bool forceBind = true;
if (params) {
m_transListCount = params->getIntValue("translist_count",64,4,256);
m_maxFullFrameDataLen = params->getIntValue("maxfullframedatalen",1400,20);
m_callTokenSecret = params->getValue("calltoken_secret");
if (!m_callTokenSecret)
for (i = 0; i < 3; i++)
m_callTokenSecret << (int)(Random::random() ^ Time::now());
m_socket.create(AF_INET,SOCK_DGRAM);
SocketAddr addr(AF_INET);
addr.host(iface);
addr.port(port);
m_socket.setBlocking(false);
bool ok = m_socket.bind(addr);
if (!ok) {
bool force = !params || params->getBoolValue("force_bind",true);
String tmp;
Thread::errorString(tmp,m_socket.error());
Debug(this,DebugWarn,"Failed to bind socket on '%s:%d'%s. %d: '%s'",
c_safe(iface),port,force ? " - trying a random port" : "",
m_socket.error(),tmp.c_str());
if (force) {
addr.port(0);
ok = m_socket.bind(addr);
if (!ok)
Debug(this,DebugWarn,"Failed to bind on any port");
else {
ok = m_socket.getSockName(addr);
if (!ok)
Debug(this,DebugWarn,"Failed to retrieve bound address");
}
}
forceBind = params->getBoolValue("force_bind",true);
}
if (ok)
Debug(this,DebugInfo,"Bound on '%s:%d'",addr.host().c_str(),addr.port());
m_transList = new ObjList*[m_transListCount];
for (unsigned int i = 0; i < m_transListCount; i++)
m_transList[i] = new ObjList;
for(unsigned int i = 0; i <= IAX2_MAX_CALLNO; i++)
m_lUsedCallNo[i] = false;
if (!m_callTokenSecret)
for (unsigned int i = 0; i < 3; i++)
m_callTokenSecret << (int)(Random::random() ^ Time::now());
bind(iface,port,forceBind);
m_startLocalCallNo = 1 + (u_int16_t)(Random::random() % IAX2_MAX_CALLNO);
if (m_startLocalCallNo < IAX2_MIN_CALLNO)
m_startLocalCallNo = IAX2_MIN_CALLNO;
if (params)
initialize(*params);
else
initialize(NamedList::empty());
initialize(params ? *params : NamedList::empty());
}
IAXEngine::~IAXEngine()
@ -178,8 +149,8 @@ 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 incomplete outgoing transaction completed (%u,%u)",
tr->localCallNo(),tr->remoteCallNo());
XDebug(this,DebugAll,"New incomplete outgoing transaction completed (%u,%u) [%p]",
tr->localCallNo(),tr->remoteCallNo(),this);
return tr->processFrame(frame);
}
}
@ -211,6 +182,10 @@ IAXTransaction* IAXEngine::addFrame(const SocketAddr& addr, IAXFrame* frame)
}
}
// Frame doesn't belong to an existing transaction
if (exiting()) {
sendInval(full,addr);
return 0;
}
// Test if it is a full frame with an IAX control message that needs a new transaction
if (!full || frame->type() != IAXFrame::IAX) {
if (full)
@ -221,6 +196,7 @@ IAXTransaction* IAXEngine::addFrame(const SocketAddr& addr, IAXFrame* frame)
case IAXControl::New:
if (!checkCallToken(addr,*full))
return 0;
break;
case IAXControl::RegReq:
case IAXControl::RegRel:
case IAXControl::Poke:
@ -234,12 +210,13 @@ IAXTransaction* IAXEngine::addFrame(const SocketAddr& addr, IAXFrame* frame)
default:
if (full->destCallNo() == 0)
Debug(this,DebugAll,
"Unsupported incoming transaction Frame(%u,%u). Source call no: %u",
frame->type(),full->subclass(),full->sourceCallNo());
"Unsupported incoming transaction Frame(%u,%u). Source call no: %u [%p]",
frame->type(),full->subclass(),full->sourceCallNo(),this);
else
Debug(this,DebugAll,"Unmatched Frame(%u,%u) for (%u,%u)",
frame->type(),full->subclass(),full->destCallNo(),full->sourceCallNo());
sendInval(full,addr);
Debug(this,DebugAll,"Unmatched Frame(%u,%u) for (%u,%u) [%p]",
frame->type(),full->subclass(),full->destCallNo(),
full->sourceCallNo(),this);
sendInval(full,addr);
return 0;
}
// Generate local number
@ -253,8 +230,8 @@ IAXTransaction* IAXEngine::addFrame(const SocketAddr& addr, IAXFrame* frame)
releaseCallNo(lcn);
}
if (!tr)
Debug(this,DebugInfo,"Failed to build incoming transaction for Frame(%u,%u)",
frame->type(),full->subclass());
Debug(this,DebugInfo,"Failed to build incoming transaction for Frame(%u,%u) [%p]",
frame->type(),full->subclass(),this);
return tr;
}
@ -268,7 +245,7 @@ IAXTransaction* IAXEngine::addFrame(const SocketAddr& addr, const unsigned char*
SocketAddr local;
m_socket.getSockName(local);
frame->fullFrame()->toString(s,local,addr,true);
Debug(this,DebugInfo,"Received frame.%s",s.c_str());
Debug(this,DebugInfo,"Received frame [%p]%s",this,s.c_str());
}
IAXTransaction* tr = addFrame(addr,frame);
if (!tr)
@ -297,8 +274,8 @@ void IAXEngine::sendInval(IAXFullFrame* frame, const SocketAddr& addr)
if (frame->type() == IAXFrame::IAX && frame->subclass() == IAXControl::Inval)
return;
DDebug(this,DebugInfo,
"Sending INVAL for unmatched frame(%u,%u) with OSeq=%u ISeq=%u",
frame->type(),frame->subclass(),frame->oSeqNo(),frame->iSeqNo());
"Sending INVAL for unmatched frame(%u,%u) with OSeq=%u ISeq=%u [%p]",
frame->type(),frame->subclass(),frame->oSeqNo(),frame->iSeqNo(),this);
IAXFullFrame* f = new IAXFullFrame(IAXFrame::IAX,IAXControl::Inval,frame->destCallNo(),
frame->sourceCallNo(),frame->iSeqNo(),frame->oSeqNo(),frame->timeStamp());
writeSocket(f->data().data(),f->data().length(),addr,f);
@ -314,8 +291,8 @@ bool IAXEngine::process()
break;
ok = true;
if ((event->final() && !event->frameType()) || !event->getTransaction()) {
XDebug(this,DebugAll,"Deleting internal event type %u Frame(%u,%u)",
event->type(),event->frameType(),event->subclass());
XDebug(this,DebugAll,"Deleting internal event type %u Frame(%u,%u) [%p]",
event->type(),event->frameType(),event->subclass(),this);
delete event;
continue;
}
@ -391,12 +368,12 @@ void IAXEngine::initOutDataAdjust(const NamedList& params, IAXTransaction* tr)
m_adjustTsOutUnderrun = under;
if (adjusted)
Debug(this,DebugConf,
"Adjust ts out set to thres=%u over=%u under=%u from thres=%s over=%s under=%s",
"Adjust ts out set to thres=%u over=%u under=%u from thres=%s over=%s under=%s [%p]",
thres,over,under,TelEngine::c_safe(thresS),
TelEngine::c_safe(overS),TelEngine::c_safe(underS));
TelEngine::c_safe(overS),TelEngine::c_safe(underS),this);
else
Debug(this,DebugAll,"Adjust ts out set to thres=%u over=%u under=%u",
thres,over,under);
Debug(this,DebugAll,"Adjust ts out set to thres=%u over=%u under=%u [%p]",
thres,over,under,this);
}
// (Re)Initialize the engine
@ -421,7 +398,8 @@ void IAXEngine::initialize(const NamedList& params)
#ifdef XDEBUG
String tiS;
m_trunkInfoDef->dump(tiS,"\r\n");
Debug(this,DebugAll,"Initialized trunk info defaults:\r\n-----\r\n%s\r\n-----",tiS.c_str());
Debug(this,DebugAll,"Initialized trunk info defaults: [%p]\r\n-----\r\n%s\r\n-----",
this,tiS.c_str());
#endif
TelEngine::destruct(ti);
}
@ -438,8 +416,8 @@ void IAXEngine::readSocket(SocketAddr& addr)
if (!m_socket.canRetry()) {
String tmp;
Thread::errorString(tmp,m_socket.error());
Debug(this,DebugWarn,"Socket read error: %s (%d)",
tmp.c_str(),m_socket.error());
Debug(this,DebugWarn,"Socket read error: %s (%d) [%p]",
tmp.c_str(),m_socket.error(),this);
}
Thread::idle(false);
continue;
@ -456,22 +434,22 @@ bool IAXEngine::writeSocket(const void* buf, int len, const SocketAddr& addr,
SocketAddr local;
m_socket.getSockName(local);
frame->toString(s,local,addr,false);
Debug(this,DebugInfo,"Sending frame.%s",s.c_str());
Debug(this,DebugInfo,"Sending frame [%p]%s",this,s.c_str());
}
len = m_socket.sendTo(buf,len,addr);
if (len == Socket::socketError()) {
if (!m_socket.canRetry()) {
String tmp;
Thread::errorString(tmp,m_socket.error());
Debug(this,DebugWarn,"Socket write error: %s (%d)",
tmp.c_str(),m_socket.error());
Debug(this,DebugWarn,"Socket write error: %s (%d) [%p]",
tmp.c_str(),m_socket.error(),this);
}
#ifdef DEBUG
else {
String tmp;
Thread::errorString(tmp,m_socket.error());
Debug(this,DebugMild,"Socket temporary unavailable: %s (%d)",
tmp.c_str(),m_socket.error());
Debug(this,DebugMild,"Socket temporary unavailable: %s (%d) [%p]",
tmp.c_str(),m_socket.error(),this);
}
#endif
return false;
@ -499,20 +477,35 @@ void IAXEngine::removeTransaction(IAXTransaction* transaction)
releaseCallNo(transaction->localCallNo());
if (!m_incompleteTransList.remove(transaction,false)) {
if (m_transList[transaction->remoteCallNo() % m_transListCount]->remove(transaction,false)) {
DDebug(this,DebugAll,"Transaction(%u,%u) removed",
transaction->localCallNo(),transaction->remoteCallNo());
DDebug(this,DebugAll,"Transaction(%u,%u) removed [%p]",
transaction->localCallNo(),transaction->remoteCallNo(),this);
}
else {
DDebug(this,DebugAll,"Trying to remove transaction(%u,%u) but does not exist",
transaction->localCallNo(),transaction->remoteCallNo());
DDebug(this,DebugAll,
"Trying to remove transaction(%u,%u) but does not exist [%p]",
transaction->localCallNo(),transaction->remoteCallNo(),this);
}
}
else {
DDebug(this,DebugAll,"Transaction(%u,%u) (incomplete outgoing) removed",
transaction->localCallNo(),transaction->remoteCallNo());
DDebug(this,DebugAll,"Transaction(%u,%u) (incomplete outgoing) removed [%p]",
transaction->localCallNo(),transaction->remoteCallNo(),this);
}
}
// Check if there are any transactions in the engine
bool IAXEngine::haveTransactions()
{
Lock lock(this);
// Incomplete transactions
if (m_incompleteTransList.skipNull())
return true;
// Complete transactions
for (int i = 0; i < m_transListCount; i++)
if (m_transList[i]->skipNull())
return true;
return false;
}
u_int32_t IAXEngine::transactionCount()
{
u_int32_t n = 0;
@ -574,10 +567,10 @@ bool IAXEngine::processTrunkFrames(const Time& time)
continue;
}
Debug(this,DebugAll,
"Removing trunk frame (%p) '%s:%d' timestamps=%s maxlen=%u interval=%ums",
"Removing trunk frame (%p) '%s:%d' timestamps=%s maxlen=%u interval=%ums [%p]",
frame,frame->addr().host().c_str(),frame->addr().port(),
String::boolText(frame->trunkTimestamps()),frame->maxLen(),
frame->sendInterval());
frame->sendInterval(),this);
l->remove();
l = l->skipNull();
}
@ -586,8 +579,8 @@ bool IAXEngine::processTrunkFrames(const Time& time)
void IAXEngine::processEvent(IAXEvent* event)
{
XDebug(this,DebugAll,"Default processing - deleting event %p Subclass %u",
event,event->subclass());
XDebug(this,DebugAll,"Default processing - deleting event %p Subclass %u [%p]",
event,event->subclass(),this);
delete event;
}
@ -655,7 +648,8 @@ u_int16_t IAXEngine::generateCallNo()
m_lUsedCallNo[i] = true;
return i;
}
Debug(this,DebugWarn,"Unable to generate call number. Transaction count: %u",transactionCount());
Debug(this,DebugWarn,"Unable to generate call number. Transaction count: %u [%p]",
transactionCount(),this);
return 0;
}
@ -668,6 +662,8 @@ IAXTransaction* IAXEngine::startLocalTransaction(IAXTransaction::Type type,
const SocketAddr& addr, IAXIEList& ieList, bool refTrans, bool startTrans)
{
Lock lck(this);
if (exiting())
return 0;
u_int16_t lcn = generateCallNo();
if (!lcn)
return 0;
@ -686,11 +682,71 @@ IAXTransaction* IAXEngine::startLocalTransaction(IAXTransaction::Type type,
return tr;
}
// Bind the socket. Terminate it before trying
bool IAXEngine::bind(const char* iface, int port, bool force)
{
if (m_socket.valid())
m_socket.terminate();
m_addr.clear();
if (!m_socket.create(AF_INET,SOCK_DGRAM)) {
String tmp;
Thread::errorString(tmp,m_socket.error());
Debug(this,DebugWarn,"Failed to create socket. %d: '%s' [%p]",
m_socket.error(),tmp.c_str(),this);
return false;
}
if (!m_socket.setBlocking(false)) {
String tmp;
Thread::errorString(tmp,m_socket.error());
Debug(this,DebugWarn,
"Failed to set socket non blocking operation mode. %d: '%s' [%p]",
m_socket.error(),tmp.c_str(),this);
m_socket.terminate();
return false;
}
SocketAddr addr(AF_INET);
addr.host(iface);
addr.port(port ? port : 4569);
bool ok = m_socket.bind(addr);
if (!ok) {
String tmp;
Thread::errorString(tmp,m_socket.error());
Debug(this,DebugWarn,"Failed to bind socket on '%s:%d'%s. %d: '%s' [%p]",
c_safe(iface),port,force ? " - trying a random port" : "",
m_socket.error(),tmp.c_str(),this);
if (force) {
addr.port(0);
ok = m_socket.bind(addr);
if (!ok)
Debug(this,DebugWarn,"Failed to bind on any port for iface='%s' [%p]",
iface,this);
else {
ok = m_socket.getSockName(addr);
if (!ok)
Debug(this,DebugWarn,"Failed to retrieve bound address [%p]",this);
}
}
}
if (!ok) {
m_socket.terminate();
return false;
}
m_addr = addr;
if (!m_addr.host())
m_addr.host("0.0.0.0");
String s;
if (addr.host() != iface && !TelEngine::null(iface))
s << " (" << iface << ")";
Debug(this,DebugInfo,"Bound on '%s:%d'%s [%p]",
m_addr.host().c_str(),m_addr.port(),s.safe(),this);
return true;
}
// Check call token on incoming call requests.
bool IAXEngine::checkCallToken(const SocketAddr& addr, IAXFullFrame& frame)
{
XDebug(this,DebugAll,"IAXEngine::checkCallToken('%s:%d') calltoken=%u",
addr.host().c_str(),addr.port(),m_callToken);
XDebug(this,DebugAll,"IAXEngine::checkCallToken('%s:%d') calltoken=%u [%p]",
addr.host().c_str(),addr.port(),m_callToken,this);
if (!m_callToken)
return true;
frame.updateIEList(true);
@ -702,9 +758,9 @@ bool IAXEngine::checkCallToken(const SocketAddr& addr, IAXFullFrame& frame)
if (!ct) {
if (m_showCallTokenFailures)
Debug(this,DebugNote,
"Missing required %s parameter in call request %u from '%s:%d'",
"Missing required %s parameter in call request %u from '%s:%d' [%p]",
IAXInfoElement::ieText(IAXInfoElement::CALLTOKEN),frame.sourceCallNo(),
addr.host().c_str(),addr.port());
addr.host().c_str(),addr.port(),this);
if (m_rejectMissingCallToken) {
IAXIEList* ies = new IAXIEList;
ies->appendString(IAXInfoElement::CAUSE,"CALLTOKEN support required");
@ -720,15 +776,15 @@ bool IAXEngine::checkCallToken(const SocketAddr& addr, IAXFullFrame& frame)
if (ct->data().length()) {
String tmp((char*)ct->data().data(),ct->data().length());
int age = addrSecretAge(tmp,m_callTokenSecret,addr);
XDebug(this,DebugAll,"Call request %u from '%s:%d' with call token age=%d",
frame.sourceCallNo(),addr.host().c_str(),addr.port(),age);
XDebug(this,DebugAll,"Call request %u from '%s:%d' with call token age=%d [%p]",
frame.sourceCallNo(),addr.host().c_str(),addr.port(),age,this);
if (age >= 0 && age <= m_callTokenAge)
return true;
if (m_showCallTokenFailures)
Debug(this,DebugNote,
"Ignoring call request %u from '%s:%d' with %s call token age=%d",
"Ignoring call request %u from '%s:%d' with %s call token age=%d [%p]",
frame.sourceCallNo(),addr.host().c_str(),addr.port(),
(age > 0) ? "old" : "invalid",age);
(age > 0) ? "old" : "invalid",age,this);
return false;
}
// Request with empty call token: send one
@ -750,8 +806,8 @@ bool IAXEngine::acceptFormatAndCapability(IAXTransaction* trans, unsigned int* c
u_int32_t transCapsNonType = IAXFormat::clear(trans->m_capability,type);
IAXFormat* fmt = trans->getFormat(type);
if (!fmt) {
DDebug(this,DebugStub,"acceptFormatAndCapability() No media %s in transaction",
IAXFormat::typeName(type));
DDebug(this,DebugStub,"acceptFormatAndCapability() No media %s in transaction [%p]",
IAXFormat::typeName(type),this);
trans->m_capability = transCapsNonType;
return false;
}
@ -761,10 +817,10 @@ bool IAXEngine::acceptFormatAndCapability(IAXTransaction* trans, unsigned int* c
capability &= IAXFormat::mask(*caps,type);
trans->m_capability = transCapsNonType | capability;
XDebug(this,DebugAll,
"acceptFormatAndCapability trans(%u,%u) type=%s caps(trans/our/param/result)=%u/%u/%u/%u",
"acceptFormatAndCapability trans(%u,%u) type=%s caps(trans/our/param/result)=%u/%u/%u/%u [%p]",
trans->localCallNo(),trans->remoteCallNo(),
fmt->typeName(),transCapsType,IAXFormat::mask(m_capability,type),
caps ? IAXFormat::mask(*caps,type) : 0,capability);
caps ? IAXFormat::mask(*caps,type) : 0,capability,this);
// Valid capability ?
if (!capability) {
// Warn if we should have media
@ -799,8 +855,9 @@ bool IAXEngine::acceptFormatAndCapability(IAXTransaction* trans, unsigned int* c
void IAXEngine::defaultEventHandler(IAXEvent* event)
{
DDebug(this,DebugAll,"defaultEventHandler - Event type: %u. Frame - Type: %u Subclass: %u",
event->type(),event->frameType(),event->subclass());
DDebug(this,DebugAll,
"defaultEventHandler - Event type: %u. Frame - Type: %u Subclass: %u [%p]",
event->type(),event->frameType(),event->subclass(),this);
IAXTransaction* tr = event->getTransaction();
switch (event->type()) {
case IAXEvent::New:
@ -810,6 +867,13 @@ void IAXEngine::defaultEventHandler(IAXEvent* event)
}
}
// Set the exiting flag
void IAXEngine::setExiting()
{
Lock lck(this);
m_exiting = true;
}
static bool getTrunkingInfo(RefPointer<IAXTrunkInfo>& ti, IAXEngine* engine,
const NamedList* params, const String& prefix, bool out)
{
@ -841,6 +905,12 @@ void IAXEngine::enableTrunking(IAXTransaction* trans, IAXTrunkInfo& data)
if (!trans || trans->type() != IAXTransaction::New)
return;
Lock lock(m_mutexTrunk);
if (m_trunking >= 0) {
m_trunking++;
if (m_trunking == 1 || 0 == ((m_trunking - 1) % 200))
Debug(this,DebugNote,"Failed to enable trunking: not available [%p]",this);
return;
}
IAXMetaTrunkFrame* frame;
// Already enabled ?
for (ObjList* l = m_trunkList.skipNull(); l; l = l->skipNext()) {
@ -855,10 +925,10 @@ void IAXEngine::enableTrunking(IAXTransaction* trans, IAXTrunkInfo& data)
if (trans->enableTrunking(frame,data.m_efficientUse)) {
m_trunkList.append(frame);
Debug(this,DebugAll,
"Added trunk frame (%p) '%s:%d' timestamps=%s maxlen=%u interval=%ums",
"Added trunk frame (%p) '%s:%d' timestamps=%s maxlen=%u interval=%ums [%p]",
frame,frame->addr().host().c_str(),frame->addr().port(),
String::boolText(frame->trunkTimestamps()),frame->maxLen(),
frame->sendInterval());
frame->sendInterval(),this);
}
else
TelEngine::destruct(frame);
@ -886,16 +956,18 @@ void IAXEngine::initTrunkIn(IAXTransaction* trans, IAXTrunkInfo& data)
#ifdef XDEBUG
String tmp;
data.dump(tmp," ",false,true,false);
Debug(this,DebugAll,"initTrunkIn(%p) callno=%u set %s",
trans,trans->localCallNo(),tmp.c_str());
Debug(this,DebugAll,"initTrunkIn(%p) callno=%u set %s [%p]",
trans,trans->localCallNo(),tmp.c_str(),this);
#endif
}
void IAXEngine::runProcessTrunkFrames()
{
while (1) {
if (Thread::check(false))
break;
processTrunkFrames();
Thread::msleep(2,true);
Thread::msleep(2,false);
}
}

View File

@ -94,7 +94,7 @@ const TokenDict IAXInfoElement::s_causeName[] = {
{"congestion", 34}, // No circuit/channel available
{"channel-congestion", 34},
{"net-out-of-order", 38}, // Network out of order
{"noconn", 41},
{"noconn", 38},
{"temporary-failure", 41}, // Temporary failure
{"congestion", 42}, // Switching equipment congestion
{"switch-congestion", 42},
@ -524,7 +524,8 @@ bool IAXIEList::createFromFrame(const IAXFullFrame* frame, bool incoming)
m_invalidIEList = i == 0xFFFF;
if (!m_invalidIEList)
return true;
Debug(DebugWarn,"IAXIEList::createFromFrame. Frame(%u,%u) with invalid IE [%p]",frame->type(),frame->subclass(),frame);
Debug(DebugWarn,"IAXIEList::createFromFrame. Frame(%u,%u) with invalid IE [%p]",
frame->type(),frame->subclass(),frame);
return false;
}

View File

@ -882,6 +882,8 @@ bool IAXTransaction::sendReject(const char* cause, u_int8_t code)
switch (type()) {
case New:
frametype = IAXControl::Reject;
if (TelEngine::null(cause))
cause = 0;
break;
case RegReq:
case RegRel:
@ -896,10 +898,10 @@ bool IAXTransaction::sendReject(const char* cause, u_int8_t code)
default:
return false;
}
Debug(m_engine,DebugAll,"Transaction(%u,%u). Reject cause='%s' [%p]",
localCallNo(),remoteCallNo(),cause,this);
Debug(m_engine,DebugAll,"Transaction(%u,%u). Reject cause='%s' code=%u [%p]",
localCallNo(),remoteCallNo(),cause,code,this);
IAXIEList* ies = new IAXIEList;
if (!TelEngine::null(cause))
if (cause)
ies->appendString(IAXInfoElement::CAUSE,cause);
if (code)
ies->appendNumeric(IAXInfoElement::CAUSECODE,code,1);
@ -1531,7 +1533,8 @@ IAXEvent* IAXTransaction::processAuthReq(IAXEvent* event)
if (bAuthMethod && bChallenge)
return event;
delete event;
return internalReject(s_iax_modNoAuthMethod);
// Code 47: noresource
return internalReject(s_iax_modNoAuthMethod,47);
}
IAXEvent* IAXTransaction::processAccept(IAXEvent* event)
@ -1549,7 +1552,8 @@ IAXEvent* IAXTransaction::processAccept(IAXEvent* event)
if (m_format.format() || m_formatVideo.format())
return event;
delete event;
return internalReject(s_iax_modNoMediaFormat);
// Code 58: nomedia
return internalReject(s_iax_modNoMediaFormat,58);
}
IAXEvent* IAXTransaction::processAuthRep(IAXEvent* event)
@ -1646,7 +1650,8 @@ IAXEvent* IAXTransaction::getEventStartTrans(IAXFullFrame* frame, bool& delFrame
break;
ev = createEvent(IAXEvent::New,false,frame,NewRemoteInvite);
if (!ev->getList().getIE(IAXInfoElement::USERNAME))
return internalReject(s_iax_modNoUsername);
// Code 96: missing-mandatory-ie
return internalReject(s_iax_modNoUsername,96);
init(ev->getList());
return ev;
case Poke:
@ -2033,7 +2038,8 @@ IAXTransaction* IAXTransaction::processMediaFrame(const IAXFullFrame* frame, int
Debug(m_engine,DebugNote,
"IAXTransaction(%u,%u). Received %s frame with unknown format=0x%x [%p]",
localCallNo(),remoteCallNo(),IAXFrame::typeText(frame->type()),recvFmt,this);
m_pendingEvent = internalReject(s_iax_modNoMediaFormat);
// Code 58: nomedia
m_pendingEvent = internalReject(s_iax_modNoMediaFormat,58);
return 0;
}
// We might have an incoming media format received with an Accept frame
@ -2049,7 +2055,8 @@ IAXTransaction* IAXTransaction::processMediaFrame(const IAXFullFrame* frame, int
DDebug(m_engine,DebugAll,
"IAXTransaction(%u,%u). Format change rejected media=%s current=%u [%p]",
localCallNo(),remoteCallNo(),fmt->typeName(),fmt->format(),this);
m_pendingEvent = internalReject(s_iax_modNoMediaFormat);
// Code 58: nomedia
m_pendingEvent = internalReject(s_iax_modNoMediaFormat,58);
return 0;
}
}
@ -2076,11 +2083,12 @@ IAXTransaction* IAXTransaction::retransmitOnVNAK(u_int16_t seqNo)
return 0;
}
IAXEvent* IAXTransaction::internalReject(String& reason)
IAXEvent* IAXTransaction::internalReject(String& reason, u_int8_t code)
{
Debug(m_engine,DebugAll,"Transaction(%u,%u). Internal reject: '%s' [%p]",
localCallNo(),remoteCallNo(),reason.c_str(),this);
sendReject(reason);
Debug(m_engine,DebugAll,
"Transaction(%u,%u). Internal reject cause='%s' code=%u [%p]",
localCallNo(),remoteCallNo(),reason.c_str(),code,this);
sendReject(reason,code);
IAXEvent* event = new IAXEvent(IAXEvent::Reject,true,true,this,IAXFrame::IAX,IAXControl::Reject);
event->getList().appendString(IAXInfoElement::CAUSE,reason);
m_localReqEnd = true;
@ -2130,6 +2138,8 @@ void IAXTransaction::postFrame(IAXFrameOut* frame)
void IAXTransaction::receivedVoiceMiniBeforeFull()
{
if (state() == Terminated || state() == Terminating)
return;
if (m_reqVoiceVNAK > 15)
return;
m_reqVoiceVNAK++;

View File

@ -2576,9 +2576,10 @@ protected:
/**
* Generate a Reject event after internally rejecting a transaction
* @param reason The reason of rejecting
* @param code Error code
* @return A valid IAXEvent
*/
IAXEvent* internalReject(String& reason);
IAXEvent* internalReject(String& reason, u_int8_t code);
/**
* Event terminated feedback
@ -2838,16 +2839,13 @@ public:
* Constructor
* @param iface Address of the interface to use, default all (0.0.0.0)
* @param port UDP port to run the protocol on
* @param transListCount Number of entries in the transaction hash table
* @param maxFullFrameDataLen Max full frame IE list (buffer) length
* @param format Default media format
* @param capab Media capabilities of this engine
* @param authRequired Automatically challenge all clients for authentication
* @param params Optional extra parameter list
* @param name Engine name
*/
IAXEngine(const char* iface, int port, u_int16_t transListCount,
u_int16_t maxFullFrameDataLen, u_int32_t format, u_int32_t capab,
bool authRequired, NamedList* params = 0);
IAXEngine(const char* iface, int port, u_int32_t format, u_int32_t capab,
const NamedList* params = 0, const char* name = "iaxengine");
/**
* Destructor
@ -2855,6 +2853,13 @@ public:
*/
virtual ~IAXEngine();
/**
* Retrieve the engine name
* @return Engine name
*/
inline const String& name() const
{ return m_name; }
/**
* Retrieve the default caller number type
* @return Default caller number type
@ -2914,13 +2919,6 @@ public:
*/
bool process();
/**
* Check if a transaction should automatically request authentication
* @return True to automatically request authentication
*/
inline bool authRequired() const
{ return m_authRequired; }
/**
* Get the timeout interval sent challenge
* @return Sent challenge timeout interval
@ -3016,6 +3014,13 @@ public:
*/
void removeTransaction(IAXTransaction* transaction);
/**
* Check if there are any transactions in the engine
* This method is thread safe
* @return True if the engine holds at least 1 transaction
*/
bool haveTransactions();
/**
* Return the transactions count
* This method is thread safe
@ -3065,6 +3070,18 @@ public:
*/
virtual void defaultEventHandler(IAXEvent* event);
/**
* Check if the engine is exiting
* @return True if the engine is exiting
*/
inline bool exiting() const
{ return m_exiting; }
/**
* Set the exiting flag
*/
virtual void setExiting();
/**
* Enable trunking for the given transaction. Allocate a trunk meta frame if needed.
* Trunk data is ignored if a trunk object for transaction remote address already exists
@ -3129,6 +3146,13 @@ public:
inline Socket& socket()
{ return m_socket; }
/**
* Retrieve the socket address on wgich we are bound
* @return Local address we are bound on
*/
inline const SocketAddr& addr() const
{ return m_addr; }
/**
* Send engine formats
* @param caps Capabilities
@ -3141,6 +3165,15 @@ public:
m_capability = caps;
}
/**
* Retrieve a port parameter
* @param params Parameters list
* @param param Parameter to retrieve
* @return The port (default, 4569, if the parameter is missing or invalid)
*/
static inline int getPort(const NamedList& params, const String& param = "port")
{ return params.getIntValue(param,4569); }
/**
* Get the MD5 data from a challenge and a password
* @param md5data Destination String
@ -3211,7 +3244,8 @@ public:
* @param nRetrans The number of retransmissions
* @return The overall timeout
*/
static unsigned int overallTout(unsigned int interval, unsigned int nRetrans);
static unsigned int overallTout(unsigned int interval = IAX2_RETRANS_INTERVAL_DEF,
unsigned int nRetrans = IAX2_RETRANS_COUNT_DEF);
protected:
/**
@ -3262,14 +3296,27 @@ protected:
const SocketAddr& addr, IAXIEList& ieList,
bool refTrans = false, bool startTrans = true);
/**
* Bind the socket. Terminate it before trying
* @param iface Address of the interface to use, default all (0.0.0.0)
* @param port UDP port to run the protocol on
* @param force Force binding if failed on required port
* @return True on success
*/
bool bind(const char* iface, int port, bool force);
int m_trunking; // Trunking capability: negative: ok, otherwise: not enabled
private:
String m_name; // Engine name
Socket m_socket; // Socket
SocketAddr m_addr; // Address we are bound on
ObjList** m_transList; // Full transactions
ObjList m_incompleteTransList; // Incomplete transactions (no remote call number)
bool m_lUsedCallNo[IAX2_MAX_CALLNO + 1]; // Used local call numnmbers flags
int m_lastGetEvIndex; // getEvent: keep last array entry
bool m_exiting; // Exiting flag
// Parameters
bool m_authRequired; // Automatically request authentication
int m_maxFullFrameDataLen; // Max full frame data (IE list) length
u_int16_t m_startLocalCallNo; // Start index of local call number allocation
u_int16_t m_transListCount; // m_transList count

File diff suppressed because it is too large Load Diff