Properly send and handle call termination reason.

git-svn-id: http://yate.null.ro/svn/yate/trunk@5522 acf43c95-373e-0410-b603-e72c3f656dc1
This commit is contained in:
marian 2013-06-04 13:31:33 +00:00
parent 59f4159cbf
commit a3fc6023a1
3 changed files with 136 additions and 22 deletions

View File

@ -29,18 +29,18 @@
using namespace TelEngine;
inline void setStringFromInteger(String& dest, u_int32_t value, u_int8_t length)
static inline void setStringFromInteger(String& dest, u_int32_t value, u_int8_t length)
{
char tmp[11];
switch (length) {
case 1:
sprintf(tmp,"%0#4x",(u_int8_t)value);
sprintf(tmp,"0x%02x",(u_int8_t)value);
break;
case 2:
sprintf(tmp,"%0#6x",(u_int16_t)value);
sprintf(tmp,"0x%04x",(u_int16_t)value);
break;
default:
sprintf(tmp,"%0#10x",value);
sprintf(tmp,"0x%08x",value);
break;
}
dest = tmp;
@ -75,7 +75,69 @@ IAXTrunkFrameTrans* IAXTrunkFrameTrans::find(ObjList& list, u_int16_t rCallNo)
/*
* IAXInfoElement
*/
TokenDict IAXInfoElement::s_ieData[] = {
const TokenDict IAXInfoElement::s_causeName[] = {
{"unallocated", 1}, // Unallocated (unassigned) number
{"noroute-to-network", 2}, // No route to specified transit network
{"noroute", 3}, // No route to destination
{"channel-unacceptable", 6}, // Channel unacceptable
{"call-delivered", 7}, // Call awarded and being delivered in an established channel
{"normal-clearing", 16}, // Normal Clearing
{"busy", 17}, // User busy
{"noresponse", 18}, // No user responding
{"noanswer", 19}, // No answer from user (user alerted)
{"rejected", 21}, // Call Rejected
{"moved", 22}, // Number changed
{"out-of-order", 27}, // Destination out of order
{"invalid-number", 28}, // Invalid number format
{"facility-rejected", 29}, // Facility rejected
{"status-enquiry-rsp", 30}, // Response to STATUS ENQUIRY
{"normal", 31}, // Normal, unspecified
{"congestion", 34}, // No circuit/channel available
{"channel-congestion", 34},
{"net-out-of-order", 38}, // Network out of order
{"noconn", 41},
{"temporary-failure", 41}, // Temporary failure
{"congestion", 42}, // Switching equipment congestion
{"switch-congestion", 42},
{"access-info-discarded", 43}, // Access information discarded
{"channel-unavailable", 44}, // Requested channel not available
{"preempted", 45}, // Preempted
{"noresource", 47}, // Resource unavailable, unspecified
{"facility-not-subscribed", 50}, // Requested facility not subscribed
{"barred-out", 52}, // Outgoing call barred
{"barred-in", 54}, // Incoming call barred
{"bearer-cap-not-auth", 57}, // Bearer capability not authorized
{"bearer-cap-not-available", 58}, // Bearer capability not presently available
{"nomedia", 58},
{"service-unavailable", 63}, // Service or option not available
{"bearer-cap-not-implemented", 65}, // Bearer capability not implemented
{"channel-type-not-implemented", 66}, // Channel type not implemented
{"facility-not-implemented", 69}, // Requested facility not implemented
{"restrict-bearer-cap-avail", 70}, // Only restricted digital information bearer capability is available
{"service-not-implemented", 79}, // Service or option not implemented, unspecified
{"invalid-callref", 81}, // Invalid call reference value
{"unknown-channel", 82}, // Identified channel does not exist
{"unknown-callid", 83}, // A suspended call exists, but this call identity does not
{"duplicate-callid", 84}, // Call identity in use
{"no-call-suspended", 85}, // No call suspended
{"suspended-call-cleared", 86}, // Call having the requested call identity has been cleared
{"incompatible-dest", 88}, // Incompatible destination
{"invalid-transit-net", 91}, // Invalid transit network selection
{"invalid-message", 95}, // Invalid message, unspecified
{"missing-mandatory-ie", 96}, // Mandatory information element is missing
{"unknown-message", 97}, // Message type non-existent or not implemented
{"wrong-message", 98}, // Message not compatible with call state, non-existent or not implemented
{"unknown-ie", 99}, // Information element non-existent or not implemented
{"invalid-ie", 100}, // Invalid information element contents
{"wrong-state-message", 101}, // Message not compatible with call state
{"timeout", 102}, // Recovery on timer expiry
{"mandatory-ie-len", 103}, // Mandatory information element length error
{"protocol-error", 111}, // Protocol error, unspecified
{"interworking", 127}, // Interworking, unspecified
{0,0}
};
const TokenDict IAXInfoElement::s_ieData[] = {
{"CALLED_NUMBER", CALLED_NUMBER},
{"CALLING_NUMBER", CALLING_NUMBER},
{"CALLING_ANI", CALLING_ANI},
@ -435,6 +497,15 @@ void IAXIEList::toBuffer(DataBlock& buf)
}
}
static inline void addNumericName(String& buf, IAXInfoElement* ie, const TokenDict* dict,
const char* prefix = " (", const char* suffix = ")")
{
int val = (static_cast<IAXInfoElementNumeric*>(ie))->data();
const char* s = lookup(val,dict);
if (s)
buf << prefix << s << suffix;
}
void IAXIEList::toString(String& dest, const char* indent)
{
ObjList* obj = m_list.skipNull();
@ -557,10 +628,13 @@ void IAXIEList::toString(String& dest, const char* indent)
case IAXInfoElement::IAX_UNKNOWN:
case IAXInfoElement::CALLINGPRES: //TODO: print more data
case IAXInfoElement::CALLINGTON: //TODO: print more data
case IAXInfoElement::CAUSECODE: //TODO: print more data
case IAXInfoElement::ENCRYPTION: //TODO: print more data
ie->toString(dest);
break;
case IAXInfoElement::CAUSECODE:
ie->toString(dest);
addNumericName(dest,ie,IAXInfoElement::s_causeName);
break;
case IAXInfoElement::MSGCOUNT:
{
u_int16_t val = (static_cast<IAXInfoElementNumeric*>(ie))->data();

View File

@ -165,9 +165,30 @@ public:
static inline const char* ieText(u_int8_t ieCode)
{ return lookup(ieCode,s_ieData); }
/**
* Retrieve the cause name associated with a given code
* @param code Cause code
* @return Cause name, 0 if not found
*/
static inline const char* causeName(int code)
{ return lookup(code,s_causeName); }
/**
* Retrieve the cause code associated with a given name
* @param name Cause name
* @param defVal Default value to return if not found
* @return Cause code
*/
static inline int causeCode(const char* name, int defVal = 0)
{ return lookup(name,s_causeName,defVal); }
/**
* Cause code dictionary
*/
static const TokenDict s_causeName[];
private:
static TokenDict s_ieData[];// Association between IE type and text
static const TokenDict s_ieData[];// Association between IE type and text
Type m_type; // Type of this IE
};

View File

@ -521,7 +521,7 @@ public:
protected:
// location: 0: from peer, else: from protocol
void hangup(int location, const char* reason = 0, bool reject = false);
void hangup(int location, const char* error = 0, const char* reason = 0, bool reject = false);
void startMedia(bool in, int type = IAXFormat::Audio);
void clearMedia(bool in, int type = IAXFormat::Audio);
void evAuthRep(IAXEvent* event);
@ -1803,7 +1803,7 @@ void YIAXConnection::callRejected(const char* error, const char* reason, const M
error = reason;
String s(error);
Lock lock(m_mutexTrans);
if (m_transaction && s == "noauth") {
if (m_transaction && error && String(error) == "noauth") {
if (safeRefIncrease()) {
Debug(this,DebugInfo,"callRejected. Requesting authentication [%p]",this);
m_transaction->sendAuth();
@ -1813,8 +1813,8 @@ void YIAXConnection::callRejected(const char* error, const char* reason, const M
error = "temporary-failure";
}
lock.drop();
Debug(this,DebugCall,"callRejected. Reason: '%s' [%p]",error,this);
hangup(0,reason,true);
Debug(this,DebugCall,"callRejected. Error: '%s' [%p]",error,this);
hangup(0,error,reason,true);
}
bool YIAXConnection::callRouted(Message& msg)
@ -1968,10 +1968,21 @@ void YIAXConnection::handleEvent(IAXEvent* event)
case IAXEvent::Hangup:
case IAXEvent::Reject:
{
String error;
String reason;
event->getList().getString(IAXInfoElement::CAUSE,reason);
DDebug(this,DebugCall,"REJECT/HANGUP: '%s' [%p]",reason.c_str(),this);
hangup(event->local() ? 1 : -1,reason);
u_int32_t code = 0;
event->getList().getNumeric(IAXInfoElement::CAUSECODE,code);
if (code) {
const char* s = IAXInfoElement::causeName(code);
if (s)
error = s;
else
error = (unsigned int)code;
}
DDebug(this,DebugCall,"REJECT/HANGUP: error='%s' reason='%s' [%p]",
error.c_str(),reason.c_str(),this);
hangup(event->local() ? 1 : -1,error,reason);
}
break;
case IAXEvent::Timeout:
@ -2003,15 +2014,15 @@ void YIAXConnection::handleEvent(IAXEvent* event)
}
}
void YIAXConnection::hangup(int location, const char* reason, bool reject)
void YIAXConnection::hangup(int location, const char* error, const char* reason, bool reject)
{
if (!m_hangup)
return;
m_hangup = false;
if (m_reason.null())
m_reason = reason;
if (m_reason.null())
m_reason = Engine::exiting() ? "shutdown" : "unknown";
if (!m_reason)
m_reason = error ? error : reason;
if (!m_reason && location != -1)
m_reason = Engine::exiting() ? "shutdown" : "";
const char* loc = location ? (location > 0 ? "internal" : "remote") : "peer";
clearMedia(true);
clearMedia(false);
@ -2034,10 +2045,18 @@ void YIAXConnection::hangup(int location, const char* reason, bool reject)
d->print(tmp);
m->addParam("iax_stats_video",tmp);
}
u_int8_t code = 0;
if (m_reason) {
int val = IAXInfoElement::causeCode(m_reason);
if (val)
code = val;
else
code = m_reason.toInteger(0,0,0,127);
}
if (reject)
m_transaction->sendReject(m_reason);
m_transaction->sendReject(reason,code);
else
m_transaction->sendHangup(m_reason);
m_transaction->sendHangup(reason,code);
m_transaction->setUserData(0);
m_transaction = 0;
}
@ -2060,7 +2079,7 @@ bool YIAXConnection::route(bool authenticated)
else {
DDebug(this,DebugAll,"Route pass 1: No username [%p]",this);
if (!iplugin.getEngine()->acceptFormatAndCapability(m_transaction)) {
hangup(0,IAXTransaction::s_iax_modNoMediaFormat,true);
hangup(0,"nomedia",0,true);
return false;
}
// Advertise the not yet authenticated username
@ -2194,7 +2213,7 @@ void YIAXConnection::evAuthRep(IAXEvent* event)
}
DDebug(this,DebugCall,"Not authenticated. Rejecting [%p]",this);
event->setFinal();
hangup(1,"noauth",true);
hangup(1,"noauth",0,true);
}
void YIAXConnection::evAuthReq(IAXEvent* event)