pjsip_options.c 28 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108
  1. /*
  2. * Asterisk -- An open source telephony toolkit.
  3. *
  4. * Copyright (C) 2013, Digium, Inc.
  5. *
  6. * Matt Jordan <mjordan@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. #include "asterisk.h"
  19. #include <pjsip.h>
  20. #include <pjsip_ua.h>
  21. #include <pjlib.h>
  22. #include "asterisk/res_pjsip.h"
  23. #include "asterisk/channel.h"
  24. #include "asterisk/pbx.h"
  25. #include "asterisk/astobj2.h"
  26. #include "asterisk/cli.h"
  27. #include "asterisk/time.h"
  28. #include "include/res_pjsip_private.h"
  29. #define DEFAULT_LANGUAGE "en"
  30. #define DEFAULT_ENCODING "text/plain"
  31. #define QUALIFIED_BUCKETS 211
  32. /*!
  33. * \internal
  34. * \brief Create a ast_sip_contact_status object.
  35. */
  36. static void *contact_status_alloc(const char *name)
  37. {
  38. struct ast_sip_contact_status *status = ast_sorcery_generic_alloc(sizeof(*status), NULL);
  39. if (!status) {
  40. ast_log(LOG_ERROR, "Unable to allocate ast_sip_contact_status\n");
  41. return NULL;
  42. }
  43. status->status = UNAVAILABLE;
  44. return status;
  45. }
  46. /*!
  47. * \internal
  48. * \brief Retrieve a ast_sip_contact_status object from sorcery creating
  49. * one if not found.
  50. */
  51. static struct ast_sip_contact_status *find_or_create_contact_status(const struct ast_sip_contact *contact)
  52. {
  53. struct ast_sip_contact_status *status;
  54. status = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), CONTACT_STATUS,
  55. ast_sorcery_object_get_id(contact));
  56. if (status) {
  57. return status;
  58. }
  59. status = ast_sorcery_alloc(ast_sip_get_sorcery(), CONTACT_STATUS,
  60. ast_sorcery_object_get_id(contact));
  61. if (!status) {
  62. ast_log(LOG_ERROR, "Unable to create ast_sip_contact_status for contact %s\n",
  63. contact->uri);
  64. return NULL;
  65. }
  66. if (ast_sorcery_create(ast_sip_get_sorcery(), status)) {
  67. ast_log(LOG_ERROR, "Unable to persist ast_sip_contact_status for contact %s\n",
  68. contact->uri);
  69. ao2_ref(status, -1);
  70. return NULL;
  71. }
  72. return status;
  73. }
  74. /*!
  75. * \internal
  76. * \brief Update an ast_sip_contact_status's elements.
  77. */
  78. static void update_contact_status(const struct ast_sip_contact *contact,
  79. enum ast_sip_contact_status_type value)
  80. {
  81. struct ast_sip_contact_status *status;
  82. struct ast_sip_contact_status *update;
  83. status = find_or_create_contact_status(contact);
  84. if (!status) {
  85. return;
  86. }
  87. update = ast_sorcery_alloc(ast_sip_get_sorcery(), CONTACT_STATUS,
  88. ast_sorcery_object_get_id(status));
  89. if (!update) {
  90. ast_log(LOG_ERROR, "Unable to create update ast_sip_contact_status for contact %s\n",
  91. contact->uri);
  92. ao2_ref(status, -1);
  93. return;
  94. }
  95. update->status = value;
  96. /* if the contact is available calculate the rtt as
  97. the diff between the last start time and "now" */
  98. update->rtt = update->status == AVAILABLE ?
  99. ast_tvdiff_us(ast_tvnow(), status->rtt_start) : 0;
  100. update->rtt_start = ast_tv(0, 0);
  101. if (ast_sorcery_update(ast_sip_get_sorcery(), update)) {
  102. ast_log(LOG_ERROR, "Unable to update ast_sip_contact_status for contact %s\n",
  103. contact->uri);
  104. }
  105. ao2_ref(update, -1);
  106. ao2_ref(status, -1);
  107. }
  108. /*!
  109. * \internal
  110. * \brief Initialize the start time on a contact status so the round
  111. * trip time can be calculated upon a valid response.
  112. */
  113. static void init_start_time(const struct ast_sip_contact *contact)
  114. {
  115. struct ast_sip_contact_status *status;
  116. struct ast_sip_contact_status *update;
  117. status = find_or_create_contact_status(contact);
  118. if (!status) {
  119. return;
  120. }
  121. update = ast_sorcery_alloc(ast_sip_get_sorcery(), CONTACT_STATUS,
  122. ast_sorcery_object_get_id(status));
  123. if (!update) {
  124. ast_log(LOG_ERROR, "Unable to create update ast_sip_contact_status for contact %s\n",
  125. contact->uri);
  126. ao2_ref(status, -1);
  127. return;
  128. }
  129. update->rtt_start = ast_tvnow();
  130. if (ast_sorcery_update(ast_sip_get_sorcery(), update)) {
  131. ast_log(LOG_ERROR, "Unable to update ast_sip_contact_status for contact %s\n",
  132. contact->uri);
  133. }
  134. ao2_ref(update, -1);
  135. ao2_ref(status, -1);
  136. }
  137. /*!
  138. * \internal
  139. * \brief Match a container contact object with the contact sorcery id looking for.
  140. *
  141. * \param obj pointer to the (user-defined part) of an object.
  142. * \param arg callback argument from ao2_callback()
  143. * \param flags flags from ao2_callback()
  144. *
  145. * \return Values are a combination of enum _cb_results.
  146. */
  147. static int match_contact_id(void *obj, void *arg, int flags)
  148. {
  149. struct ast_sip_contact *contact = obj;
  150. const char *looking_for = arg;
  151. return strcmp(ast_sorcery_object_get_id(contact), looking_for) ? 0 : CMP_MATCH;
  152. }
  153. /*!
  154. * \internal
  155. * \brief For an endpoint try to match the given contact sorcery id.
  156. */
  157. static int on_endpoint(void *obj, void *arg, int flags)
  158. {
  159. struct ast_sip_endpoint *endpoint = obj;
  160. struct ast_sip_contact *contact;
  161. char *looking_for = arg;
  162. char *aor_name;
  163. char *aors;
  164. if (!arg || ast_strlen_zero(endpoint->aors)) {
  165. return 0;
  166. }
  167. aors = ast_strdupa(endpoint->aors);
  168. while ((aor_name = strsep(&aors, ","))) {
  169. struct ast_sip_aor *aor;
  170. struct ao2_container *contacts;
  171. aor = ast_sip_location_retrieve_aor(aor_name);
  172. if (!aor) {
  173. continue;
  174. }
  175. contacts = ast_sip_location_retrieve_aor_contacts(aor);
  176. ao2_ref(aor, -1);
  177. if (!contacts) {
  178. continue;
  179. }
  180. contact = ao2_callback(contacts, 0, match_contact_id, looking_for);
  181. ao2_ref(contacts, -1);
  182. if (contact) {
  183. ao2_ref(contact, -1);
  184. return CMP_MATCH;
  185. }
  186. }
  187. return 0;
  188. }
  189. /*!
  190. * \internal
  191. * \brief Find an endpoint associated with the given contact.
  192. */
  193. static struct ast_sip_endpoint *find_an_endpoint(struct ast_sip_contact *contact)
  194. {
  195. char *looking_for = (char *) ast_sorcery_object_get_id(contact);
  196. struct ao2_container *endpoints = ast_sip_get_endpoints();
  197. struct ast_sip_endpoint *endpoint;
  198. endpoint = ao2_callback(endpoints, 0, on_endpoint, looking_for);
  199. ao2_ref(endpoints, -1);
  200. return endpoint;
  201. }
  202. /*!
  203. * \internal
  204. * \brief Receive a response to the qualify contact request.
  205. */
  206. static void qualify_contact_cb(void *token, pjsip_event *e)
  207. {
  208. struct ast_sip_contact *contact = token;
  209. switch(e->body.tsx_state.type) {
  210. default:
  211. ast_log(LOG_ERROR, "Unexpected PJSIP event %d\n", e->body.tsx_state.type);
  212. /* Fall through */
  213. case PJSIP_EVENT_TRANSPORT_ERROR:
  214. case PJSIP_EVENT_TIMER:
  215. update_contact_status(contact, UNAVAILABLE);
  216. break;
  217. case PJSIP_EVENT_RX_MSG:
  218. update_contact_status(contact, AVAILABLE);
  219. break;
  220. }
  221. ao2_cleanup(contact);
  222. }
  223. /*!
  224. * \internal
  225. * \brief Attempt to qualify the contact
  226. *
  227. * \details Sends a SIP OPTIONS request to the given contact in order to make
  228. * sure that contact is available.
  229. */
  230. static int qualify_contact(struct ast_sip_endpoint *endpoint, struct ast_sip_contact *contact)
  231. {
  232. pjsip_tx_data *tdata;
  233. RAII_VAR(struct ast_sip_endpoint *, endpoint_local, NULL, ao2_cleanup);
  234. if (contact->authenticate_qualify) {
  235. endpoint_local = ao2_bump(endpoint);
  236. if (!endpoint_local) {
  237. /*
  238. * Find the "first" endpoint to completely qualify the contact - any
  239. * endpoint that is associated with the contact should do.
  240. */
  241. endpoint_local = find_an_endpoint(contact);
  242. if (!endpoint_local) {
  243. ast_log(LOG_ERROR, "Unable to find an endpoint to qualify contact %s\n",
  244. contact->uri);
  245. return -1;
  246. }
  247. }
  248. }
  249. if (ast_sip_create_request("OPTIONS", NULL, NULL, NULL, contact, &tdata)) {
  250. ast_log(LOG_ERROR, "Unable to create request to qualify contact %s\n",
  251. contact->uri);
  252. return -1;
  253. }
  254. /* If an outbound proxy is specified set it on this request */
  255. if (!ast_strlen_zero(contact->outbound_proxy) &&
  256. ast_sip_set_outbound_proxy(tdata, contact->outbound_proxy)) {
  257. pjsip_tx_data_dec_ref(tdata);
  258. ast_log(LOG_ERROR, "Unable to apply outbound proxy on request to qualify contact %s\n",
  259. contact->uri);
  260. return -1;
  261. }
  262. init_start_time(contact);
  263. ao2_ref(contact, +1);
  264. if (ast_sip_send_request(tdata, NULL, endpoint_local, contact, qualify_contact_cb)
  265. != PJ_SUCCESS) {
  266. ast_log(LOG_ERROR, "Unable to send request to qualify contact %s\n",
  267. contact->uri);
  268. update_contact_status(contact, UNAVAILABLE);
  269. ao2_ref(contact, -1);
  270. return -1;
  271. }
  272. return 0;
  273. }
  274. /*!
  275. * \internal
  276. * \brief Scheduling context for sending QUALIFY request at specified intervals.
  277. */
  278. static struct ast_sched_context *sched;
  279. /*!
  280. * \internal
  281. * \brief Container to hold all actively scheduled qualifies.
  282. */
  283. static struct ao2_container *sched_qualifies;
  284. /*!
  285. * \internal
  286. * \brief Structure to hold qualify contact scheduling information.
  287. */
  288. struct sched_data {
  289. /*! The scheduling id */
  290. int id;
  291. /*! The the contact being checked */
  292. struct ast_sip_contact *contact;
  293. };
  294. /*!
  295. * \internal
  296. * \brief Destroy the scheduled data and remove from scheduler.
  297. */
  298. static void sched_data_destructor(void *obj)
  299. {
  300. struct sched_data *data = obj;
  301. ao2_cleanup(data->contact);
  302. }
  303. /*!
  304. * \internal
  305. * \brief Create the scheduling data object.
  306. */
  307. static struct sched_data *sched_data_create(struct ast_sip_contact *contact)
  308. {
  309. struct sched_data *data;
  310. data = ao2_t_alloc(sizeof(*data), sched_data_destructor, contact->uri);
  311. if (!data) {
  312. ast_log(LOG_ERROR, "Unable to create schedule qualify data for contact %s\n",
  313. contact->uri);
  314. return NULL;
  315. }
  316. data->contact = contact;
  317. ao2_ref(data->contact, +1);
  318. return data;
  319. }
  320. /*!
  321. * \internal
  322. * \brief Send a qualify contact request within a threaded task.
  323. */
  324. static int qualify_contact_task(void *obj)
  325. {
  326. struct ast_sip_contact *contact = obj;
  327. int res;
  328. res = qualify_contact(NULL, contact);
  329. ao2_ref(contact, -1);
  330. return res;
  331. }
  332. /*!
  333. * \internal
  334. * \brief Send a scheduled qualify contact request.
  335. */
  336. static int qualify_contact_sched(const void *obj)
  337. {
  338. struct sched_data *data = (struct sched_data *) obj;
  339. ao2_ref(data->contact, +1);
  340. if (ast_sip_push_task(NULL, qualify_contact_task, data->contact)) {
  341. ao2_ref(data->contact, -1);
  342. }
  343. /*
  344. * Always reschedule rather than have a potential race cleaning
  345. * up the data object ref between self deletion and an external
  346. * deletion.
  347. */
  348. return 1;
  349. }
  350. /*!
  351. * \internal
  352. * \brief Set up a scheduled qualify contact check.
  353. */
  354. static void schedule_qualify(struct ast_sip_contact *contact)
  355. {
  356. struct sched_data *data;
  357. data = sched_data_create(contact);
  358. if (!data) {
  359. return;
  360. }
  361. ast_assert(contact->qualify_frequency != 0);
  362. ao2_t_ref(data, +1, "Ref for qualify_contact_sched() scheduler entry");
  363. data->id = ast_sched_add_variable(sched, contact->qualify_frequency * 1000,
  364. qualify_contact_sched, data, 0);
  365. if (data->id < 0) {
  366. ao2_t_ref(data, -1, "Cleanup failed scheduler add");
  367. ast_log(LOG_ERROR, "Unable to schedule qualify for contact %s\n",
  368. contact->uri);
  369. } else if (!ao2_link(sched_qualifies, data)) {
  370. AST_SCHED_DEL_UNREF(sched, data->id,
  371. ao2_t_ref(data, -1, "Cleanup scheduler for failed ao2_link"));
  372. }
  373. ao2_t_ref(data, -1, "Done setting up scheduler entry");
  374. }
  375. /*!
  376. * \internal
  377. * \brief Remove the contact from the scheduler.
  378. */
  379. static void unschedule_qualify(struct ast_sip_contact *contact)
  380. {
  381. struct sched_data *data;
  382. data = ao2_find(sched_qualifies, contact, OBJ_UNLINK | OBJ_SEARCH_KEY);
  383. if (!data) {
  384. return;
  385. }
  386. AST_SCHED_DEL_UNREF(sched, data->id,
  387. ao2_t_ref(data, -1, "Delete scheduler entry ref"));
  388. ao2_t_ref(data, -1, "Done with ao2_find ref");
  389. }
  390. /*!
  391. * \internal
  392. * \brief Qualify the given contact and set up scheduling if configured.
  393. */
  394. static void qualify_and_schedule(struct ast_sip_contact *contact)
  395. {
  396. unschedule_qualify(contact);
  397. if (contact->qualify_frequency) {
  398. ao2_ref(contact, +1);
  399. if (ast_sip_push_task(NULL, qualify_contact_task, contact)) {
  400. ao2_ref(contact, -1);
  401. }
  402. schedule_qualify(contact);
  403. }
  404. }
  405. /*!
  406. * \internal
  407. * \brief A new contact has been created make sure it is available.
  408. */
  409. static void contact_created(const void *obj)
  410. {
  411. qualify_and_schedule((struct ast_sip_contact *) obj);
  412. }
  413. /*!
  414. * \internal
  415. * \brief A contact has been deleted remove status tracking.
  416. */
  417. static void contact_deleted(const void *obj)
  418. {
  419. struct ast_sip_contact *contact = (struct ast_sip_contact *) obj;
  420. struct ast_sip_contact_status *status;
  421. unschedule_qualify(contact);
  422. status = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), CONTACT_STATUS,
  423. ast_sorcery_object_get_id(contact));
  424. if (!status) {
  425. return;
  426. }
  427. if (ast_sorcery_delete(ast_sip_get_sorcery(), status)) {
  428. ast_log(LOG_ERROR, "Unable to delete ast_sip_contact_status for contact %s\n",
  429. contact->uri);
  430. }
  431. ao2_ref(status, -1);
  432. }
  433. static const struct ast_sorcery_observer contact_observer = {
  434. .created = contact_created,
  435. .deleted = contact_deleted
  436. };
  437. static pj_bool_t options_start(void)
  438. {
  439. sched = ast_sched_context_create();
  440. if (!sched) {
  441. return -1;
  442. }
  443. if (ast_sched_start_thread(sched)) {
  444. ast_sched_context_destroy(sched);
  445. sched = NULL;
  446. return -1;
  447. }
  448. if (ast_sorcery_observer_add(ast_sip_get_sorcery(), "contact", &contact_observer)) {
  449. ast_log(LOG_WARNING, "Unable to add contact observer\n");
  450. ast_sched_context_destroy(sched);
  451. sched = NULL;
  452. return -1;
  453. }
  454. return PJ_SUCCESS;
  455. }
  456. static int sched_qualifies_empty(void *obj, void *arg, int flags)
  457. {
  458. ao2_t_ref(obj, -1, "Release ref held by destroyed scheduler context.");
  459. return CMP_MATCH;
  460. }
  461. static pj_bool_t options_stop(void)
  462. {
  463. ast_sorcery_observer_remove(ast_sip_get_sorcery(), "contact", &contact_observer);
  464. if (sched) {
  465. ast_sched_context_destroy(sched);
  466. sched = NULL;
  467. }
  468. /* Empty the container of scheduling data refs. */
  469. ao2_callback(sched_qualifies, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE,
  470. sched_qualifies_empty, NULL);
  471. return PJ_SUCCESS;
  472. }
  473. static pj_status_t send_options_response(pjsip_rx_data *rdata, int code)
  474. {
  475. pjsip_endpoint *endpt = ast_sip_get_pjsip_endpoint();
  476. pjsip_dialog *dlg = pjsip_rdata_get_dlg(rdata);
  477. pjsip_transaction *trans = pjsip_rdata_get_tsx(rdata);
  478. pjsip_tx_data *tdata;
  479. const pjsip_hdr *hdr;
  480. pjsip_response_addr res_addr;
  481. pj_status_t status;
  482. /* Make the response object */
  483. if ((status = ast_sip_create_response(rdata, code, NULL, &tdata) != PJ_SUCCESS)) {
  484. ast_log(LOG_ERROR, "Unable to create response (%d)\n", status);
  485. return status;
  486. }
  487. /* Add appropriate headers */
  488. if ((hdr = pjsip_endpt_get_capability(endpt, PJSIP_H_ACCEPT, NULL))) {
  489. pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)pjsip_hdr_clone(tdata->pool, hdr));
  490. }
  491. if ((hdr = pjsip_endpt_get_capability(endpt, PJSIP_H_ALLOW, NULL))) {
  492. pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)pjsip_hdr_clone(tdata->pool, hdr));
  493. }
  494. if ((hdr = pjsip_endpt_get_capability(endpt, PJSIP_H_SUPPORTED, NULL))) {
  495. pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)pjsip_hdr_clone(tdata->pool, hdr));
  496. }
  497. /*
  498. * XXX TODO: pjsip doesn't care a lot about either of these headers -
  499. * while it provides specific methods to create them, they are defined
  500. * to be the standard string header creation. We never did add them
  501. * in chan_sip, although RFC 3261 says they SHOULD. Hard coded here.
  502. */
  503. ast_sip_add_header(tdata, "Accept-Encoding", DEFAULT_ENCODING);
  504. ast_sip_add_header(tdata, "Accept-Language", DEFAULT_LANGUAGE);
  505. if (dlg && trans) {
  506. status = pjsip_dlg_send_response(dlg, trans, tdata);
  507. } else {
  508. /* Get where to send request. */
  509. if ((status = pjsip_get_response_addr(
  510. tdata->pool, rdata, &res_addr)) != PJ_SUCCESS) {
  511. ast_log(LOG_ERROR, "Unable to get response address (%d)\n",
  512. status);
  513. pjsip_tx_data_dec_ref(tdata);
  514. return status;
  515. }
  516. status = ast_sip_send_response(&res_addr, tdata,
  517. ast_pjsip_rdata_get_endpoint(rdata));
  518. }
  519. if (status != PJ_SUCCESS) {
  520. ast_log(LOG_ERROR, "Unable to send response (%d)\n", status);
  521. }
  522. return status;
  523. }
  524. static pj_bool_t options_on_rx_request(pjsip_rx_data *rdata)
  525. {
  526. RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
  527. pjsip_uri *ruri;
  528. pjsip_sip_uri *sip_ruri;
  529. char exten[AST_MAX_EXTENSION];
  530. if (pjsip_method_cmp(&rdata->msg_info.msg->line.req.method,
  531. &pjsip_options_method)) {
  532. return PJ_FALSE;
  533. }
  534. if (!(endpoint = ast_pjsip_rdata_get_endpoint(rdata))) {
  535. return PJ_FALSE;
  536. }
  537. ruri = rdata->msg_info.msg->line.req.uri;
  538. if (!PJSIP_URI_SCHEME_IS_SIP(ruri) && !PJSIP_URI_SCHEME_IS_SIPS(ruri)) {
  539. send_options_response(rdata, 416);
  540. return -1;
  541. }
  542. sip_ruri = pjsip_uri_get_uri(ruri);
  543. ast_copy_pj_str(exten, &sip_ruri->user, sizeof(exten));
  544. if (ast_shutting_down()) {
  545. send_options_response(rdata, 503);
  546. } else if (!ast_strlen_zero(exten) && !ast_exists_extension(NULL, endpoint->context, exten, 1, NULL)) {
  547. send_options_response(rdata, 404);
  548. } else {
  549. send_options_response(rdata, 200);
  550. }
  551. return PJ_TRUE;
  552. }
  553. static pjsip_module options_module = {
  554. .name = {"Options Module", 14},
  555. .id = -1,
  556. .priority = PJSIP_MOD_PRIORITY_APPLICATION,
  557. .start = options_start,
  558. .stop = options_stop,
  559. .on_rx_request = options_on_rx_request,
  560. };
  561. /*!
  562. * \internal
  563. * \brief Send qualify request to the given contact.
  564. */
  565. static int cli_on_contact(void *obj, void *arg, void *data, int flags)
  566. {
  567. struct ast_sip_contact *contact = obj;
  568. struct ast_sip_endpoint *endpoint = data;
  569. int *cli_fd = arg;
  570. ast_cli(*cli_fd, " contact %s\n", contact->uri);
  571. qualify_contact(endpoint, contact);
  572. return 0;
  573. }
  574. /*!
  575. * \brief Data pushed to threadpool to qualify endpoints from the CLI
  576. */
  577. struct qualify_data {
  578. /*! Endpoint that is being qualified */
  579. struct ast_sip_endpoint *endpoint;
  580. /*! CLI File descriptor for printing messages */
  581. int cli_fd;
  582. };
  583. static struct qualify_data *qualify_data_alloc(struct ast_sip_endpoint *endpoint, int cli_fd)
  584. {
  585. struct qualify_data *qual_data;
  586. qual_data = ast_malloc(sizeof(*qual_data));
  587. if (!qual_data) {
  588. return NULL;
  589. }
  590. qual_data->endpoint = ao2_bump(endpoint);
  591. qual_data->cli_fd = cli_fd;
  592. return qual_data;
  593. }
  594. static void qualify_data_destroy(struct qualify_data *qual_data)
  595. {
  596. ao2_cleanup(qual_data->endpoint);
  597. ast_free(qual_data);
  598. }
  599. /*!
  600. * \internal
  601. * \brief For an endpoint iterate over and qualify all aors/contacts
  602. */
  603. static int cli_qualify_contacts(void *data)
  604. {
  605. char *aors;
  606. char *aor_name;
  607. RAII_VAR(struct qualify_data *, qual_data, data, qualify_data_destroy);
  608. struct ast_sip_endpoint *endpoint = qual_data->endpoint;
  609. int cli_fd = qual_data->cli_fd;
  610. const char *endpoint_name = ast_sorcery_object_get_id(endpoint);
  611. if (ast_strlen_zero(endpoint->aors)) {
  612. ast_cli(cli_fd, "Endpoint %s has no AoR's configured\n",
  613. endpoint_name);
  614. return 0;
  615. }
  616. aors = ast_strdupa(endpoint->aors);
  617. while ((aor_name = strsep(&aors, ","))) {
  618. struct ast_sip_aor *aor;
  619. struct ao2_container *contacts;
  620. aor = ast_sip_location_retrieve_aor(aor_name);
  621. if (!aor) {
  622. continue;
  623. }
  624. contacts = ast_sip_location_retrieve_aor_contacts(aor);
  625. if (contacts) {
  626. ast_cli(cli_fd, "Sending qualify to endpoint %s\n", endpoint_name);
  627. ao2_callback_data(contacts, OBJ_NODATA, cli_on_contact, &cli_fd, endpoint);
  628. ao2_ref(contacts, -1);
  629. }
  630. ao2_ref(aor, -1);
  631. }
  632. return 0;
  633. }
  634. static char *cli_qualify(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
  635. {
  636. RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
  637. const char *endpoint_name;
  638. struct qualify_data *qual_data;
  639. switch (cmd) {
  640. case CLI_INIT:
  641. e->command = "pjsip qualify";
  642. e->usage =
  643. "Usage: pjsip qualify <endpoint>\n"
  644. " Send a SIP OPTIONS request to all contacts on the endpoint.\n";
  645. return NULL;
  646. case CLI_GENERATE:
  647. return NULL;
  648. }
  649. if (a->argc != 3) {
  650. return CLI_SHOWUSAGE;
  651. }
  652. endpoint_name = a->argv[2];
  653. if (!(endpoint = ast_sorcery_retrieve_by_id(
  654. ast_sip_get_sorcery(), "endpoint", endpoint_name))) {
  655. ast_cli(a->fd, "Unable to retrieve endpoint %s\n", endpoint_name);
  656. return CLI_FAILURE;
  657. }
  658. qual_data = qualify_data_alloc(endpoint, a->fd);
  659. if (!qual_data) {
  660. return CLI_FAILURE;
  661. }
  662. if (ast_sip_push_task(NULL, cli_qualify_contacts, qual_data)) {
  663. qualify_data_destroy(qual_data);
  664. return CLI_FAILURE;
  665. }
  666. return CLI_SUCCESS;
  667. }
  668. /*!
  669. * \internal
  670. * \brief Send qualify request to the given contact.
  671. */
  672. static int ami_contact_cb(void *obj, void *arg, int flags)
  673. {
  674. struct ast_sip_contact *contact = obj;
  675. ao2_ref(contact, +1);
  676. if (ast_sip_push_task(NULL, qualify_contact_task, contact)) {
  677. ao2_ref(contact, -1);
  678. }
  679. return 0;
  680. }
  681. static int ami_sip_qualify(struct mansession *s, const struct message *m)
  682. {
  683. const char *endpoint_name = astman_get_header(m, "Endpoint");
  684. RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
  685. char *aors;
  686. char *aor_name;
  687. if (ast_strlen_zero(endpoint_name)) {
  688. astman_send_error(s, m, "Endpoint parameter missing.");
  689. return 0;
  690. }
  691. endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint",
  692. endpoint_name);
  693. if (!endpoint) {
  694. astman_send_error(s, m, "Unable to retrieve endpoint\n");
  695. return 0;
  696. }
  697. /* send a qualify for all contacts registered with the endpoint */
  698. if (ast_strlen_zero(endpoint->aors)) {
  699. astman_send_error(s, m, "No AoRs configured for endpoint\n");
  700. return 0;
  701. }
  702. aors = ast_strdupa(endpoint->aors);
  703. while ((aor_name = strsep(&aors, ","))) {
  704. struct ast_sip_aor *aor;
  705. struct ao2_container *contacts;
  706. aor = ast_sip_location_retrieve_aor(aor_name);
  707. if (!aor) {
  708. continue;
  709. }
  710. contacts = ast_sip_location_retrieve_aor_contacts(aor);
  711. if (contacts) {
  712. ao2_callback(contacts, OBJ_NODATA, ami_contact_cb, NULL);
  713. ao2_ref(contacts, -1);
  714. }
  715. ao2_ref(aor, -1);
  716. }
  717. astman_send_ack(s, m, "Endpoint found, will qualify");
  718. return 0;
  719. }
  720. static struct ast_cli_entry cli_options[] = {
  721. AST_CLI_DEFINE(cli_qualify, "Send an OPTIONS request to a PJSIP endpoint")
  722. };
  723. static int sched_qualifies_hash_fn(const void *obj, int flags)
  724. {
  725. const struct sched_data *object;
  726. const struct ast_sip_contact *key;
  727. switch (flags & OBJ_SEARCH_MASK) {
  728. case OBJ_SEARCH_KEY:
  729. key = obj;
  730. break;
  731. case OBJ_SEARCH_OBJECT:
  732. object = obj;
  733. key = object->contact;
  734. break;
  735. default:
  736. /* Hash can only work on something with a full key. */
  737. ast_assert(0);
  738. return 0;
  739. }
  740. return ast_str_hash(ast_sorcery_object_get_id(key));
  741. }
  742. static int sched_qualifies_cmp_fn(void *obj, void *arg, int flags)
  743. {
  744. const struct sched_data *object_left = obj;
  745. const struct sched_data *object_right = arg;
  746. struct ast_sip_contact *right_key = arg;
  747. int cmp;
  748. switch (flags & OBJ_SEARCH_MASK) {
  749. case OBJ_SEARCH_OBJECT:
  750. right_key = object_right->contact;
  751. /* Fall through */
  752. case OBJ_SEARCH_KEY:
  753. cmp = strcmp(ast_sorcery_object_get_id(object_left->contact),
  754. ast_sorcery_object_get_id(right_key));
  755. break;
  756. case OBJ_SEARCH_PARTIAL_KEY:
  757. /* Not supported by container. */
  758. ast_assert(0);
  759. return 0;
  760. default:
  761. /*
  762. * What arg points to is specific to this traversal callback
  763. * and has no special meaning to astobj2.
  764. */
  765. cmp = 0;
  766. break;
  767. }
  768. if (cmp) {
  769. return 0;
  770. }
  771. /*
  772. * At this point the traversal callback is identical to a sorted
  773. * container.
  774. */
  775. return CMP_MATCH;
  776. }
  777. int ast_sip_initialize_sorcery_qualify(void)
  778. {
  779. struct ast_sorcery *sorcery = ast_sip_get_sorcery();
  780. /* initialize sorcery ast_sip_contact_status resource */
  781. ast_sorcery_apply_default(sorcery, CONTACT_STATUS, "memory", NULL);
  782. if (ast_sorcery_internal_object_register(sorcery, CONTACT_STATUS,
  783. contact_status_alloc, NULL, NULL)) {
  784. ast_log(LOG_ERROR, "Unable to register ast_sip_contact_status in sorcery\n");
  785. return -1;
  786. }
  787. ast_sorcery_object_field_register_nodoc(sorcery, CONTACT_STATUS, "rtt", "0", OPT_UINT_T,
  788. 1, FLDSET(struct ast_sip_contact_status, status));
  789. ast_sorcery_object_field_register_nodoc(sorcery, CONTACT_STATUS, "rtt", "0", OPT_UINT_T,
  790. 1, FLDSET(struct ast_sip_contact_status, rtt));
  791. return 0;
  792. }
  793. static int qualify_and_schedule_cb(void *obj, void *arg, int flags)
  794. {
  795. struct ast_sip_contact *contact = obj;
  796. struct ast_sip_aor *aor = arg;
  797. contact->qualify_frequency = aor->qualify_frequency;
  798. contact->authenticate_qualify = aor->authenticate_qualify;
  799. qualify_and_schedule(contact);
  800. return 0;
  801. }
  802. /*!
  803. * \internal
  804. * \brief Qualify and schedule an endpoint's contacts
  805. *
  806. * \details For the given endpoint retrieve its list of aors, qualify all
  807. * contacts, and schedule for checks if configured.
  808. */
  809. static int qualify_and_schedule_all_cb(void *obj, void *arg, int flags)
  810. {
  811. struct ast_sip_endpoint *endpoint = obj;
  812. char *aors;
  813. char *aor_name;
  814. if (ast_strlen_zero(endpoint->aors)) {
  815. return 0;
  816. }
  817. aors = ast_strdupa(endpoint->aors);
  818. while ((aor_name = strsep(&aors, ","))) {
  819. struct ast_sip_aor *aor;
  820. struct ao2_container *contacts;
  821. aor = ast_sip_location_retrieve_aor(aor_name);
  822. if (!aor) {
  823. continue;
  824. }
  825. contacts = ast_sip_location_retrieve_aor_contacts(aor);
  826. if (contacts) {
  827. ao2_callback(contacts, OBJ_NODATA, qualify_and_schedule_cb, aor);
  828. ao2_ref(contacts, -1);
  829. }
  830. ao2_ref(aor, -1);
  831. }
  832. return 0;
  833. }
  834. static void qualify_and_schedule_all(void)
  835. {
  836. struct ao2_container *endpoints = ast_sip_get_endpoints();
  837. if (!endpoints) {
  838. return;
  839. }
  840. ao2_callback(endpoints, OBJ_NODATA, qualify_and_schedule_all_cb, NULL);
  841. ao2_ref(endpoints, -1);
  842. }
  843. static const char *status_map [] = {
  844. [UNAVAILABLE] = "Unreachable",
  845. [AVAILABLE] = "Reachable",
  846. };
  847. static int format_contact_status(void *obj, void *arg, int flags)
  848. {
  849. struct ast_sip_contact_wrapper *wrapper = obj;
  850. struct ast_sip_contact *contact = wrapper->contact;
  851. struct ast_sip_ami *ami = arg;
  852. struct ast_sip_contact_status *status;
  853. struct ast_str *buf;
  854. const struct ast_sip_endpoint *endpoint = ami->arg;
  855. buf = ast_sip_create_ami_event("ContactStatusDetail", ami);
  856. if (!buf) {
  857. return -1;
  858. }
  859. status = ast_sorcery_retrieve_by_id(
  860. ast_sip_get_sorcery(), CONTACT_STATUS,
  861. ast_sorcery_object_get_id(contact));
  862. ast_str_append(&buf, 0, "AOR: %s\r\n", wrapper->aor_id);
  863. ast_str_append(&buf, 0, "URI: %s\r\n", contact->uri);
  864. if (status) {
  865. ast_str_append(&buf, 0, "Status: %s\r\n", status_map[status->status]);
  866. ast_str_append(&buf, 0, "RoundtripUsec: %" PRId64 "\r\n", status->rtt);
  867. } else {
  868. ast_str_append(&buf, 0, "Status: Unknown\r\n");
  869. ast_str_append(&buf, 0, "RoundtripUsec: N/A\r\n");
  870. }
  871. ast_str_append(&buf, 0, "EndpointName: %s\r\n",
  872. ast_sorcery_object_get_id(endpoint));
  873. astman_append(ami->s, "%s\r\n", ast_str_buffer(buf));
  874. ami->count++;
  875. ast_free(buf);
  876. ao2_cleanup(status);
  877. return 0;
  878. }
  879. static int format_contact_status_for_aor(void *obj, void *arg, int flags)
  880. {
  881. struct ast_sip_aor *aor = obj;
  882. return ast_sip_for_each_contact(aor, format_contact_status, arg);
  883. }
  884. static int format_ami_contact_status(const struct ast_sip_endpoint *endpoint,
  885. struct ast_sip_ami *ami)
  886. {
  887. ami->arg = (void *)endpoint;
  888. return ast_sip_for_each_aor(endpoint->aors, format_contact_status_for_aor, ami);
  889. }
  890. static struct ast_sip_endpoint_formatter contact_status_formatter = {
  891. .format_ami = format_ami_contact_status
  892. };
  893. int ast_res_pjsip_init_options_handling(int reload)
  894. {
  895. static const pj_str_t STR_OPTIONS = { "OPTIONS", 7 };
  896. if (reload) {
  897. qualify_and_schedule_all();
  898. return 0;
  899. }
  900. sched_qualifies = ao2_t_container_alloc(QUALIFIED_BUCKETS,
  901. sched_qualifies_hash_fn, sched_qualifies_cmp_fn,
  902. "Create container for scheduled qualifies");
  903. if (!sched_qualifies) {
  904. return -1;
  905. }
  906. if (pjsip_endpt_register_module(ast_sip_get_pjsip_endpoint(), &options_module) != PJ_SUCCESS) {
  907. ao2_cleanup(sched_qualifies);
  908. sched_qualifies = NULL;
  909. return -1;
  910. }
  911. if (pjsip_endpt_add_capability(ast_sip_get_pjsip_endpoint(), NULL, PJSIP_H_ALLOW,
  912. NULL, 1, &STR_OPTIONS) != PJ_SUCCESS) {
  913. pjsip_endpt_unregister_module(ast_sip_get_pjsip_endpoint(), &options_module);
  914. ao2_cleanup(sched_qualifies);
  915. sched_qualifies = NULL;
  916. return -1;
  917. }
  918. ast_sip_register_endpoint_formatter(&contact_status_formatter);
  919. ast_manager_register2("PJSIPQualify", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, ami_sip_qualify, NULL, NULL, NULL);
  920. ast_cli_register_multiple(cli_options, ARRAY_LEN(cli_options));
  921. qualify_and_schedule_all();
  922. return 0;
  923. }
  924. void ast_res_pjsip_cleanup_options_handling(void)
  925. {
  926. ast_cli_unregister_multiple(cli_options, ARRAY_LEN(cli_options));
  927. ast_manager_unregister("PJSIPQualify");
  928. ast_sip_unregister_endpoint_formatter(&contact_status_formatter);
  929. pjsip_endpt_unregister_module(ast_sip_get_pjsip_endpoint(), &options_module);
  930. ao2_cleanup(sched_qualifies);
  931. sched_qualifies = NULL;
  932. }