From 3526441e41791a7f25dc40c6c785f1171f889230 Mon Sep 17 00:00:00 2001 From: Igor Goncharovsky <igorg@iqtek.ru> Date: Fri, 18 Nov 2022 08:16:50 +0600 Subject: [PATCH] res_pjsip_rfc3326: Add SIP causes support for RFC3326 Add ability to set HANGUPCAUSE when SIP causecode received in BYE (in addition to currently supported Q.850). ASTERISK-30319 #close Change-Id: I3f55622dc680ce713a2ffb5a458ef5dd39fcf645 --- channels/chan_pjsip.c | 95 +-------------------- doc/CHANGES-staging/res_rtp_rfc3326_sip.txt | 5 ++ include/asterisk/res_pjsip.h | 13 ++- res/res_pjsip.c | 92 ++++++++++++++++++++ res/res_pjsip_rfc3326.c | 31 ++++--- 5 files changed, 130 insertions(+), 106 deletions(-) create mode 100644 doc/CHANGES-staging/res_rtp_rfc3326_sip.txt diff --git a/channels/chan_pjsip.c b/channels/chan_pjsip.c index 22ed5ecf3f..47f72b0e52 100644 --- a/channels/chan_pjsip.c +++ b/channels/chan_pjsip.c @@ -2881,97 +2881,6 @@ static int chan_pjsip_sendtext(struct ast_channel *ast, const char *text) return rc; } -/*! \brief Convert SIP hangup causes to Asterisk hangup causes */ -static int hangup_sip2cause(int cause) -{ - /* Possible values taken from causes.h */ - - switch(cause) { - case 401: /* Unauthorized */ - return AST_CAUSE_CALL_REJECTED; - case 403: /* Not found */ - return AST_CAUSE_CALL_REJECTED; - case 404: /* Not found */ - return AST_CAUSE_UNALLOCATED; - case 405: /* Method not allowed */ - return AST_CAUSE_INTERWORKING; - case 407: /* Proxy authentication required */ - return AST_CAUSE_CALL_REJECTED; - case 408: /* No reaction */ - return AST_CAUSE_NO_USER_RESPONSE; - case 409: /* Conflict */ - return AST_CAUSE_NORMAL_TEMPORARY_FAILURE; - case 410: /* Gone */ - return AST_CAUSE_NUMBER_CHANGED; - case 411: /* Length required */ - return AST_CAUSE_INTERWORKING; - case 413: /* Request entity too large */ - return AST_CAUSE_INTERWORKING; - case 414: /* Request URI too large */ - return AST_CAUSE_INTERWORKING; - case 415: /* Unsupported media type */ - return AST_CAUSE_INTERWORKING; - case 420: /* Bad extension */ - return AST_CAUSE_NO_ROUTE_DESTINATION; - case 480: /* No answer */ - return AST_CAUSE_NO_ANSWER; - case 481: /* No answer */ - return AST_CAUSE_INTERWORKING; - case 482: /* Loop detected */ - return AST_CAUSE_INTERWORKING; - case 483: /* Too many hops */ - return AST_CAUSE_NO_ANSWER; - case 484: /* Address incomplete */ - return AST_CAUSE_INVALID_NUMBER_FORMAT; - case 485: /* Ambiguous */ - return AST_CAUSE_UNALLOCATED; - case 486: /* Busy everywhere */ - return AST_CAUSE_BUSY; - case 487: /* Request terminated */ - return AST_CAUSE_INTERWORKING; - case 488: /* No codecs approved */ - return AST_CAUSE_BEARERCAPABILITY_NOTAVAIL; - case 491: /* Request pending */ - return AST_CAUSE_INTERWORKING; - case 493: /* Undecipherable */ - return AST_CAUSE_INTERWORKING; - case 500: /* Server internal failure */ - return AST_CAUSE_FAILURE; - case 501: /* Call rejected */ - return AST_CAUSE_FACILITY_REJECTED; - case 502: - return AST_CAUSE_DESTINATION_OUT_OF_ORDER; - case 503: /* Service unavailable */ - return AST_CAUSE_CONGESTION; - case 504: /* Gateway timeout */ - return AST_CAUSE_RECOVERY_ON_TIMER_EXPIRE; - case 505: /* SIP version not supported */ - return AST_CAUSE_INTERWORKING; - case 600: /* Busy everywhere */ - return AST_CAUSE_USER_BUSY; - case 603: /* Decline */ - return AST_CAUSE_CALL_REJECTED; - case 604: /* Does not exist anywhere */ - return AST_CAUSE_UNALLOCATED; - case 606: /* Not acceptable */ - return AST_CAUSE_BEARERCAPABILITY_NOTAVAIL; - default: - if (cause < 500 && cause >= 400) { - /* 4xx class error that is unknown - someting wrong with our request */ - return AST_CAUSE_INTERWORKING; - } else if (cause < 600 && cause >= 500) { - /* 5xx class error - problem in the remote end */ - return AST_CAUSE_CONGESTION; - } else if (cause < 700 && cause >= 600) { - /* 6xx - global errors in the 4xx class */ - return AST_CAUSE_INTERWORKING; - } - return AST_CAUSE_NORMAL; - } - /* Never reached */ - return 0; -} - static void chan_pjsip_session_begin(struct ast_sip_session *session) { RAII_VAR(struct ast_datastore *, datastore, NULL, ao2_cleanup); @@ -3016,7 +2925,7 @@ static void chan_pjsip_session_end(struct ast_sip_session *session) ast_set_hangupsource(session->channel, ast_channel_name(session->channel), 0); if (!ast_channel_hangupcause(session->channel) && session->inv_session) { - int cause = hangup_sip2cause(session->inv_session->cause); + int cause = ast_sip_hangup_sip2cause(session->inv_session->cause); ast_queue_hangup_with_cause(session->channel, cause); } else { @@ -3210,7 +3119,7 @@ static void chan_pjsip_incoming_response_update_cause(struct ast_sip_session *se snprintf(cause_code->code, data_size - sizeof(*cause_code) + 1, "SIP %d %.*s", status.code, (int) pj_strlen(&status.reason), pj_strbuf(&status.reason)); - cause_code->ast_cause = hangup_sip2cause(status.code); + cause_code->ast_cause = ast_sip_hangup_sip2cause(status.code); ast_queue_control_data(session->channel, AST_CONTROL_PVT_CAUSE_CODE, cause_code, data_size); ast_channel_hangupcause_hash_set(session->channel, cause_code, data_size); diff --git a/doc/CHANGES-staging/res_rtp_rfc3326_sip.txt b/doc/CHANGES-staging/res_rtp_rfc3326_sip.txt new file mode 100644 index 0000000000..62a73925ca --- /dev/null +++ b/doc/CHANGES-staging/res_rtp_rfc3326_sip.txt @@ -0,0 +1,5 @@ +Subject: res_pjsip_rfc3326 + +Add ability to set HANGUPCAUSE when SIP causecode received in BYE Reason header (in +addition to currently supported Q.850). The first header found will be used to set +the HANGUPCAUSE variable. diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h index 3e19d8d17d..a49a56e10d 100644 --- a/include/asterisk/res_pjsip.h +++ b/include/asterisk/res_pjsip.h @@ -3962,7 +3962,7 @@ int ast_sip_is_uri_sip_sips(pjsip_uri *uri); * * \param uri The pjsip_uri to check * - * \retva; 1 if allowed + * \retval 1 if allowed * \retval 0 if not allowed */ int ast_sip_is_allowed_uri(pjsip_uri *uri); @@ -4013,4 +4013,15 @@ struct pjsip_param *ast_sip_pjsip_uri_get_other_param(pjsip_uri *uri, const pj_s */ unsigned int ast_sip_get_all_codecs_on_empty_reinvite(void); + +/*! + * \brief Convert SIP hangup causes to Asterisk hangup causes + * + * \param cause SIP cause + * + * \retval matched cause code from causes.h + */ +const int ast_sip_hangup_sip2cause(int cause); + + #endif /* _RES_PJSIP_H */ diff --git a/res/res_pjsip.c b/res/res_pjsip.c index 38a91bdea0..827384741c 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -40,6 +40,7 @@ #include "asterisk/uuid.h" #include "asterisk/sorcery.h" #include "asterisk/file.h" +#include "asterisk/causes.h" #include "asterisk/cli.h" #include "asterisk/callerid.h" #include "asterisk/res_pjsip_cli.h" @@ -2796,6 +2797,97 @@ struct pjsip_param *ast_sip_pjsip_uri_get_other_param(pjsip_uri *uri, const pj_s return NULL; } +/*! \brief Convert SIP hangup causes to Asterisk hangup causes */ +const int ast_sip_hangup_sip2cause(int cause) +{ + /* Possible values taken from causes.h */ + + switch(cause) { + case 401: /* Unauthorized */ + return AST_CAUSE_CALL_REJECTED; + case 403: /* Not found */ + return AST_CAUSE_CALL_REJECTED; + case 404: /* Not found */ + return AST_CAUSE_UNALLOCATED; + case 405: /* Method not allowed */ + return AST_CAUSE_INTERWORKING; + case 407: /* Proxy authentication required */ + return AST_CAUSE_CALL_REJECTED; + case 408: /* No reaction */ + return AST_CAUSE_NO_USER_RESPONSE; + case 409: /* Conflict */ + return AST_CAUSE_NORMAL_TEMPORARY_FAILURE; + case 410: /* Gone */ + return AST_CAUSE_NUMBER_CHANGED; + case 411: /* Length required */ + return AST_CAUSE_INTERWORKING; + case 413: /* Request entity too large */ + return AST_CAUSE_INTERWORKING; + case 414: /* Request URI too large */ + return AST_CAUSE_INTERWORKING; + case 415: /* Unsupported media type */ + return AST_CAUSE_INTERWORKING; + case 420: /* Bad extension */ + return AST_CAUSE_NO_ROUTE_DESTINATION; + case 480: /* No answer */ + return AST_CAUSE_NO_ANSWER; + case 481: /* No answer */ + return AST_CAUSE_INTERWORKING; + case 482: /* Loop detected */ + return AST_CAUSE_INTERWORKING; + case 483: /* Too many hops */ + return AST_CAUSE_NO_ANSWER; + case 484: /* Address incomplete */ + return AST_CAUSE_INVALID_NUMBER_FORMAT; + case 485: /* Ambiguous */ + return AST_CAUSE_UNALLOCATED; + case 486: /* Busy everywhere */ + return AST_CAUSE_BUSY; + case 487: /* Request terminated */ + return AST_CAUSE_INTERWORKING; + case 488: /* No codecs approved */ + return AST_CAUSE_BEARERCAPABILITY_NOTAVAIL; + case 491: /* Request pending */ + return AST_CAUSE_INTERWORKING; + case 493: /* Undecipherable */ + return AST_CAUSE_INTERWORKING; + case 500: /* Server internal failure */ + return AST_CAUSE_FAILURE; + case 501: /* Call rejected */ + return AST_CAUSE_FACILITY_REJECTED; + case 502: + return AST_CAUSE_DESTINATION_OUT_OF_ORDER; + case 503: /* Service unavailable */ + return AST_CAUSE_CONGESTION; + case 504: /* Gateway timeout */ + return AST_CAUSE_RECOVERY_ON_TIMER_EXPIRE; + case 505: /* SIP version not supported */ + return AST_CAUSE_INTERWORKING; + case 600: /* Busy everywhere */ + return AST_CAUSE_USER_BUSY; + case 603: /* Decline */ + return AST_CAUSE_CALL_REJECTED; + case 604: /* Does not exist anywhere */ + return AST_CAUSE_UNALLOCATED; + case 606: /* Not acceptable */ + return AST_CAUSE_BEARERCAPABILITY_NOTAVAIL; + default: + if (cause < 500 && cause >= 400) { + /* 4xx class error that is unknown - someting wrong with our request */ + return AST_CAUSE_INTERWORKING; + } else if (cause < 600 && cause >= 500) { + /* 5xx class error - problem in the remote end */ + return AST_CAUSE_CONGESTION; + } else if (cause < 700 && cause >= 600) { + /* 6xx - global errors in the 4xx class */ + return AST_CAUSE_INTERWORKING; + } + return AST_CAUSE_NORMAL; + } + /* Never reached */ + return 0; +} + #ifdef TEST_FRAMEWORK AST_TEST_DEFINE(xml_sanitization_end_null) { diff --git a/res/res_pjsip_rfc3326.c b/res/res_pjsip_rfc3326.c index 7d096c1f7d..458b5e97d3 100644 --- a/res/res_pjsip_rfc3326.c +++ b/res/res_pjsip_rfc3326.c @@ -42,6 +42,7 @@ static void rfc3326_use_reason_header(struct ast_sip_session *session, struct pj char *cause; char *text; int code; + int cause_q850, cause_sip; header = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_reason, NULL); for (; header; @@ -49,21 +50,27 @@ static void rfc3326_use_reason_header(struct ast_sip_session *session, struct pj ast_copy_pj_str(buf, &header->hvalue, sizeof(buf)); cause = ast_skip_blanks(buf); - if (strncasecmp(cause, "Q.850", 5) || !(cause = strstr(cause, "cause="))) { + cause_q850 = !strncasecmp(cause, "Q.850", 5); + cause_sip = !strncasecmp(cause, "SIP", 3); + if ((cause_q850 || cause_sip) && (cause = strstr(cause, "cause="))) { + /* If text is present get rid of it */ + if ((text = strchr(cause, ';'))) { + *text = '\0'; + } + + if (sscanf(cause, "cause=%30d", &code) != 1) { + continue; + } + } else { continue; } - - /* If text is present get rid of it */ - if ((text = strstr(cause, ";"))) { - *text = '\0'; + if (cause_q850) { + ast_channel_hangupcause_set(session->channel, code & 0x7f); + break; + } else if (cause_sip) { + ast_channel_hangupcause_set(session->channel, ast_sip_hangup_sip2cause(code)); + break; } - - if (sscanf(cause, "cause=%30d", &code) != 1) { - continue; - } - - ast_channel_hangupcause_set(session->channel, code & 0x7f); - break; } } -- GitLab