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