diff --git a/conf.d/yiaxchan.conf.sample b/conf.d/yiaxchan.conf.sample index 271bce35..2aea3f92 100644 --- a/conf.d/yiaxchan.conf.sample +++ b/conf.d/yiaxchan.conf.sample @@ -7,6 +7,10 @@ ; 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 + ; tos: keyword: Type Of Service to set in outgoing UDP packets ; numeric TOS value or: lowdelay, throughput, reliability, mincost ;tos=0 diff --git a/libs/yiax/engine.cpp b/libs/yiax/engine.cpp index ffb250b4..098ab153 100644 --- a/libs/yiax/engine.cpp +++ b/libs/yiax/engine.cpp @@ -32,7 +32,8 @@ using namespace TelEngine; IAXEngine::IAXEngine(const char* iface, 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, u_int32_t trunkSendInterval, bool authRequired) + u_int32_t format, u_int32_t capab, u_int32_t trunkSendInterval, bool authRequired, + NamedList* params) : Mutex(true,"IAXEngine"), m_lastGetEvIndex(0), m_authRequired(authRequired), @@ -69,8 +70,28 @@ IAXEngine::IAXEngine(const char* iface, int port, u_int16_t transListCount, u_in addr.host(iface); addr.port(port); m_socket.setBlocking(false); - if (!m_socket.bind(addr)) - Debug(this,DebugWarn,"Failed to bind socket to %s:%d",c_safe(iface),port); + 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"); + } + } + } + if (ok) + Debug(this,DebugInfo,"Bound on '%s:%d'",addr.host().c_str(),addr.port()); m_startLocalCallNo = 1 + (u_int16_t)(Random::random() % IAX2_MAX_CALLNO); } @@ -219,9 +240,12 @@ void IAXEngine::readSocket(SocketAddr& addr) while (1) { int len = m_socket.recvFrom(buf,sizeof(buf),addr); if (len == Socket::socketError()) { - if (!m_socket.canRetry()) + if (!m_socket.canRetry()) { + String tmp; + Thread::errorString(tmp,m_socket.error()); Debug(this,DebugWarn,"Socket read error: %s (%d)", - ::strerror(m_socket.error()),m_socket.error()); + tmp.c_str(),m_socket.error()); + } Thread::idle(true); continue; } @@ -240,9 +264,12 @@ bool IAXEngine::writeSocket(const void* buf, int len, const SocketAddr& addr, IA } len = m_socket.sendTo(buf,len,addr); if (len == Socket::socketError()) { - if (!m_socket.canRetry()) + if (!m_socket.canRetry()) { + String tmp; + Thread::errorString(tmp,m_socket.error()); Debug(this,DebugWarn,"Socket write error: %s (%d)", - ::strerror(m_socket.error()),m_socket.error()); + tmp.c_str(),m_socket.error()); + } #ifdef DEBUG else Debug(this,DebugMild,"Socket temporary unavailable: %s (%d)", diff --git a/libs/yiax/yateiax.h b/libs/yiax/yateiax.h index e5e2e960..8c473934 100644 --- a/libs/yiax/yateiax.h +++ b/libs/yiax/yateiax.h @@ -2036,10 +2036,12 @@ public: * @param capab Media capabilities of this engine * @param trunkSendInterval Send trunk meta frame interval * @param authRequired Automatically challenge all clients for authentication + * @param params Optional extra parameter list */ IAXEngine(const char* iface, 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, u_int32_t trunkSendInterval, bool authRequired); + u_int32_t format, u_int32_t capab, u_int32_t trunkSendInterval, bool authRequired, + NamedList* params = 0); /** * Destructor diff --git a/modules/yiaxchan.cpp b/modules/yiaxchan.cpp index e698e09a..74f726aa 100644 --- a/modules/yiaxchan.cpp +++ b/modules/yiaxchan.cpp @@ -263,7 +263,8 @@ public: */ YIAXEngine(const char* iface, 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 trunkSendInterval, bool authRequired); + u_int16_t maxFullFrameDataLen, u_int32_t trunkSendInterval, bool authRequired, + NamedList* params); virtual ~YIAXEngine() {} @@ -944,10 +945,10 @@ void YIAXTrunking::run() YIAXEngine::YIAXEngine(const char* iface, 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 trunkSendInterval, bool authRequired) + u_int32_t trunkSendInterval, bool authRequired, NamedList* params) : IAXEngine(iface,port,transListCount,retransCount,retransInterval,authTimeout, transTimeout,maxFullFrameDataLen,iplugin.defaultCodec(),iplugin.codecs(), - trunkSendInterval,authRequired), + trunkSendInterval,authRequired,params), m_threadsCreated(false) { } @@ -1250,7 +1251,7 @@ void YIAXDriver::initialize() String iface = s_cfg.getValue("general","addr"); bool authReq = s_cfg.getBoolValue("registrar","auth_required",true); m_iaxEngine = new YIAXEngine(iface,m_port,transListCount,retransCount,retransInterval,authTimeout, - transTimeout,maxFullFrameDataLen,trunkSendInterval,authReq); + transTimeout,maxFullFrameDataLen,trunkSendInterval,authReq,s_cfg.getSection("general")); m_iaxEngine->debugChain(this); int tos = s_cfg.getIntValue("general","tos",dict_tos,0); if (tos && !m_iaxEngine->socket().setTOS(tos))