res_pjsip_path.c 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  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. /*** MODULEINFO
  19. <depend>pjproject</depend>
  20. <depend>res_pjsip</depend>
  21. <support_level>core</support_level>
  22. ***/
  23. #include "asterisk.h"
  24. #include <pjsip.h>
  25. #include <pjsip_ua.h>
  26. #include "asterisk/res_pjsip.h"
  27. #include "asterisk/res_pjsip_session.h"
  28. #include "asterisk/module.h"
  29. #include "asterisk/strings.h"
  30. static const pj_str_t PATH_NAME = { "Path", 4 };
  31. static pj_str_t PATH_SUPPORTED_NAME = { "path", 4 };
  32. static struct ast_sip_aor *find_aor(struct ast_sip_endpoint *endpoint, pjsip_uri *uri)
  33. {
  34. char *configured_aors, *aor_name;
  35. pjsip_sip_uri *sip_uri;
  36. char *domain_name;
  37. char *username;
  38. struct ast_str *id = NULL;
  39. if (ast_strlen_zero(endpoint->aors)) {
  40. return NULL;
  41. }
  42. sip_uri = pjsip_uri_get_uri(uri);
  43. domain_name = ast_alloca(sip_uri->host.slen + 1);
  44. ast_copy_pj_str(domain_name, &sip_uri->host, sip_uri->host.slen + 1);
  45. username = ast_alloca(sip_uri->user.slen + 1);
  46. ast_copy_pj_str(username, &sip_uri->user, sip_uri->user.slen + 1);
  47. /*
  48. * We may want to match without any user options getting
  49. * in the way.
  50. */
  51. AST_SIP_USER_OPTIONS_TRUNCATE_CHECK(username);
  52. configured_aors = ast_strdupa(endpoint->aors);
  53. /* Iterate the configured AORs to see if the user or the user+domain match */
  54. while ((aor_name = ast_strip(strsep(&configured_aors, ",")))) {
  55. struct ast_sip_domain_alias *alias = NULL;
  56. if (ast_strlen_zero(aor_name)) {
  57. continue;
  58. }
  59. if (!strcmp(username, aor_name)) {
  60. break;
  61. }
  62. if (!id && !(id = ast_str_create(strlen(username) + sip_uri->host.slen + 2))) {
  63. aor_name = NULL;
  64. break;
  65. }
  66. ast_str_set(&id, 0, "%s@", username);
  67. if ((alias = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "domain_alias", domain_name))) {
  68. ast_str_append(&id, 0, "%s", alias->domain);
  69. ao2_cleanup(alias);
  70. } else {
  71. ast_str_append(&id, 0, "%s", domain_name);
  72. }
  73. if (!strcmp(aor_name, ast_str_buffer(id))) {
  74. break;
  75. }
  76. }
  77. ast_free(id);
  78. if (ast_strlen_zero(aor_name)) {
  79. return NULL;
  80. }
  81. return ast_sip_location_retrieve_aor(aor_name);
  82. }
  83. /*!
  84. * \brief Get the path string associated with this contact and tdata
  85. *
  86. * \param endpoint The endpoint from which to pull associated path data
  87. * \param contact_uri The URI identifying the associated contact
  88. * \param path_str The place to store the retrieved path information
  89. *
  90. * \retval zero on success
  91. * \retval non-zero on failure or no available path information
  92. */
  93. static int path_get_string(pj_pool_t *pool, struct ast_sip_contact *contact, pj_str_t *path_str)
  94. {
  95. if (!contact || ast_strlen_zero(contact->path)) {
  96. return -1;
  97. }
  98. *path_str = pj_strdup3(pool, contact->path);
  99. return 0;
  100. }
  101. static int add_supported(pjsip_tx_data *tdata)
  102. {
  103. pjsip_supported_hdr *hdr;
  104. hdr = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_SUPPORTED, NULL);
  105. if (!hdr) {
  106. /* insert a new Supported header */
  107. hdr = pjsip_supported_hdr_create(tdata->pool);
  108. if (!hdr) {
  109. return -1;
  110. }
  111. pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *)hdr);
  112. }
  113. /* add on to the existing Supported header */
  114. pj_strassign(&hdr->values[hdr->count++], &PATH_SUPPORTED_NAME);
  115. return 0;
  116. }
  117. /*!
  118. * \internal
  119. * \brief Adds a Route header to an outgoing request if
  120. * path information is available.
  121. *
  122. * \param endpoint The endpoint with which this request is associated
  123. * \param contact The contact to which this request is being sent
  124. * \param tdata The outbound request
  125. */
  126. static void path_outgoing_request(struct ast_sip_endpoint *endpoint, struct ast_sip_contact *contact, pjsip_tx_data *tdata)
  127. {
  128. RAII_VAR(struct ast_sip_aor *, aor, NULL, ao2_cleanup);
  129. if (!endpoint) {
  130. return;
  131. }
  132. aor = find_aor(endpoint, tdata->msg->line.req.uri);
  133. if (!aor || !aor->support_path) {
  134. return;
  135. }
  136. if (add_supported(tdata)) {
  137. return;
  138. }
  139. if (contact && !ast_strlen_zero(contact->path)) {
  140. ast_sip_set_outbound_proxy(tdata, contact->path);
  141. }
  142. }
  143. static void path_session_outgoing_request(struct ast_sip_session *session, pjsip_tx_data *tdata)
  144. {
  145. path_outgoing_request(session->endpoint, session->contact, tdata);
  146. }
  147. /*!
  148. * \internal
  149. * \brief Adds a path header to an outgoing 2XX response
  150. *
  151. * \param endpoint The endpoint to which the INVITE response is to be sent
  152. * \param contact The contact to which the INVITE response is to be sent
  153. * \param tdata The outbound INVITE response
  154. */
  155. static void path_outgoing_response(struct ast_sip_endpoint *endpoint, struct ast_sip_contact *contact, pjsip_tx_data *tdata)
  156. {
  157. struct pjsip_status_line status = tdata->msg->line.status;
  158. pj_str_t path_dup;
  159. pjsip_generic_string_hdr *path_hdr;
  160. pjsip_contact_hdr *contact_hdr;
  161. RAII_VAR(struct ast_sip_aor *, aor, NULL, ao2_cleanup);
  162. pjsip_cseq_hdr *cseq = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CSEQ, NULL);
  163. const pj_str_t REGISTER_METHOD = {"REGISTER", 8};
  164. if (!endpoint
  165. || !pj_stristr(&REGISTER_METHOD, &cseq->method.name)
  166. || !PJSIP_IS_STATUS_IN_CLASS(status.code, 200)) {
  167. return;
  168. }
  169. contact_hdr = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CONTACT, NULL);
  170. if (!contact_hdr) {
  171. return;
  172. }
  173. aor = find_aor(endpoint, contact_hdr->uri);
  174. if (!aor || !aor->support_path || add_supported(tdata)
  175. || path_get_string(tdata->pool, contact, &path_dup)) {
  176. return;
  177. }
  178. path_hdr = pjsip_generic_string_hdr_create(tdata->pool, &PATH_NAME, &path_dup);
  179. if (!path_hdr) {
  180. return;
  181. }
  182. pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)path_hdr);
  183. }
  184. static void path_session_outgoing_response(struct ast_sip_session *session, pjsip_tx_data *tdata)
  185. {
  186. path_outgoing_response(session->endpoint, session->contact, tdata);
  187. }
  188. static struct ast_sip_supplement path_supplement = {
  189. .priority = AST_SIP_SUPPLEMENT_PRIORITY_CHANNEL - 100,
  190. .outgoing_request = path_outgoing_request,
  191. .outgoing_response = path_outgoing_response,
  192. };
  193. static struct ast_sip_session_supplement path_session_supplement = {
  194. .priority = AST_SIP_SUPPLEMENT_PRIORITY_CHANNEL - 100,
  195. .outgoing_request = path_session_outgoing_request,
  196. .outgoing_response = path_session_outgoing_response,
  197. };
  198. static int load_module(void)
  199. {
  200. CHECK_PJSIP_SESSION_MODULE_LOADED();
  201. if (ast_sip_register_supplement(&path_supplement)) {
  202. return AST_MODULE_LOAD_DECLINE;
  203. }
  204. if (ast_sip_session_register_supplement(&path_session_supplement)) {
  205. ast_sip_unregister_supplement(&path_supplement);
  206. return AST_MODULE_LOAD_DECLINE;
  207. }
  208. return AST_MODULE_LOAD_SUCCESS;
  209. }
  210. static int unload_module(void)
  211. {
  212. ast_sip_unregister_supplement(&path_supplement);
  213. ast_sip_session_unregister_supplement(&path_session_supplement);
  214. return 0;
  215. }
  216. AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP Path Header Support",
  217. .support_level = AST_MODULE_SUPPORT_CORE,
  218. .load = load_module,
  219. .unload = unload_module,
  220. .load_pri = AST_MODPRI_APP_DEPEND,
  221. );