Asterisk - The Open Source Telephony Project GIT-master-a358458
res_pjsip_path.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 * Kinsey Moore <kmoore@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/strings.h"
35
36static const pj_str_t PATH_NAME = { "Path", 4 };
37static pj_str_t PATH_SUPPORTED_NAME = { "path", 4 };
38
39static struct ast_sip_aor *find_aor(struct ast_sip_contact *contact)
40{
41 if (!contact) {
42 return NULL;
43 }
44 if (ast_strlen_zero(contact->aor)) {
45 return NULL;
46 }
47
48 return ast_sip_location_retrieve_aor(contact->aor);
49}
50
51/*!
52 * \brief Get the path string associated with this contact and tdata
53 *
54 * \param pool
55 * \param contact The URI identifying the associated contact
56 * \param path_str The place to store the retrieved path information
57 *
58 * \retval zero on success
59 * \retval non-zero on failure or no available path information
60 */
61static int path_get_string(pj_pool_t *pool, struct ast_sip_contact *contact, pj_str_t *path_str)
62{
63 if (!contact || ast_strlen_zero(contact->path)) {
64 return -1;
65 }
66
67 *path_str = pj_strdup3(pool, contact->path);
68 return 0;
69}
70
71static int add_supported(pjsip_tx_data *tdata)
72{
73 pjsip_supported_hdr *hdr;
74 int i;
75
76 hdr = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_SUPPORTED, NULL);
77 if (!hdr) {
78 /* insert a new Supported header */
79 hdr = pjsip_supported_hdr_create(tdata->pool);
80 if (!hdr) {
81 return -1;
82 }
83
84 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *)hdr);
85 }
86
87 /* Don't add the value if it's already there */
88 for (i = 0; i < hdr->count; ++i) {
89 if (pj_stricmp(&hdr->values[i], &PATH_SUPPORTED_NAME) == 0) {
90 return 0;
91 }
92 }
93
94 if (hdr->count >= PJSIP_GENERIC_ARRAY_MAX_COUNT) {
95 return -1;
96 }
97
98 /* add on to the existing Supported header */
99 pj_strassign(&hdr->values[hdr->count++], &PATH_SUPPORTED_NAME);
100
101 return 0;
102}
103
104/*!
105 * \internal
106 * \brief Adds a Route header to an outgoing request if
107 * path information is available.
108 *
109 * \param endpoint The endpoint with which this request is associated
110 * \param contact The contact to which this request is being sent
111 * \param tdata The outbound request
112 */
113static void path_outgoing_request(struct ast_sip_endpoint *endpoint, struct ast_sip_contact *contact, pjsip_tx_data *tdata)
114{
115 RAII_VAR(struct ast_sip_aor *, aor, NULL, ao2_cleanup);
116
117 if (!endpoint) {
118 return;
119 }
120
121 aor = find_aor(contact);
122 if (!aor || !aor->support_path) {
123 return;
124 }
125
126 if (add_supported(tdata)) {
127 return;
128 }
129
130 if (contact && !ast_strlen_zero(contact->path)) {
131 ast_sip_set_outbound_proxy(tdata, contact->path);
132 }
133}
134
135static void path_session_outgoing_request(struct ast_sip_session *session, pjsip_tx_data *tdata)
136{
137 path_outgoing_request(session->endpoint, session->contact, tdata);
138}
139
140/*!
141 * \internal
142 * \brief Adds a path header to an outgoing 2XX response
143 *
144 * \param endpoint The endpoint to which the INVITE response is to be sent
145 * \param contact The contact to which the INVITE response is to be sent
146 * \param tdata The outbound INVITE response
147 */
148static void path_outgoing_response(struct ast_sip_endpoint *endpoint, struct ast_sip_contact *contact, pjsip_tx_data *tdata)
149{
150 struct pjsip_status_line status = tdata->msg->line.status;
151 pj_str_t path_dup;
152 pjsip_generic_string_hdr *path_hdr;
153 RAII_VAR(struct ast_sip_aor *, aor, NULL, ao2_cleanup);
154 pjsip_cseq_hdr *cseq = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CSEQ, NULL);
155 const pj_str_t REGISTER_METHOD = {"REGISTER", 8};
156
157 if (!endpoint
158 || !pj_stristr(&REGISTER_METHOD, &cseq->method.name)
159 || !PJSIP_IS_STATUS_IN_CLASS(status.code, 200)) {
160 return;
161 }
162
163 aor = find_aor(contact);
164 if (!aor || !aor->support_path || add_supported(tdata)
165 || path_get_string(tdata->pool, contact, &path_dup)) {
166 return;
167 }
168
169 path_hdr = pjsip_generic_string_hdr_create(tdata->pool, &PATH_NAME, &path_dup);
170 if (!path_hdr) {
171 return;
172 }
173
174 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)path_hdr);
175}
176
177static void path_session_outgoing_response(struct ast_sip_session *session, pjsip_tx_data *tdata)
178{
179 path_outgoing_response(session->endpoint, session->contact, tdata);
180}
181
184 .outgoing_request = path_outgoing_request,
185 .outgoing_response = path_outgoing_response,
186};
187
190 .outgoing_request = path_session_outgoing_request,
191 .outgoing_response = path_session_outgoing_response,
192};
193
194static int load_module(void)
195{
198
200}
201
202static int unload_module(void)
203{
206 return 0;
207}
208
209AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP Path Header Support",
210 .support_level = AST_MODULE_SUPPORT_CORE,
211 .load = load_module,
212 .unload = unload_module,
213 .load_pri = AST_MODPRI_APP_DEPEND,
214 .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
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
Asterisk module definitions.
@ AST_MODFLAG_LOAD_ORDER
Definition: module.h:317
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
Definition: module.h:543
@ AST_MODPRI_APP_DEPEND
Definition: module.h:328
@ 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
void ast_sip_unregister_supplement(struct ast_sip_supplement *supplement)
Unregister a an supplement to SIP out of dialog processing.
Definition: res_pjsip.c:1476
struct ast_sip_aor * ast_sip_location_retrieve_aor(const char *aor_name)
Retrieve a named AOR.
Definition: location.c:147
void ast_sip_register_supplement(struct ast_sip_supplement *supplement)
Register a supplement to SIP out of dialog processing.
Definition: res_pjsip.c:1456
@ AST_SIP_SUPPLEMENT_PRIORITY_CHANNEL
Definition: res_pjsip.h:3186
int ast_sip_set_outbound_proxy(pjsip_tx_data *tdata, const char *proxy)
Set the outbound proxy for an outbound SIP message.
Definition: res_pjsip.c:1992
static void path_outgoing_response(struct ast_sip_endpoint *endpoint, struct ast_sip_contact *contact, pjsip_tx_data *tdata)
static void path_session_outgoing_response(struct ast_sip_session *session, pjsip_tx_data *tdata)
static struct ast_sip_aor * find_aor(struct ast_sip_contact *contact)
static struct ast_sip_supplement path_supplement
static int path_get_string(pj_pool_t *pool, struct ast_sip_contact *contact, pj_str_t *path_str)
Get the path string associated with this contact and tdata.
static int add_supported(pjsip_tx_data *tdata)
static void path_session_outgoing_request(struct ast_sip_session *session, pjsip_tx_data *tdata)
static void path_outgoing_request(struct ast_sip_endpoint *endpoint, struct ast_sip_contact *contact, pjsip_tx_data *tdata)
static const pj_str_t PATH_NAME
static pj_str_t PATH_SUPPORTED_NAME
static struct ast_sip_session_supplement path_session_supplement
static int load_module(void)
static int unload_module(void)
#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
String manipulation functions.
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
A SIP address of record.
Definition: res_pjsip.h:478
Contact associated with an address of record.
Definition: res_pjsip.h:392
const ast_string_field aor
Definition: res_pjsip.h:414
const ast_string_field path
Definition: res_pjsip.h:414
An entity with which Asterisk communicates.
Definition: res_pjsip.h:963
A supplement to SIP message processing.
enum ast_sip_supplement_priority priority
A structure describing a SIP session.
A supplement to SIP message processing.
Definition: res_pjsip.h:3198
enum ast_sip_supplement_priority priority
Definition: res_pjsip.h:3202
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:941