res_pjsip_path.c 6.8 KB

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