Added support for call token IAX extension. The frame is now keeping its own IE list to avoid parsing it again.
git-svn-id: http://voip.null.ro/svn/yate@4480 acf43c95-373e-0410-b603-e72c3f656dc1
This commit is contained in:
parent
253c8006af
commit
8503442db4
|
@ -11,6 +11,25 @@
|
|||
; Defaults to yes
|
||||
;force_bind=yes
|
||||
|
||||
; calltoken_in: boolean: Use call token ip address authentication on incoming calls
|
||||
; Note: If the caller don't support the call token IAX extension the call request
|
||||
; will be ignored anyway
|
||||
; This parameter is applied on reload
|
||||
; Defaults to no
|
||||
;calltoken_in=no
|
||||
|
||||
; calltoken_out: boolean: Offer call token ip address authentication on outgoing calls
|
||||
; This parameter is applied on reload and can be overridden from routing
|
||||
; Defaults to yes
|
||||
;calltoken_out=yes
|
||||
|
||||
; calltoken_rejectmissing: boolean: Reject incoming calls without call token support
|
||||
; when calltoken_in is enabled
|
||||
; If disabled the requests will be ignored (dropped)
|
||||
; This parameter is applied on reload
|
||||
; Defaults to yes
|
||||
;calltoken_rejectmissing=yes
|
||||
|
||||
; tos: keyword: Type Of Service to set in outgoing UDP packets
|
||||
; numeric TOS value or: lowdelay, throughput, reliability, mincost
|
||||
;tos=0
|
||||
|
@ -29,6 +48,11 @@
|
|||
; It is a bad idea to set a low priority for anything but testing
|
||||
;thread=normal
|
||||
|
||||
; printmsg: boolean: Print sent/received frames to output if the module's debug
|
||||
; level is at least 9
|
||||
; This parameter is applied on reload
|
||||
; Defaults to yes
|
||||
;printmsg=yes
|
||||
|
||||
[formats]
|
||||
; This section allows to individually enable or disable the codecs
|
||||
|
|
|
@ -30,6 +30,25 @@
|
|||
|
||||
using namespace TelEngine;
|
||||
|
||||
// Local call number to set when rejecting calls with missing call token
|
||||
#define IAX2_CALLTOKEN_REJ_CALLNO 1
|
||||
// Local call number to set when sending call token message
|
||||
#define IAX2_CALLTOKEN_CALLNO 1
|
||||
// Minimum value for local call numbers
|
||||
#define IAX2_MIN_CALLNO 2
|
||||
|
||||
// Build an MD5 digest from secret, address, integer value and engine run id
|
||||
// MD5(addr.host() + secret + addr.port() + t)
|
||||
static void buildSecretDigest(String& buf, const String& secret, unsigned int t,
|
||||
const SocketAddr& addr)
|
||||
{
|
||||
String tmp;
|
||||
tmp << addr.host() << secret << addr.port() << t;
|
||||
MD5 md5(tmp);
|
||||
buf << md5.hexDigest();
|
||||
}
|
||||
|
||||
|
||||
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,
|
||||
|
@ -44,6 +63,10 @@ IAXEngine::IAXEngine(const char* iface, int port, u_int16_t transListCount, u_in
|
|||
m_retransInterval(retransInterval),
|
||||
m_authTimeout(authTimeout),
|
||||
m_transTimeout(transTimeout),
|
||||
m_callToken(false),
|
||||
m_callTokenAge(10),
|
||||
m_showCallTokenFailures(false),
|
||||
m_printMsg(true),
|
||||
m_format(format),
|
||||
m_capability(capab),
|
||||
m_mutexTrunk(true,"IAXEngine::Trunk"),
|
||||
|
@ -65,6 +88,11 @@ IAXEngine::IAXEngine(const char* iface, int port, u_int16_t transListCount, u_in
|
|||
m_transListCount = transListCount;
|
||||
for(i = 0; i <= IAX2_MAX_CALLNO; i++)
|
||||
m_lUsedCallNo[i] = false;
|
||||
if (params)
|
||||
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);
|
||||
|
@ -93,6 +121,12 @@ IAXEngine::IAXEngine(const char* iface, int port, u_int16_t transListCount, u_in
|
|||
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);
|
||||
if (m_startLocalCallNo < IAX2_MIN_CALLNO)
|
||||
m_startLocalCallNo = IAX2_MIN_CALLNO;
|
||||
if (params)
|
||||
initialize(*params);
|
||||
else
|
||||
initialize(NamedList::empty());
|
||||
}
|
||||
|
||||
IAXEngine::~IAXEngine()
|
||||
|
@ -111,12 +145,29 @@ IAXTransaction* IAXEngine::addFrame(const SocketAddr& addr, IAXFrame* frame)
|
|||
Lock lock(this);
|
||||
// Transaction exists for this frame?
|
||||
// Incomplete transactions. They MUST receive a full frame
|
||||
if (frame->fullFrame()) {
|
||||
IAXFullFrame* fullFrame = frame->fullFrame();
|
||||
if (fullFrame) {
|
||||
l = m_incompleteTransList.skipNull();
|
||||
for (; l; l = l->next()) {
|
||||
tr = static_cast<IAXTransaction*>(l->get());
|
||||
if (!(tr && tr->localCallNo() == frame->fullFrame()->destCallNo() && addr == tr->remoteAddr()))
|
||||
if (!(tr && tr->localCallNo() == fullFrame->destCallNo() && addr == tr->remoteAddr()))
|
||||
continue;
|
||||
// Incomplete outgoing receiving call token
|
||||
if (fullFrame->type() == IAXFrame::IAX &&
|
||||
fullFrame->subclass() == IAXControl::CallToken) {
|
||||
RefPointer<IAXTransaction> t = tr;
|
||||
lock.drop();
|
||||
if (!t)
|
||||
return 0;
|
||||
fullFrame->updateIEList(true);
|
||||
IAXIEList* list = fullFrame->ieList();
|
||||
DataBlock db;
|
||||
if (list)
|
||||
list->getBinary(IAXInfoElement::CALLTOKEN,db);
|
||||
t->processCallToken(db);
|
||||
t = 0;
|
||||
return 0;
|
||||
}
|
||||
// Complete transaction
|
||||
if (tr->processFrame(frame)) {
|
||||
tr->m_rCallNo = frame->sourceCallNo();
|
||||
|
@ -136,7 +187,7 @@ IAXTransaction* IAXEngine::addFrame(const SocketAddr& addr, IAXFrame* frame)
|
|||
if (!(tr && tr->remoteCallNo() == frame->sourceCallNo()))
|
||||
continue;
|
||||
// Mini frame
|
||||
if (!frame->fullFrame()) {
|
||||
if (!fullFrame) {
|
||||
if (addr == tr->remoteAddr()) {
|
||||
// keep transaction referenced but unlock the engine
|
||||
RefPointer<IAXTransaction> t = tr;
|
||||
|
@ -147,7 +198,7 @@ IAXTransaction* IAXEngine::addFrame(const SocketAddr& addr, IAXFrame* frame)
|
|||
}
|
||||
// Full frame
|
||||
// Has a local number assigned? If not, test socket
|
||||
if ((frame->fullFrame())->destCallNo() || addr == tr->remoteAddr()) {
|
||||
if (fullFrame->destCallNo() || addr == tr->remoteAddr()) {
|
||||
// keep transaction referenced but unlock the engine
|
||||
RefPointer<IAXTransaction> t = tr;
|
||||
lock.drop();
|
||||
|
@ -156,10 +207,12 @@ IAXTransaction* IAXEngine::addFrame(const SocketAddr& addr, IAXFrame* frame)
|
|||
}
|
||||
// Frame doesn't belong to an existing transaction
|
||||
// Test if it is a full frame with an IAX control message that needs a new transaction
|
||||
if (!frame->fullFrame() || frame->type() != IAXFrame::IAX)
|
||||
if (!fullFrame || frame->type() != IAXFrame::IAX)
|
||||
return 0;
|
||||
switch (frame->fullFrame()->subclass()) {
|
||||
switch (fullFrame->subclass()) {
|
||||
case IAXControl::New:
|
||||
if (!checkCallToken(addr,*fullFrame))
|
||||
return 0;
|
||||
case IAXControl::RegReq:
|
||||
case IAXControl::RegRel:
|
||||
case IAXControl::Poke:
|
||||
|
@ -170,14 +223,14 @@ IAXTransaction* IAXEngine::addFrame(const SocketAddr& addr, IAXFrame* frame)
|
|||
case IAXControl::FwDownl:
|
||||
default:
|
||||
#ifdef DEBUG
|
||||
if (frame->fullFrame()) {
|
||||
if (frame->fullFrame()->destCallNo() == 0)
|
||||
if (fullFrame) {
|
||||
if (fullFrame->destCallNo() == 0)
|
||||
Debug(this,DebugAll,"Unsupported incoming transaction Frame(%u,%u). Source call no: %u",
|
||||
frame->type(),frame->fullFrame()->subclass(),frame->fullFrame()->sourceCallNo());
|
||||
frame->type(),fullFrame->subclass(),fullFrame->sourceCallNo());
|
||||
#ifdef XDEBUG
|
||||
else
|
||||
Debug(this,DebugAll,"Unmatched Frame(%u,%u) for (%u,%u)",
|
||||
frame->type(),frame->fullFrame()->subclass(),frame->fullFrame()->destCallNo(),frame->fullFrame()->sourceCallNo());
|
||||
frame->type(),fullFrame->subclass(),fullFrame->destCallNo(),fullFrame->sourceCallNo());
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
@ -188,7 +241,7 @@ IAXTransaction* IAXEngine::addFrame(const SocketAddr& addr, IAXFrame* frame)
|
|||
if (!lcn)
|
||||
return 0;
|
||||
// Create and add transaction
|
||||
tr = IAXTransaction::factoryIn(this,(IAXFullFrame*)frame->fullFrame(),lcn,addr);
|
||||
tr = IAXTransaction::factoryIn(this,fullFrame,lcn,addr);
|
||||
if (tr)
|
||||
m_transList[frame->sourceCallNo() % m_transListCount]->append(tr);
|
||||
else
|
||||
|
@ -201,7 +254,7 @@ IAXTransaction* IAXEngine::addFrame(const SocketAddr& addr, const unsigned char*
|
|||
IAXFrame* frame = IAXFrame::parse(buf,len,this,&addr);
|
||||
if (!frame)
|
||||
return 0;
|
||||
if (frame->fullFrame() && debugAt(DebugAll)) {
|
||||
if (m_printMsg && frame->fullFrame() && debugAt(DebugInfo)) {
|
||||
String s;
|
||||
SocketAddr local;
|
||||
m_socket.getSockName(local);
|
||||
|
@ -233,6 +286,20 @@ bool IAXEngine::process()
|
|||
return ok;
|
||||
}
|
||||
|
||||
// (Re)Initialize the engine
|
||||
void IAXEngine::initialize(const NamedList& params)
|
||||
{
|
||||
m_callToken = params.getBoolValue("calltoken_in");
|
||||
int callTokenAge = params.getIntValue("calltoken_age",10);
|
||||
if (callTokenAge > 1 && callTokenAge < 25)
|
||||
m_callTokenAge = callTokenAge;
|
||||
else
|
||||
m_callTokenAge = 10;
|
||||
m_showCallTokenFailures = params.getBoolValue("calltoken_printfailure");
|
||||
m_rejectMissingCallToken = params.getBoolValue("calltoken_rejectmissing",true);
|
||||
m_printMsg = params.getBoolValue("printmsg",true);
|
||||
}
|
||||
|
||||
void IAXEngine::readSocket(SocketAddr& addr)
|
||||
{
|
||||
unsigned char buf[1500];
|
||||
|
@ -255,7 +322,7 @@ void IAXEngine::readSocket(SocketAddr& addr)
|
|||
|
||||
bool IAXEngine::writeSocket(const void* buf, int len, const SocketAddr& addr, IAXFullFrame* frame)
|
||||
{
|
||||
if (frame && debugAt(DebugAll)) {
|
||||
if (m_printMsg && frame && debugAt(DebugInfo)) {
|
||||
String s;
|
||||
SocketAddr local;
|
||||
m_socket.getSockName(local);
|
||||
|
@ -412,13 +479,13 @@ u_int16_t IAXEngine::generateCallNo()
|
|||
|
||||
m_startLocalCallNo++;
|
||||
if (m_startLocalCallNo > IAX2_MAX_CALLNO)
|
||||
m_startLocalCallNo = 1;
|
||||
m_startLocalCallNo = IAX2_MIN_CALLNO;
|
||||
for (i = m_startLocalCallNo; i <= IAX2_MAX_CALLNO; i++)
|
||||
if (!m_lUsedCallNo[i]) {
|
||||
m_lUsedCallNo[i] = true;
|
||||
return i;
|
||||
}
|
||||
for (i = 1; i < m_startLocalCallNo; i++)
|
||||
for (i = IAX2_MIN_CALLNO; i < m_startLocalCallNo; i++)
|
||||
if (!m_lUsedCallNo[i]) {
|
||||
m_lUsedCallNo[i] = true;
|
||||
return i;
|
||||
|
@ -449,6 +516,63 @@ IAXTransaction* IAXEngine::startLocalTransaction(IAXTransaction::Type type, cons
|
|||
return tr;
|
||||
}
|
||||
|
||||
// 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);
|
||||
if (!m_callToken)
|
||||
return true;
|
||||
frame.updateIEList(true);
|
||||
IAXIEList* list = frame.ieList();
|
||||
IAXInfoElementBinary* ct = 0;
|
||||
if (list)
|
||||
ct = static_cast<IAXInfoElementBinary*>(list->getIE(IAXInfoElement::CALLTOKEN));
|
||||
// No call token support
|
||||
if (!ct) {
|
||||
if (m_showCallTokenFailures)
|
||||
Debug(this,DebugNote,
|
||||
"Missing required %s parameter in call request %u from '%s:%d'",
|
||||
IAXInfoElement::ieText(IAXInfoElement::CALLTOKEN),frame.sourceCallNo(),
|
||||
addr.host().c_str(),addr.port());
|
||||
if (m_rejectMissingCallToken) {
|
||||
IAXIEList* ies = new IAXIEList;
|
||||
ies->appendString(IAXInfoElement::CAUSE,"CALLTOKEN support required");
|
||||
IAXFullFrame* rsp = new IAXFullFrame(IAXFrame::IAX,IAXControl::Reject,
|
||||
IAX2_CALLTOKEN_REJ_CALLNO,frame.sourceCallNo(),0,1,2,
|
||||
ies,maxFullFrameDataLen());
|
||||
writeSocket(addr,rsp);
|
||||
TelEngine::destruct(rsp);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// Request with call token
|
||||
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);
|
||||
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",
|
||||
frame.sourceCallNo(),addr.host().c_str(),addr.port(),
|
||||
(age > 0) ? "old" : "invalid",age);
|
||||
return false;
|
||||
}
|
||||
// Request with empty call token: send one
|
||||
String tmp;
|
||||
buildAddrSecret(tmp,m_callTokenSecret,addr);
|
||||
IAXIEList* ies = new IAXIEList;
|
||||
ies->appendBinary(IAXInfoElement::CALLTOKEN,(unsigned char*)tmp.c_str(),tmp.length());
|
||||
IAXFullFrame* rsp = new IAXFullFrame(IAXFrame::IAX,IAXControl::CallToken,
|
||||
IAX2_CALLTOKEN_CALLNO,frame.sourceCallNo(),0,1,1,ies,maxFullFrameDataLen());
|
||||
writeSocket(addr,rsp);
|
||||
TelEngine::destruct(rsp);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IAXEngine::acceptFormatAndCapability(IAXTransaction* trans)
|
||||
{
|
||||
if (!trans)
|
||||
|
@ -567,27 +691,52 @@ bool IAXEngine::isMD5ChallengeCorrect(const String& md5data, const String& chall
|
|||
return md5data == md5.hexDigest();
|
||||
}
|
||||
|
||||
// Build a time signed secret used to authenticate an IP address
|
||||
void IAXEngine::buildAddrSecret(String& buf, const String& secret, const SocketAddr& addr)
|
||||
{
|
||||
unsigned int t = Time::secNow();
|
||||
buildSecretDigest(buf,secret,t,addr);
|
||||
buf << "." << t;
|
||||
}
|
||||
|
||||
// Decode a secret built using buildAddrSecret()
|
||||
int IAXEngine::addrSecretAge(const String& buf, const String& secret, const SocketAddr& addr)
|
||||
{
|
||||
int pos = buf.find('.');
|
||||
if (pos < 1)
|
||||
return -1;
|
||||
int t = buf.substr(pos + 1).toInteger();
|
||||
String tmp;
|
||||
buildSecretDigest(tmp,secret,t,addr);
|
||||
return (tmp == buf.substr(0,pos)) ? (Time::secNow() - t) : -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* IAXEvent
|
||||
*/
|
||||
IAXEvent::IAXEvent(Type type, bool local, bool final, IAXTransaction* transaction, u_int8_t frameType, u_int32_t subclass)
|
||||
: m_type(type), m_frameType(frameType), m_subClass(subclass), m_local(local), m_final(final), m_transaction(0)
|
||||
|
||||
: m_type(type), m_frameType(frameType), m_subClass(subclass),
|
||||
m_local(local), m_final(final), m_transaction(0), m_ieList(0)
|
||||
{
|
||||
if (transaction && transaction->ref())
|
||||
m_transaction = transaction;
|
||||
m_ieList = new IAXIEList;
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
IAXEvent::IAXEvent(Type type, bool local, bool final, IAXTransaction* transaction, IAXFullFrame* frame)
|
||||
: m_type(type), m_frameType(0), m_subClass(0), m_local(local),
|
||||
m_final(final), m_transaction(0), m_ieList(0)
|
||||
{
|
||||
if (transaction && transaction->ref())
|
||||
m_transaction = transaction;
|
||||
if (frame) {
|
||||
m_frameType = frame->type();
|
||||
m_subClass = frame->subclass();
|
||||
frame->updateIEList(true);
|
||||
m_ieList = frame->removeIEList(false);
|
||||
}
|
||||
if (!m_ieList)
|
||||
m_ieList = new IAXIEList;
|
||||
}
|
||||
|
||||
IAXEvent::~IAXEvent()
|
||||
|
@ -598,6 +747,8 @@ IAXEvent::~IAXEvent()
|
|||
m_transaction->eventTerminated(this);
|
||||
m_transaction->deref();
|
||||
}
|
||||
if (m_ieList)
|
||||
delete m_ieList;
|
||||
}
|
||||
|
||||
/* vi: set ts=8 sw=4 sts=4 noet: */
|
||||
|
|
|
@ -101,6 +101,7 @@ TokenDict IAXInfoElement::s_ieData[] = {
|
|||
{"RR_DELAY", RR_DELAY},
|
||||
{"RR_DROPPED", RR_DROPPED},
|
||||
{"RR_OOO", RR_OOO},
|
||||
{"CALLTOKEN", CALLTOKEN},
|
||||
{0,0}
|
||||
};
|
||||
|
||||
|
@ -186,7 +187,11 @@ void IAXInfoElementBinary::toBuffer(DataBlock& buf)
|
|||
|
||||
void IAXInfoElementBinary::toString(String& buf)
|
||||
{
|
||||
buf << "Binary data";
|
||||
if (!m_data.length())
|
||||
return;
|
||||
String tmp;
|
||||
tmp.hexify(m_data.data(),m_data.length(),' ');
|
||||
buf << tmp;
|
||||
}
|
||||
|
||||
IAXInfoElementBinary* IAXInfoElementBinary::packIP(const SocketAddr& addr)
|
||||
|
@ -206,6 +211,25 @@ bool IAXInfoElementBinary::unpackIP(SocketAddr& addr, IAXInfoElementBinary* ie)
|
|||
/*
|
||||
* IAXIEList
|
||||
*/
|
||||
IAXIEList::IAXIEList()
|
||||
: m_invalidIEList(false)
|
||||
{
|
||||
XDebug(DebugInfo,"IAXIEList::IAXIEList() [%p]",this);
|
||||
}
|
||||
|
||||
IAXIEList::IAXIEList(const IAXFullFrame* frame, bool incoming)
|
||||
: m_invalidIEList(false)
|
||||
{
|
||||
XDebug(DebugInfo,"IAXIEList::IAXIEList(%p,%u) [%p]",frame,incoming,this);
|
||||
if (frame)
|
||||
createFromFrame(frame,incoming);
|
||||
}
|
||||
|
||||
IAXIEList::~IAXIEList()
|
||||
{
|
||||
XDebug(DebugInfo,"IAXIEList::~IAXIEList() [%p]",this);
|
||||
}
|
||||
|
||||
void IAXIEList::insertVersion()
|
||||
{
|
||||
if (!getIE(IAXInfoElement::VERSION))
|
||||
|
@ -282,6 +306,7 @@ bool IAXIEList::createFromFrame(const IAXFullFrame* frame, bool incoming)
|
|||
case IAXInfoElement::SERVICEIDENT: // Length must be 6
|
||||
case IAXInfoElement::FWBLOCKDATA: // Length can be 0
|
||||
case IAXInfoElement::ENKEY:
|
||||
case IAXInfoElement::CALLTOKEN:
|
||||
if (data[i-1] == IAXInfoElement::SERVICEIDENT && data[i] != 6) {
|
||||
i = 0xFFFF;
|
||||
break;
|
||||
|
@ -353,9 +378,10 @@ bool IAXIEList::createFromFrame(const IAXFullFrame* frame, bool incoming)
|
|||
i += 1;
|
||||
break;
|
||||
default:
|
||||
Debug(DebugWarn,"IAXIEList::createFromFrame. Frame(%u,%u) with unknown IE identifier %u [%p]",
|
||||
Debug(DebugInfo,"IAX Frame(%u,%u) with unknown IE identifier %u [%p]",
|
||||
frame->type(),frame->subclass(),data[i-1],frame);
|
||||
i = 0xFFFF;
|
||||
appendBinary((IAXInfoElement::Type)data[i-1],data+i+1,data[i]);
|
||||
i += data[i] + 1;
|
||||
}
|
||||
if (i == 0xFFFF)
|
||||
break;
|
||||
|
@ -393,7 +419,15 @@ void IAXIEList::toString(String& dest, const char* indent)
|
|||
ie->toString(dest);
|
||||
continue;
|
||||
}
|
||||
dest << IAXInfoElement::ieText(ie->type());
|
||||
const char* name = IAXInfoElement::ieText(ie->type());
|
||||
if (name)
|
||||
dest << name;
|
||||
else {
|
||||
u_int8_t t = ie->type();
|
||||
String tmp;
|
||||
tmp.hexify(&t,1);
|
||||
dest << "0x" << tmp;
|
||||
}
|
||||
if (ie->type() != IAXInfoElement::AUTOANSWER)
|
||||
dest << ": ";
|
||||
switch (ie->type()) {
|
||||
|
@ -436,6 +470,7 @@ void IAXIEList::toString(String& dest, const char* indent)
|
|||
case IAXInfoElement::SERVICEIDENT:
|
||||
case IAXInfoElement::FWBLOCKDATA:
|
||||
case IAXInfoElement::ENKEY:
|
||||
case IAXInfoElement::CALLTOKEN:
|
||||
ie->toString(dest);
|
||||
break;
|
||||
// 4 bytes
|
||||
|
@ -510,6 +545,7 @@ void IAXIEList::toString(String& dest, const char* indent)
|
|||
case IAXInfoElement::AUTOANSWER:
|
||||
break;
|
||||
default: ;
|
||||
ie->toString(dest);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -660,6 +696,7 @@ TokenDict IAXControl::s_types[] = {
|
|||
{"PROVISION", Provision},
|
||||
{"FWDOWNL", FwDownl},
|
||||
{"FWDATA", FwData},
|
||||
{"CALLTOKEN", CallToken},
|
||||
{0,0}
|
||||
};
|
||||
|
||||
|
@ -818,7 +855,7 @@ u_int32_t IAXFrame::unpackSubclass(u_int8_t value)
|
|||
return value;
|
||||
}
|
||||
|
||||
const IAXFullFrame* IAXFrame::fullFrame() const
|
||||
IAXFullFrame* IAXFrame::fullFrame()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
@ -850,7 +887,8 @@ IAXFullFrame::IAXFullFrame(Type type, u_int32_t subclass, u_int16_t sCallNo, u_i
|
|||
u_int32_t tStamp, bool retrans,
|
||||
const unsigned char* buf, unsigned int len)
|
||||
: IAXFrame(type,sCallNo,tStamp,retrans,buf,len),
|
||||
m_dCallNo(dCallNo), m_oSeqNo(oSeqNo), m_iSeqNo(iSeqNo), m_subclass(subclass)
|
||||
m_dCallNo(dCallNo), m_oSeqNo(oSeqNo), m_iSeqNo(iSeqNo), m_subclass(subclass),
|
||||
m_ieList(0)
|
||||
{
|
||||
// XDebug(DebugAll,"IAXFullFrame::IAXFullFrame(%u,%u) [%p]",
|
||||
// type,subclass,this);
|
||||
|
@ -861,42 +899,31 @@ IAXFullFrame::IAXFullFrame(Type type, u_int32_t subclass, u_int16_t sCallNo, u_i
|
|||
u_int32_t tStamp,
|
||||
const unsigned char* buf, unsigned int len)
|
||||
: IAXFrame(type,sCallNo,tStamp,false,0,0),
|
||||
m_dCallNo(dCallNo), m_oSeqNo(oSeqNo), m_iSeqNo(iSeqNo), m_subclass(subclass)
|
||||
m_dCallNo(dCallNo), m_oSeqNo(oSeqNo), m_iSeqNo(iSeqNo), m_subclass(subclass),
|
||||
m_ieList(0)
|
||||
{
|
||||
// XDebug(DebugAll,"IAXFullFrame::IAXFullFrame(%u,%u) [%p]",
|
||||
// type,subclass,this);
|
||||
setDataHeader();
|
||||
if (buf)
|
||||
m_data.append((void*)buf,(unsigned int)len);
|
||||
}
|
||||
|
||||
unsigned char header[12];
|
||||
DataBlock ie;
|
||||
|
||||
// Full frame flag + Source call number
|
||||
header[0] = 0x80 | (unsigned char)(sourceCallNo() >> 8);
|
||||
header[1] = (unsigned char)(sourceCallNo());
|
||||
// Retrans + Destination call number
|
||||
header[2] = (unsigned char)(destCallNo() >> 8); // retrans is false: bit 7 is 0
|
||||
header[3] = (unsigned char)destCallNo();
|
||||
// Timestamp
|
||||
header[4] = (unsigned char)(timeStamp() >> 24);
|
||||
header[5] = (unsigned char)(timeStamp() >> 16);
|
||||
header[6] = (unsigned char)(timeStamp() >> 8);
|
||||
header[7] = (unsigned char)timeStamp();
|
||||
// oSeqNo + iSeqNo
|
||||
header[8] = m_oSeqNo;
|
||||
header[9] = m_iSeqNo;
|
||||
// Type
|
||||
header[10] = type;
|
||||
// Subclass
|
||||
header[11] = packSubclass(m_subclass);
|
||||
// Set data
|
||||
m_data.assign(header,sizeof(header));
|
||||
if (buf) {
|
||||
ie.assign((void*)buf,(unsigned int)len);
|
||||
m_data += ie;
|
||||
}
|
||||
// Constructor. Constructs an outgoing full frame
|
||||
IAXFullFrame::IAXFullFrame(Type type, u_int32_t subclass, u_int16_t sCallNo, u_int16_t dCallNo,
|
||||
unsigned char oSeqNo, unsigned char iSeqNo,
|
||||
u_int32_t tStamp, IAXIEList* ieList, u_int16_t maxlen)
|
||||
: IAXFrame(type,sCallNo,tStamp,false,0,0),
|
||||
m_dCallNo(dCallNo), m_oSeqNo(oSeqNo), m_iSeqNo(iSeqNo), m_subclass(subclass),
|
||||
m_ieList(ieList)
|
||||
{
|
||||
// XDebug(DebugAll,"IAXFullFrame::IAXFullFrame(%u,%u) [%p]",
|
||||
// type,subclass,this);
|
||||
updateBuffer(maxlen);
|
||||
}
|
||||
|
||||
void IAXFullFrame::toString(String& dest, const SocketAddr& local,
|
||||
const SocketAddr& remote, bool incoming) const
|
||||
const SocketAddr& remote, bool incoming)
|
||||
{
|
||||
#define STARTLINE(indent) "\r\n" << indent
|
||||
#define TMP_TEXT (tmp ? tmp : unk)
|
||||
|
@ -941,7 +968,6 @@ void IAXFullFrame::toString(String& dest, const SocketAddr& local,
|
|||
break;
|
||||
default:
|
||||
subc = unk;
|
||||
|
||||
}
|
||||
setStringFromInteger(stmp,subclass(),4);
|
||||
dest << " - " << subc << " (" << stmp << ")";
|
||||
|
@ -969,16 +995,15 @@ void IAXFullFrame::toString(String& dest, const SocketAddr& local,
|
|||
dest << ". Retrans: " << String::boolText(retrans());
|
||||
dest << ". Sequence numbers: Out: " << oSeqNo() << " In: " << iSeqNo();
|
||||
// IEs
|
||||
IAXIEList ieList;
|
||||
bool hasIE = ieList.createFromFrame(this,incoming);
|
||||
if (hasIE) {
|
||||
updateIEList(incoming);
|
||||
if (!m_ieList->empty()) {
|
||||
String aux;
|
||||
aux << STARTLINE(" ");
|
||||
ieList.toString(dest,aux);
|
||||
m_ieList->toString(dest,aux);
|
||||
}
|
||||
if (!hasIE) {
|
||||
if (m_ieList->empty()) {
|
||||
dest << STARTLINE(" ");
|
||||
if (ieList.invalidIEList())
|
||||
if (m_ieList->invalidIEList())
|
||||
dest << "Error parsing Information Element(s)";
|
||||
else
|
||||
dest << "No Information Element(s)";
|
||||
|
@ -988,17 +1013,87 @@ void IAXFullFrame::toString(String& dest, const SocketAddr& local,
|
|||
#undef STARTLINE
|
||||
}
|
||||
|
||||
// Rebuild frame buffer from the list of IEs
|
||||
void IAXFullFrame::updateBuffer(u_int16_t maxlen)
|
||||
{
|
||||
setDataHeader();
|
||||
if (!m_ieList)
|
||||
return;
|
||||
DataBlock tmp;
|
||||
m_ieList->toBuffer(tmp);
|
||||
if (tmp.length() <= maxlen)
|
||||
m_data += tmp;
|
||||
else
|
||||
Debug(DebugNote,"Frame(%u,%u) buffer too long (%u > %u) [%p]",
|
||||
type(),subclass(),tmp.length(),maxlen,this);
|
||||
}
|
||||
|
||||
// Update IE list from buffer if not already done
|
||||
bool IAXFullFrame::updateIEList(bool incoming)
|
||||
{
|
||||
if (!m_ieList)
|
||||
m_ieList = new IAXIEList(this,incoming);
|
||||
return !m_ieList->invalidIEList();
|
||||
}
|
||||
|
||||
// Remove the IE list
|
||||
IAXIEList* IAXFullFrame::removeIEList(bool delObj)
|
||||
{
|
||||
if (!m_ieList)
|
||||
return 0;
|
||||
IAXIEList* old = m_ieList;
|
||||
m_ieList = 0;
|
||||
if (delObj) {
|
||||
delete old;
|
||||
old = 0;
|
||||
}
|
||||
return old;
|
||||
}
|
||||
|
||||
IAXFullFrame::~IAXFullFrame()
|
||||
{
|
||||
// XDebug(DebugAll,"IAXFullFrame::~IAXFullFrame(%u,%u) [%p]",
|
||||
// type(),m_subclass,this);
|
||||
}
|
||||
|
||||
const IAXFullFrame* IAXFullFrame::fullFrame() const
|
||||
IAXFullFrame* IAXFullFrame::fullFrame()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
// Destroyed notification. Clear data
|
||||
void IAXFullFrame::destroyed()
|
||||
{
|
||||
removeIEList();
|
||||
IAXFrame::destroyed();
|
||||
}
|
||||
|
||||
// Build frame buffer header
|
||||
void IAXFullFrame::setDataHeader()
|
||||
{
|
||||
unsigned char header[12];
|
||||
// Full frame flag + Source call number
|
||||
header[0] = 0x80 | (unsigned char)(sourceCallNo() >> 8);
|
||||
header[1] = (unsigned char)(sourceCallNo());
|
||||
// Retrans + Destination call number
|
||||
header[2] = (unsigned char)(destCallNo() >> 8); // retrans is false: bit 7 is 0
|
||||
header[3] = (unsigned char)destCallNo();
|
||||
// Timestamp
|
||||
header[4] = (unsigned char)(timeStamp() >> 24);
|
||||
header[5] = (unsigned char)(timeStamp() >> 16);
|
||||
header[6] = (unsigned char)(timeStamp() >> 8);
|
||||
header[7] = (unsigned char)timeStamp();
|
||||
// oSeqNo + iSeqNo
|
||||
header[8] = m_oSeqNo;
|
||||
header[9] = m_iSeqNo;
|
||||
// Type
|
||||
header[10] = type();
|
||||
// Subclass
|
||||
header[11] = packSubclass(m_subclass);
|
||||
// Set data
|
||||
m_data.assign(header,sizeof(header));
|
||||
}
|
||||
|
||||
/*
|
||||
* IAXFrameOut
|
||||
*/
|
||||
|
|
|
@ -69,7 +69,7 @@ IAXTransaction::IAXTransaction(IAXEngine* engine, IAXFullFrame* frame, u_int16_t
|
|||
m_format(0),
|
||||
m_formatIn(0),
|
||||
m_formatOut(0),
|
||||
m_capability(0),
|
||||
m_capability(0), m_callToken(false),
|
||||
m_trunkFrame(0)
|
||||
{
|
||||
XDebug(m_engine,DebugAll,"IAXTransaction::IAXTransaction(%u,%u) incoming [%p]",
|
||||
|
@ -137,7 +137,7 @@ IAXTransaction::IAXTransaction(IAXEngine* engine, Type type, u_int16_t lcallno,
|
|||
m_format(0),
|
||||
m_formatIn(0),
|
||||
m_formatOut(0),
|
||||
m_capability(0),
|
||||
m_capability(0), m_callToken(false),
|
||||
m_trunkFrame(0)
|
||||
{
|
||||
XDebug(m_engine,DebugAll,"IAXTransaction::IAXTransaction(%u,%u) outgoing. [%p]",
|
||||
|
@ -153,25 +153,27 @@ IAXTransaction::IAXTransaction(IAXEngine* engine, Type type, u_int16_t lcallno,
|
|||
m_retransInterval = engine->retransInterval();
|
||||
m_timeToNextPing = m_timeStamp + m_pingInterval;
|
||||
init(ieList);
|
||||
ieList.clear();
|
||||
IAXControl::Type frametype;
|
||||
IAXIEList* ies = new IAXIEList;
|
||||
// Create IE list to send
|
||||
switch (type) {
|
||||
case New:
|
||||
ieList.insertVersion();
|
||||
ieList.appendString(IAXInfoElement::USERNAME,m_username);
|
||||
ieList.appendString(IAXInfoElement::CALLING_NUMBER,m_callingNo);
|
||||
ieList.appendString(IAXInfoElement::CALLING_NAME,m_callingName);
|
||||
ieList.appendString(IAXInfoElement::CALLED_NUMBER,m_calledNo);
|
||||
ieList.appendString(IAXInfoElement::CALLED_CONTEXT,m_calledContext);
|
||||
ieList.appendNumeric(IAXInfoElement::FORMAT,m_format,4);
|
||||
ieList.appendNumeric(IAXInfoElement::CAPABILITY,m_capability,4);
|
||||
ies->insertVersion();
|
||||
ies->appendString(IAXInfoElement::USERNAME,m_username);
|
||||
ies->appendString(IAXInfoElement::CALLING_NUMBER,m_callingNo);
|
||||
ies->appendString(IAXInfoElement::CALLING_NAME,m_callingName);
|
||||
ies->appendString(IAXInfoElement::CALLED_NUMBER,m_calledNo);
|
||||
ies->appendString(IAXInfoElement::CALLED_CONTEXT,m_calledContext);
|
||||
ies->appendNumeric(IAXInfoElement::FORMAT,m_format,4);
|
||||
ies->appendNumeric(IAXInfoElement::CAPABILITY,m_capability,4);
|
||||
if (m_callToken)
|
||||
ies->appendBinary(IAXInfoElement::CALLTOKEN,0,0);
|
||||
frametype = IAXControl::New;
|
||||
break;
|
||||
case RegReq:
|
||||
case RegRel:
|
||||
ieList.appendString(IAXInfoElement::USERNAME,m_username);
|
||||
ieList.appendNumeric(IAXInfoElement::REFRESH,m_expire,2);
|
||||
ies->appendString(IAXInfoElement::USERNAME,m_username);
|
||||
ies->appendNumeric(IAXInfoElement::REFRESH,m_expire,2);
|
||||
frametype = (type == RegReq ? IAXControl::RegReq : IAXControl::RegRel);
|
||||
break;
|
||||
case Poke:
|
||||
|
@ -180,17 +182,11 @@ IAXTransaction::IAXTransaction(IAXEngine* engine, Type type, u_int16_t lcallno,
|
|||
default:
|
||||
XDebug(m_engine,DebugAll,"IAXTransaction::IAXTransaction(%u,%u) outgoing. Unsupported type: %u. [%p]",
|
||||
localCallNo(),remoteCallNo(),m_type,this);
|
||||
delete ies;
|
||||
m_type = Incorrect;
|
||||
return;
|
||||
}
|
||||
DataBlock d;
|
||||
ieList.toBuffer(d);
|
||||
if (d.length() > (unsigned int)m_engine->maxFullFrameDataLen()) {
|
||||
XDebug(m_engine,DebugAll,"IAXTransaction::IAXTransaction(%u,%u). Buffer too long (%u > %u). [%p]",
|
||||
localCallNo(),remoteCallNo(),d.length(),(unsigned int)m_engine->maxFullFrameDataLen(),this);
|
||||
d.clear();
|
||||
}
|
||||
postFrame(IAXFrame::IAX,frametype,(void*)(d.data()),d.length());
|
||||
postFrameIes(IAXFrame::IAX,frametype,ies);
|
||||
changeState(NewLocalInvite);
|
||||
}
|
||||
|
||||
|
@ -475,19 +471,18 @@ bool IAXTransaction::sendAccept()
|
|||
((type() == RegReq || type() == RegRel) && state() == NewRemoteInvite_RepRecv)))
|
||||
return false;
|
||||
if (type() == New) {
|
||||
unsigned char d[12] = {IAXInfoElement::FORMAT,4,m_format >> 24,m_format >> 16,m_format >> 8,m_format,
|
||||
IAXInfoElement::CAPABILITY,4,m_capability >> 24,m_capability >> 16,m_capability >> 8,m_capability};
|
||||
postFrame(IAXFrame::IAX,IAXControl::Accept,d,sizeof(d),0,true);
|
||||
IAXIEList* ies = new IAXIEList;
|
||||
ies->appendNumeric(IAXInfoElement::FORMAT,m_format,4);
|
||||
ies->appendNumeric(IAXInfoElement::CAPABILITY,m_capability,4);
|
||||
postFrameIes(IAXFrame::IAX,IAXControl::Accept,ies,0,true);
|
||||
changeState(Connected);
|
||||
}
|
||||
else {
|
||||
IAXIEList ieList;
|
||||
ieList.appendString(IAXInfoElement::USERNAME,m_username);
|
||||
ieList.appendNumeric(IAXInfoElement::REFRESH,m_expire,2);
|
||||
ieList.appendIE(IAXInfoElementBinary::packIP(remoteAddr()));
|
||||
DataBlock data;
|
||||
ieList.toBuffer(data);
|
||||
postFrame(IAXFrame::IAX,IAXControl::RegAck,data.data(),data.length(),0,true);
|
||||
IAXIEList* ies = new IAXIEList;
|
||||
ies->appendString(IAXInfoElement::USERNAME,m_username);
|
||||
ies->appendNumeric(IAXInfoElement::REFRESH,m_expire,2);
|
||||
ies->appendIE(IAXInfoElementBinary::packIP(remoteAddr()));
|
||||
postFrameIes(IAXFrame::IAX,IAXControl::RegAck,ies,0,true);
|
||||
changeState(Terminating);
|
||||
m_localReqEnd = true;
|
||||
}
|
||||
|
@ -496,27 +491,15 @@ bool IAXTransaction::sendAccept()
|
|||
|
||||
bool IAXTransaction::sendHangup(const char* cause, u_int8_t code)
|
||||
{
|
||||
String s(cause);
|
||||
unsigned char d[3];
|
||||
DataBlock data,aux;
|
||||
|
||||
Lock lock(this);
|
||||
if (type() != New || state() == Terminated || state() == Terminating)
|
||||
return false;
|
||||
if (cause) {
|
||||
d[0] = IAXInfoElement::CAUSE;
|
||||
d[1] = s.length();
|
||||
data.assign(d,2);
|
||||
data.append(s);
|
||||
}
|
||||
if (code) {
|
||||
d[0] = IAXInfoElement::CAUSECODE;
|
||||
d[1] = 1;
|
||||
d[2] = code;
|
||||
aux.assign(d,3);
|
||||
data += aux;
|
||||
}
|
||||
postFrame(IAXFrame::IAX,IAXControl::Hangup,data.data(),data.length(),0,true);
|
||||
IAXIEList* ies = new IAXIEList;
|
||||
if (!TelEngine::null(cause))
|
||||
ies->appendString(IAXInfoElement::CAUSE,cause);
|
||||
if (code)
|
||||
ies->appendNumeric(IAXInfoElement::CAUSECODE,code,1);
|
||||
postFrameIes(IAXFrame::IAX,IAXControl::Hangup,ies,0,true);
|
||||
changeState(Terminating);
|
||||
m_localReqEnd = true;
|
||||
Debug(m_engine,DebugAll,"Transaction(%u,%u). Hangup call. Cause: '%s'",localCallNo(),remoteCallNo(),cause);
|
||||
|
@ -525,10 +508,6 @@ bool IAXTransaction::sendHangup(const char* cause, u_int8_t code)
|
|||
|
||||
bool IAXTransaction::sendReject(const char* cause, u_int8_t code)
|
||||
{
|
||||
String s(cause);
|
||||
unsigned char d[3];
|
||||
DataBlock data,aux;
|
||||
|
||||
Lock lock(this);
|
||||
if (state() == Terminated || state() == Terminating)
|
||||
return false;
|
||||
|
@ -545,20 +524,12 @@ bool IAXTransaction::sendReject(const char* cause, u_int8_t code)
|
|||
default:
|
||||
return false;
|
||||
}
|
||||
if (cause) {
|
||||
d[0] = IAXInfoElement::CAUSE;
|
||||
d[1] = s.length();
|
||||
data.assign(d,2);
|
||||
data.append(s);
|
||||
}
|
||||
if (code) {
|
||||
d[0] = IAXInfoElement::CAUSECODE;
|
||||
d[1] = 1;
|
||||
d[2] = code;
|
||||
aux.assign(d,3);
|
||||
data += aux;
|
||||
}
|
||||
postFrame(IAXFrame::IAX,frametype,data.data(),data.length(),0,true);
|
||||
IAXIEList* ies = new IAXIEList;
|
||||
if (!TelEngine::null(cause))
|
||||
ies->appendString(IAXInfoElement::CAUSE,cause);
|
||||
if (code)
|
||||
ies->appendNumeric(IAXInfoElement::CAUSECODE,code,1);
|
||||
postFrameIes(IAXFrame::IAX,frametype,ies,0,true);
|
||||
Debug(m_engine,DebugAll,"Transaction(%u,%u). Reject. Cause: '%s'",localCallNo(),remoteCallNo(),cause);
|
||||
changeState(Terminating);
|
||||
m_localReqEnd = true;
|
||||
|
@ -579,22 +550,24 @@ bool IAXTransaction::sendAuth()
|
|||
default:
|
||||
return false;
|
||||
}
|
||||
IAXIEList ieList;
|
||||
ieList.appendString(IAXInfoElement::USERNAME,m_username);
|
||||
ieList.appendNumeric(IAXInfoElement::AUTHMETHODS,m_authmethod,2);
|
||||
ieList.appendString(IAXInfoElement::CHALLENGE,m_challenge);
|
||||
DataBlock data;
|
||||
ieList.toBuffer(data);
|
||||
IAXControl::Type t = IAXControl::Unsupport;
|
||||
switch (type()) {
|
||||
case New:
|
||||
postFrame(IAXFrame::IAX,IAXControl::AuthReq,data.data(),data.length(),0,false);
|
||||
t = IAXControl::AuthReq;
|
||||
break;
|
||||
case RegReq:
|
||||
case RegRel:
|
||||
postFrame(IAXFrame::IAX,IAXControl::RegAuth,data.data(),data.length(),0,false);
|
||||
t = IAXControl::RegAuth;
|
||||
break;
|
||||
default: ;
|
||||
}
|
||||
if (t != IAXControl::Unsupport) {
|
||||
IAXIEList* ies = new IAXIEList;
|
||||
ies->appendString(IAXInfoElement::USERNAME,m_username);
|
||||
ies->appendNumeric(IAXInfoElement::AUTHMETHODS,m_authmethod,2);
|
||||
ies->appendString(IAXInfoElement::CHALLENGE,m_challenge);
|
||||
postFrameIes(IAXFrame::IAX,t,ies);
|
||||
}
|
||||
changeState(NewRemoteInvite_AuthSent);
|
||||
return true;
|
||||
}
|
||||
|
@ -605,7 +578,7 @@ bool IAXTransaction::sendAuthReply(const String& response)
|
|||
if (state() != NewLocalInvite_AuthRecv)
|
||||
return false;
|
||||
m_authdata = response;
|
||||
IAXIEList ieList;
|
||||
IAXIEList* ies = new IAXIEList;
|
||||
IAXControl::Type subclass;
|
||||
switch (type()) {
|
||||
case New:
|
||||
|
@ -613,21 +586,22 @@ bool IAXTransaction::sendAuthReply(const String& response)
|
|||
break;
|
||||
case RegReq:
|
||||
subclass = IAXControl::RegReq;
|
||||
ieList.appendString(IAXInfoElement::USERNAME,m_username);
|
||||
ies->appendString(IAXInfoElement::USERNAME,m_username);
|
||||
break;
|
||||
case RegRel:
|
||||
subclass = IAXControl::RegRel;
|
||||
ieList.appendString(IAXInfoElement::USERNAME,m_username);
|
||||
ies->appendString(IAXInfoElement::USERNAME,m_username);
|
||||
break;
|
||||
default:
|
||||
delete ies;
|
||||
return false;
|
||||
}
|
||||
if (m_authmethod != IAXAuthMethod::MD5)
|
||||
if (m_authmethod != IAXAuthMethod::MD5) {
|
||||
delete ies;
|
||||
return false;
|
||||
ieList.appendString(IAXInfoElement::MD5_RESULT,response);
|
||||
DataBlock data;
|
||||
ieList.toBuffer(data);
|
||||
postFrame(IAXFrame::IAX,subclass,data.data(),data.length(),0,false);
|
||||
}
|
||||
ies->appendString(IAXInfoElement::MD5_RESULT,response);
|
||||
postFrameIes(IAXFrame::IAX,subclass,ies);
|
||||
changeState(NewLocalInvite_RepSent);
|
||||
return true;
|
||||
}
|
||||
|
@ -681,6 +655,41 @@ bool IAXTransaction::enableTrunking(IAXMetaTrunkFrame* trunkFrame)
|
|||
return true;
|
||||
}
|
||||
|
||||
// Process a received call token
|
||||
void IAXTransaction::processCallToken(const DataBlock& callToken)
|
||||
{
|
||||
Lock lock(this);
|
||||
IAXFrameOut* frame = 0;
|
||||
if (state() == NewLocalInvite && m_callToken) {
|
||||
ObjList* o = m_outFrames.skipNull();
|
||||
frame = o ? static_cast<IAXFrameOut*>(o->get()) : 0;
|
||||
if (frame && frame->type() != IAXFrame::IAX && frame->subclass() != IAXControl::New)
|
||||
frame = 0;
|
||||
}
|
||||
m_callToken = false;
|
||||
if (!frame) {
|
||||
Debug(m_engine,DebugNote,
|
||||
"Transaction(%u,%u). Received call token in invalid state [%p]",
|
||||
localCallNo(),remoteCallNo(),this);
|
||||
return;
|
||||
}
|
||||
frame->updateIEList(false);
|
||||
IAXIEList* ies = frame->ieList();
|
||||
if (!ies) {
|
||||
Debug(m_engine,DebugNote,
|
||||
"Transaction(%u,%u). No IE list in first frame [%p]",
|
||||
localCallNo(),remoteCallNo(),this);
|
||||
return;
|
||||
}
|
||||
IAXInfoElementBinary* ct = static_cast<IAXInfoElementBinary*>(ies->getIE(IAXInfoElement::CALLTOKEN));
|
||||
if (ct)
|
||||
ct->setData(callToken.data(),callToken.length());
|
||||
else
|
||||
ies->appendBinary(IAXInfoElement::CALLTOKEN,(unsigned char*)callToken.data(),callToken.length());
|
||||
frame->updateBuffer(m_engine->maxFullFrameDataLen());
|
||||
sendFrame(frame);
|
||||
}
|
||||
|
||||
void IAXTransaction::print()
|
||||
{
|
||||
static SocketAddr addr;
|
||||
|
@ -712,8 +721,10 @@ void IAXTransaction::init(IAXIEList& ieList)
|
|||
ieList.getString(IAXInfoElement::CALLED_CONTEXT,m_calledContext);
|
||||
ieList.getNumeric(IAXInfoElement::FORMAT,m_format);
|
||||
ieList.getNumeric(IAXInfoElement::CAPABILITY,m_capability);
|
||||
if (outgoing())
|
||||
if (outgoing()) {
|
||||
m_formatOut = m_format;
|
||||
m_callToken = (0 != ieList.getIE(IAXInfoElement::CALLTOKEN));
|
||||
}
|
||||
else
|
||||
m_formatIn = m_format;
|
||||
break;
|
||||
|
@ -788,7 +799,7 @@ bool IAXTransaction::changeState(State newState)
|
|||
return true;
|
||||
}
|
||||
|
||||
IAXEvent* IAXTransaction::terminate(u_int8_t evType, bool local, const IAXFullFrame* frame, bool createIEList)
|
||||
IAXEvent* IAXTransaction::terminate(u_int8_t evType, bool local, IAXFullFrame* frame, bool createIEList)
|
||||
{
|
||||
IAXEvent* ev;
|
||||
if (createIEList)
|
||||
|
@ -805,7 +816,7 @@ IAXEvent* IAXTransaction::terminate(u_int8_t evType, bool local, const IAXFullFr
|
|||
return ev;
|
||||
}
|
||||
|
||||
IAXEvent* IAXTransaction::waitForTerminate(u_int8_t evType, bool local, const IAXFullFrame* frame)
|
||||
IAXEvent* IAXTransaction::waitForTerminate(u_int8_t evType, bool local, IAXFullFrame* frame)
|
||||
{
|
||||
IAXEvent* ev = new IAXEvent((IAXEvent::Type)evType,local,true,this,frame);
|
||||
Debug(m_engine,DebugAll,"Transaction(%u,%u). Terminating. Event: %u, Frame(%u,%u)",
|
||||
|
@ -820,23 +831,24 @@ void IAXTransaction::postFrame(IAXFrame::Type type, u_int32_t subclass, void* da
|
|||
Lock lock(this);
|
||||
if (state() == Terminated)
|
||||
return;
|
||||
if (!tStamp) {
|
||||
tStamp = (u_int32_t)timeStamp();
|
||||
if (m_lastFullFrameOut) {
|
||||
// adjust timestamp to be different from the last sent
|
||||
int32_t delta = tStamp - m_lastFullFrameOut;
|
||||
if (delta <= 0)
|
||||
tStamp = m_lastFullFrameOut + 1;
|
||||
}
|
||||
m_lastFullFrameOut = tStamp;
|
||||
}
|
||||
adjustTStamp(tStamp);
|
||||
IAXFrameOut* frame = new IAXFrameOut(type,subclass,m_lCallNo,m_rCallNo,m_oSeqNo,m_iSeqNo,tStamp,
|
||||
(unsigned char*)data,len,m_retransCount,m_retransInterval,ackOnly);
|
||||
DDebug(m_engine,DebugAll,"Transaction(%u,%u) posting Frame(%u,%u) oseq=%u iseq=%u stamp=%u [%p]",
|
||||
localCallNo(),remoteCallNo(),type,subclass,m_oSeqNo,m_iSeqNo,tStamp,this);
|
||||
incrementSeqNo(frame,false);
|
||||
m_outFrames.append(frame);
|
||||
sendFrame(frame);
|
||||
postFrame(frame);
|
||||
}
|
||||
|
||||
// Constructs an IAXFrameOut frame, send it to remote peer and put it in the transmission list
|
||||
void IAXTransaction::postFrameIes(IAXFrame::Type type, u_int32_t subclass, IAXIEList* ies,
|
||||
u_int32_t tStamp, bool ackOnly)
|
||||
{
|
||||
Lock lock(this);
|
||||
if (state() == Terminated)
|
||||
return;
|
||||
adjustTStamp(tStamp);
|
||||
IAXFrameOut* frame = new IAXFrameOut(type,subclass,m_lCallNo,m_rCallNo,m_oSeqNo,
|
||||
m_iSeqNo,tStamp,ies,m_engine->maxFullFrameDataLen(),m_retransCount,
|
||||
m_retransInterval,ackOnly);
|
||||
postFrame(frame);
|
||||
}
|
||||
|
||||
bool IAXTransaction::sendFrame(IAXFrameOut* frame, bool vnak)
|
||||
|
@ -854,7 +866,7 @@ bool IAXTransaction::sendFrame(IAXFrameOut* frame, bool vnak)
|
|||
return b;
|
||||
}
|
||||
|
||||
IAXEvent* IAXTransaction::createEvent(u_int8_t evType, bool local, const IAXFullFrame* frame, State newState)
|
||||
IAXEvent* IAXTransaction::createEvent(u_int8_t evType, bool local, IAXFullFrame* frame, State newState)
|
||||
{
|
||||
IAXEvent* ev;
|
||||
changeState(newState);
|
||||
|
@ -1257,7 +1269,7 @@ bool IAXTransaction::sendConnected(IAXFullFrame::ControlType subclass, IAXFrame:
|
|||
{
|
||||
if (state() != Connected)
|
||||
return false;
|
||||
postFrame(frametype,subclass,0,0,0,true);
|
||||
postFrameIes(frametype,subclass,0,0,true);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1291,8 +1303,10 @@ void IAXTransaction::sendVNAK()
|
|||
|
||||
void IAXTransaction::sendUnsupport(u_int32_t subclass)
|
||||
{
|
||||
unsigned char d[3] = {IAXInfoElement::IAX_UNKNOWN,1,IAXFrame::packSubclass(subclass)};
|
||||
postFrame(IAXFrame::IAX,IAXControl::Unsupport,d,sizeof(d),0,true);
|
||||
IAXIEList* ies = new IAXIEList;
|
||||
u_int8_t val = IAXFrame::packSubclass(subclass);
|
||||
ies->appendNumeric(IAXInfoElement::IAX_UNKNOWN,val,1);
|
||||
postFrameIes(IAXFrame::IAX,IAXControl::Unsupport,ies,0,true);
|
||||
}
|
||||
|
||||
IAXEvent* IAXTransaction::processInternalOutgoingRequest(IAXFrameOut* frame, bool& delFrame)
|
||||
|
@ -1328,7 +1342,7 @@ IAXEvent* IAXTransaction::processInternalIncomingRequest(const IAXFullFrame* fra
|
|||
return 0;
|
||||
}
|
||||
|
||||
IAXEvent* IAXTransaction::processMidCallControl(const IAXFullFrame* frame, bool& delFrame)
|
||||
IAXEvent* IAXTransaction::processMidCallControl(IAXFullFrame* frame, bool& delFrame)
|
||||
{
|
||||
delFrame = true;
|
||||
switch (frame->subclass()) {
|
||||
|
@ -1358,7 +1372,7 @@ IAXEvent* IAXTransaction::processMidCallControl(const IAXFullFrame* frame, bool&
|
|||
return 0;
|
||||
}
|
||||
|
||||
IAXEvent* IAXTransaction::processMidCallIAXControl(const IAXFullFrame* frame, bool& delFrame)
|
||||
IAXEvent* IAXTransaction::processMidCallIAXControl(IAXFullFrame* frame, bool& delFrame)
|
||||
{
|
||||
delFrame = true;
|
||||
switch (frame->subclass()) {
|
||||
|
@ -1408,7 +1422,7 @@ IAXEvent* IAXTransaction::processMidCallIAXControl(const IAXFullFrame* frame, bo
|
|||
return 0;
|
||||
}
|
||||
|
||||
IAXEvent* IAXTransaction::remoteRejectCall(const IAXFullFrame* frame, bool& delFrame)
|
||||
IAXEvent* IAXTransaction::remoteRejectCall(IAXFullFrame* frame, bool& delFrame)
|
||||
{
|
||||
delFrame = true;
|
||||
switch (type()) {
|
||||
|
@ -1449,8 +1463,8 @@ IAXTransaction* IAXTransaction::processVoiceFrame(const IAXFullFrame* frame)
|
|||
if (m_formatIn) {
|
||||
if (frame->subclass() && frame->subclass() != m_formatIn) {
|
||||
// Format changed.
|
||||
if (m_engine->voiceFormatChanged(this,frame->fullFrame()->subclass()))
|
||||
m_formatIn = frame->fullFrame()->subclass();
|
||||
if (m_engine->voiceFormatChanged(this,frame->subclass()))
|
||||
m_formatIn = frame->subclass();
|
||||
else {
|
||||
DDebug(m_engine,DebugAll,"IAXTransaction(%u,%u). Process Voice Frame. Media format (%u) change rejected!",
|
||||
localCallNo(),remoteCallNo(),m_format);
|
||||
|
@ -1511,4 +1525,31 @@ void IAXTransaction::eventTerminated(IAXEvent* event)
|
|||
}
|
||||
}
|
||||
|
||||
void IAXTransaction::adjustTStamp(u_int32_t& tStamp)
|
||||
{
|
||||
if (tStamp)
|
||||
return;
|
||||
tStamp = (u_int32_t)timeStamp();
|
||||
if (m_lastFullFrameOut) {
|
||||
// adjust timestamp to be different from the last sent
|
||||
int32_t delta = tStamp - m_lastFullFrameOut;
|
||||
if (delta <= 0)
|
||||
tStamp = m_lastFullFrameOut + 1;
|
||||
}
|
||||
m_lastFullFrameOut = tStamp;
|
||||
}
|
||||
|
||||
void IAXTransaction::postFrame(IAXFrameOut* frame)
|
||||
{
|
||||
if (!frame)
|
||||
return;
|
||||
DDebug(m_engine,DebugAll,
|
||||
"Transaction(%u,%u) posting Frame(%u,%u) oseq=%u iseq=%u stamp=%u [%p]",
|
||||
localCallNo(),remoteCallNo(),frame->type(),frame->subclass(),
|
||||
m_oSeqNo,m_iSeqNo,frame->timeStamp(),this);
|
||||
incrementSeqNo(frame,false);
|
||||
m_outFrames.append(frame);
|
||||
sendFrame(frame);
|
||||
}
|
||||
|
||||
/* vi: set ts=8 sw=4 sts=4 noet: */
|
||||
|
|
|
@ -123,6 +123,7 @@ public:
|
|||
RR_DELAY = 0x31, // W
|
||||
RR_DROPPED = 0x32, // DW
|
||||
RR_OOO = 0x33, // DW
|
||||
CALLTOKEN = 0X36, // BIN
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -307,6 +308,14 @@ public:
|
|||
inline DataBlock& data()
|
||||
{ return m_data; }
|
||||
|
||||
/**
|
||||
* Set the data
|
||||
* @param buf Source buffer to construct this IE
|
||||
* @param len Buffer length
|
||||
*/
|
||||
inline void setData(void* buf, unsigned len)
|
||||
{ m_data.assign(buf,len); }
|
||||
|
||||
/**
|
||||
* Constructs a buffer containing this Information Element
|
||||
* @param buf Destination buffer
|
||||
|
@ -348,22 +357,19 @@ public:
|
|||
/**
|
||||
* Constructor
|
||||
*/
|
||||
inline IAXIEList() : m_invalidIEList(false)
|
||||
{}
|
||||
IAXIEList();
|
||||
|
||||
/**
|
||||
* Constructor. Construct the list from an IAXFullFrame object
|
||||
* @param frame Source object
|
||||
* @param incoming True if it is an incoming frame
|
||||
*/
|
||||
inline IAXIEList(const IAXFullFrame* frame, bool incoming = true) : m_invalidIEList(false)
|
||||
{ createFromFrame(frame,incoming); }
|
||||
IAXIEList(const IAXFullFrame* frame, bool incoming = true);
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
inline ~IAXIEList()
|
||||
{}
|
||||
~IAXIEList();
|
||||
|
||||
/**
|
||||
* Get the invalid IE list flag
|
||||
|
@ -378,6 +384,13 @@ public:
|
|||
inline void clear()
|
||||
{ m_list.clear(); }
|
||||
|
||||
/**
|
||||
* Check if the list is empty
|
||||
* @return True if the list is empty
|
||||
*/
|
||||
inline bool empty()
|
||||
{ return 0 == m_list.skipNull(); }
|
||||
|
||||
/**
|
||||
* Insert a VERSION Information Element in the list if not already done
|
||||
*/
|
||||
|
@ -644,6 +657,7 @@ public:
|
|||
Provision = 0x23,
|
||||
FwDownl = 0x24,
|
||||
FwData = 0x25,
|
||||
CallToken = 0x28,
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -737,7 +751,7 @@ public:
|
|||
* Get a pointer to this frame if it is a full frame
|
||||
* @return A pointer to this frame if it is a full frame or 0
|
||||
*/
|
||||
virtual const IAXFullFrame* fullFrame() const;
|
||||
virtual IAXFullFrame* fullFrame();
|
||||
|
||||
/**
|
||||
* Parse a received buffer and returns a IAXFrame pointer if valid
|
||||
|
@ -852,6 +866,22 @@ public:
|
|||
u_int32_t tStamp,
|
||||
const unsigned char* buf = 0, unsigned int len = 0);
|
||||
|
||||
/**
|
||||
* Constructor. Constructs an outgoing full frame
|
||||
* @param type Frame type
|
||||
* @param subclass Frame subclass
|
||||
* @param sCallNo Source (remote) call number
|
||||
* @param dCallNo Destination (local) call number
|
||||
* @param oSeqNo Outgoing sequence number
|
||||
* @param iSeqNo Incoming (expected) sequence number
|
||||
* @param tStamp Frame timestamp
|
||||
* @param ieList List of frame IEs
|
||||
* @param maxlen Max frame data length
|
||||
*/
|
||||
IAXFullFrame(Type type, u_int32_t subclass, u_int16_t sCallNo, u_int16_t dCallNo,
|
||||
unsigned char oSeqNo, unsigned char iSeqNo,
|
||||
u_int32_t tStamp, IAXIEList* ieList, u_int16_t maxlen);
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
|
@ -889,7 +919,34 @@ public:
|
|||
* Get a pointer to this frame if it is a full frame
|
||||
* @return A pointer to this frame
|
||||
*/
|
||||
virtual const IAXFullFrame* fullFrame() const;
|
||||
virtual IAXFullFrame* fullFrame();
|
||||
|
||||
/**
|
||||
* Rebuild frame buffer from the list of IEs
|
||||
* @param maxlen Max frame data length
|
||||
*/
|
||||
void updateBuffer(u_int16_t maxlen);
|
||||
|
||||
/**
|
||||
* Retrieve the IE list
|
||||
* @return IAXIEList pointer or NULL
|
||||
*/
|
||||
inline IAXIEList* ieList()
|
||||
{ return m_ieList; }
|
||||
|
||||
/**
|
||||
* Update IE list from buffer if not already done
|
||||
* @param incoming True if this is an incoming frame
|
||||
* @return True if the list is valid
|
||||
*/
|
||||
bool updateIEList(bool incoming);
|
||||
|
||||
/**
|
||||
* Remove the IE list
|
||||
* @param delObj True to delete it
|
||||
* @return IAXIEList pointer or NULL if requested to delete it or already NULL
|
||||
*/
|
||||
IAXIEList* removeIEList(bool delObj = true);
|
||||
|
||||
/**
|
||||
* Fill a string with this frame
|
||||
|
@ -899,7 +956,7 @@ public:
|
|||
* @param incoming True if it is an incoming frame
|
||||
*/
|
||||
void toString(String& dest, const SocketAddr& local, const SocketAddr& remote,
|
||||
bool incoming) const;
|
||||
bool incoming);
|
||||
|
||||
/**
|
||||
* Get the string associated with the given IAX control type
|
||||
|
@ -909,12 +966,21 @@ public:
|
|||
static inline const char* controlTypeText(int type)
|
||||
{ return lookup(type,s_controlTypes,0); }
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Destroyed notification. Clear data
|
||||
*/
|
||||
virtual void destroyed();
|
||||
|
||||
private:
|
||||
// Build frame buffer header
|
||||
void setDataHeader();
|
||||
static TokenDict s_controlTypes[]; // Keep the association between control types and their names
|
||||
u_int16_t m_dCallNo; // Destination call number
|
||||
unsigned char m_oSeqNo; // Out sequence number
|
||||
unsigned char m_iSeqNo; // In sequence number
|
||||
u_int32_t m_subclass; // Subclass
|
||||
IAXIEList* m_ieList; // List of IEs
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -947,6 +1013,30 @@ public:
|
|||
m_nextTransTime(Time::msecNow() + m_retransTimeInterval)
|
||||
{}
|
||||
|
||||
/**
|
||||
* Constructor. Constructs an outgoing full frame
|
||||
* @param type Frame type
|
||||
* @param subclass Frame subclass
|
||||
* @param sCallNo Source (remote) call number
|
||||
* @param dCallNo Destination (local) call number
|
||||
* @param oSeqNo Outgoing sequence number
|
||||
* @param iSeqNo Incoming (expected) sequence number
|
||||
* @param tStamp Frame timestamp
|
||||
* @param ieList List of frame IEs
|
||||
* @param maxlen Max frame data length
|
||||
* @param retransCount Retransmission counter
|
||||
* @param retransInterval Time interval to the next retransmission
|
||||
* @param ackOnly Acknoledge only flag. If true, the frame only expects an ACK
|
||||
*/
|
||||
inline IAXFrameOut(Type type, u_int32_t subclass, u_int16_t sCallNo, u_int16_t dCallNo,
|
||||
unsigned char oSeqNo, unsigned char iSeqNo, u_int32_t tStamp,
|
||||
IAXIEList* ieList, u_int16_t maxlen,
|
||||
u_int16_t retransCount, u_int32_t retransInterval, bool ackOnly)
|
||||
: IAXFullFrame(type,subclass,sCallNo,dCallNo,oSeqNo,iSeqNo,tStamp,ieList,maxlen),
|
||||
m_ack(false), m_ackOnly(ackOnly), m_retransCount(retransCount), m_retransTimeInterval(retransInterval),
|
||||
m_nextTransTime(Time::msecNow() + m_retransTimeInterval)
|
||||
{}
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
|
@ -1448,6 +1538,13 @@ public:
|
|||
*/
|
||||
bool enableTrunking(IAXMetaTrunkFrame* trunkFrame);
|
||||
|
||||
/**
|
||||
* Process a received call token
|
||||
* This method is thread safe
|
||||
* @param callToken Received call token
|
||||
*/
|
||||
void processCallToken(const DataBlock& callToken);
|
||||
|
||||
/**
|
||||
* Print transaction data on stdin
|
||||
*/
|
||||
|
@ -1534,7 +1631,7 @@ protected:
|
|||
* @param createIEList If true create IE list in the generated event
|
||||
* @return Pointer to a valid IAXEvent
|
||||
*/
|
||||
IAXEvent* terminate(u_int8_t evType, bool local, const IAXFullFrame* frame = 0, bool createIEList = true);
|
||||
IAXEvent* terminate(u_int8_t evType, bool local, IAXFullFrame* frame = 0, bool createIEList = true);
|
||||
|
||||
/**
|
||||
* Wait for ACK to terminate the transaction. No more events will be generated
|
||||
|
@ -1543,7 +1640,7 @@ protected:
|
|||
* @param frame Frame to build event from
|
||||
* @return Pointer to a valid IAXEvent
|
||||
*/
|
||||
IAXEvent* waitForTerminate(u_int8_t evType, bool local, const IAXFullFrame* frame);
|
||||
IAXEvent* waitForTerminate(u_int8_t evType, bool local, IAXFullFrame* frame);
|
||||
|
||||
/**
|
||||
* Constructs an IAXFrameOut frame, send it to remote peer and put it in the transmission list
|
||||
|
@ -1558,6 +1655,18 @@ protected:
|
|||
void postFrame(IAXFrame::Type type, u_int32_t subclass, void* data = 0, u_int16_t len = 0, u_int32_t tStamp = 0,
|
||||
bool ackOnly = false);
|
||||
|
||||
/**
|
||||
* Constructs an IAXFrameOut frame, send it to remote peer and put it in the transmission list
|
||||
* This method is thread safe
|
||||
* @param type Frame type
|
||||
* @param subclass Frame subclass
|
||||
* @param ies Frame IE list
|
||||
* @param tStamp Frame timestamp. If 0 the transaction timestamp will be used
|
||||
* @param ackOnly Frame's acknoledge only flag
|
||||
*/
|
||||
void postFrameIes(IAXFrame::Type type, u_int32_t subclass, IAXIEList* ies, u_int32_t tStamp = 0,
|
||||
bool ackOnly = false);
|
||||
|
||||
/**
|
||||
* Send a full frame to remote peer
|
||||
* @param frame Frame to send
|
||||
|
@ -1574,7 +1683,7 @@ protected:
|
|||
* @param newState The transaction new state
|
||||
* @return Pointer to an IAXEvent or 0 (invalid IE list)
|
||||
*/
|
||||
IAXEvent* createEvent(u_int8_t evType, bool local, const IAXFullFrame* frame, State newState);
|
||||
IAXEvent* createEvent(u_int8_t evType, bool local, IAXFullFrame* frame, State newState);
|
||||
|
||||
/**
|
||||
* Create an event from a received frame that is a response to a sent frame and
|
||||
|
@ -1748,7 +1857,7 @@ protected:
|
|||
* @param delFrame Delete frame flag. If true on exit, a request was found
|
||||
* @return A valid IAXEvent or 0
|
||||
*/
|
||||
IAXEvent* processMidCallControl(const IAXFullFrame* frame, bool& delFrame);
|
||||
IAXEvent* processMidCallControl(IAXFullFrame* frame, bool& delFrame);
|
||||
|
||||
/**
|
||||
* Process mid call IAX control frames
|
||||
|
@ -1756,7 +1865,7 @@ protected:
|
|||
* @param delFrame Delete frame flag. If true on exit, a request was found
|
||||
* @return A valid IAXEvent or 0
|
||||
*/
|
||||
IAXEvent* processMidCallIAXControl(const IAXFullFrame* frame, bool& delFrame);
|
||||
IAXEvent* processMidCallIAXControl(IAXFullFrame* frame, bool& delFrame);
|
||||
|
||||
/**
|
||||
* Test if frame is a Reject/RegRej frame
|
||||
|
@ -1764,7 +1873,7 @@ protected:
|
|||
* @param delFrame Delete frame flag. If true on exit, a request was found
|
||||
* @return A valid IAXEvent or 0.
|
||||
*/
|
||||
IAXEvent* remoteRejectCall(const IAXFullFrame* frame, bool& delFrame);
|
||||
IAXEvent* remoteRejectCall(IAXFullFrame* frame, bool& delFrame);
|
||||
|
||||
/**
|
||||
* Terminate the transaction if state is Terminating on a remote request
|
||||
|
@ -1818,6 +1927,9 @@ protected:
|
|||
}
|
||||
|
||||
private:
|
||||
void adjustTStamp(u_int32_t& tStamp);
|
||||
void postFrame(IAXFrameOut* frame);
|
||||
|
||||
// Params
|
||||
bool m_localInitTrans; // True: local initiated transaction
|
||||
bool m_localReqEnd; // Local client requested terminate
|
||||
|
@ -1867,6 +1979,7 @@ private:
|
|||
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
|
||||
bool m_callToken; // Call token supported/expected
|
||||
// Meta trunking
|
||||
IAXMetaTrunkFrame* m_trunkFrame; // Reference to a trunk frame if trunking is enabled for this transaction
|
||||
};
|
||||
|
@ -1979,7 +2092,7 @@ public:
|
|||
* @return IE list reference
|
||||
*/
|
||||
inline IAXIEList& getList()
|
||||
{ return m_ieList; }
|
||||
{ return *m_ieList; }
|
||||
|
||||
protected:
|
||||
/**
|
||||
|
@ -2001,7 +2114,7 @@ protected:
|
|||
* @param transaction IAX transaction that generated the event
|
||||
* @param frame The frame that generated the event
|
||||
*/
|
||||
IAXEvent(Type type, bool local, bool final, IAXTransaction* transaction, const IAXFullFrame* frame = 0);
|
||||
IAXEvent(Type type, bool local, bool final, IAXTransaction* transaction, IAXFullFrame* frame = 0);
|
||||
|
||||
private:
|
||||
inline IAXEvent() {} // Default constructor
|
||||
|
@ -2012,7 +2125,7 @@ private:
|
|||
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
|
||||
IAXIEList* m_ieList; // IAXInfoElement list
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -2138,6 +2251,12 @@ public:
|
|||
inline u_int32_t capability() const
|
||||
{ return m_capability; }
|
||||
|
||||
/**
|
||||
* (Re)Initialize the engine
|
||||
* @param params Parameter list
|
||||
*/
|
||||
void initialize(const NamedList& params);
|
||||
|
||||
/**
|
||||
* Read data from socket
|
||||
* @param addr Socket to read from
|
||||
|
@ -2149,11 +2268,20 @@ public:
|
|||
* @param buf Data to write
|
||||
* @param len Data length
|
||||
* @param addr Socket to write to
|
||||
* @param frame Optional frame to be printed if debug is DebugAll
|
||||
* @param frame Optional frame to be printed
|
||||
* @return True on success
|
||||
*/
|
||||
bool writeSocket(const void* buf, int len, const SocketAddr& addr, IAXFullFrame* frame = 0);
|
||||
|
||||
/**
|
||||
* Write a full frame to socket
|
||||
* @param addr Socket to write to
|
||||
* @param frame Frame to write
|
||||
* @return True on success
|
||||
*/
|
||||
inline bool writeSocket(const SocketAddr& addr, IAXFullFrame* frame)
|
||||
{ return !frame || writeSocket(frame->data().data(),frame->data().length(),addr,frame); }
|
||||
|
||||
/**
|
||||
* Read events
|
||||
*/
|
||||
|
@ -2188,6 +2316,15 @@ public:
|
|||
virtual bool voiceFormatChanged(IAXTransaction* trans, u_int32_t format)
|
||||
{ return false; }
|
||||
|
||||
/**
|
||||
* Check call token on incoming call requests.
|
||||
* This method is called by the engine when processing an incoming call request
|
||||
* @param addr The address from where the call request was received
|
||||
* @param frame Received frame
|
||||
* @return True if accepted, false to ignore the call
|
||||
*/
|
||||
virtual bool checkCallToken(const SocketAddr& addr, IAXFullFrame& frame);
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
@ -2241,6 +2378,25 @@ public:
|
|||
*/
|
||||
static bool isMD5ChallengeCorrect(const String& md5data, const String& challenge, const String& password);
|
||||
|
||||
/**
|
||||
* Build a time signed secret used to authenticate an IP address
|
||||
* @param buf Destination buffer
|
||||
* @param secret Extra secret to add to MD5 sum
|
||||
* @param addr Socket address
|
||||
*/
|
||||
static void buildAddrSecret(String& buf, const String& secret,
|
||||
const SocketAddr& addr);
|
||||
|
||||
/**
|
||||
* Decode a secret built using buildAddrSecret()
|
||||
* @param buf Input buffer
|
||||
* @param secret Extra secret to check
|
||||
* @param addr Socket address
|
||||
* @return Secret age, negative if invalid
|
||||
*/
|
||||
static int addrSecretAge(const String& buf, const String& secret,
|
||||
const SocketAddr& addr);
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Process all trunk meta frames in the queue
|
||||
|
@ -2303,6 +2459,12 @@ private:
|
|||
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
|
||||
bool m_callToken; // Call token required on incoming calls
|
||||
String m_callTokenSecret; // Secret used to generate call tokens
|
||||
int m_callTokenAge; // Max allowed call token age
|
||||
bool m_showCallTokenFailures; // Print incoming call token failures to output
|
||||
bool m_rejectMissingCallToken; // Reject/ignore incoming calls without call token if mandatory
|
||||
bool m_printMsg; // Print frame to output
|
||||
// Media
|
||||
u_int32_t m_format; // The default media format
|
||||
u_int32_t m_capability; // The media capability
|
||||
|
|
|
@ -540,6 +540,7 @@ private:
|
|||
static Configuration s_cfg; // Configuration file
|
||||
static YIAXLineContainer s_lines; // Lines
|
||||
static Thread::Priority s_priority = Thread::Normal; // Threads priority
|
||||
static bool s_callTokenOut = true; // Send an empty call token on outgoing calls
|
||||
static YIAXDriver iplugin; // Init the driver
|
||||
|
||||
static String s_statusCmd = "status";
|
||||
|
@ -1031,6 +1032,8 @@ IAXTransaction* YIAXEngine::call(SocketAddr& addr, NamedList& params)
|
|||
}
|
||||
ieList.appendNumeric(IAXInfoElement::FORMAT,format,4);
|
||||
ieList.appendNumeric(IAXInfoElement::CAPABILITY,codecs,4);
|
||||
if (params.getBoolValue("calltoken_out",s_callTokenOut))
|
||||
ieList.appendBinary(IAXInfoElement::CALLTOKEN,0,0);
|
||||
return startLocalTransaction(IAXTransaction::New,addr,ieList);
|
||||
}
|
||||
|
||||
|
@ -1206,6 +1209,11 @@ void YIAXDriver::initialize()
|
|||
// Load configuration
|
||||
s_cfg = Engine::configFile("yiaxchan");
|
||||
s_cfg.load();
|
||||
NamedList* gen = s_cfg.getSection("general");
|
||||
NamedList dummy("general");
|
||||
if (!gen)
|
||||
gen = &dummy;
|
||||
s_callTokenOut = gen->getBoolValue("calltoken_out",true);
|
||||
// Codec capabilities
|
||||
m_defaultCodec = 0;
|
||||
m_codecs = 0;
|
||||
|
@ -1231,8 +1239,10 @@ void YIAXDriver::initialize()
|
|||
m_defaultCodec = fallback;
|
||||
unlock();
|
||||
// Setup driver if this is the first call
|
||||
if (m_iaxEngine)
|
||||
if (m_iaxEngine) {
|
||||
m_iaxEngine->initialize(*gen);
|
||||
return;
|
||||
}
|
||||
setup();
|
||||
installRelay(Halt);
|
||||
installRelay(Route);
|
||||
|
@ -1251,7 +1261,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,s_cfg.getSection("general"));
|
||||
transTimeout,maxFullFrameDataLen,trunkSendInterval,authReq,gen);
|
||||
m_iaxEngine->debugChain(this);
|
||||
int tos = s_cfg.getIntValue("general","tos",dict_tos,0);
|
||||
if (tos && !m_iaxEngine->socket().setTOS(tos))
|
||||
|
|
Loading…
Reference in New Issue