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:
parent
59f4159cbf
commit
a3fc6023a1
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue