Asterisk - The Open Source Telephony Project  18.5.0
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 <[email protected]>
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 
36 static const pj_str_t PATH_NAME = { "Path", 4 };
37 static pj_str_t PATH_SUPPORTED_NAME = { "path", 4 };
38 
39 static struct ast_sip_aor *find_aor(struct ast_sip_endpoint *endpoint, pjsip_uri *uri)
40 {
41  char *configured_aors, *aor_name;
42  pjsip_sip_uri *sip_uri;
43  char *domain_name;
44  char *username;
45  struct ast_str *id = NULL;
46 
47  if (ast_strlen_zero(endpoint->aors)) {
48  return NULL;
49  }
50 
51  sip_uri = pjsip_uri_get_uri(uri);
52  domain_name = ast_alloca(sip_uri->host.slen + 1);
53  ast_copy_pj_str(domain_name, &sip_uri->host, sip_uri->host.slen + 1);
54  username = ast_alloca(sip_uri->user.slen + 1);
55  ast_copy_pj_str(username, &sip_uri->user, sip_uri->user.slen + 1);
56 
57  /*
58  * We may want to match without any user options getting
59  * in the way.
60  */
62 
63  configured_aors = ast_strdupa(endpoint->aors);
64 
65  /* Iterate the configured AORs to see if the user or the user+domain match */
66  while ((aor_name = ast_strip(strsep(&configured_aors, ",")))) {
67  struct ast_sip_domain_alias *alias = NULL;
68 
69  if (ast_strlen_zero(aor_name)) {
70  continue;
71  }
72 
73  if (!strcmp(username, aor_name)) {
74  break;
75  }
76 
77  if (!id && !(id = ast_str_create(strlen(username) + sip_uri->host.slen + 2))) {
78  aor_name = NULL;
79  break;
80  }
81 
82  ast_str_set(&id, 0, "%s@", username);
83  if ((alias = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "domain_alias", domain_name))) {
84  ast_str_append(&id, 0, "%s", alias->domain);
85  ao2_cleanup(alias);
86  } else {
87  ast_str_append(&id, 0, "%s", domain_name);
88  }
89 
90  if (!strcmp(aor_name, ast_str_buffer(id))) {
91  break;
92  }
93  }
94  ast_free(id);
95 
96  if (ast_strlen_zero(aor_name)) {
97  return NULL;
98  }
99 
100  return ast_sip_location_retrieve_aor(aor_name);
101 }
102 
103 /*!
104  * \brief Get the path string associated with this contact and tdata
105  *
106  * \param endpoint The endpoint from which to pull associated path data
107  * \param contact_uri The URI identifying the associated contact
108  * \param path_str The place to store the retrieved path information
109  *
110  * \retval zero on success
111  * \retval non-zero on failure or no available path information
112  */
113 static int path_get_string(pj_pool_t *pool, struct ast_sip_contact *contact, pj_str_t *path_str)
114 {
115  if (!contact || ast_strlen_zero(contact->path)) {
116  return -1;
117  }
118 
119  *path_str = pj_strdup3(pool, contact->path);
120  return 0;
121 }
122 
123 static int add_supported(pjsip_tx_data *tdata)
124 {
125  pjsip_supported_hdr *hdr;
126  int i;
127 
128  hdr = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_SUPPORTED, NULL);
129  if (!hdr) {
130  /* insert a new Supported header */
131  hdr = pjsip_supported_hdr_create(tdata->pool);
132  if (!hdr) {
133  return -1;
134  }
135 
136  pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *)hdr);
137  }
138 
139  /* Don't add the value if it's already there */
140  for (i = 0; i < hdr->count; ++i) {
141  if (pj_stricmp(&hdr->values[i], &PATH_SUPPORTED_NAME) == 0) {
142  return 0;
143  }
144  }
145 
146  if (hdr->count >= PJSIP_GENERIC_ARRAY_MAX_COUNT) {
147  return -1;
148  }
149 
150  /* add on to the existing Supported header */
151  pj_strassign(&hdr->values[hdr->count++], &PATH_SUPPORTED_NAME);
152 
153  return 0;
154 }
155 
156 /*!
157  * \internal
158  * \brief Adds a Route header to an outgoing request if
159  * path information is available.
160  *
161  * \param endpoint The endpoint with which this request is associated
162  * \param contact The contact to which this request is being sent
163  * \param tdata The outbound request
164  */
165 static void path_outgoing_request(struct ast_sip_endpoint *endpoint, struct ast_sip_contact *contact, pjsip_tx_data *tdata)
166 {
167  RAII_VAR(struct ast_sip_aor *, aor, NULL, ao2_cleanup);
168 
169  if (!endpoint) {
170  return;
171  }
172 
173  aor = find_aor(endpoint, tdata->msg->line.req.uri);
174  if (!aor || !aor->support_path) {
175  return;
176  }
177 
178  if (add_supported(tdata)) {
179  return;
180  }
181 
182  if (contact && !ast_strlen_zero(contact->path)) {
183  ast_sip_set_outbound_proxy(tdata, contact->path);
184  }
185 }
186 
187 static void path_session_outgoing_request(struct ast_sip_session *session, pjsip_tx_data *tdata)
188 {
189  path_outgoing_request(session->endpoint, session->contact, tdata);
190 }
191 
192 /*!
193  * \internal
194  * \brief Adds a path header to an outgoing 2XX response
195  *
196  * \param endpoint The endpoint to which the INVITE response is to be sent
197  * \param contact The contact to which the INVITE response is to be sent
198  * \param tdata The outbound INVITE response
199  */
200 static void path_outgoing_response(struct ast_sip_endpoint *endpoint, struct ast_sip_contact *contact, pjsip_tx_data *tdata)
201 {
202  struct pjsip_status_line status = tdata->msg->line.status;
203  pj_str_t path_dup;
204  pjsip_generic_string_hdr *path_hdr;
205  pjsip_contact_hdr *contact_hdr;
206  RAII_VAR(struct ast_sip_aor *, aor, NULL, ao2_cleanup);
207  pjsip_cseq_hdr *cseq = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CSEQ, NULL);
208  const pj_str_t REGISTER_METHOD = {"REGISTER", 8};
209 
210  if (!endpoint
211  || !pj_stristr(&REGISTER_METHOD, &cseq->method.name)
212  || !PJSIP_IS_STATUS_IN_CLASS(status.code, 200)) {
213  return;
214  }
215 
216  contact_hdr = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CONTACT, NULL);
217  if (!contact_hdr) {
218  return;
219  }
220 
221  aor = find_aor(endpoint, contact_hdr->uri);
222  if (!aor || !aor->support_path || add_supported(tdata)
223  || path_get_string(tdata->pool, contact, &path_dup)) {
224  return;
225  }
226 
227  path_hdr = pjsip_generic_string_hdr_create(tdata->pool, &PATH_NAME, &path_dup);
228  if (!path_hdr) {
229  return;
230  }
231 
232  pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)path_hdr);
233 }
234 
235 static void path_session_outgoing_response(struct ast_sip_session *session, pjsip_tx_data *tdata)
236 {
237  path_outgoing_response(session->endpoint, session->contact, tdata);
238 }
239 
242  .outgoing_request = path_outgoing_request,
243  .outgoing_response = path_outgoing_response,
244 };
245 
248  .outgoing_request = path_session_outgoing_request,
249  .outgoing_response = path_session_outgoing_response,
250 };
251 
252 static int load_module(void)
253 {
254  ast_sip_register_supplement(&path_supplement);
255  ast_sip_session_register_supplement(&path_session_supplement);
256 
258 }
259 
260 static int unload_module(void)
261 {
262  ast_sip_unregister_supplement(&path_supplement);
263  ast_sip_session_unregister_supplement(&path_session_supplement);
264  return 0;
265 }
266 
267 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP Path Header Support",
268  .support_level = AST_MODULE_SUPPORT_CORE,
269  .load = load_module,
270  .unload = unload_module,
271  .load_pri = AST_MODPRI_APP_DEPEND,
272  .requires = "res_pjsip,res_pjsip_session",
273 );
struct ast_sip_endpoint * endpoint
#define AST_SIP_USER_OPTIONS_TRUNCATE_CHECK(str)
Truncate the URI user field options string if enabled.
Definition: res_pjsip.h:3036
static struct ast_sip_aor * find_aor(struct ast_sip_endpoint *endpoint, pjsip_uri *uri)
Asterisk main include file. File version handling, generic pbx functions.
A SIP address of record.
Definition: res_pjsip.h:361
static int add_supported(pjsip_tx_data *tdata)
String manipulation functions.
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.
const ast_string_field path
Definition: res_pjsip.h:303
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:714
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:5047
static pj_pool_t * pool
Global memory pool for configuration and timers.
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition: strings.h:1091
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:5240
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
A structure describing a SIP session.
#define ast_strlen_zero(foo)
Definition: strings.h:52
void * ast_sorcery_retrieve_by_id(const struct ast_sorcery *sorcery, const char *type, const char *id)
Retrieve an object using its unique identifier.
Definition: sorcery.c:1853
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
Definition: strings.h:1065
static void path_session_outgoing_request(struct ast_sip_session *session, pjsip_tx_data *tdata)
#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:911
static struct ast_mansession session
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
Definition: strings.h:219
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
static int load_module(void)
An entity with which Asterisk communicates.
Definition: res_pjsip.h:812
static void path_outgoing_request(struct ast_sip_endpoint *endpoint, struct ast_sip_contact *contact, pjsip_tx_data *tdata)
struct ast_sip_aor * ast_sip_location_retrieve_aor(const char *aor_name)
Retrieve a named AOR.
Definition: location.c:147
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: astmm.h:290
void ast_sip_register_supplement(struct ast_sip_supplement *supplement)
Register a supplement to SIP out of dialog processing.
Definition: res_pjsip.c:4511
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:584
void ast_sip_unregister_supplement(struct ast_sip_supplement *supplement)
Unregister a an supplement to SIP out of dialog processing.
Definition: res_pjsip.c:4531
Contact associated with an address of record.
Definition: res_pjsip.h:281
enum ast_sip_supplement_priority priority
#define ast_free(a)
Definition: astmm.h:182
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS|AST_MODFLAG_LOAD_ORDER, "HTTP Phone Provisioning",.support_level=AST_MODULE_SUPPORT_EXTENDED,.load=load_module,.unload=unload_module,.reload=reload,.load_pri=AST_MODPRI_CHANNEL_DEPEND,.requires="http",)
A supplement to SIP message processing.
static struct ast_sip_session_supplement path_session_supplement
char * strsep(char **str, const char *delims)
const ast_string_field domain
Definition: res_pjsip.h:265
struct ast_sorcery * ast_sip_get_sorcery(void)
Get a pointer to the SIP sorcery structure.
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
A supplement to SIP message processing.
Definition: res_pjsip.h:2888
static const pj_str_t PATH_NAME
static void path_outgoing_response(struct ast_sip_endpoint *endpoint, struct ast_sip_contact *contact, pjsip_tx_data *tdata)
static int unload_module(void)
const ast_string_field aors
Definition: res_pjsip.h:821
static void path_session_outgoing_response(struct ast_sip_session *session, pjsip_tx_data *tdata)
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
struct ast_sip_contact * contact
Asterisk module definitions.
#define ast_str_create(init_len)
Create a malloc&#39;ed dynamic length string.
Definition: strings.h:620
static pj_str_t PATH_SUPPORTED_NAME
#define ast_sip_session_register_supplement(supplement)
static struct ast_sip_supplement path_supplement
enum ast_sip_supplement_priority priority
Definition: res_pjsip.h:2892