Asterisk - The Open Source Telephony Project GIT-master-d5a0626
res_pjsip_rfc3326.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 2013, Digium, Inc.
5 *
6 * Joshua Colp <jcolp@digium.com>
7 *
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
13 *
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
17 */
18
19/*** MODULEINFO
20 <depend>pjproject</depend>
21 <depend>res_pjsip</depend>
22 <depend>res_pjsip_session</depend>
23 <support_level>core</support_level>
24 ***/
25
26#include "asterisk.h"
27
28#include <pjsip.h>
29#include <pjsip_ua.h>
30
31#include "asterisk/res_pjsip.h"
33#include "asterisk/module.h"
34#include "asterisk/causes.h"
35#include "asterisk/threadpool.h"
36
37static void rfc3326_use_reason_header(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
38{
39 static const pj_str_t str_reason = { "Reason", 6 };
40 pjsip_generic_string_hdr *header;
41 char buf[20];
42 char *cause;
43 int code_q850 = 0, code_sip = 0;
44
45 header = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_reason, NULL);
46 for (; header;
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));
50 cause = ast_skip_blanks(buf);
51
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) {
57 *code = 0;
58 }
59 }
60 }
61
62 if (code_q850) {
63 ast_channel_hangupcause_set(session->channel, code_q850 & 0x7f);
64 } else if (code_sip) {
66 }
67}
68
69static int rfc3326_incoming_request(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
70{
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)) ||
73 !session->channel) {
74 return 0;
75 }
76
78
79 return 0;
80}
81
82static void rfc3326_incoming_response(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
83{
84 struct pjsip_status_line status = rdata->msg_info.msg->line.status;
85
86 if ((status.code < 300) || !session->channel) {
87 return;
88 }
89
91}
92
93static void rfc3326_add_reason_header(struct ast_sip_session *session, struct pjsip_tx_data *tdata)
94{
95 char buf[20];
96
98 ast_sip_add_header(tdata, "Reason", "SIP;cause=200;text=\"Call completed elsewhere\"");
99 }
100
101 if (session->endpoint && session->endpoint->suppress_q850_reason_headers) {
102 ast_debug(1, "A Q.850 '%s'(%i) Reason header was suppressed for endpoint '%s'\n",
104 (ast_channel_hangupcause(session->channel) & 0x7f),
106 } else {
107 snprintf(buf, sizeof(buf), "Q.850;cause=%i", ast_channel_hangupcause(session->channel) & 0x7f);
108 ast_sip_add_header(tdata, "Reason", buf);
109 }
110}
111
112static void rfc3326_outgoing_request(struct ast_sip_session *session, struct pjsip_tx_data *tdata)
113{
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))
116 || !session->channel
117 /*
118 * The session->channel has been seen to go away on us between
119 * checks so we must also be running under the call's serializer
120 * thread.
121 */
123 return;
124 }
125
127}
128
129static void rfc3326_outgoing_response(struct ast_sip_session *session, struct pjsip_tx_data *tdata)
130{
131 struct pjsip_status_line status = tdata->msg->line.status;
132
133 if (status.code < 300
134 || !session->channel
136 return;
137 }
138
140}
141
144 .incoming_response = rfc3326_incoming_response,
145 .outgoing_request = rfc3326_outgoing_request,
146 .outgoing_response = rfc3326_outgoing_response,
147};
148
149static int load_module(void)
150{
153}
154
155static int unload_module(void)
156{
158 return 0;
159}
160
162 .support_level = AST_MODULE_SUPPORT_CORE,
163 .load = load_module,
164 .unload = unload_module,
165 .load_pri = AST_MODPRI_APP_DEPEND,
166 .requires = "res_pjsip,res_pjsip_session",
jack_status_t status
Definition: app_jack.c:146
Asterisk main include file. File version handling, generic pbx functions.
static struct ast_mansession session
Internal Asterisk hangup causes.
#define AST_CAUSE_ANSWERED_ELSEWHERE
Definition: causes.h:114
int ast_channel_hangupcause(const struct ast_channel *chan)
const char * ast_cause2str(int cause) attribute_pure
Gives the string form of a given cause code.
Definition: channel.c:612
void ast_channel_hangupcause_set(struct ast_channel *chan, int value)
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
#define ast_debug(level,...)
Log a DEBUG message.
Asterisk module definitions.
@ AST_MODFLAG_LOAD_ORDER
Definition: module.h:331
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
Definition: module.h:557
@ AST_MODPRI_APP_DEPEND
Definition: module.h:342
@ AST_MODULE_SUPPORT_CORE
Definition: module.h:121
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
@ AST_MODULE_LOAD_SUCCESS
Definition: module.h:70
const int ast_sip_hangup_sip2cause(int cause)
Convert SIP hangup causes to Asterisk hangup causes.
Definition: res_pjsip.c:3531
void ast_copy_pj_str(char *dest, const pj_str_t *src, size_t size)
Copy a pj_str_t into a standard character buffer.
Definition: res_pjsip.c:2201
int ast_sip_add_header(pjsip_tx_data *tdata, const char *name, const char *value)
Add a header to an outbound SIP message.
Definition: res_pjsip.c:2008
static struct ast_sip_session_supplement rfc3326_supplement
static void rfc3326_add_reason_header(struct ast_sip_session *session, struct pjsip_tx_data *tdata)
static void rfc3326_use_reason_header(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
static int load_module(void)
static int unload_module(void)
static void rfc3326_outgoing_response(struct ast_sip_session *session, struct pjsip_tx_data *tdata)
static void rfc3326_outgoing_request(struct ast_sip_session *session, struct pjsip_tx_data *tdata)
static void rfc3326_incoming_response(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
static int rfc3326_incoming_request(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
#define ast_sip_session_register_supplement(supplement)
void ast_sip_session_unregister_supplement(struct ast_sip_session_supplement *supplement)
Unregister a an supplement to SIP session processing.
Definition: pjsip_session.c:63
#define NULL
Definition: resample.c:96
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2317
char * ast_skip_blanks(const char *str)
Gets a pointer to the first non-whitespace character in a string.
Definition: strings.h:161
A supplement to SIP message processing.
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....
A structure describing a SIP session.
struct header * next
struct ast_taskprocessor * ast_threadpool_serializer_get_current(void)
Get the threadpool serializer currently associated with this thread.
Definition: threadpool.c:1393