Fixed bug: avoid rejecting a call when a full Voice frame is received before processing Accept.

git-svn-id: http://yate.null.ro/svn/yate/trunk@5551 acf43c95-373e-0410-b603-e72c3f656dc1
This commit is contained in:
marian 2013-06-24 09:13:17 +00:00
parent 5f3ab731e3
commit cab5d6ebc4
2 changed files with 82 additions and 14 deletions

View File

@ -55,6 +55,8 @@ String IAXTransaction::s_iax_modNoMediaFormat("Unsupported or missing media form
String IAXTransaction::s_iax_modInvalidAuth("Invalid authentication request, response or challenge");
String IAXTransaction::s_iax_modNoUsername("Username is missing");
static const String s_voiceBeforeAccept = "Received full Voice before Accept";
unsigned char IAXTransaction::m_maxInFrames = 100;
static inline bool canUpdLastAckSeq(u_int32_t seq, u_int32_t last)
@ -82,6 +84,7 @@ IAXTransaction::IAXTransaction(IAXEngine* engine, IAXFullFrame* frame, u_int16_t
m_type(Incorrect),
m_state(Unknown),
m_destroy(false),
m_accepted(false),
m_timeStamp(Time::msecNow() - 1),
m_timeout(0),
m_addr(addr),
@ -156,6 +159,7 @@ IAXTransaction::IAXTransaction(IAXEngine* engine, Type type, u_int16_t lcallno,
m_type(type),
m_state(Unknown),
m_destroy(false),
m_accepted(false),
m_timeStamp(Time::msecNow() - 1),
m_timeout(0),
m_addr(addr),
@ -255,6 +259,7 @@ IAXTransaction::~IAXTransaction()
{
if (m_startIEs)
delete m_startIEs;
setPendingEvent();
XDebug(m_engine,DebugAll,"IAXTransaction::~IAXTransaction(%u,%u). [%p]",
localCallNo(),remoteCallNo(),this);
}
@ -342,7 +347,21 @@ IAXTransaction* IAXTransaction::processFrame(IAXFrame* frame)
if (state() == Terminating)
return 0;
int t = IAXFormat::Audio;
if (frame->type() == IAXFrame::Video)
if (frame->type() == IAXFrame::Voice) {
if (outgoing()) {
if (!m_accepted) {
// Code 101: wrong-state-message
IAXEvent* e = checkAcceptRecv(s_voiceBeforeAccept,101);
if (e) {
setPendingEvent(e);
return 0;
}
}
}
else if (!m_accepted)
setPendingEvent(internalReject(s_voiceBeforeAccept,101));
}
else
t = IAXFormat::Video;
if (!processMediaFrame(full,t))
return 0;
@ -672,7 +691,6 @@ IAXEvent* IAXTransaction::getEvent(const Time& now)
IAXEvent* ev = 0;
GenObject* obj;
bool delFrame;
Lock lock(this);
if (state() == Terminated)
return 0;
@ -832,6 +850,7 @@ bool IAXTransaction::sendAccept(unsigned int* expires)
(type() == RegReq && state() == NewRemoteInvite) ||
((type() == RegReq || type() == RegRel) && state() == NewRemoteInvite_RepRecv)))
return false;
m_accepted = true;
if (type() == New) {
IAXIEList* ies = new IAXIEList;
ies->appendNumeric(IAXInfoElement::FORMAT,m_format.format() | m_formatVideo.format(),4);
@ -1543,13 +1562,10 @@ IAXEvent* IAXTransaction::processAccept(IAXEvent* event)
return event;
Debug(m_engine,DebugAll,"Transaction(%u,%u). Accept received [%p]",
localCallNo(),remoteCallNo(),this);
u_int32_t fmt = 0;
event->getList().getNumeric(IAXInfoElement::FORMAT,fmt);
m_format.set(&fmt,0,0);
m_formatVideo.set(&fmt,0,0);
m_engine->acceptFormatAndCapability(this,0,IAXFormat::Audio);
m_engine->acceptFormatAndCapability(this,0,IAXFormat::Video);
if (m_format.format() || m_formatVideo.format())
if (m_accepted)
return event;
m_accepted = true;
if (processAcceptFmt(&event->getList()))
return event;
delete event;
// Code 58: nomedia
@ -2039,7 +2055,7 @@ IAXTransaction* IAXTransaction::processMediaFrame(const IAXFullFrame* frame, int
"IAXTransaction(%u,%u). Received %s frame with unknown format=0x%x [%p]",
localCallNo(),remoteCallNo(),IAXFrame::typeText(frame->type()),recvFmt,this);
// Code 58: nomedia
m_pendingEvent = internalReject(s_iax_modNoMediaFormat,58);
setPendingEvent(internalReject(s_iax_modNoMediaFormat,58));
return 0;
}
// We might have an incoming media format received with an Accept frame
@ -2056,7 +2072,7 @@ IAXTransaction* IAXTransaction::processMediaFrame(const IAXFullFrame* frame, int
"IAXTransaction(%u,%u). Format change rejected media=%s current=%u [%p]",
localCallNo(),remoteCallNo(),fmt->typeName(),fmt->format(),this);
// Code 58: nomedia
m_pendingEvent = internalReject(s_iax_modNoMediaFormat,58);
setPendingEvent(internalReject(s_iax_modNoMediaFormat,58));
return 0;
}
}
@ -2083,14 +2099,16 @@ IAXTransaction* IAXTransaction::retransmitOnVNAK(u_int16_t seqNo)
return 0;
}
IAXEvent* IAXTransaction::internalReject(String& reason, u_int8_t code)
IAXEvent* IAXTransaction::internalReject(const char* reason, u_int8_t code)
{
Debug(m_engine,DebugAll,
"Transaction(%u,%u). Internal reject cause='%s' code=%u [%p]",
localCallNo(),remoteCallNo(),reason.c_str(),code,this);
localCallNo(),remoteCallNo(),reason,code,this);
sendReject(reason,code);
IAXEvent* event = new IAXEvent(IAXEvent::Reject,true,true,this,IAXFrame::IAX,IAXControl::Reject);
event->getList().appendString(IAXInfoElement::CAUSE,reason);
if (code)
event->getList().appendNumeric(IAXInfoElement::CAUSECODE,code,1);
m_localReqEnd = true;
return event;
}
@ -2160,6 +2178,13 @@ void IAXTransaction::resetTrunk()
TelEngine::destruct(m_trunkFrame);
}
void IAXTransaction::setPendingEvent(IAXEvent* ev)
{
if (m_pendingEvent)
delete m_pendingEvent;
m_pendingEvent = ev;
}
void IAXTransaction::init()
{
Debug(m_engine,DebugAll,"Transaction %s call=%u type=%s remote=%s:%d [%p]",
@ -2177,4 +2202,40 @@ void IAXTransaction::init()
ti = 0;
}
// Process accept format and caps
bool IAXTransaction::processAcceptFmt(IAXIEList* list)
{
Debug(m_engine,DebugAll,"Transaction(%u,%u). Processing Accept format [%p]",
localCallNo(),remoteCallNo(),this);
if (!list)
return false;
u_int32_t fmt = 0;
list->getNumeric(IAXInfoElement::FORMAT,fmt);
m_format.set(&fmt,0,0);
m_formatVideo.set(&fmt,0,0);
m_engine->acceptFormatAndCapability(this,0,IAXFormat::Audio);
m_engine->acceptFormatAndCapability(this,0,IAXFormat::Video);
return m_format.format() || m_formatVideo.format();
}
// Process queued ACCEPT. Reject with given reason/code if not found
// Reject with 'nomedia' if found and format is not acceptable
IAXEvent* IAXTransaction::checkAcceptRecv(const char* reason, u_int8_t code)
{
IAXFullFrame* f = 0;
for (ObjList* o = m_inFrames.skipNull(); o; o = o->skipNext()) {
f = static_cast<IAXFullFrame*>(o->get());
if (f->type() == IAXFrame::IAX && f->subclass() == IAXControl::Accept)
break;
f = 0;
}
if (!f)
return internalReject(reason,code);
m_accepted = true;
if (processAcceptFmt(f->ieList()))
return 0;
// Code 58: nomedia
return internalReject(s_iax_modNoMediaFormat,58);
}
/* vi: set ts=8 sw=4 sts=4 noet: */

View File

@ -2579,7 +2579,7 @@ protected:
* @param code Error code
* @return A valid IAXEvent
*/
IAXEvent* internalReject(String& reason, u_int8_t code);
IAXEvent* internalReject(const char* reason, u_int8_t code);
/**
* Event terminated feedback
@ -2604,12 +2604,18 @@ private:
void receivedVoiceMiniBeforeFull();
void resetTrunk();
void init();
void setPendingEvent(IAXEvent* ev = 0);
inline void restartTrunkIn(u_int64_t now, u_int32_t ts) {
m_trunkInStartTime = now;
u_int64_t dt = (now - m_lastVoiceFrameIn) / 1000;
m_trunkInTsDelta = m_lastVoiceFrameInTs + (u_int32_t)dt;
m_trunkInFirstTs = ts;
}
// Process accept format and caps
bool processAcceptFmt(IAXIEList* list);
// Process queued ACCEPT. Reject with given reason/code if not found
// Reject with 'nomedia' if found and format is not acceptable
IAXEvent* checkAcceptRecv(const char* reason, u_int8_t code);
// Params
bool m_localInitTrans; // True: local initiated transaction
@ -2617,6 +2623,7 @@ private:
Type m_type; // Transaction type
State m_state; // Transaction state
bool m_destroy; // Destroy flag
bool m_accepted; // ACCEPT received and processed
u_int64_t m_timeStamp; // Transaction creation timestamp
u_int64_t m_timeout; // Transaction timeout in Terminating state
SocketAddr m_addr; // Socket