[Home]

Summary:ASTERISK-23484: HANGUPCAUSE can't get any information on a hungup inbound channel unless called with no arguments, plus unaffected by use_q850_reason
Reporter:Nick Adams (Narkov)Labels:
Date Opened:2014-03-13 19:21:54Date Closed:
Priority:MajorRegression?
Status:Open/NewComponents:Channels/chan_sip/General Channels/General Functions/func_hangupcause
Versions:SVN 11.8.1 13.18.4 Frequency of
Occurrence
Related
Issues:
Environment:Ubuntu 13.04; x86_64; Kernal 3.8.0-27-genericAttachments:( 0) myDebugLog
Description:My provider returns SIP 404 response for a Q.850 code of 3 ("No route to destination"). I want Asterisk to prioritise the Q.850 Reason code instead of using the SIP 404 when populating the HANGUPCAUSE variable as the Q.850 code gives me more detail and greater control in my dialplan.

I've set "use_q850_reason=yes" in sip.conf and Asterisk correctly identifies the Reason header:

{quote}
SIP/2.0 404 Not Found
Via: SIP/2.0/UDP 172.X.X.X:5060;branch=z9hG4bK728b99fd;rport=5060
Max-Forwards: 68
From: "Anonymous" <sip:anonymous@anonymous.invalid>;tag=as31832f10
To: <sip:614XXXXXXXX@172.X.X.X:5060>;tag=Ztm3ZB2Xr0jgp
Call-ID: 59a1c91a4be33a1b2fc4a90f5c5e8224@172.X.X.X:5060
CSeq: 102 INVITE
User-Agent: FreeSWITCH-mod_sofia/1.2.10+git~20130624T144607Z~998ae35dbf
Accept: application/sdp
Allow: INVITE, ACK, BYE, CANCEL, OPTIONS, MESSAGE, INFO, UPDATE, REGISTER, NOTIFY
Supported: timer, precondition, path, replaces
Allow-Events: talk, hold, conference, refer
Reason: Q.850;cause=3;text="NO_ROUTE_DESTINATION"
Content-Length: 0

<------------->
--- (14 headers 0 lines) ---
Using Reason header for cause code: 3
{quote}

I use the below dialplan to originate the call into:
{quote}
exten => s,1,Dial(SIP/MyProvider/614xxxxxxxx,30,g)
exten => s,n,NoOp(DEBUG1:HANGUPCAUSE=$\{HANGUPCAUSE\} DIALSTATUS=$\{DIALSTATUS\})
exten => s,n,Hangup

exten => t,1,Hangup

exten => h,1,NoOp(DEBUG2: HANGUPCAUSE=$\{HANGUPCAUSE\} DIALSTATUS=$\{DIALSTATUS\})
{quote}

Despite Asterisk correctly extracting the Reason code ("3"), the HANGUPCAUSE returns "1":

{quote}
Executing [614XXXXXX@CallSpooler:2] NoOp("Local/614XXXXXX@CallSpooler-00000001;2", "DEBUG1:  HANGUPCAUSE=1 DIALSTATUS=CHANUNAVAIL") in new stack
-- Executing [h@CallSpooler:1] NoOp("Local/614XXXXXX@CallSpooler-00000000;2", "DEBUG2: HANGUPCAUSE=1 DIALSTATUS=CHANUNAVAIL") in new stack
{quote}

The expectation is that the HANGUPCAUSE variable should be set to "3" however it seems to be set to "1". I'm not sure if there is a conflict between the HANGUPCAUSE of the Local channel as opposed to the SIP channel however the Q.850 reason seems to be clobbered.
Comments:By: Nick Adams (Narkov) 2014-03-13 21:08:04.047-0500

Could the reason for this bug be that the SIP 404 response is clobbering the HANGUPCAUSE field set by use_q850_reason code? I'm not that familar with the Asterisk code base however could the fix in ASTERISK-19914 be causing this?

By: Rusty Newton (rnewton) 2014-03-17 15:22:46.395-0500

Could you set up a test for comparison that doesn't involve the local channels? That, is a SIP channel connected out another SIP channel.

If you can do that and provide an [Asterisk full log|https://wiki.asterisk.org/wiki/display/AST/Collecting+Debug+Information] showing the whole thing (be sure you have both DEBUG and VERBOSE) would be immensely helpful.

By: Nick Adams (Narkov) 2014-03-17 17:01:15.799-0500

Debug output

By: Nick Adams (Narkov) 2014-03-17 17:08:37.952-0500

Hi Rusty. Thanks for picking this up. Attached is a full log output as requested. I've anonymised some parts so please let me know if you need anything else.

The crucial lines are as follows:

Line 595 = Q.850 response from provider: "Reason: Q.850;cause=3;text="NO_ROUTE_DESTINATION"
Line 615 = chan_sip correctly extracting the Q.850 code: "chan_sip.c: Using Reason header for cause code: 3"
Line 650 = pbx.c saying HANGUPCAUSE is '1'
Line 680 = Q.850;cause=1 being returned to the originating channel. The expectation was that this would be Q.850;cause=3

By: Nick Adams (Narkov) 2014-03-26 01:29:51.408-0500

Firstly - I'm not a C coder so please forgive me if this is vague or misleading.

I've just conducted some regression testing and found that the value of HANGUPCAUSE in this particular situation (SIP 404 & "Reason: Q.850;cause=3") returns HANGUPCAUSE=34 in 10.5.2 and changes to HANGUPCAUSE=1 starting with 10.6 and every version thereafter. This suggests that the patch from ASTERISK-19914 is indeed overwriting the "use_q850_reason" directive.

This still seems like a herring as I don't believe that HANGUPCAUSE=34 is correct as "use_q850_reason" implies that the Reason header should be used to set HANGUPCAUSE and therefore be equal to "3" in my example. Line 23760 of chan_sip.c correctly sets the HANGUPCAUSE from the q850 code but then, and this is where I'm not sure, chan_sip.c:23040 seems to overwrite this based on the hangup_sip2cause/SIP 404 translation.

"sip_queue_hangup_cause" should only be set if the cause hasn't already been set. Am I on the right track here?

By: Rusty Newton (rnewton) 2014-04-04 18:18:54.752-0500

bq. Firstly - I'm not a C coder so please forgive me if this is vague or misleading.

I'm not a C developer either, so I'm going to refrain from commenting on the code.

It is useful to note that from 10 to 11, I believe HANGUPCAUSE went from channel variable to function.  I'm not going to address 10 in my testing or research since it is end of life and no longer supported.

I tested a few scenarios to help us all understand the current behavior of HANGUPCAUSE, as I rarely use it and it was a little confusing combined with the use_q850_reason option. I used a pre-dial handler to set a hangup handler on the created outbound channel, so that we could see the returned HANGUPCAUSE values on both the dialing (inbound) and outbound channels.

I then had Asterisk call SIPp, where SIPp returns a SIP 404 with a Reason header just like yours "Reason: Q.850;cause=3;text="NO_ROUTE_DESTINATION""

I verified that in test cases where I enabled use_q850_reason, that in the debug I saw "chan_sip.c: Using Reason header for cause code: 3" during the processing of the 404. I presume that in these cases I should see some effect on what HANGUPCAUSE returns based on the description of use_q850_reason in sip.conf.sample

In the below excerpts of my test output, first you see HANGUPCAUSE output from the created outbound channel hanging up, then below it you'll see output from the dialing channel hanging up. Also, excuse some of the wiki formatting. It doesn't like curly braces and parens.



With use_q850_reason *undefined* and calling HANGUPCAUSE with no arguments

{noformat}
   -- Executing [s@hdlr1:1] Verbose("SIP/10.24.18.124:5061-00000002", "0,"HANGUP HANDLER - HANGUPCAUSE = 1 DIALSTATUS = "") in new stack
<snip>
   -- Executing [888@from-internal:2] Verbose("SIP/6001-00000001", "0,"HANGUPCAUSE = 1 DIALSTATUS = CHANUNAVAIL"") in new stack
{noformat}

With use_q850_reason=yes and calling HANGUPCAUSE with no arguments

{noformat}
   -- Executing [s@hdlr1:1] Verbose("SIP/10.24.18.124:5061-00000001", "0,"HANGUP HANDLER - HANGUPCAUSE = 1 DIALSTATUS = "") in new stack
<snip>
   -- Executing [888@from-internal:2] Verbose("SIP/6001-00000000", "0,"HANGUPCAUSE = 1 DIALSTATUS = CHANUNAVAIL"") in new stack
{noformat}

With use_q850_reason *undefined* and calling HANGUPCAUSE(${CHANNEL},ast)

{noformat}
   -- Executing [s@hdlr1:1] Verbose("SIP/10.24.18.124:5061-00000001", "0,"HANGUP HANDLER - HANGUPCAUSE = Unallocated (unassigned) number DIALSTATUS = "") in new stack
<snip>
[Apr  4 17:08:27] WARNING[16598][C-00000000]: func_hangupcause.c:140 hangupcause_read: Unable to find information for channel SIP/6001-00000000
   -- Executing [888@from-internal:2] Verbose("SIP/6001-00000000", "0,"HANGUPCAUSE =  DIALSTATUS = CHANUNAVAIL"") in new stack
{noformat}

With use_q850_reason=yes and calling HANGUPCAUSE(${CHANNEL},ast)

{noformat}
   -- Executing [s@hdlr1:1] Verbose("SIP/10.24.18.124:5061-00000001", "0,"HANGUP HANDLER - HANGUPCAUSE = Unallocated (unassigned) number DIALSTATUS = "") in new stack
<snip>
[Apr  4 17:01:39] WARNING[16438][C-00000000]: func_hangupcause.c:140 hangupcause_read: Unable to find information for channel SIP/6001-00000000
   -- Executing [888@from-internal:2] Verbose("SIP/6001-00000000", "0,"HANGUPCAUSE =  DIALSTATUS = CHANUNAVAIL"") in new stack
{noformat}

With use_q850_reason *undefined* and calling HANGUPCAUSE(${CHANNEL},tech)

{noformat}
   -- Executing [s@hdlr1:1] Verbose("SIP/10.24.18.124:5061-00000001", "0,"HANGUP HANDLER - HANGUPCAUSE = SIP 404 Not Found DIALSTATUS = "") in new stack
<snip>
[Apr  4 17:06:48] WARNING[16545][C-00000000]: func_hangupcause.c:140 hangupcause_read: Unable to find information for channel SIP/6001-00000000
   -- Executing [888@from-internal:2] Verbose("SIP/6001-00000000", "0,"HANGUPCAUSE =  DIALSTATUS = CHANUNAVAIL"") in new stack
{noformat}

With use_q850_reason=yes and calling HANGUPCAUSE(${CHANNEL},tech)

{noformat}
   -- Executing [s@hdlr1:1] Verbose("SIP/10.24.18.124:5061-00000001", "0,"HANGUP HANDLER - HANGUPCAUSE = SIP 404 Not Found DIALSTATUS = "") in new stack
<snip>
[Apr  4 17:03:59] WARNING[16491][C-00000000]: func_hangupcause.c:140 hangupcause_read: Unable to find information for channel SIP/6001-00000000
   -- Executing [888@from-internal:2] Verbose("SIP/6001-00000000", "0,"HANGUPCAUSE =  DIALSTATUS = CHANUNAVAIL"") in new stack
{noformat}


A few observations, some of which may be undefined behavior or bugs.

# The [documentation|https://wiki.asterisk.org/wiki/display/AST/Asterisk+11+Function_HANGUPCAUSE] doesn't specify what HANGUPCAUSE should return when called with no arguments. In your problem scenario, you are calling it with no arguments. I tested that in my first two examples. Calling HANGUPCAUSE with no arguments appears to be returning a Q.850 cause code of 1, with no description. This doesn't appear to be the "Asterisk translated cause code" or the "Channel technology specific" cause code described in the HANGUPCAUSE documentation.
# When calling HANGUPCAUSE, in the second argument field, you can pass two different values to specify that we want either Asterisk's translated cause codes, or Channel technology specific cause codes. I test these in the third through sixth examples.
## The Asterisk translated cause codes come out fine on the outbound channel and are unaffected by use_q850_reason
## The technology specific cause codes come out fine on the outbound channel and are unaffected by use_q850_reason
## Neither the the ast or tech options return any data for the dialing channel.
## I don't know if use_q850_reason is supposed to overwrite both the translated and channel tech cause information. It doesn't appear to overwrite either in my testing, for either channel, which I think represents your reported issue still.

I don't think the HANGUPCAUSE function is using the information from the Reason header at all when use_q850_reason is enabled. Also, I don't think use_q850_reason should overwrite the information HANGUPCAUSE provides when passed the ast or tech options. There should probably be a third option like "q850", but it seems that calling HANGUPCAUSE without arguments returns a q850 cause code with no description.... so, yeah someone should investigate and fix, then document this behavior. I'm not sure what the best solution is.

It does look like use_q850_reason or HANGUPCAUSE is broke.


By: Rusty Newton (rnewton) 2014-04-04 18:30:05.363-0500

A thing I just noticed, I was using a hangup handler on the outbound channel, but not on the inbound channel. I wonder if that affects when HANGUPCAUSE has access to the data retrieved with the ast or tech options.

By: Nick Adams (Narkov) 2014-06-17 21:09:37.115-0500

Is there anything I can do to assist in speeding up a resolution here?

By: art (art) 2015-10-27 07:27:28.246-0500

I also stumbled to this bug. It seem that if you get 404 response with Q.850 reason asterisk will overwrite it with reason code 1 (=404). If you get response code 500 with Q.850 reason header, asterisk will use it as reason code.

I tried to figure where it overwrite it, but there seems to be so many possibilities and I think asterisk has to set it 1/404 to handle correctly sip messages in call.

Note, HANGUPCAUSE is channel variable and HANGUPCAUSE(chan,tech) is dialplan function.

My current way to resolve this is to add few channel variables, which I can then access from dialplan, through hangup handlers:

I modified handle_response function in chan_sip.c (around line number 23709 in asterisk 11.7.0):
{code}
if (rp && sscanf(rp + 6, "%30d", &cause) == 1) {
        ast_channel_hangupcause_set(owner, cause & 0x7f);
        pbx_builtin_setvar_helper(owner , "Q850REASONTEXT" , ast_cause2str(cause)); // added
        char buf[20]; // added
        snprintf(buf, sizeof(buf), "%d", ast_channel_hangupcause(p->owner)); // added
        pbx_builtin_setvar_helper(owner , "Q850REASONCODE" , buf); // added
        if (req->debug)
                 ast_verbose("Using Reason header for cause code: %d\n", ast_channel_hangupcause(owner));
}
{code}

By: Nick Adams (Narkov) 2015-10-27 18:10:07.830-0500

Thanks for the suggestion Art - much appreciated. This doesn't seem to work for me and I think it is because I'm seeing multiple "Reason" header lines:

{noformat}Reason: SIP;cause=404;text="Not Found"
Reason: Q.850;cause=1;text="Unallocated (unassigned) number"{noformat}

As the SIP Reason header doesn't match, I think the Q.850 code is ignored. Is this your understanding as well? If so, are you able to provide an adapted solution?

By: art (art) 2015-10-28 03:11:44.457-0500

Try with following dialplan:

{noformat}
[outbound-chan-q850cause]
exten => s,1,NoOp(set q850 reason)
same => n,Set(MASTER_CHANNEL(Q850REASONCODE)=${Q850REASONCODE})
same => n,Set(MASTER_CHANNEL(Q850REASONTEXT)=${Q850REASONTEXT})
same => n,Return()

[set-hangup-q850]
exten => s,1,Set(CHANNEL(hangup_handler_push)=outbound-chan-q850cause,s,1)
same => n,Return()

[dial]
exten => _XXX.,1,NoOp(test call)
same => n,Dial(SIP/test/${EXTEN},,b(set-hangup-q850^s^1))

exten => h,1,DumpChan()
{noformat}

Asterisk uses only "Reason: Q.850" header, with "use_q850_reason=yes" setting.
I think asterisk first sets reason to q.850 header reason, but changes it later to same as SIP response code ( 404, which is same as ast/isdn reason 1).