123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267 |
- /*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Kinsey Moore <kmoore@digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
- /*** MODULEINFO
- <depend>pjproject</depend>
- <depend>res_pjsip</depend>
- <support_level>core</support_level>
- ***/
- #include "asterisk.h"
- #include <pjsip.h>
- #include <pjsip_ua.h>
- #include "asterisk/res_pjsip.h"
- #include "asterisk/res_pjsip_session.h"
- #include "asterisk/module.h"
- #include "asterisk/strings.h"
- static const pj_str_t PATH_NAME = { "Path", 4 };
- static pj_str_t PATH_SUPPORTED_NAME = { "path", 4 };
- static struct ast_sip_aor *find_aor(struct ast_sip_endpoint *endpoint, pjsip_uri *uri)
- {
- char *configured_aors, *aor_name;
- pjsip_sip_uri *sip_uri;
- char *domain_name;
- char *username;
- struct ast_str *id = NULL;
- if (ast_strlen_zero(endpoint->aors)) {
- return NULL;
- }
- sip_uri = pjsip_uri_get_uri(uri);
- domain_name = ast_alloca(sip_uri->host.slen + 1);
- ast_copy_pj_str(domain_name, &sip_uri->host, sip_uri->host.slen + 1);
- username = ast_alloca(sip_uri->user.slen + 1);
- ast_copy_pj_str(username, &sip_uri->user, sip_uri->user.slen + 1);
- /*
- * We may want to match without any user options getting
- * in the way.
- */
- AST_SIP_USER_OPTIONS_TRUNCATE_CHECK(username);
- configured_aors = ast_strdupa(endpoint->aors);
- /* Iterate the configured AORs to see if the user or the user+domain match */
- while ((aor_name = ast_strip(strsep(&configured_aors, ",")))) {
- struct ast_sip_domain_alias *alias = NULL;
- if (ast_strlen_zero(aor_name)) {
- continue;
- }
- if (!strcmp(username, aor_name)) {
- break;
- }
- if (!id && !(id = ast_str_create(strlen(username) + sip_uri->host.slen + 2))) {
- aor_name = NULL;
- break;
- }
- ast_str_set(&id, 0, "%s@", username);
- if ((alias = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "domain_alias", domain_name))) {
- ast_str_append(&id, 0, "%s", alias->domain);
- ao2_cleanup(alias);
- } else {
- ast_str_append(&id, 0, "%s", domain_name);
- }
- if (!strcmp(aor_name, ast_str_buffer(id))) {
- break;
- }
- }
- ast_free(id);
- if (ast_strlen_zero(aor_name)) {
- return NULL;
- }
- return ast_sip_location_retrieve_aor(aor_name);
- }
- /*!
- * \brief Get the path string associated with this contact and tdata
- *
- * \param endpoint The endpoint from which to pull associated path data
- * \param contact_uri The URI identifying the associated contact
- * \param path_str The place to store the retrieved path information
- *
- * \retval zero on success
- * \retval non-zero on failure or no available path information
- */
- static int path_get_string(pj_pool_t *pool, struct ast_sip_contact *contact, pj_str_t *path_str)
- {
- if (!contact || ast_strlen_zero(contact->path)) {
- return -1;
- }
- *path_str = pj_strdup3(pool, contact->path);
- return 0;
- }
- static int add_supported(pjsip_tx_data *tdata)
- {
- pjsip_supported_hdr *hdr;
- hdr = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_SUPPORTED, NULL);
- if (!hdr) {
- /* insert a new Supported header */
- hdr = pjsip_supported_hdr_create(tdata->pool);
- if (!hdr) {
- return -1;
- }
- pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *)hdr);
- }
- /* add on to the existing Supported header */
- pj_strassign(&hdr->values[hdr->count++], &PATH_SUPPORTED_NAME);
- return 0;
- }
- /*!
- * \internal
- * \brief Adds a Route header to an outgoing request if
- * path information is available.
- *
- * \param endpoint The endpoint with which this request is associated
- * \param contact The contact to which this request is being sent
- * \param tdata The outbound request
- */
- static void path_outgoing_request(struct ast_sip_endpoint *endpoint, struct ast_sip_contact *contact, pjsip_tx_data *tdata)
- {
- RAII_VAR(struct ast_sip_aor *, aor, NULL, ao2_cleanup);
- if (!endpoint) {
- return;
- }
- aor = find_aor(endpoint, tdata->msg->line.req.uri);
- if (!aor || !aor->support_path) {
- return;
- }
- if (add_supported(tdata)) {
- return;
- }
- if (contact && !ast_strlen_zero(contact->path)) {
- ast_sip_set_outbound_proxy(tdata, contact->path);
- }
- }
- static void path_session_outgoing_request(struct ast_sip_session *session, pjsip_tx_data *tdata)
- {
- path_outgoing_request(session->endpoint, session->contact, tdata);
- }
- /*!
- * \internal
- * \brief Adds a path header to an outgoing 2XX response
- *
- * \param endpoint The endpoint to which the INVITE response is to be sent
- * \param contact The contact to which the INVITE response is to be sent
- * \param tdata The outbound INVITE response
- */
- static void path_outgoing_response(struct ast_sip_endpoint *endpoint, struct ast_sip_contact *contact, pjsip_tx_data *tdata)
- {
- struct pjsip_status_line status = tdata->msg->line.status;
- pj_str_t path_dup;
- pjsip_generic_string_hdr *path_hdr;
- pjsip_contact_hdr *contact_hdr;
- RAII_VAR(struct ast_sip_aor *, aor, NULL, ao2_cleanup);
- pjsip_cseq_hdr *cseq = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CSEQ, NULL);
- const pj_str_t REGISTER_METHOD = {"REGISTER", 8};
- if (!endpoint
- || !pj_stristr(®ISTER_METHOD, &cseq->method.name)
- || !PJSIP_IS_STATUS_IN_CLASS(status.code, 200)) {
- return;
- }
- contact_hdr = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CONTACT, NULL);
- if (!contact_hdr) {
- return;
- }
- aor = find_aor(endpoint, contact_hdr->uri);
- if (!aor || !aor->support_path || add_supported(tdata)
- || path_get_string(tdata->pool, contact, &path_dup)) {
- return;
- }
- path_hdr = pjsip_generic_string_hdr_create(tdata->pool, &PATH_NAME, &path_dup);
- if (!path_hdr) {
- return;
- }
- pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)path_hdr);
- }
- static void path_session_outgoing_response(struct ast_sip_session *session, pjsip_tx_data *tdata)
- {
- path_outgoing_response(session->endpoint, session->contact, tdata);
- }
- static struct ast_sip_supplement path_supplement = {
- .priority = AST_SIP_SUPPLEMENT_PRIORITY_CHANNEL - 100,
- .outgoing_request = path_outgoing_request,
- .outgoing_response = path_outgoing_response,
- };
- static struct ast_sip_session_supplement path_session_supplement = {
- .priority = AST_SIP_SUPPLEMENT_PRIORITY_CHANNEL - 100,
- .outgoing_request = path_session_outgoing_request,
- .outgoing_response = path_session_outgoing_response,
- };
- static int load_module(void)
- {
- CHECK_PJSIP_SESSION_MODULE_LOADED();
- if (ast_sip_register_supplement(&path_supplement)) {
- return AST_MODULE_LOAD_DECLINE;
- }
- if (ast_sip_session_register_supplement(&path_session_supplement)) {
- ast_sip_unregister_supplement(&path_supplement);
- return AST_MODULE_LOAD_DECLINE;
- }
- return AST_MODULE_LOAD_SUCCESS;
- }
- static int unload_module(void)
- {
- ast_sip_unregister_supplement(&path_supplement);
- ast_sip_session_unregister_supplement(&path_session_supplement);
- return 0;
- }
- AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP Path Header Support",
- .support_level = AST_MODULE_SUPPORT_CORE,
- .load = load_module,
- .unload = unload_module,
- .load_pri = AST_MODPRI_APP_DEPEND,
- );
|