ASTERISK converting Error 503 to Error 404

Hi,

We are seeing from ASTERISK logs that ASTERISK is receiving error 503 from our GSM Gateway but ASTERISK is sending error 404 to the dialer(source of the call). I can’t find any conversion from 503 to 404 in RFC 3261. Please help if this conversion is allowed in any other international standards or if this is a problem within ASTERISK.

SIP Is not an ISO standard, so there are no International standards in this area.

The relevant RFC is RFC 3398, as the backbone of Asterisk is based on ISDN, not on SIP. Asterisk is a back to back user agent, not a SIP proxy, which means that what happens between incoming and outgoing SIP sessions is outside the scope of RFC 3261.

However, 503 is a catchall error, and, in this case, it is likely that there is a Reason header giving the ISDN cause code. Asterisk will use that in preference to doing its own translation from SIP Cause to ISDN one.

1 Like

Thanks for the reply David.

The GSM Gateway has the following reason for sending error 503
Reason: GSM;cause=0;text=“Radio link fail”

This is really valid for error 503. I don’t know why ASTERISK sent error 404 on the source and did not forwarded the error 503 it received.

I don’t think ISDN cause code 0 is defined! However, this isn’t an ISDN code, it is a GSM one, and I can’t, quickly, find a list of those.

I’m quite sure that Asterisk does not really use the information in the reason header when deciding what response to send. I’ve never seen it matter, at all.

The GSM gateway you use, do you talk to it using SIP or is it connected directly to the Asterisk server? (Via USB, Serial, whatever)

In either way, you might want to check the response on the outgoing leg of the call, and make sure the cause is set based on whatever you get back. Try checking the DIALSTATUS variable right after the call through the GSM gateway.

Here’s a list of possible values of DIALSTATUS from the Asterisk 20 manual.

CHANUNAVAIL - Either the dialed peer exists but is not currently reachable, e.g. endpoint is not registered, or an attempt was made to call a nonexistent location, e.g. nonexistent DNS hostname.
CONGESTION - Channel or switching congestion occured when routing the call. This can occur if there is a slow or no response from the remote end.
NOANSWER - Called party did not answer.
BUSY - The called party was busy or indicated a busy status. Note that some SIP devices will respond with 486 Busy if their Do Not Disturb modes are active. In this case, you can use DEVICE_STATUS to check if the endpoint is actually in use, if needed.
ANSWER - The call was answered. Any other result implicitly indicates the call was not answered.
CANCEL - Dial was cancelled before call was answered or reached some other terminating event.
DONTCALL - For the Privacy and Screening Modes. Will be set if the called party chooses to send the calling party to the 'Go Away' script.
TORTURE - For the Privacy and Screening Modes. Will be set if the called party chooses to send the calling party to the 'torture' script.
INVALIDARGS - Dial failed due to invalid syntax.

You can then hangup the calling channel with Hangup(x) where x is the desired cause code from this list: https://wiki.asterisk.org/wiki/display/AST/Hangup+Cause+Mappings

chan_sip certainly does implement this, but it is optional, and only applies to Q.850 not GSM numbers. It would take me longer to find any equivalent in chan_pjsip.

/*!
 * \brief Parses SIP reason header according to RFC3326 and sets channel's hangupcause if configured so
 *  and header present
 *
 * \note This is used in BYE and CANCEL request and SIP response, but according to RFC3326 it could
 *       appear in any request, but makes not a lot of sense in others than BYE or CANCEL.
 *       Currently only implemented for Q.850 status codes.
 * \retval 0 success
 * \retval -1 on failure or if not configured
 */
static int use_reason_header(struct sip_pvt *pvt, struct sip_request *req)
{
	int ret, cause;
	const char *rp, *rh;

	if (!pvt->owner) {
		return -1;
	}

	if (!ast_test_flag(&pvt->flags[1], SIP_PAGE2_Q850_REASON) ||
		!(rh = sip_get_header(req, "Reason"))) {
		return -1;
	}

	rh = ast_skip_blanks(rh);
	if (strncasecmp(rh, "Q.850", 5)) {
		return -1;
	}

	ret = -1;
	cause = ast_channel_hangupcause(pvt->owner);
	rp = strstr(rh, "cause=");
	if (rp && sscanf(rp + 6, "%3d", &cause) == 1) {
		ret = 0;
		ast_channel_hangupcause_set(pvt->owner, cause & 0x7f);
		if (req->debug) {
			ast_verbose("Using Reason header for cause code: %d\n",
						ast_channel_hangupcause(pvt->owner));
		}
	}
	return ret;
}

It’s HANGUPCAUSE that determines what SIP status will be sent, and for that you will need the full list of Q.850 (ISDN) causes codes.

In the absence of any Reason header processing, this line line in chan_pjsip will convert 503 into the Q.850 code (34):

and this line will convert it back to 503:

There is very similar code in chan_sip.

However it is important to remember that the mismatch between SIP and Q.850 means that not all such mappings will be identity mappings.

Just did a quick search in the source for “Reason” nothing immediately poped out, but it’s probably in there, unless pjsip does things differently.

As or chan_sip, in my world it does not exist anymore, haven’t used it for years. :wink:

I don’t see HANGUPCAUSE mentioned on the Dial command page, except for when using the c parameter. Maybe some missing documentation? Or is it not set by the Dial command but something else?

The HANGUPCAUSE in question here is set by the channel driver. It’s not a real channel variable, but rather the value of a field in the channel data structure. It can be set elsewhere.

Dial sets the DIALSTATUS based on, amongst other things, a summary of the result of looking up the hangup cause on all the channels involved in a parallel dial ( & ):

If you use the causecode parameter in the hangup application, it sets the HANGUPCAUSE value for the channel being terminated, as that is what is used for the status sent, not the DIALSTATUS.

1 Like

I sometimes use it for insight into the code because I know my way around it, and because it is self contained. The handling of Reason headers, in chan_pjsip, may well be in PJProject, rather than Asterisk code.

1 Like

It’s handled in the RFC3326 module[1].

[1] asterisk/res_pjsip_rfc3326.c at master · asterisk/asterisk · GitHub

1 Like

Looks like both channel drivers would ignore GSM cause codes, so I think we need ot see the complete dialplan path, to see if something would be changing the cause code.

I’m assuming there is only one Reason header; there can be different ones for different sets of codes.

Hi. Thanks for the many responses.

We are using chan_pjsip. Our GSM Gateway and the ASTERISK Server is connected to a common Switch. The GSM Gateway sent SIP error 503 with Reason: GSM;cause=0;text=“Radio link fail.”

I checked the dial plan and there was nothing there that converts error 503 to error 404.

I’ve checked the code and there is nothing there, either. You have a stalemate, and we are not in a position to check your analysis.

One thing you could do is add diagnostic code to report the actual value of HANGUPCAUSE.

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.