Properly handle trunk frames without miniframe timestamps.

git-svn-id: http://yate.null.ro/svn/yate/trunk@5344 acf43c95-373e-0410-b603-e72c3f656dc1
This commit is contained in:
marian 2012-12-07 15:41:13 +00:00
parent 8137d40d31
commit fd88ed1260
4 changed files with 133 additions and 8 deletions

View File

@ -268,6 +268,19 @@ IAXTransaction* IAXEngine::addFrame(const SocketAddr& addr, const unsigned char*
return tr;
}
// Find a complete transaction
IAXTransaction* IAXEngine::findTransaction(const SocketAddr& addr, u_int16_t rCallNo)
{
Lock lck(this);
ObjList* o = m_transList[rCallNo % m_transListCount]->skipNull();
for (; o; o = o->skipNext()) {
IAXTransaction* tr = static_cast<IAXTransaction*>(o->get());
if (tr->remoteCallNo() == rCallNo && addr == tr->remoteAddr())
return tr->ref() ? tr : 0;
}
return 0;
}
void IAXEngine::sendInval(IAXFullFrame* frame, const SocketAddr& addr)
{
if (!frame)

View File

@ -46,6 +46,32 @@ inline void setStringFromInteger(String& dest, u_int32_t value, u_int8_t length)
dest = tmp;
}
class IAXTrunkFrameTrans : public GenObject
{
public:
inline IAXTrunkFrameTrans(IAXTransaction* tr, u_int32_t frameTs)
: m_tr(tr), m_frameTs(frameTs), m_trunkIndex(0)
{}
~IAXTrunkFrameTrans()
{ TelEngine::destruct(m_tr); }
static IAXTrunkFrameTrans* find(ObjList& list, u_int16_t rCallNo);
IAXTransaction* m_tr;
u_int32_t m_frameTs;
unsigned int m_trunkIndex;
};
IAXTrunkFrameTrans* IAXTrunkFrameTrans::find(ObjList& list, u_int16_t rCallNo)
{
for (ObjList* o = list.skipNull(); o; o = o->skipNext()) {
IAXTrunkFrameTrans* t = static_cast<IAXTrunkFrameTrans*>(o->get());
if (t->m_tr->remoteCallNo() == rCallNo)
return t;
}
return 0;
}
/*
* IAXInfoElement
*/
@ -824,11 +850,10 @@ IAXFrame* IAXFrame::parse(const unsigned char* buf, unsigned int len, IAXEngine*
if (buf[2] != 1)
return 0;
bool tstamps = (buf[3] & 1) != 0;
// u_int32_t ts = (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7];
buf += 8;
len -= 8;
if (tstamps) {
// Trunk timestamps (mini frames)
buf += 8;
len -= 8;
while (len >= 6) {
u_int16_t dlen = (buf[0] << 8) | buf[1];
if ((unsigned int)(dlen + 6) > len)
@ -850,6 +875,11 @@ IAXFrame* IAXFrame::parse(const unsigned char* buf, unsigned int len, IAXEngine*
}
else {
// No trunk timestamps
u_int32_t ts = (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7];
buf += 8;
len -= 8;
u_int64_t timeMs = Time::msecNow();
ObjList list;
while (len >= 4) {
u_int16_t dlen = (buf[2] << 8) | buf[3];
if ((unsigned int)(dlen + 4) > len)
@ -860,9 +890,27 @@ IAXFrame* IAXFrame::parse(const unsigned char* buf, unsigned int len, IAXEngine*
retrans = true;
scn &= 0x7fff;
}
IAXFrame* frame = new IAXFrame(IAXFrame::Voice,scn,0,retrans,buf+4,dlen);
engine->addFrame(*addr,frame);
frame->deref();
IAXTrunkFrameTrans* t = IAXTrunkFrameTrans::find(list,scn);
if (!t) {
IAXTransaction* tr = engine->findTransaction(*addr,scn);
if (tr) {
u_int32_t frameTs = 0;
if (tr->updateTrunkRecvTs(frameTs,ts,timeMs)) {
t = new IAXTrunkFrameTrans(tr,frameTs);
list.append(t);
}
else
TelEngine::destruct(tr);
}
}
else
// Adjust timestamp: there are more packets for the same transaction
t->m_frameTs++;
if (t) {
IAXFrame* frame = new IAXFrame(IAXFrame::Voice,scn,t->m_frameTs,retrans,buf+4,dlen);
if (!t->m_tr->processFrame(frame))
frame->deref();
}
dlen += 4;
buf += dlen;
len -= dlen;

View File

@ -76,7 +76,8 @@ IAXTransaction::IAXTransaction(IAXEngine* engine, IAXFullFrame* frame, u_int16_t
m_expire(60),
m_format(IAXFormat::Audio), m_formatVideo(IAXFormat::Video),
m_capability(0), m_callToken(false),
m_trunkFrame(0)
m_trunkFrame(0),
m_trunkInOffsetTimeMs(0), m_trunkInLastTs(0), m_warnTrunkInTimestamp(true)
{
Debug(m_engine,DebugAll,"Transaction(%u,%u) incoming type=%u remote=%s:%d [%p]",
localCallNo(),remoteCallNo(),m_type,m_addr.host().c_str(),m_addr.port(),this);
@ -139,7 +140,8 @@ IAXTransaction::IAXTransaction(IAXEngine* engine, Type type, u_int16_t lcallno,
m_expire(60),
m_format(IAXFormat::Audio), m_formatVideo(IAXFormat::Video),
m_capability(0), m_callToken(false),
m_trunkFrame(0)
m_trunkFrame(0),
m_trunkInOffsetTimeMs(0), m_trunkInLastTs(0), m_warnTrunkInTimestamp(true)
{
Debug(m_engine,DebugAll,"Transaction(%u,%u) outgoing type=%u remote=%s:%d [%p]",
localCallNo(),remoteCallNo(),m_type,m_addr.host().c_str(),m_addr.port(),this);
@ -838,6 +840,47 @@ void IAXTransaction::processCallToken(const DataBlock& callToken)
sendFrame(frame);
}
// Update transaction incoming trunk data (used for trunk without timestamps)
bool IAXTransaction::updateTrunkRecvTs(u_int32_t& frameTs, u_int32_t ts, u_int64_t currentTimeMs)
{
Lock lck(this);
if (m_trunkInLastTs) {
bool ok = (ts > m_trunkInLastTs);
if (!ok) {
// Allow frames older then 5 seconds to restart trunk
if ((m_trunkInLastTs - ts) >= 5000) {
ok = true;
m_trunkInOffsetTimeMs = 0;
}
else
ok = (m_trunkInOffsetTimeMs == 0);
}
if (!ok) {
if (m_warnTrunkInTimestamp) {
Debug(m_engine,DebugNote,
"Transaction(%u,%u) ignoring trunked mini-frame without timestamps from %s:%d with ts=%u last=%u [%p]",
localCallNo(),remoteCallNo(),remoteAddr().host().c_str(),remoteAddr().port(),
ts,m_trunkInLastTs,this);
m_warnTrunkInTimestamp = false;
}
return false;
}
m_warnTrunkInTimestamp = true;
}
m_trunkInLastTs = ts;
if (!m_trunkInOffsetTimeMs) {
if (!currentTimeMs)
currentTimeMs = Time::msecNow();
u_int64_t trunkStart = currentTimeMs - ts;
m_trunkInOffsetTimeMs = (int64_t)m_timeStamp - trunkStart;
}
if (m_trunkInOffsetTimeMs >= 0)
frameTs = ts - (u_int32_t)m_trunkInOffsetTimeMs;
else
frameTs = ts + (u_int32_t)(-m_trunkInOffsetTimeMs);
return true;
}
void IAXTransaction::print(bool printStats, bool printFrames, const char* location)
{
if (m_engine && !m_engine->debugAt(DebugAll))

View File

@ -1791,6 +1791,15 @@ public:
*/
void processCallToken(const DataBlock& callToken);
/**
* Update transaction incoming trunk data (used for trunk without timestamps)
* @param frameTs Address of variable to be set with frame timestamp
* @param ts Trunk frame timestamp
* @param currentTimeMs Current time
* @return True if accepted
*/
bool updateTrunkRecvTs(u_int32_t& frameTs, u_int32_t ts, u_int64_t currentTimeMs);
/**
* Print transaction data on stdin
* @param printStats True to print media statistics
@ -2236,6 +2245,9 @@ private:
bool m_callToken; // Call token supported/expected
// Meta trunking
IAXMetaTrunkFrame* m_trunkFrame; // Reference to a trunk frame if trunking is enabled for this transaction
int64_t m_trunkInOffsetTimeMs; // Offset between transaction start and trunk start
u_int32_t m_trunkInLastTs; // Last received trunk timestamp
bool m_warnTrunkInTimestamp; // Warn incoming trunk invalid timestamp
};
/**
@ -2433,6 +2445,15 @@ public:
*/
IAXTransaction* addFrame(const SocketAddr& addr, const unsigned char* buf, unsigned int len);
/**
* Find a complete transaction.
* This method is thread safe
* @param addr Remote address
* @param rCallNo Remote transaction call number
* @return Referrenced pointer to the transaction or 0
*/
IAXTransaction* findTransaction(const SocketAddr& addr, u_int16_t rCallNo);
/**
* Process media from remote peer. Descendents must override this method
* @param transaction IAXTransaction that owns the call leg