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:
parent
b3f76e22c0
commit
5f3ab731e3
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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++;
|
||||
|
|
|
@ -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
|
||||
|
|
2078
modules/yiaxchan.cpp
2078
modules/yiaxchan.cpp
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue