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;
|
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];
|
char tmp[11];
|
||||||
switch (length) {
|
switch (length) {
|
||||||
case 1:
|
case 1:
|
||||||
sprintf(tmp,"%0#4x",(u_int8_t)value);
|
sprintf(tmp,"0x%02x",(u_int8_t)value);
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
sprintf(tmp,"%0#6x",(u_int16_t)value);
|
sprintf(tmp,"0x%04x",(u_int16_t)value);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
sprintf(tmp,"%0#10x",value);
|
sprintf(tmp,"0x%08x",value);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
dest = tmp;
|
dest = tmp;
|
||||||
|
@ -75,7 +75,69 @@ IAXTrunkFrameTrans* IAXTrunkFrameTrans::find(ObjList& list, u_int16_t rCallNo)
|
||||||
/*
|
/*
|
||||||
* IAXInfoElement
|
* 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},
|
{"CALLED_NUMBER", CALLED_NUMBER},
|
||||||
{"CALLING_NUMBER", CALLING_NUMBER},
|
{"CALLING_NUMBER", CALLING_NUMBER},
|
||||||
{"CALLING_ANI", CALLING_ANI},
|
{"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)
|
void IAXIEList::toString(String& dest, const char* indent)
|
||||||
{
|
{
|
||||||
ObjList* obj = m_list.skipNull();
|
ObjList* obj = m_list.skipNull();
|
||||||
|
@ -557,10 +628,13 @@ void IAXIEList::toString(String& dest, const char* indent)
|
||||||
case IAXInfoElement::IAX_UNKNOWN:
|
case IAXInfoElement::IAX_UNKNOWN:
|
||||||
case IAXInfoElement::CALLINGPRES: //TODO: print more data
|
case IAXInfoElement::CALLINGPRES: //TODO: print more data
|
||||||
case IAXInfoElement::CALLINGTON: //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
|
case IAXInfoElement::ENCRYPTION: //TODO: print more data
|
||||||
ie->toString(dest);
|
ie->toString(dest);
|
||||||
break;
|
break;
|
||||||
|
case IAXInfoElement::CAUSECODE:
|
||||||
|
ie->toString(dest);
|
||||||
|
addNumericName(dest,ie,IAXInfoElement::s_causeName);
|
||||||
|
break;
|
||||||
case IAXInfoElement::MSGCOUNT:
|
case IAXInfoElement::MSGCOUNT:
|
||||||
{
|
{
|
||||||
u_int16_t val = (static_cast<IAXInfoElementNumeric*>(ie))->data();
|
u_int16_t val = (static_cast<IAXInfoElementNumeric*>(ie))->data();
|
||||||
|
|
|
@ -165,9 +165,30 @@ public:
|
||||||
static inline const char* ieText(u_int8_t ieCode)
|
static inline const char* ieText(u_int8_t ieCode)
|
||||||
{ return lookup(ieCode,s_ieData); }
|
{ 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:
|
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
|
Type m_type; // Type of this IE
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -521,7 +521,7 @@ public:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// location: 0: from peer, else: from protocol
|
// 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 startMedia(bool in, int type = IAXFormat::Audio);
|
||||||
void clearMedia(bool in, int type = IAXFormat::Audio);
|
void clearMedia(bool in, int type = IAXFormat::Audio);
|
||||||
void evAuthRep(IAXEvent* event);
|
void evAuthRep(IAXEvent* event);
|
||||||
|
@ -1803,7 +1803,7 @@ void YIAXConnection::callRejected(const char* error, const char* reason, const M
|
||||||
error = reason;
|
error = reason;
|
||||||
String s(error);
|
String s(error);
|
||||||
Lock lock(m_mutexTrans);
|
Lock lock(m_mutexTrans);
|
||||||
if (m_transaction && s == "noauth") {
|
if (m_transaction && error && String(error) == "noauth") {
|
||||||
if (safeRefIncrease()) {
|
if (safeRefIncrease()) {
|
||||||
Debug(this,DebugInfo,"callRejected. Requesting authentication [%p]",this);
|
Debug(this,DebugInfo,"callRejected. Requesting authentication [%p]",this);
|
||||||
m_transaction->sendAuth();
|
m_transaction->sendAuth();
|
||||||
|
@ -1813,8 +1813,8 @@ void YIAXConnection::callRejected(const char* error, const char* reason, const M
|
||||||
error = "temporary-failure";
|
error = "temporary-failure";
|
||||||
}
|
}
|
||||||
lock.drop();
|
lock.drop();
|
||||||
Debug(this,DebugCall,"callRejected. Reason: '%s' [%p]",error,this);
|
Debug(this,DebugCall,"callRejected. Error: '%s' [%p]",error,this);
|
||||||
hangup(0,reason,true);
|
hangup(0,error,reason,true);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool YIAXConnection::callRouted(Message& msg)
|
bool YIAXConnection::callRouted(Message& msg)
|
||||||
|
@ -1968,10 +1968,21 @@ void YIAXConnection::handleEvent(IAXEvent* event)
|
||||||
case IAXEvent::Hangup:
|
case IAXEvent::Hangup:
|
||||||
case IAXEvent::Reject:
|
case IAXEvent::Reject:
|
||||||
{
|
{
|
||||||
|
String error;
|
||||||
String reason;
|
String reason;
|
||||||
event->getList().getString(IAXInfoElement::CAUSE,reason);
|
event->getList().getString(IAXInfoElement::CAUSE,reason);
|
||||||
DDebug(this,DebugCall,"REJECT/HANGUP: '%s' [%p]",reason.c_str(),this);
|
u_int32_t code = 0;
|
||||||
hangup(event->local() ? 1 : -1,reason);
|
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;
|
break;
|
||||||
case IAXEvent::Timeout:
|
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)
|
if (!m_hangup)
|
||||||
return;
|
return;
|
||||||
m_hangup = false;
|
m_hangup = false;
|
||||||
if (m_reason.null())
|
if (!m_reason)
|
||||||
m_reason = reason;
|
m_reason = error ? error : reason;
|
||||||
if (m_reason.null())
|
if (!m_reason && location != -1)
|
||||||
m_reason = Engine::exiting() ? "shutdown" : "unknown";
|
m_reason = Engine::exiting() ? "shutdown" : "";
|
||||||
const char* loc = location ? (location > 0 ? "internal" : "remote") : "peer";
|
const char* loc = location ? (location > 0 ? "internal" : "remote") : "peer";
|
||||||
clearMedia(true);
|
clearMedia(true);
|
||||||
clearMedia(false);
|
clearMedia(false);
|
||||||
|
@ -2034,10 +2045,18 @@ void YIAXConnection::hangup(int location, const char* reason, bool reject)
|
||||||
d->print(tmp);
|
d->print(tmp);
|
||||||
m->addParam("iax_stats_video",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)
|
if (reject)
|
||||||
m_transaction->sendReject(m_reason);
|
m_transaction->sendReject(reason,code);
|
||||||
else
|
else
|
||||||
m_transaction->sendHangup(m_reason);
|
m_transaction->sendHangup(reason,code);
|
||||||
m_transaction->setUserData(0);
|
m_transaction->setUserData(0);
|
||||||
m_transaction = 0;
|
m_transaction = 0;
|
||||||
}
|
}
|
||||||
|
@ -2060,7 +2079,7 @@ bool YIAXConnection::route(bool authenticated)
|
||||||
else {
|
else {
|
||||||
DDebug(this,DebugAll,"Route pass 1: No username [%p]",this);
|
DDebug(this,DebugAll,"Route pass 1: No username [%p]",this);
|
||||||
if (!iplugin.getEngine()->acceptFormatAndCapability(m_transaction)) {
|
if (!iplugin.getEngine()->acceptFormatAndCapability(m_transaction)) {
|
||||||
hangup(0,IAXTransaction::s_iax_modNoMediaFormat,true);
|
hangup(0,"nomedia",0,true);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Advertise the not yet authenticated username
|
// Advertise the not yet authenticated username
|
||||||
|
@ -2194,7 +2213,7 @@ void YIAXConnection::evAuthRep(IAXEvent* event)
|
||||||
}
|
}
|
||||||
DDebug(this,DebugCall,"Not authenticated. Rejecting [%p]",this);
|
DDebug(this,DebugCall,"Not authenticated. Rejecting [%p]",this);
|
||||||
event->setFinal();
|
event->setFinal();
|
||||||
hangup(1,"noauth",true);
|
hangup(1,"noauth",0,true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void YIAXConnection::evAuthReq(IAXEvent* event)
|
void YIAXConnection::evAuthReq(IAXEvent* event)
|
||||||
|
|
Loading…
Reference in New Issue