31 #include "asterisk/res_pjsip.h"
32 #include "asterisk/res_pjsip_session.h"
35 #include "asterisk/threadpool.h"
37 static void rfc3326_use_reason_header(
struct ast_sip_session *session,
struct pjsip_rx_data *rdata)
39 static const pj_str_t str_reason = {
"Reason", 6 };
40 pjsip_generic_string_hdr *
header;
43 int code_q850 = 0, code_sip = 0;
45 header = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_reason, NULL);
47 header = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_reason, header->next)) {
48 int cause_q850, cause_sip;
49 ast_copy_pj_str(buf, &header->hvalue,
sizeof(buf));
52 cause_q850 = !strncasecmp(cause,
"Q.850", 5);
53 cause_sip = !strncasecmp(cause,
"SIP", 3);
54 if ((cause_q850 || cause_sip) && (cause = strstr(cause,
"cause="))) {
55 int *code = cause_q850 ? &code_q850 : &code_sip;
56 if (sscanf(cause,
"cause=%30d", code) != 1) {
63 ast_channel_hangupcause_set(session->
channel, code_q850 & 0x7f);
64 }
else if (code_sip) {
65 ast_channel_hangupcause_set(session->
channel, ast_sip_hangup_sip2cause(code_sip));
69 static int rfc3326_incoming_request(
struct ast_sip_session *session,
struct pjsip_rx_data *rdata)
71 if ((pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_bye_method) &&
72 pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_cancel_method)) ||
77 rfc3326_use_reason_header(session, rdata);
82 static void rfc3326_incoming_response(
struct ast_sip_session *session,
struct pjsip_rx_data *rdata)
84 struct pjsip_status_line status = rdata->msg_info.msg->line.status;
86 if ((status.code < 300) || !session->
channel) {
90 rfc3326_use_reason_header(session, rdata);
93 static void rfc3326_add_reason_header(
struct ast_sip_session *session,
struct pjsip_tx_data *tdata)
97 if (ast_channel_hangupcause(session->
channel) == AST_CAUSE_ANSWERED_ELSEWHERE) {
98 ast_sip_add_header(tdata,
"Reason",
"SIP;cause=200;text=\"Call completed elsewhere\"");
102 ast_debug(1,
"A Q.850 '%s'(%i) Reason header was suppressed for endpoint '%s'\n",
104 (ast_channel_hangupcause(session->
channel) & 0x7f),
107 snprintf(buf,
sizeof(buf),
"Q.850;cause=%i", ast_channel_hangupcause(session->
channel) & 0x7f);
108 ast_sip_add_header(tdata,
"Reason", buf);
112 static void rfc3326_outgoing_request(
struct ast_sip_session *session,
struct pjsip_tx_data *tdata)
114 if ((pjsip_method_cmp(&tdata->msg->line.req.method, &pjsip_bye_method)
115 && pjsip_method_cmp(&tdata->msg->line.req.method, &pjsip_cancel_method))
122 || session->
serializer != ast_threadpool_serializer_get_current()) {
126 rfc3326_add_reason_header(session, tdata);
129 static void rfc3326_outgoing_response(
struct ast_sip_session *session,
struct pjsip_tx_data *tdata)
131 struct pjsip_status_line status = tdata->msg->line.status;
133 if (status.code < 300
135 || session->
serializer != ast_threadpool_serializer_get_current()) {
139 rfc3326_add_reason_header(session, tdata);
144 .incoming_response = rfc3326_incoming_response,
145 .outgoing_request = rfc3326_outgoing_request,
146 .outgoing_response = rfc3326_outgoing_response,
149 static int load_module(
void)
151 ast_sip_session_register_supplement(&rfc3326_supplement);
155 static int unload_module(
void)
157 ast_sip_session_unregister_supplement(&rfc3326_supplement);
161 AST_MODULE_INFO(
ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER,
"PJSIP RFC3326 Support",
162 .support_level = AST_MODULE_SUPPORT_CORE,
164 .unload = unload_module,
166 .requires =
"res_pjsip,res_pjsip_session",
struct ast_sip_endpoint * endpoint
Asterisk main include file. File version handling, generic pbx functions.
int(* incoming_request)(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
Called on incoming SIP request This method can indicate a failure in processing in its return...
const char * ast_cause2str(int cause) attribute_pure
Gives the string form of a given cause code.
A structure describing a SIP session.
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
struct ast_channel * channel
#define ast_debug(level,...)
Log a DEBUG message.
struct ast_taskprocessor * serializer
char * ast_skip_blanks(const char *str)
Gets a pointer to the first non-whitespace character in a string.
A supplement to SIP message processing.
Internal Asterisk hangup causes.
#define ASTERISK_GPL_KEY
The text the key() function should return.
Asterisk module definitions.
unsigned int suppress_q850_reason_headers