From a3fc6023a13280e3c3a43879018c14e2d4538cf6 Mon Sep 17 00:00:00 2001 From: marian Date: Tue, 4 Jun 2013 13:31:33 +0000 Subject: [PATCH] Properly send and handle call termination reason. git-svn-id: http://yate.null.ro/svn/yate/trunk@5522 acf43c95-373e-0410-b603-e72c3f656dc1 --- libs/yiax/frame.cpp | 86 ++++++++++++++++++++++++++++++++++++++++---- libs/yiax/yateiax.h | 23 +++++++++++- modules/yiaxchan.cpp | 49 +++++++++++++++++-------- 3 files changed, 136 insertions(+), 22 deletions(-) diff --git a/libs/yiax/frame.cpp b/libs/yiax/frame.cpp index 47a1bcfe..66473e8e 100644 --- a/libs/yiax/frame.cpp +++ b/libs/yiax/frame.cpp @@ -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(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(ie))->data(); diff --git a/libs/yiax/yateiax.h b/libs/yiax/yateiax.h index 860339d9..c2d1c035 100644 --- a/libs/yiax/yateiax.h +++ b/libs/yiax/yateiax.h @@ -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 }; diff --git a/modules/yiaxchan.cpp b/modules/yiaxchan.cpp index 36383c77..509e5ca6 100644 --- a/modules/yiaxchan.cpp +++ b/modules/yiaxchan.cpp @@ -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)