pjsip_options.c 29 KB

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