Asterisk - The Open Source Telephony Project GIT-master-70eff7f
Loading...
Searching...
No Matches
pjsip_options.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 2018, Digium, Inc.
5 *
6 * Joshua Colp <jcolp@digium.com>
7 * Richard Mudgett <rmudgett@digium.com>
8 *
9 * See http://www.asterisk.org for more information about
10 * the Asterisk project. Please do not directly contact
11 * any of the maintainers of this project for assistance;
12 * the project provides a web site, mailing lists and IRC
13 * channels for your use.
14 *
15 * This program is free software, distributed under the terms of
16 * the GNU General Public License Version 2. See the LICENSE file
17 * at the top of the source tree.
18 */
19
20#include "asterisk.h"
21
22#include <pjsip.h>
23#include <pjsip_ua.h>
24#include <pjlib.h>
25
26#include "asterisk/res_pjsip.h"
27#include "asterisk/channel.h"
28#include "asterisk/pbx.h"
29#include "asterisk/astobj2.h"
30#include "asterisk/cli.h"
31#include "asterisk/time.h"
32#include "asterisk/test.h"
33#include "asterisk/statsd.h"
36
37/*
38 * This implementation for OPTIONS support is based around the idea
39 * that realistically an AOR generally has very few contacts and is
40 * referenced by only a few endpoints. While it is perfectly fine for
41 * use in opposite scenarios it works best in the above case. It is
42 * also not shy to keeping state but it is reactive to outside changes
43 * so it can be updated.
44 *
45 * The lowest level object in here is a contact and its associated
46 * contact status. The result of an OPTIONS request to a contact is
47 * reflected in the contact status. The scheduling of these OPTIONS
48 * request is driven by the AOR. The AOR periodicially (according to
49 * configuration) sends OPTIONS requests out to any contacts
50 * associated with it. Contacts themselves are not individually
51 * scheduled. Contacts can be added or deleted as appropriate with no
52 * requirement to reschedule.
53 *
54 * The next level object up is the AOR itself. The result of a contact
55 * status change is fed into it and the result composited with all
56 * other contacts. This may result in the AOR itself changing state
57 * (it can be either AVAILABLE or UNAVAILABLE).
58 *
59 * The highest level object up is the endpoint state compositor (ESC).
60 * The result of AOR state changes is fed into it and the result
61 * composited with all other referenced AORs. This may result in the
62 * endpoint itself changing state (it can be either ONLINE or
63 * OFFLINE). If this occurs the permanent endpoint is updated to
64 * reflect it.
65 *
66 * The threading model errs on the side of a world where things are
67 * not constantly changing. That is: A world where AORs and endpoints
68 * are not being constantly added/removed. This more closely mirrors
69 * the usage of the vast majority of people. This scenario can still
70 * be done but it may not be applied immediately.
71 *
72 * Manipulation of which AORs, endpoint state compositors, and
73 * contacts exist is done within a single serializer. This ensures
74 * that no matter the source threads order is preserved and you won't
75 * get into a weird situation where things are referencing other
76 * things that should have already been destroyed.
77 *
78 * Operations which impact the state of an AOR are done within a
79 * serializer that is specific to the AOR. This includes the result of
80 * a contact status change. This change is queued and executed on the
81 * AOR serializer afterwards.
82 *
83 * Operations which impact an endpoint state compositor are protected
84 * by a lock. This is done as the endpoint state compositor usage is
85 * minimal and the overhead of using a serializer and queueing things
86 * is not warranted.
87 *
88 * AORs which do not have a qualify frequency are also kept in here
89 * but do not require the same criteria as qualified AORs to be
90 * considered available. In their case as long as at least 1 contact
91 * is configured on the AOR (or added to it by registration) it is
92 * considered available.
93 */
94
95#define DEFAULT_LANGUAGE "en"
96#define DEFAULT_ENCODING "identity"
97
98/*! \brief These are the number of buckets to store AORs in */
99#ifdef LOW_MEMORY
100#define AOR_BUCKETS 61
101#else
102#define AOR_BUCKETS 1567
103#endif
104
105/*! \brief These are the number of contact status buckets */
106#ifdef LOW_MEMORY
107#define CONTACT_STATUS_BUCKETS 61
108#else
109#define CONTACT_STATUS_BUCKETS 1567
110#endif
111
112/*! \brief These are the number of buckets (per AOR) to use to store contacts */
113#define CONTACT_BUCKETS 13
114
115/*! \brief These are the number of buckets to store endpoint state compositors */
116#define ENDPOINT_STATE_COMPOSITOR_BUCKETS 13
117
118/*! \brief The initial vector size for the endpoint state compositors on an AOR */
119#define ENDPOINT_STATE_COMPOSITOR_INITIAL_SIZE 1
120
121/*! \brief These are the number of buckets (per endpoint state compositor) to use to store AOR statuses */
122#define AOR_STATUS_BUCKETS 3
123
124/*! \brief Maximum wait time to join the below shutdown group */
125#define MAX_UNLOAD_TIMEOUT_TIME 10 /* Seconds */
126
127/*!
128 * \brief Structure which contains status information for an AOR feeding an endpoint state compositor
129 */
131 /*! \brief The last contributed available status of the named AOR (1 if available, 0 if not available) */
133 /*! \brief The name of the AOR */
134 char name[0];
135};
136
137/*!
138 * \brief Structure which contains composites information for endpoint state
139 */
141 /*! \brief The last contributed available status of the AORs feeding this compositor */
143 /*!
144 * \brief Non-zero if the compositor is in normal operation. i.e. Not being setup/reconfigured.
145 *
146 * \details
147 * The aor layer can only update its aor_statuses record when not active.
148 * When active the aor layer can update its aor_statuses record, calculate the new
149 * number of available aors, determine if the endpoint compositor changed state,
150 * and report it.
151 */
152 char active;
153 /*! \brief The name of the endpoint */
154 char name[0];
155};
156
157/*!
158 * \brief Structure which contains an AOR and contacts for qualifying purposes
159 */
161 /*! \brief The scheduler task for this AOR */
163 /*! \brief The serializer for this AOR */
165 /*! \brief All contacts associated with this AOR */
167 /*!
168 * \brief Only dynamic contacts associated with this AOR
169 * \note Used to speed up applying AOR configuration by
170 * minimizing wild card sorcery access.
171 */
173 /*! \brief The endpoint state compositors we are feeding, a reference is held to each */
175 /*! \brief The number of available contacts on this AOR */
176 unsigned int available;
177 /*! \brief Frequency to send OPTIONS requests to AOR contacts. 0 is disabled. */
178 unsigned int qualify_frequency;
179 /*! \brief If true only authenticate if OPTIONS response is 2XX */
181 /*! If true authenticate the qualify challenge response if needed */
183 /*! \brief Qualify timeout. 0 is diabled. */
185 /*! \brief The name of the AOR */
186 char name[0];
187};
188
189/*!
190 * \internal
191 * \brief Container of active SIP AORs for qualifying
192 */
194
195/*!
196 * \internal
197 * \brief Container of contact statuses
198 */
200
201/*!
202 * \internal
203 * \brief Container of endpoint state compositors
204 */
206
207/*!
208 * \internal
209 * \brief Serializer for AOR, endpoint state compositor, and contact existence management
210 */
212
213static pj_status_t send_options_response(pjsip_rx_data *rdata, int code)
214{
215 pjsip_endpoint *endpt = ast_sip_get_pjsip_endpoint();
216 pjsip_dialog *dlg = pjsip_rdata_get_dlg(rdata);
217 pjsip_transaction *trans = pjsip_rdata_get_tsx(rdata);
218 pjsip_tx_data *tdata;
219 const pjsip_hdr *hdr;
220 pj_status_t status;
221
222 /* Make the response object */
223 status = ast_sip_create_response(rdata, code, NULL, &tdata);
224 if (status != PJ_SUCCESS) {
225 ast_log(LOG_ERROR, "Unable to create response (%d)\n", status);
226 return status;
227 }
228
229 /* Add appropriate headers */
230 if ((hdr = pjsip_endpt_get_capability(endpt, PJSIP_H_ACCEPT, NULL))) {
231 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)pjsip_hdr_clone(tdata->pool, hdr));
232 }
233 if ((hdr = pjsip_endpt_get_capability(endpt, PJSIP_H_ALLOW, NULL))) {
234 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)pjsip_hdr_clone(tdata->pool, hdr));
235 }
236 if ((hdr = pjsip_endpt_get_capability(endpt, PJSIP_H_SUPPORTED, NULL))) {
237 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)pjsip_hdr_clone(tdata->pool, hdr));
238 }
239
240 /*
241 * XXX TODO: pjsip doesn't care a lot about either of these headers -
242 * while it provides specific methods to create them, they are defined
243 * to be the standard string header creation. Hard coded here.
244 */
245 ast_sip_add_header(tdata, "Accept-Encoding", DEFAULT_ENCODING);
246 ast_sip_add_header(tdata, "Accept-Language", DEFAULT_LANGUAGE);
247
248 if (dlg && trans) {
249 status = pjsip_dlg_send_response(dlg, trans, tdata);
250 } else {
251 struct ast_sip_endpoint *endpoint;
252
253 endpoint = ast_pjsip_rdata_get_endpoint(rdata);
254 status = ast_sip_send_stateful_response(rdata, tdata, endpoint);
255 ao2_cleanup(endpoint);
256 }
257
258 if (status != PJ_SUCCESS) {
259 ast_log(LOG_ERROR, "Unable to send response (%d)\n", status);
260 }
261
262 return status;
263}
264
265static pj_bool_t options_on_rx_request(pjsip_rx_data *rdata)
266{
267 RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
268 pjsip_uri *ruri;
269 char exten[AST_MAX_EXTENSION];
270
271 if (pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_options_method)) {
272 return PJ_FALSE;
273 }
274
275 if (!(endpoint = ast_pjsip_rdata_get_endpoint(rdata))) {
276 return PJ_FALSE;
277 }
278
279 ruri = rdata->msg_info.msg->line.req.uri;
280 if (!ast_sip_is_allowed_uri(ruri)) {
281 send_options_response(rdata, 416);
282 return PJ_TRUE;
283 }
284
285 ast_copy_pj_str(exten, ast_sip_pjsip_uri_get_username(ruri), sizeof(exten));
286
287 /*
288 * We may want to match in the dialplan without any user
289 * options getting in the way.
290 */
292
293 if (ast_shutting_down()) {
294 /*
295 * Not taking any new calls at this time.
296 * Likely a server availability OPTIONS poll.
297 */
298 send_options_response(rdata, 503);
299 } else if (!ast_strlen_zero(exten)
300 && !ast_exists_extension(NULL, endpoint->context, exten, 1, NULL)) {
301 send_options_response(rdata, 404);
302 } else {
303 send_options_response(rdata, 200);
304 }
305 return PJ_TRUE;
306}
307
308static pjsip_module options_module = {
309 .name = {"Options Module", 14},
310 .id = -1,
311 .priority = PJSIP_MOD_PRIORITY_APPLICATION,
312 .on_rx_request = options_on_rx_request,
313};
314
315static const char *status_map[] = {
316 [UNAVAILABLE] = "Unreachable",
317 [AVAILABLE] = "Reachable",
318 [UNKNOWN] = "Unknown",
319 [CREATED] = "NonQualified",
320 [REMOVED] = "Removed",
321};
322
323static const char *short_status_map[] = {
324 [UNAVAILABLE] = "Unavail",
325 [AVAILABLE] = "Avail",
326 [UNKNOWN] = "Unknown",
327 [CREATED] = "NonQual",
328 [REMOVED] = "Removed",
329};
330
336
342
343/*! \brief Destructor for contact statuses */
344static void sip_contact_status_dtor(void *obj)
345{
346 struct ast_sip_contact_status *contact_status = obj;
347
349
350 ast_string_field_free_memory(contact_status);
351}
352
354{
355 struct ast_sip_contact_status *contact_status;
356 size_t size = sizeof(*contact_status) + strlen(name) + 1;
357
358 contact_status = ao2_alloc_options(size, sip_contact_status_dtor,
360 if (!contact_status) {
361 return NULL;
362 }
363 if (ast_string_field_init(contact_status, 256)) {
364 ao2_ref(contact_status, -1);
365 return NULL;
366 }
367 AST_VECTOR_INIT(&contact_status->security_mechanisms, 0);
368 strcpy(contact_status->name, name); /* SAFE */
369 return contact_status;
370}
371
373{
374 struct ast_sip_contact_status *dst;
375
376 dst = sip_contact_status_alloc(src->name);
377 if (!dst) {
378 return NULL;
379 }
380
381 if (ast_string_fields_copy(dst, src)) {
382 ao2_ref(dst, -1);
383 return NULL;
384 }
385 dst->rtt = src->rtt;
386 dst->status = src->status;
387 dst->last_status = src->last_status;
388
390 return dst;
391}
392
393/*! \brief Hashing function for contact statuses */
395
396/*! \brief Sort function for contact statuses */
398
399/*! \brief Comparator function for contact statuses */
401
402/*! \brief Helper function to allocate a contact statuses container */
404{
405 /*
406 * Replace duplicate objects so we can update the immutable
407 * contact status objects by simply linking in a new object.
408 */
411 ast_sip_contact_status_hash_fn, ast_sip_contact_status_sort_fn,
412 ast_sip_contact_status_cmp_fn);
413}
414
415/*! \brief Function which publishes a contact status update to all interested endpoints */
416static void sip_options_publish_contact_state(const struct sip_options_aor *aor_options,
417 const struct ast_sip_contact_status *contact_status)
418{
419 int i;
420
421 for (i = 0; i < AST_VECTOR_SIZE(&aor_options->compositors); ++i) {
422 const struct sip_options_endpoint_state_compositor *endpoint_state_compositor;
423
424 endpoint_state_compositor = AST_VECTOR_GET(&aor_options->compositors, i);
426 contact_status);
427 }
428}
429
430/*!
431 * \brief Task to notify endpoints of a contact status change
432 * \note Run by management_serializer
433 */
435{
436 struct ast_sip_contact_status *contact_status = obj;
437 struct sip_options_aor *aor_options;
438
439 aor_options = ao2_find(sip_options_aors, contact_status->aor, OBJ_SEARCH_KEY);
440 if (aor_options) {
441 sip_options_publish_contact_state(aor_options, contact_status);
442 ao2_ref(aor_options, -1);
443 }
444 ao2_ref(contact_status, -1);
445
446 return 0;
447}
448
450{
451 struct ast_taskprocessor *mgmt_serializer = management_serializer;
452
453 if (mgmt_serializer) {
454 ao2_ref(contact_status, +1);
456 contact_status)) {
457 ao2_ref(contact_status, -1);
458 }
459 }
460}
461
463{
464 struct ast_sip_contact_status *contact_status;
465 int res;
466
467 /*
468 * At startup a contact status can be retrieved when static contacts
469 * are themselves being setup. This happens before we are fully setup.
470 * Since we don't actually trigger qualify or anything as a result it
471 * is safe to do so. They'll just get back a contact status that will
472 * be updated later. At this time they only care that the contact
473 * status gets created for the static contact anyway.
474 */
476 /*
477 * We haven't been pre-initialized or we are shutting down.
478 * Neither situation should happen.
479 */
480 ast_assert(0);
481 return NULL;
482 }
483
485
486 /* If contact status for this contact already exists just return it */
487 contact_status = ao2_find(sip_options_contact_statuses,
489 if (contact_status) {
491 return contact_status;
492 }
493
494 /* Otherwise we have to create and store a new contact status */
495 contact_status = sip_contact_status_alloc(ast_sorcery_object_get_id(contact));
496 if (!contact_status) {
498 return NULL;
499 }
500
501 contact_status->rtt = 0;
502 contact_status->status = CREATED;
503 contact_status->last_status = CREATED;
504 res = ast_string_field_set(contact_status, uri, contact->uri);
505 res |= ast_string_field_set(contact_status, aor, contact->aor);
506 if (res) {
508 ao2_ref(contact_status, -1);
509 return NULL;
510 }
511
514
515 ast_statsd_log_string_va("PJSIP.contacts.states.%s", AST_STATSD_GAUGE,
516 "+1", 1.0, ast_sip_get_contact_status_label(contact_status->status));
517
518 sip_options_contact_status_update(contact_status);
519
520 return contact_status;
521}
522
528
529/*! \brief Hashing function for OPTIONS AORs */
531
532/*! \brief Comparator function for SIP OPTIONS AORs */
534
535/*! \brief Hashing function for endpoint state compositors */
537
538/*! \brief Comparator function for endpoint state compositors */
540
541/*! \brief Structure used to contain information for an OPTIONS callback */
543 /*! \brief The contact we qualified */
545 /*! \brief The AOR options */
547 /*! \brief The time at which this OPTIONS attempt was started */
548 struct timeval rtt_start;
549 /*! \brief The new status of the contact */
551};
552
553/*!
554 * \brief Return the current state of an endpoint state compositor
555 * \pre The endpoint_state_compositor lock must be held.
556 */
558 const struct sip_options_endpoint_state_compositor *endpoint_state_compositor)
559{
560 struct ao2_iterator it_aor_statuses;
561 struct sip_options_endpoint_aor_status *aor_status;
563
564 it_aor_statuses = ao2_iterator_init(endpoint_state_compositor->aor_statuses, 0);
565 for (; (aor_status = ao2_iterator_next(&it_aor_statuses)); ao2_ref(aor_status, -1)) {
566 if (aor_status->available) {
568 ao2_ref(aor_status, -1);
569 break;
570 }
571 }
572 ao2_iterator_destroy(&it_aor_statuses);
573
574 return state;
575}
576
577/*!
578 * \brief Update the AOR status on an endpoint state compositor
579 * \pre The endpoint_state_compositor lock must be held.
580 */
582 const char *name, enum ast_sip_contact_status_type status)
583{
584 struct sip_options_endpoint_aor_status *aor_status;
585 enum ast_endpoint_state endpoint_state;
586
587 aor_status = ao2_find(endpoint_state_compositor->aor_statuses, name,
589 if (!aor_status) {
590 /* The AOR status doesn't exist already so we don't need to go any further */
591 if (status == REMOVED) {
592 return;
593 }
594
595 aor_status = ao2_alloc_options(sizeof(*aor_status) + strlen(name) + 1, NULL,
597 if (!aor_status) {
598 return;
599 }
600
601 strcpy(aor_status->name, name); /* SAFE */
602 ao2_link(endpoint_state_compositor->aor_statuses, aor_status);
603 }
604
605 if (status == REMOVED) {
606 /*
607 * If the AOR is being removed then remove its AOR status
608 * from the endpoint compositor.
609 */
610 ao2_unlink(endpoint_state_compositor->aor_statuses, aor_status);
611 } else {
612 aor_status->available = (status == AVAILABLE ? 1 : 0);
613 }
614 ao2_ref(aor_status, -1);
615
616 if (!endpoint_state_compositor->active) {
617 return;
618 }
619
620 /* If this AOR is available then the endpoint itself has to be online */
621 if (status == AVAILABLE) {
622 ast_debug(3, "Endpoint state compositor '%s' is online as AOR '%s' is available\n",
623 endpoint_state_compositor->name, name);
624 endpoint_state = AST_ENDPOINT_ONLINE;
625 } else {
626 endpoint_state =
627 sip_options_get_endpoint_state_compositor_state(endpoint_state_compositor);
628 }
629
630 ast_sip_persistent_endpoint_update_state(endpoint_state_compositor->name,
631 endpoint_state);
632}
633
634/*! \brief Function which notifies endpoint state compositors of a state change of an AOR */
637{
638 int i;
639
640 /* Iterate through the associated endpoint state compositors updating them */
641 for (i = 0; i < AST_VECTOR_SIZE(&aor_options->compositors); ++i) {
642 struct sip_options_endpoint_state_compositor *endpoint_state_compositor;
643
644 endpoint_state_compositor = AST_VECTOR_GET(&aor_options->compositors, i);
645
646 ao2_lock(endpoint_state_compositor);
647 sip_options_update_endpoint_state_compositor_aor(endpoint_state_compositor,
648 aor_options->name, status);
649 ao2_unlock(endpoint_state_compositor);
650 }
651
652 if (status == REMOVED) {
654 }
655}
656
657/*!
658 * \brief Task to notify an AOR of a contact status change
659 * \note Run by aor_options->serializer
660 */
662{
663 struct sip_options_contact_callback_data *contact_callback_data = obj;
664 struct ast_sip_contact *contact;
665 struct ast_sip_contact_status *cs_old;
666 struct ast_sip_contact_status *cs_new;
667
668 /*
669 * Determine if this is a late arriving notification, as it is
670 * possible that we get a callback from PJSIP giving us contact
671 * status but in the mean time said contact has been removed
672 * from the controlling AOR.
673 */
674
675 if (!contact_callback_data->aor_options->qualify_frequency) {
676 /* Contact qualify response is late */
677 ao2_ref(contact_callback_data, -1);
678 return 0;
679 }
680
681 contact = ao2_find(contact_callback_data->aor_options->contacts,
682 contact_callback_data->contact, OBJ_SEARCH_OBJECT);
683 if (!contact) {
684 /* Contact qualify response is late */
685 ao2_ref(contact_callback_data, -1);
686 return 0;
687 }
688 ao2_ref(contact, -1);
689
691 ast_sorcery_object_get_id(contact_callback_data->contact), OBJ_SEARCH_KEY);
692 if (!cs_old) {
693 /* Contact qualify response is late */
694 ao2_ref(contact_callback_data, -1);
695 return 0;
696 }
697
698 /* Update the contact specific status information */
699 cs_new = sip_contact_status_copy(cs_old);
700 ao2_ref(cs_old, -1);
701 if (!cs_new) {
702 ao2_ref(contact_callback_data, -1);
703 return 0;
704 }
705 cs_new->last_status = cs_new->status;
706 cs_new->status = contact_callback_data->status;
707 cs_new->rtt =
708 cs_new->status == AVAILABLE
709 ? ast_tvdiff_us(ast_tvnow(), contact_callback_data->rtt_start)
710 : 0;
712
713 /*
714 * If the status has changed then notify the endpoint state compositors
715 * and publish our events.
716 */
717 if (cs_new->last_status != cs_new->status) {
718 if (cs_new->status == AVAILABLE) {
719 /* If this is the first available contact then the AOR has become available */
720 ++contact_callback_data->aor_options->available;
721 if (contact_callback_data->aor_options->available == 1) {
723 contact_callback_data->aor_options, AVAILABLE);
724 }
725 } else if (cs_new->last_status == AVAILABLE) {
726 ast_assert(cs_new->status == UNAVAILABLE);
727
728 /* If there are no more available contacts then this AOR is unavailable */
729 --contact_callback_data->aor_options->available;
730 if (!contact_callback_data->aor_options->available) {
732 contact_callback_data->aor_options, UNAVAILABLE);
733 }
734 }
735
736 ast_verb(3, "Contact %s/%s is now %s. RTT: %.3f msec\n",
737 cs_new->aor,
738 cs_new->uri,
740 cs_new->rtt / 1000.0);
741
742 ast_statsd_log_string_va("PJSIP.contacts.states.%s", AST_STATSD_GAUGE,
744 ast_statsd_log_string_va("PJSIP.contacts.states.%s", AST_STATSD_GAUGE,
745 "+1", 1.0, ast_sip_get_contact_status_label(cs_new->status));
746
748
749 ast_test_suite_event_notify("AOR_CONTACT_UPDATE",
750 "Contact: %s\r\n"
751 "Status: %s",
752 cs_new->name,
754 } else {
755 ast_debug(3, "Contact %s/%s status didn't change: %s, RTT: %.3f msec\n",
756 cs_new->aor,
757 cs_new->uri,
759 cs_new->rtt / 1000.0);
760 }
761
762 ast_statsd_log_full_va("PJSIP.contacts.%s.rtt", AST_STATSD_TIMER,
763 cs_new->status != AVAILABLE ? -1 : cs_new->rtt / 1000,
764 1.0,
765 cs_new->name);
766
767 ast_test_suite_event_notify("AOR_CONTACT_QUALIFY_RESULT",
768 "Contact: %s\r\n"
769 "Status: %s\r\n"
770 "RTT: %" PRId64,
771 cs_new->name,
773 cs_new->rtt);
774
775 ast_debug(3, "AOR '%s' now has %d available contacts\n",
776 contact_callback_data->aor_options->name,
777 contact_callback_data->aor_options->available);
778
779 ao2_ref(cs_new, -1);
780 ao2_ref(contact_callback_data, -1);
781
782 return 0;
783}
784
785/*! \brief Callback for when we get a result from a SIP OPTIONS request (a response or a timeout) */
786static void qualify_contact_cb(void *token, pjsip_event *e)
787{
788 struct sip_options_contact_callback_data *contact_callback_data = token;
790
791 switch(e->body.tsx_state.type) {
792 default:
793 ast_log(LOG_ERROR, "Unexpected PJSIP event %u\n", e->body.tsx_state.type);
794 /* Fall through */
795 case PJSIP_EVENT_TRANSPORT_ERROR:
796 case PJSIP_EVENT_TIMER:
798 break;
799 case PJSIP_EVENT_RX_MSG:
800 if (contact_callback_data->aor_options->qualify_2xx_only &&
801 (e->body.tsx_state.tsx->status_code < 200 || e->body.tsx_state.tsx->status_code >= 300)) {
803 } else {
805 }
806 break;
807 }
808
809 /* Update the callback data with the new status, this will get handled in the AOR serializer */
810 contact_callback_data->status = status;
811
812 if (ast_sip_push_task(contact_callback_data->aor_options->serializer,
813 sip_options_contact_status_notify_task, contact_callback_data)) {
814 ast_log(LOG_WARNING, "Unable to queue contact status update for '%s' on AOR '%s', state will be incorrect\n",
815 ast_sorcery_object_get_id(contact_callback_data->contact),
816 contact_callback_data->aor_options->name);
817 ao2_ref(contact_callback_data, -1);
818 }
819
820 /* The task inherited our reference so we don't unreference here */
821}
822
823/*! \brief Destructor for contact callback data */
825{
826 struct sip_options_contact_callback_data *contact_callback_data = obj;
827
828 ao2_cleanup(contact_callback_data->contact);
829 ao2_cleanup(contact_callback_data->aor_options);
830}
831
832/*! \brief Contact callback data allocator */
835{
836 struct sip_options_contact_callback_data *contact_callback_data;
837
838 contact_callback_data = ao2_alloc_options(sizeof(*contact_callback_data),
840 if (!contact_callback_data) {
841 return NULL;
842 }
843
844 contact_callback_data->contact = ao2_bump(contact);
845 contact_callback_data->aor_options = ao2_bump(aor_options);
846 contact_callback_data->rtt_start = ast_tvnow();
847
848 return contact_callback_data;
849}
850
851/*! \brief Send a SIP OPTIONS request for a contact */
852static int sip_options_qualify_contact(void *obj, void *arg, int flags)
853{
854 struct ast_sip_contact *contact = obj;
855 struct sip_options_aor *aor_options = arg;
856 RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
857 pjsip_tx_data *tdata;
858 struct ast_sip_contact_status *contact_status;
859 struct sip_options_contact_callback_data *contact_callback_data;
860
861 ast_debug(3, "Qualifying contact '%s' on AOR '%s'\n",
863
865 endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint",
867 }
868 if (!endpoint && AST_VECTOR_SIZE(&aor_options->compositors)) {
869 struct sip_options_endpoint_state_compositor *endpoint_state_compositor;
870
871 endpoint_state_compositor = AST_VECTOR_GET(&aor_options->compositors, 0);
872 endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint",
873 endpoint_state_compositor->name);
874 }
875 if (!endpoint) {
876 ast_debug(3, "Could not find an endpoint to qualify contact '%s' on AOR '%s'\n",
877 ast_sorcery_object_get_id(contact), aor_options->name);
878 return 0;
879 }
880
881 if (ast_sip_create_request("OPTIONS", NULL, endpoint, NULL, contact, &tdata)) {
882 ast_log(LOG_ERROR, "Unable to create request to qualify contact %s on AOR %s\n",
883 contact->uri, aor_options->name);
884 return 0;
885 }
886
887 /* If an outbound proxy is specified set it on this request */
888 if (!ast_strlen_zero(contact->outbound_proxy) &&
890 ast_log(LOG_ERROR, "Unable to apply outbound proxy on request to qualify contact %s\n",
891 contact->uri);
892 pjsip_tx_data_dec_ref(tdata);
893 return 0;
894 }
895
896 contact_status = ast_res_pjsip_find_or_create_contact_status(contact);
897 if (!contact_status) {
898 ast_log(LOG_ERROR, "Unable to retrieve contact status information for contact %s on AOR %s\n",
899 contact->uri, aor_options->name);
900 pjsip_tx_data_dec_ref(tdata);
901 return 0;
902 }
903 ao2_ref(contact_status, -1);
904
905 contact_callback_data = sip_options_contact_callback_data_alloc(contact, aor_options);
906 if (!contact_callback_data) {
907 ast_log(LOG_ERROR, "Unable to create object to contain callback data for contact %s on AOR %s\n",
908 contact->uri, aor_options->name);
909 pjsip_tx_data_dec_ref(tdata);
910 return 0;
911 }
912
913 if (ast_sip_send_out_of_dialog_request(tdata, endpoint,
914 (int)(aor_options->qualify_timeout * 1000), contact_callback_data,
916 ast_log(LOG_ERROR, "Unable to send request to qualify contact %s on AOR %s\n",
917 contact->uri, aor_options->name);
918 ao2_ref(contact_callback_data, -1);
919 }
920
921 return 0;
922}
923
924/*!
925 * \brief Task to qualify contacts of an AOR
926 * \note Run by aor_options->serializer
927 */
928static int sip_options_qualify_aor(void *obj)
929{
930 struct sip_options_aor *aor_options = obj;
931
932 ast_debug(3, "Qualifying all contacts on AOR '%s'\n", aor_options->name);
933
934 /* Attempt to send an OPTIONS request to every contact on this AOR */
936 (struct sip_options_aor *) aor_options);
937
938 /* Always reschedule to the frequency we should go */
939 return aor_options->qualify_frequency * 1000;
940}
941
942/*! \brief Forward declaration of this helpful function */
943static int sip_options_remove_contact(void *obj, void *arg, int flags);
944
945/*! \brief Destructor function for SIP OPTIONS AORs */
946static void sip_options_aor_dtor(void *obj)
947{
948 struct sip_options_aor *aor_options = obj;
949
950 /*
951 * Any contacts are unreachable since the AOR is being destroyed
952 * so remove their contact status
953 */
954 if (aor_options->contacts) {
956 sip_options_remove_contact, aor_options);
957 ao2_ref(aor_options->contacts, -1);
958 }
959 ao2_cleanup(aor_options->dynamic_contacts);
960
962
963 ast_assert(AST_VECTOR_SIZE(&aor_options->compositors) == 0);
964 AST_VECTOR_FREE(&aor_options->compositors);
965}
966
967/*! \brief Allocator for AOR OPTIONS */
969{
970 struct sip_options_aor *aor_options;
971
972 aor_options = ao2_alloc_options(sizeof(*aor_options) + strlen(ast_sorcery_object_get_id(aor)) + 1,
974 if (!aor_options) {
975 return NULL;
976 }
977
978 strcpy(aor_options->name, ast_sorcery_object_get_id(aor)); /* SAFE */
979
981 if (!aor_options->serializer) {
982 ao2_ref(aor_options, -1);
983 return NULL;
984 }
985
987 ao2_ref(aor_options, -1);
988 return NULL;
989 }
990
994 if (!aor_options->contacts) {
995 ao2_ref(aor_options, -1);
996 return NULL;
997 }
998
1002 if (!aor_options->dynamic_contacts) {
1003 ao2_ref(aor_options, -1);
1004 return NULL;
1005 }
1006
1007 return aor_options;
1008}
1009
1010/*! \brief Remove contact status for a hint */
1012 struct ast_sip_contact *contact)
1013{
1014 struct ast_sip_contact_status *cs_new;
1015 struct ast_sip_contact_status *cs_old;
1016
1019 if (!cs_old) {
1020 ast_debug(3, "Attempted to remove contact status for '%s' but it does not exist\n",
1021 ast_sorcery_object_get_id(contact));
1022 return;
1023 }
1024
1025 ast_verb(2, "Contact %s/%s has been deleted\n", contact->aor, contact->uri);
1026
1027 /* Update the contact status to reflect its new state */
1028 cs_new = sip_contact_status_copy(cs_old);
1029 if (!cs_new) {
1030 /*
1031 * We'll have to violate the immutable property because we
1032 * couldn't create a new one to modify and we are deleting
1033 * the contact status anyway.
1034 */
1035 cs_new = cs_old;
1036 } else {
1037 ao2_ref(cs_old, -1);
1038 }
1039 cs_new->last_status = cs_new->status;
1040 cs_new->status = REMOVED;
1041 cs_new->rtt = 0;
1042
1043 ast_statsd_log_string_va("PJSIP.contacts.states.%s", AST_STATSD_GAUGE,
1044 "-1", 1.0, ast_sip_get_contact_status_label(cs_new->last_status));
1045 ast_statsd_log_string_va("PJSIP.contacts.states.%s", AST_STATSD_GAUGE,
1046 "+1", 1.0, ast_sip_get_contact_status_label(cs_new->status));
1047
1049
1050 /*
1051 * The only time we need to update the AOR is if this contact was
1052 * available and qualify is in use, otherwise we can just stop
1053 * early.
1054 */
1055 if (!aor_options->qualify_frequency || cs_new->last_status != AVAILABLE) {
1056 ao2_ref(cs_new, -1);
1057 return;
1058 }
1059
1060 --aor_options->available;
1061 if (!aor_options->available) {
1063 }
1064
1065 ast_debug(3, "AOR '%s' now has %d available contacts\n", aor_options->name,
1066 aor_options->available);
1067
1068 ao2_ref(cs_new, -1);
1069}
1070
1071/*! \brief Task data for AOR creation or updating */
1073 /*! \brief The AOR options for this AOR */
1075 /*! \brief The AOR which contains the new configuraton */
1077 /*! \brief Optional container of existing AOR s*/
1079 /*! \brief Whether this AOR is being added */
1081};
1082
1083/*! \brief Callback function to remove a contact and its contact status from an AOR */
1084static int sip_options_remove_contact(void *obj, void *arg, int flags)
1085{
1086 struct ast_sip_contact *contact = obj;
1087 struct sip_options_aor *aor_options = arg;
1088
1089 sip_options_remove_contact_status(aor_options, contact);
1090
1091 return CMP_MATCH;
1092}
1093
1094/*! \brief Determine an initial time for scheduling AOR qualifying */
1096{
1097 int initial_interval;
1098 int max_time = ast_sip_get_max_initial_qualify_time();
1099
1100 if (max_time && max_time < qualify_frequency) {
1101 initial_interval = max_time;
1102 } else {
1103 initial_interval = qualify_frequency;
1104 }
1105
1106 initial_interval = (int)((initial_interval * 1000) * ast_random_double());
1107 return 0 < initial_interval ? initial_interval : 1;
1108}
1109
1110/*! \brief Set the contact status for a contact */
1113{
1114 struct ast_sip_contact_status *cs_new;
1115
1116 /* Update the contact specific status information */
1117 cs_new = sip_contact_status_copy(contact_status);
1118 if (!cs_new) {
1119 return;
1120 }
1121 cs_new->last_status = cs_new->status;
1122 cs_new->status = status;
1123
1124 /*
1125 * We need to always set the RTT to zero because we haven't completed
1126 * an OPTIONS ping so RTT is unknown. If the OPTIONS ping were still
1127 * running it will be refreshed on the next go round anyway.
1128 */
1129 cs_new->rtt = 0;
1130
1132
1133 if (cs_new->status != cs_new->last_status) {
1134 ast_verb(3, "Contact %s/%s is now %s.\n",
1135 cs_new->aor, cs_new->uri,
1137
1138 ast_statsd_log_string_va("PJSIP.contacts.states.%s", AST_STATSD_GAUGE,
1139 "-1", 1.0, ast_sip_get_contact_status_label(cs_new->last_status));
1140 ast_statsd_log_string_va("PJSIP.contacts.states.%s", AST_STATSD_GAUGE,
1141 "+1", 1.0, ast_sip_get_contact_status_label(cs_new->status));
1142
1144
1145 ast_test_suite_event_notify("AOR_CONTACT_UPDATE",
1146 "Contact: %s\r\n"
1147 "Status: %s",
1148 cs_new->name,
1150 }
1151 ao2_ref(cs_new, -1);
1152}
1153
1154/*! \brief Transition the contact status to unqualified mode */
1155static int sip_options_set_contact_status_unqualified(void *obj, void *arg, int flags)
1156{
1157 struct ast_sip_contact *contact = obj;
1158 struct ast_sip_contact_status *contact_status;
1159
1160 contact_status = ast_res_pjsip_find_or_create_contact_status(contact);
1161 if (!contact_status) {
1162 return 0;
1163 }
1164
1165 switch (contact_status->status) {
1166 case AVAILABLE:
1167 case UNAVAILABLE:
1168 case UNKNOWN:
1169 sip_options_set_contact_status(contact_status, CREATED);
1170 break;
1171 case CREATED:
1172 case REMOVED:
1173 break;
1174 }
1175
1176 ao2_ref(contact_status, -1);
1177
1178 return 0;
1179}
1180
1181/*! \brief Transition the contact status to qualified mode */
1182static int sip_options_set_contact_status_qualified(void *obj, void *arg, int flags)
1183{
1184 struct ast_sip_contact *contact = obj;
1185 struct ast_sip_contact_status *contact_status;
1186
1187 contact_status = ast_res_pjsip_find_or_create_contact_status(contact);
1188 if (!contact_status) {
1189 return 0;
1190 }
1191
1192 switch (contact_status->status) {
1193 case AVAILABLE:
1195 break;
1196 case UNAVAILABLE:
1197 case UNKNOWN:
1198 case CREATED:
1199 case REMOVED:
1200 break;
1201 }
1202
1203 ao2_ref(contact_status, -1);
1204
1205 return 0;
1206}
1207
1208/*! \brief Count AVAILABLE qualified contacts. */
1209static int sip_options_contact_status_available_count(void *obj, void *arg, int flags)
1210{
1211 struct ast_sip_contact *contact = obj;
1212 unsigned int *available = arg;
1213 struct ast_sip_contact_status *contact_status;
1214
1215 contact_status = ast_res_pjsip_find_or_create_contact_status(contact);
1216 if (!contact_status) {
1217 return 0;
1218 }
1219
1220 /* Count qualified available contacts. */
1221 switch (contact_status->status) {
1222 case AVAILABLE:
1223 ++*available;
1224 break;
1225 case UNAVAILABLE:
1226 case UNKNOWN:
1227 case CREATED:
1228 case REMOVED:
1229 break;
1230 }
1231
1232 ao2_ref(contact_status, -1);
1233
1234 return 0;
1235}
1236
1237/*!
1238 * \brief Function which applies configuration to an AOR options structure
1239 * \note Run by aor_options->serializer (or management_serializer on aor_options creation)
1240 */
1242 struct ast_sip_aor *aor, int is_new)
1243{
1244 struct ao2_container *existing_contacts;
1245 struct ast_sip_contact *contact;
1246 struct ao2_iterator iter;
1247
1248 ast_debug(3, "Configuring AOR '%s' with current state of configuration and world\n",
1249 aor_options->name);
1250
1251 /*
1252 * Permanent contacts, since we receive no notification that they
1253 * are gone, follow the same approach as AORs. We create a copy
1254 * of the existing container and any reused contacts are removed
1255 * from it. Any contacts remaining in the container after
1256 * processing no longer exist so we need to remove their state.
1257 */
1258 existing_contacts = ao2_container_clone(aor_options->contacts, 0);
1259 if (!existing_contacts) {
1260 ast_log(LOG_WARNING, "Synchronization of AOR '%s' failed for qualify, retaining existing state\n",
1261 aor_options->name);
1262 return;
1263 }
1264
1266 NULL, NULL);
1267
1268 /* Process permanent contacts */
1269 if (aor->permanent_contacts) {
1270 iter = ao2_iterator_init(aor->permanent_contacts, 0);
1271 for (; (contact = ao2_iterator_next(&iter)); ao2_ref(contact, -1)) {
1272 ao2_find(existing_contacts, ast_sorcery_object_get_id(contact),
1274 ao2_link(aor_options->contacts, contact);
1275 }
1276 ao2_iterator_destroy(&iter);
1277 }
1278
1279 /*
1280 * If this is newly added we need to see if there are any
1281 * existing dynamic contacts to add. Ones that are added
1282 * after creation will occur as a result of the contact
1283 * observer creation callback.
1284 */
1285 if (is_new) {
1286 size_t prefix_len = strlen(ast_sorcery_object_get_id(aor)) + sizeof(";@") - 1;
1287 char prefix[prefix_len + 1];
1288 struct ao2_container *contacts;
1289
1290 sprintf(prefix, "%s;@", ast_sorcery_object_get_id(aor)); /* Safe */
1292 prefix, prefix_len);
1293 if (contacts) {
1294 ao2_container_dup(aor_options->dynamic_contacts, contacts, 0);
1295 ao2_ref(contacts, -1);
1296 }
1297 }
1298
1299 /* Process dynamic contacts */
1300 iter = ao2_iterator_init(aor_options->dynamic_contacts, 0);
1301 for (; (contact = ao2_iterator_next(&iter)); ao2_ref(contact, -1)) {
1302 ao2_find(existing_contacts, ast_sorcery_object_get_id(contact),
1304 ao2_link(aor_options->contacts, contact);
1305 }
1306 ao2_iterator_destroy(&iter);
1307
1308 /* Any contacts left no longer exist, so raise events and make them disappear */
1309 ao2_callback(existing_contacts, OBJ_NODATA | OBJ_UNLINK,
1310 sip_options_remove_contact, aor_options);
1311 ao2_ref(existing_contacts, -1);
1312
1313 /*
1314 * Update the available count if we transition between qualified
1315 * and unqualified. In the qualified case we need to start with
1316 * 0 available as the qualify process will take care of it. In
1317 * the unqualified case it is based on the number of contacts
1318 * present.
1319 */
1320 if (!aor->qualify_frequency) {
1321 ao2_callback(aor_options->contacts, OBJ_NODATA,
1323 aor_options->available = ao2_container_count(aor_options->contacts);
1324 ast_debug(3, "AOR '%s' is unqualified, number of available contacts is therefore '%d'\n",
1325 aor_options->name, aor_options->available);
1326 } else if (!aor_options->qualify_frequency) {
1327 ao2_callback(aor_options->contacts, OBJ_NODATA,
1329 aor_options->available = 0;
1330 ast_debug(3, "AOR '%s' has transitioned from unqualified to qualified, reset available contacts to 0\n",
1331 aor_options->name);
1332 } else {
1333 /*
1334 * Count the number of AVAILABLE qualified contacts to ensure
1335 * the count is in sync with reality.
1336 */
1337 aor_options->available = 0;
1338 ao2_callback(aor_options->contacts, OBJ_NODATA,
1340 }
1341
1342 aor_options->authenticate_qualify = aor->authenticate_qualify;
1343 aor_options->qualify_2xx_only = aor->qualify_2xx_only;
1344 aor_options->qualify_timeout = aor->qualify_timeout;
1345
1346 /*
1347 * If we need to stop or start the scheduled callback then do so.
1348 * This occurs due to the following:
1349 * 1. The qualify frequency has changed
1350 * 2. Contacts were added when previously there were none
1351 * 3. There are no contacts but previously there were some
1352 */
1353 if (aor_options->qualify_frequency != aor->qualify_frequency
1354 || (!aor_options->sched_task && ao2_container_count(aor_options->contacts))
1355 || (aor_options->sched_task && !ao2_container_count(aor_options->contacts))) {
1356 if (aor_options->sched_task) {
1358 ao2_ref(aor_options->sched_task, -1);
1359 aor_options->sched_task = NULL;
1360 }
1361
1362 /* If there is still a qualify frequency then schedule this */
1363 aor_options->qualify_frequency = aor->qualify_frequency;
1364 if (aor_options->qualify_frequency
1365 && ao2_container_count(aor_options->contacts)) {
1366 aor_options->sched_task = ast_sip_schedule_task(aor_options->serializer,
1370 if (!aor_options->sched_task) {
1371 ast_log(LOG_ERROR, "Unable to schedule qualify for contacts of AOR '%s'\n",
1372 aor_options->name);
1373 }
1374 }
1375 }
1376
1377 ast_debug(3, "AOR '%s' now has %d available contacts\n", aor_options->name,
1378 aor_options->available);
1379}
1380
1381/*!
1382 * \brief Task to synchronize an AOR with our local state
1383 * \note Run by aor_options->serializer (or management_serializer on aor_options creation)
1384 */
1386{
1388 int i;
1389
1390 ast_debug(3, "Synchronizing AOR '%s' with current state of configuration and world\n",
1391 task_data->aor_options->name);
1392
1394 task_data->added);
1395
1396 /*
1397 * Endpoint state compositors are removed in this operation but not
1398 * added. To reduce the amount of work done they are done later. In
1399 * the mean time things can still qualify and once an endpoint state
1400 * compositor is added to the AOR it will be updated with the current
1401 * state.
1402 */
1403 for (i = 0; i < AST_VECTOR_SIZE(&task_data->aor_options->compositors); ++i) {
1404 struct sip_options_endpoint_state_compositor *endpoint_state_compositor;
1405
1406 endpoint_state_compositor = AST_VECTOR_GET(&task_data->aor_options->compositors, i);
1407
1408 ao2_lock(endpoint_state_compositor);
1409 endpoint_state_compositor->active = 0;
1410 sip_options_update_endpoint_state_compositor_aor(endpoint_state_compositor,
1411 task_data->aor_options->name, REMOVED);
1412 ao2_unlock(endpoint_state_compositor);
1413 }
1414 AST_VECTOR_RESET(&task_data->aor_options->compositors, ao2_cleanup);
1415
1416 return 0;
1417}
1418
1419/*!
1420 * \brief Synchronize an AOR with our local state
1421 * \note Run by management_serializer
1422 */
1423static int sip_options_synchronize_aor(void *obj, void *arg, int flags)
1424{
1426 .aor = obj,
1427 .existing = arg,
1428 };
1429
1430 task_data.aor_options = ao2_find(sip_options_aors,
1432 if (!task_data.aor_options) {
1433 task_data.aor_options = sip_options_aor_alloc(task_data.aor);
1434 if (!task_data.aor_options) {
1435 return 0;
1436 }
1437
1438 task_data.added = 1;
1439
1440 /* Nothing is aware of this AOR yet so we can just update it in this thread */
1442 ao2_link(sip_options_aors, task_data.aor_options);
1443 } else {
1444 /* This AOR already exists so we have to do manipulation in its serializer */
1445 ast_sip_push_task_wait_serializer(task_data.aor_options->serializer,
1447 }
1448
1449 ao2_ref(task_data.aor_options, -1);
1450
1451 if (task_data.existing) {
1454 }
1455
1456 return 0;
1457}
1458
1459/*! \brief Destructor for endpoint state compositors */
1461{
1462 struct sip_options_endpoint_state_compositor *endpoint_state_compositor = obj;
1463
1464 ao2_cleanup(endpoint_state_compositor->aor_statuses);
1465}
1466
1467/*! \brief Hashing function for endpoint AOR status */
1469
1470/*! \brief Comparator function for endpoint AOR status */
1472
1473/*! \brief Find (or create) an endpoint state compositor */
1475{
1476 struct sip_options_endpoint_state_compositor *endpoint_state_compositor;
1477
1479 endpoint_state_compositor = ao2_find(sip_options_endpoint_state_compositors,
1481 if (endpoint_state_compositor) {
1483 return endpoint_state_compositor;
1484 }
1485
1486 endpoint_state_compositor = ao2_alloc(sizeof(*endpoint_state_compositor)
1487 + strlen(ast_sorcery_object_get_id(endpoint)) + 1,
1489 if (!endpoint_state_compositor) {
1491 return NULL;
1492 }
1493
1494 /*
1495 * NOTE: The endpoint_state_compositor->aor_statuses container is
1496 * externally protected by the endpoint_state_compositor lock.
1497 */
1498 endpoint_state_compositor->aor_statuses = ao2_container_alloc_hash(
1500 sip_options_endpoint_aor_status_hash_fn, NULL,
1501 sip_options_endpoint_aor_status_cmp_fn);
1502 if (!endpoint_state_compositor->aor_statuses) {
1504 ao2_ref(endpoint_state_compositor, -1);
1505 return NULL;
1506 }
1507
1508 strcpy(endpoint_state_compositor->name, ast_sorcery_object_get_id(endpoint)); /* SAFE */
1509
1510 ao2_link_flags(sip_options_endpoint_state_compositors, endpoint_state_compositor,
1511 OBJ_NOLOCK);
1513
1514 return endpoint_state_compositor;
1515}
1516
1517/*! \brief Task details for adding an AOR to an endpoint state compositor */
1519 /*! \brief The AOR options that the endpoint state compositor should be added to */
1521 /*! \brief The endpoint state compositor */
1523};
1524
1525/*!
1526 * \brief Task which adds an AOR to an endpoint state compositor
1527 * \note Run by aor_options->serializer
1528 */
1530{
1532
1533 ast_debug(3, "Adding endpoint compositor '%s' to AOR '%s'\n",
1534 task_data->endpoint_state_compositor->name, task_data->aor_options->name);
1535
1536 ao2_ref(task_data->endpoint_state_compositor, +1);
1537 if (AST_VECTOR_APPEND(&task_data->aor_options->compositors,
1538 task_data->endpoint_state_compositor)) {
1539 /* Failed to add so no need to update the endpoint status. Nothing changed. */
1540 ao2_ref(task_data->endpoint_state_compositor, -1);
1541 return 0;
1542 }
1543
1544 ao2_lock(task_data->endpoint_state_compositor);
1546 task_data->aor_options->name,
1547 task_data->aor_options->available ? AVAILABLE : UNAVAILABLE);
1548 ao2_unlock(task_data->endpoint_state_compositor);
1549
1550 return 0;
1551}
1552
1553/*!
1554 * \brief Task which adds removes an AOR from an endpoint state compositor
1555 * \note Run by aor_options->serializer
1556 */
1558{
1560 int i;
1561
1562 ast_debug(3, "Removing endpoint compositor '%s' from AOR '%s'\n",
1563 task_data->endpoint_state_compositor->name,
1564 task_data->aor_options->name);
1565
1566 for (i = 0; i < AST_VECTOR_SIZE(&task_data->aor_options->compositors); ++i) {
1567 struct sip_options_endpoint_state_compositor *endpoint_state_compositor;
1568
1569 endpoint_state_compositor = AST_VECTOR_GET(&task_data->aor_options->compositors, i);
1570 if (endpoint_state_compositor != task_data->endpoint_state_compositor) {
1571 continue;
1572 }
1573
1574 AST_VECTOR_REMOVE(&task_data->aor_options->compositors, i, 0);
1575 ao2_ref(endpoint_state_compositor, -1);
1576 break;
1577 }
1578
1579 return 0;
1580}
1581
1582/*!
1583 * \brief Synchronize an endpoint with our local state
1584 * \note Run by management_serializer
1585 */
1586static int sip_options_synchronize_endpoint(void *obj, void *arg, int flags)
1587{
1588 struct ast_sip_endpoint *endpoint = obj;
1589 struct ast_sip_aor *aor = arg;
1590 char *aors;
1591 char *aor_name;
1593
1594 if (ast_strlen_zero(endpoint->aors)) {
1595 /* There are no AORs, so really... who the heck knows */
1596 ast_debug(3, "Endpoint '%s' is not interested in any AORs so not creating endpoint state compositor\n",
1597 ast_sorcery_object_get_id(endpoint));
1598 return 0;
1599 }
1600
1601 ast_debug(3, "Synchronizing endpoint '%s' with AORs '%s'\n",
1602 ast_sorcery_object_get_id(endpoint), endpoint->aors);
1603
1604 aors = ast_strdupa(endpoint->aors);
1605 while ((aor_name = ast_strip(strsep(&aors, ",")))) {
1606 if (ast_strlen_zero(aor_name)) {
1607 continue;
1608 }
1609 if (aor && strcasecmp(ast_sorcery_object_get_id(aor), aor_name)) {
1610 ast_debug(3, "Filtered AOR '%s' on endpoint '%s' as we are looking for '%s'\n",
1611 aor_name, ast_sorcery_object_get_id(endpoint),
1613 continue;
1614 }
1615
1616 task_data.aor_options = ao2_find(sip_options_aors, aor_name, OBJ_SEARCH_KEY);
1617 if (!task_data.aor_options) {
1618 /*
1619 * They have referenced an invalid AOR. If that's all they've
1620 * done we will set them to offline at the end.
1621 */
1622 ast_debug(3, "Endpoint '%s' referenced invalid AOR '%s'\n",
1623 ast_sorcery_object_get_id(endpoint), aor_name);
1624 continue;
1625 }
1626
1627 if (!task_data.endpoint_state_compositor) {
1628 /*
1629 * We create an endpoint state compositor only after we know
1630 * for sure we need it.
1631 */
1632 task_data.endpoint_state_compositor =
1634 if (!task_data.endpoint_state_compositor) {
1636 "Could not create endpoint state compositor for '%s', endpoint state will be incorrect\n",
1637 ast_sorcery_object_get_id(endpoint));
1638 ao2_ref(task_data.aor_options, -1);
1641 return 0;
1642 }
1643 }
1644
1645 /* We use a synchronous task so that we don't flood the system */
1646 ast_sip_push_task_wait_serializer(task_data.aor_options->serializer,
1648
1649 ao2_ref(task_data.aor_options, -1);
1650
1651 /*
1652 * If we filtered on a specific AOR name then the endpoint can
1653 * only reference it once so break early.
1654 */
1655 if (aor) {
1656 break;
1657 }
1658 }
1659
1660 if (task_data.endpoint_state_compositor) {
1661 /*
1662 * If an endpoint state compositor is present determine the current state
1663 * of the endpoint and update it.
1664 */
1665 ao2_lock(task_data.endpoint_state_compositor);
1666 task_data.endpoint_state_compositor->active = 1;
1669 ao2_unlock(task_data.endpoint_state_compositor);
1670
1671 ao2_ref(task_data.endpoint_state_compositor, -1);
1672 } else if (!aor) {
1673 /* If no explicit AOR is specified we are updating the endpoint itself, so then set
1674 * it to offline if no endpoint compositor exists as they referenced an invalid AOR
1675 * or none at all
1676 */
1677 ast_debug(3, "Endpoint '%s' has no AORs feeding it, setting it to offline state as default\n",
1678 ast_sorcery_object_get_id(endpoint));
1681 }
1682
1683 return 0;
1684}
1685
1686/*!
1687 * \brief Task which removes an AOR from all of the ESCs it is reporting to
1688 * \note Run by aor_options->serializer
1689 */
1690static int sip_options_aor_remove_task(void *obj)
1691{
1692 struct sip_options_aor *aor_options = obj;
1693
1695
1696 if (aor_options->sched_task) {
1698 ao2_ref(aor_options->sched_task, -1);
1699 aor_options->sched_task = NULL;
1700 }
1701
1702 return 0;
1703}
1704
1705/*!
1706 * \brief Callback which removes any unused AORs that remained after reloading
1707 * \note Run by management_serializer
1708 */
1709static int sip_options_unused_aor(void *obj, void *arg, int flags)
1710{
1711 struct sip_options_aor *aor_options = obj;
1712
1713 ast_debug(3, "AOR '%s' is no longer configured, removing it\n", aor_options->name);
1714
1716 aor_options);
1717 ao2_unlink(sip_options_aors, aor_options);
1718
1719 return CMP_MATCH;
1720}
1721
1722/*!
1723 * \brief Callback function used to unlink and remove event state compositors that have no AORs feeding them
1724 * \note Run by management_serializer
1725 */
1726static int sip_options_unused_endpoint_state_compositor(void *obj, void *arg, int flags)
1727{
1728 struct sip_options_endpoint_state_compositor *endpoint_state_compositor = obj;
1729
1730 if (ao2_container_count(endpoint_state_compositor->aor_statuses)) {
1731 return 0;
1732 }
1733
1734 /* No AORs are feeding this endpoint state compositor */
1735 ast_sip_persistent_endpoint_update_state(endpoint_state_compositor->name,
1737
1738 return CMP_MATCH;
1739}
1740
1741/*! \brief Structure which contains information required to synchronize */
1743 /*! \brief Whether this is a reload or not */
1745};
1746
1747/*!
1748 * \brief Task to synchronize our local container of AORs and endpoint state compositors with the current configuration
1749 * \note Run by management_serializer
1750 */
1751static int sip_options_synchronize_task(void *obj)
1752{
1754 struct ao2_container *existing = NULL;
1755 struct ao2_container *objects;
1756
1757 /*
1758 * When reloading we keep track of the existing AORs so we can
1759 * terminate old ones that are no longer referenced or used.
1760 */
1761 if (task_data->reload) {
1763 if (!existing) {
1764 return 0;
1765 }
1766 }
1767
1770 if (objects) {
1771 /* Go through the returned AORs and synchronize with our local state */
1773 ao2_ref(objects, -1);
1774 }
1775
1776 /*
1777 * Any AORs remaining in existing are no longer referenced by
1778 * the current container of AORs we retrieved, so remove them.
1779 */
1780 if (existing) {
1783 ao2_ref(existing, -1);
1784 }
1785
1788 if (objects) {
1789 /* Go through the provided endpoints and update AORs */
1791 ao2_ref(objects, -1);
1792 }
1793
1794 /*
1795 * All endpoint state compositors that don't have any AORs
1796 * feeding them information can be removed. If they end
1797 * up getting needed later they'll just be recreated.
1798 */
1802
1803 return 0;
1804}
1805
1806/*! \brief Synchronize our local container of AORs and endpoint state compositors with the current configuration */
1816
1817/*!
1818 * \brief Unlink AORs feeding the endpoint status compositor
1819 * \note Run by management_serializer
1820 */
1822 struct sip_options_endpoint_state_compositor *endpoint_state_compositor)
1823{
1824 struct ao2_iterator it_aor_statuses;
1825 struct sip_options_endpoint_aor_status *aor_status;
1827 .endpoint_state_compositor = endpoint_state_compositor,
1828 };
1829
1832
1833 /* Unlink AOR feeders pointing to endpoint */
1835 for (; (aor_status = ao2_iterator_next(&it_aor_statuses)); ao2_ref(aor_status, -1)) {
1836 task_data.aor_options = ao2_find(sip_options_aors, aor_status->name,
1838 if (!task_data.aor_options) {
1839 continue;
1840 }
1841
1842 ast_debug(3, "Removing endpoint state compositor '%s' from AOR '%s'\n",
1843 ast_sorcery_object_get_id(endpoint), aor_status->name);
1845 ast_sip_push_task_wait_serializer(task_data.aor_options->serializer,
1848 ao2_ref(task_data.aor_options, -1);
1849 }
1850 ao2_iterator_destroy(&it_aor_statuses);
1851
1852 /*
1853 * We do not need to remove the AOR feeder status memory from the
1854 * aor_statuses container. The endpoint_state_compositor is about
1855 * to die and do it for us.
1856 */
1857
1859}
1860
1861/*!
1862 * \brief Task to delete an endpoint from the known universe
1863 * \note Run by management_serializer
1864 */
1866{
1867 struct ast_sip_endpoint *endpoint = obj;
1868 struct sip_options_endpoint_state_compositor *endpoint_state_compositor;
1869
1870 endpoint_state_compositor = ao2_find(sip_options_endpoint_state_compositors,
1872 if (!endpoint_state_compositor) {
1873 return 0;
1874 }
1875
1876 ast_debug(3, "Endpoint '%s' has been deleted, removing endpoint state compositor from AORs\n",
1877 ast_sorcery_object_get_id(endpoint));
1878 sip_options_endpoint_unlink_aor_feeders(endpoint, endpoint_state_compositor);
1879 ao2_ref(endpoint_state_compositor, -1);
1880
1881 return 0;
1882}
1883
1884/*! \brief Observer callback invoked on endpoint deletion */
1890
1891/*!
1892 * \brief Task to synchronize the endpoint
1893 * \note Run by management_serializer
1894 */
1896{
1897 struct ast_sip_endpoint *endpoint = obj;
1898 struct sip_options_endpoint_state_compositor *endpoint_state_compositor;
1899
1900 ast_debug(3, "Endpoint '%s' has been created or modified, updating state\n",
1901 ast_sorcery_object_get_id(endpoint));
1902
1903 endpoint_state_compositor = ao2_find(sip_options_endpoint_state_compositors,
1905 if (endpoint_state_compositor) {
1906 /* Unlink the AORs currently feeding the endpoint. */
1907 sip_options_endpoint_unlink_aor_feeders(endpoint, endpoint_state_compositor);
1908 ao2_ref(endpoint_state_compositor, -1);
1909 }
1910
1911 /* Connect the AORs that now feed the endpoint. */
1913 return 0;
1914}
1915
1916/*! \brief Observer callback invoked on endpoint creation or modification */
1922
1923/*! \brief Observer callbacks for endpoints */
1929
1930/*!
1931 * \brief Task to synchronize an AOR with our local state
1932 * \note Run by aor_options->serializer
1933 */
1934static int sip_options_update_aor_task(void *obj)
1935{
1937 int available = task_data->aor_options->available;
1938
1939 ast_debug(3, "Individually updating AOR '%s' with current state of configuration and world\n",
1940 task_data->aor_options->name);
1941
1943 task_data->added);
1944
1945 if (!available && task_data->aor_options->available) {
1946 ast_debug(3, "After modifying AOR '%s' it has now become available\n",
1947 task_data->aor_options->name);
1949 } else if (available && !task_data->aor_options->available) {
1950 ast_debug(3, "After modifying AOR '%s' it has become unavailable\n",
1951 task_data->aor_options->name);
1953 }
1954
1955 return 0;
1956}
1957
1958/*!
1959 * \brief Task to synchronize the AOR
1960 * \note Run by management_serializer
1961 */
1963{
1964 struct ast_sip_aor *aor = obj;
1965 struct sip_options_aor *aor_options;
1966
1969 if (!aor_options) {
1970 struct ao2_container *endpoints;
1971
1972 aor_options = sip_options_aor_alloc(aor);
1973 if (!aor_options) {
1974 return 0;
1975 }
1976
1977 /*
1978 * This is a newly added AOR and we need to establish any
1979 * endpoint state compositors that may reference only the
1980 * AOR. If these need to be updated later then they'll
1981 * be done by modifying the endpoint or issuing a reload.
1982 */
1983 sip_options_apply_aor_configuration(aor_options, aor, 1);
1984 ao2_link(sip_options_aors, aor_options);
1985
1986 /*
1987 * Using LIKE doesn't seem to work very well with non-realtime so we
1988 * fetch everything right now and do a filter on our side.
1989 */
1992 if (endpoints) {
1994 ao2_ref(endpoints, -1);
1995 }
1996 } else {
1998 .aor_options = aor_options,
1999 .aor = aor,
2000 };
2001
2002 /*
2003 * If this AOR was modified we have to do our work in its serializer
2004 * instead of this thread to ensure that things aren't modified by
2005 * multiple threads.
2006 */
2009 }
2010
2011 ao2_ref(aor_options, -1);
2012
2013 return 0;
2014}
2015
2016/*! \brief Observer callback invoked on AOR creation or modification */
2022
2023/*!
2024 * \brief Task to delete an AOR from the known universe
2025 * \note Run by management_serializer
2026 */
2028{
2029 struct ast_sip_aor *aor = obj;
2030 struct sip_options_aor *aor_options;
2031
2034 if (!aor_options) {
2035 return 0;
2036 }
2037
2038 ast_debug(3, "AOR '%s' has been deleted, removing it\n", aor_options->name);
2039
2041 aor_options);
2042 ao2_ref(aor_options, -1);
2043
2044 return 0;
2045}
2046
2047/*! \brief Observer callback invoked on AOR deletion */
2053
2054/*! \brief Observer callbacks for AORs */
2057 .updated = aor_observer_modified,
2058 .deleted = aor_observer_deleted,
2059};
2060
2061/*! \brief Task details for adding an AOR to an endpoint state compositor */
2063 /*! \brief The AOR options that the contact is referring to */
2065 /*! \brief The contact itself */
2067};
2068
2069
2070/*!
2071 * \brief Check if the contact qualify options are different than local aor qualify options
2072 */
2073static int has_qualify_changed (const struct ast_sip_contact *contact, const struct sip_options_aor *aor_options)
2074{
2075 if (!contact) {
2076 return 0;
2077 }
2078
2079 if (!aor_options) {
2080 if (contact->qualify_frequency) {
2081 return 1;
2082 }
2083 } else if (contact->qualify_frequency != aor_options->qualify_frequency
2084 || contact->authenticate_qualify != aor_options->authenticate_qualify
2085 || contact->qualify_2xx_only != aor_options->qualify_2xx_only
2086 || ((int)(contact->qualify_timeout * 1000)) != ((int)(aor_options->qualify_timeout * 1000))) {
2087 return 1;
2088 }
2089
2090 return 0;
2091}
2092
2093/*!
2094 * \brief Task which adds a dynamic contact to an AOR
2095 * \note Run by aor_options->serializer
2096 */
2097static int sip_options_contact_add_task(void *obj)
2098{
2100 struct ast_sip_contact_status *contact_status;
2101
2102 ao2_link(task_data->aor_options->dynamic_contacts, task_data->contact);
2103 ao2_link(task_data->aor_options->contacts, task_data->contact);
2104
2105 contact_status = ast_res_pjsip_find_or_create_contact_status(task_data->contact);
2106 ao2_cleanup(contact_status);
2107
2108 if (task_data->aor_options->qualify_frequency) {
2109 /* There will always be a contact here, and we need to immediately schedule
2110 * a qualify so that contacts are not waiting for the qualify_frequency
2111 * timer duration before qualifying.
2112 */
2113 ast_debug(3, "Starting scheduled callback on AOR '%s' for qualifying as there is now a contact on it\n",
2114 task_data->aor_options->name);
2115 /*
2116 * We immediately schedule the initial qualify so that we get
2117 * reachable/unreachable as soon as possible. Realistically
2118 * since they pretty much just registered they should be
2119 * reachable.
2120 */
2121 if (task_data->aor_options->sched_task) {
2122 ast_sip_sched_task_cancel(task_data->aor_options->sched_task);
2123 ao2_ref(task_data->aor_options->sched_task, -1);
2124 task_data->aor_options->sched_task = NULL;
2125 }
2126 task_data->aor_options->sched_task = ast_sip_schedule_task(
2127 task_data->aor_options->serializer, 1, sip_options_qualify_aor,
2128 ast_taskprocessor_name(task_data->aor_options->serializer),
2129 task_data->aor_options,
2131 if (!task_data->aor_options->sched_task) {
2132 ast_log(LOG_ERROR, "Unable to schedule qualify for contacts of AOR '%s'\n",
2133 task_data->aor_options->name);
2134 }
2135 } else {
2136 /*
2137 * If this was the first contact added to a non-qualified AOR then
2138 * it should become available.
2139 */
2140 task_data->aor_options->available =
2141 ao2_container_count(task_data->aor_options->contacts);
2142 if (task_data->aor_options->available == 1) {
2143 ast_debug(3, "An unqualified contact has been added to AOR '%s' so it is now available\n",
2144 task_data->aor_options->name);
2146 AVAILABLE);
2147 }
2148 }
2149
2150 return 0;
2151}
2152
2153/*!
2154 * \brief Task to add a dynamic contact to an AOR in its serializer
2155 * \note Run by management_serializer
2156 */
2158{
2160
2161 task_data.contact = obj;
2162 task_data.aor_options = ao2_find(sip_options_aors, task_data.contact->aor,
2164
2165 if (has_qualify_changed(task_data.contact, task_data.aor_options)) {
2166 struct ast_sip_aor *aor;
2167
2169 task_data.contact->aor);
2170 if (aor) {
2171 ast_debug(3, "AOR '%s' qualify options have been modified. Synchronize an AOR local state\n",
2172 task_data.contact->aor);
2174 ao2_ref(aor, -1);
2175 }
2176 }
2177
2178 if (!task_data.aor_options) {
2179 return 0;
2180 }
2181
2182 ast_sip_push_task_wait_serializer(task_data.aor_options->serializer,
2184 ao2_ref(task_data.aor_options, -1);
2185
2186 return 0;
2187}
2188
2189/*! \brief Observer callback invoked on contact creation */
2195
2196/*!
2197 * \brief Task which updates a dynamic contact to an AOR
2198 * \note Run by aor_options->serializer
2199 */
2201{
2203 struct ast_sip_contact_status *contact_status;
2204
2205 contact_status = ast_sip_get_contact_status(task_data->contact);
2206 if (contact_status) {
2207 switch (contact_status->status) {
2208 case CREATED:
2209 case UNAVAILABLE:
2210 case AVAILABLE:
2211 case UNKNOWN:
2212 /* Refresh the ContactStatus AMI events. */
2213 sip_options_contact_status_update(contact_status);
2214 break;
2215 case REMOVED:
2216 break;
2217 }
2218 ao2_ref(contact_status, -1);
2219 }
2220
2221 ao2_ref(task_data->contact, -1);
2222 ao2_ref(task_data->aor_options, -1);
2224 return 0;
2225}
2226
2227/*! \brief Observer callback invoked on contact update */
2228static void contact_observer_updated(const void *obj)
2229{
2230 const struct ast_sip_contact *contact = obj;
2231 struct sip_options_aor *aor_options = ao2_find(sip_options_aors, contact->aor, OBJ_SEARCH_KEY);
2232
2233 if (has_qualify_changed(contact, aor_options)) {
2234 struct ast_sip_aor *aor;
2235
2237 contact->aor);
2238 if (aor) {
2239 ast_debug(3, "AOR '%s' qualify options have been modified. Synchronize an AOR local state\n",
2240 contact->aor);
2243 ao2_ref(aor, -1);
2244 }
2245 }
2246
2249
2250 task_data = ast_malloc(sizeof(*task_data));
2251 if (!task_data) {
2252 ao2_ref(aor_options, -1);
2253 return;
2254 }
2255
2256 task_data->contact = (struct ast_sip_contact *) contact;
2257 /* task_data takes ownership of aor_options and will take care of releasing the ref */
2258 task_data->aor_options = aor_options;
2259
2260 ao2_ref(task_data->contact, +1);
2261 if (ast_sip_push_task(task_data->aor_options->serializer,
2263 ao2_ref(task_data->contact, -1);
2264 ao2_ref(task_data->aor_options, -1);
2266 }
2267 } else {
2268 ao2_cleanup(aor_options);
2269 }
2270}
2271
2272/*!
2273 * \brief Task which deletes a dynamic contact from an AOR
2274 * \note Run by aor_options->serializer
2275 */
2277{
2279
2280 ao2_find(task_data->aor_options->dynamic_contacts, task_data->contact,
2282 ao2_find(task_data->aor_options->contacts, task_data->contact,
2284
2286
2287 if (task_data->aor_options->qualify_frequency) {
2288 /* If this is the last contact then we need to stop the scheduled callback */
2289 if (!ao2_container_count(task_data->aor_options->contacts)) {
2290 ast_debug(3, "Terminating scheduled callback on AOR '%s' as there are no contacts to qualify\n",
2291 task_data->aor_options->name);
2292 if (task_data->aor_options->sched_task) {
2293 ast_sip_sched_task_cancel(task_data->aor_options->sched_task);
2294 ao2_ref(task_data->aor_options->sched_task, -1);
2295 task_data->aor_options->sched_task = NULL;
2296 }
2297 }
2298 } else {
2299 task_data->aor_options->available =
2300 ao2_container_count(task_data->aor_options->contacts);
2301 if (!task_data->aor_options->available) {
2302 ast_debug(3, "An unqualified contact has been removed from AOR '%s' leaving no remaining contacts\n",
2303 task_data->aor_options->name);
2305 UNAVAILABLE);
2306 }
2307 }
2308
2309 return 0;
2310}
2311
2312/*!
2313 * \brief Task to delete a contact from an AOR in its serializer
2314 * \note Run by management_serializer
2315 */
2317{
2319
2320 task_data.contact = obj;
2321 task_data.aor_options = ao2_find(sip_options_aors, task_data.contact->aor,
2323 if (!task_data.aor_options) {
2324 /* For contacts that are deleted we don't really care if there is no AOR locally */
2325 return 0;
2326 }
2327
2328 ast_sip_push_task_wait_serializer(task_data.aor_options->serializer,
2330 ao2_ref(task_data.aor_options, -1);
2331
2332 return 0;
2333}
2334
2335/*! \brief Observer callback invoked on contact deletion */
2341
2342/*! \brief Observer callbacks for contacts */
2348
2349static char *cli_qualify(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2350{
2351 RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
2352 const char *endpoint_name;
2353 char *aors;
2354 char *aor_name;
2355
2356 switch (cmd) {
2357 case CLI_INIT:
2358 e->command = "pjsip qualify";
2359 e->usage =
2360 "Usage: pjsip qualify <endpoint>\n"
2361 " Send a SIP OPTIONS request to all contacts on the endpoint.\n";
2362 return NULL;
2363 case CLI_GENERATE:
2364 return NULL;
2365 }
2366
2367 if (a->argc != 3) {
2368 return CLI_SHOWUSAGE;
2369 }
2370
2371 endpoint_name = a->argv[2];
2372
2373 endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint",
2374 endpoint_name);
2375 if (!endpoint) {
2376 ast_cli(a->fd, "Unable to retrieve endpoint %s\n", endpoint_name);
2377 return CLI_FAILURE;
2378 }
2379
2380 if (ast_strlen_zero(endpoint->aors)) {
2381 ast_cli(a->fd, "No AORs configured for endpoint '%s'\n", endpoint_name);
2382 return CLI_FAILURE;
2383 }
2384
2385 aors = ast_strdupa(endpoint->aors);
2386 while ((aor_name = ast_strip(strsep(&aors, ",")))) {
2387 struct sip_options_aor *aor_options;
2388
2389 aor_options = ao2_find(sip_options_aors, aor_name, OBJ_SEARCH_KEY);
2390 if (!aor_options) {
2391 continue;
2392 }
2393
2394 ast_cli(a->fd, "Qualifying AOR '%s' on endpoint '%s'\n", aor_name, endpoint_name);
2396 aor_options);
2397 ao2_ref(aor_options, -1);
2398 }
2399
2400 return CLI_SUCCESS;
2401}
2402
2404{
2405 struct ao2_container *contacts;
2406
2409
2410 return contacts;
2411}
2412
2413static int sip_contact_to_ami(const struct ast_sip_contact *contact,
2414 struct ast_str **buf)
2415{
2416 return ast_sip_sorcery_object_to_ami(contact, buf);
2417}
2418
2419static int format_ami_contactlist_handler(void *obj, void *arg, int flags)
2420{
2421 struct ast_sip_contact *contact = obj;
2422 struct ast_sip_ami *ami = arg;
2423 struct ast_str *buf;
2425
2426 buf = ast_sip_create_ami_event("ContactList", ami);
2427 if (!buf) {
2428 return CMP_STOP;
2429 }
2430
2431 if (sip_contact_to_ami(contact, &buf)) {
2432 ast_free(buf);
2433 return CMP_STOP;
2434 }
2435
2436 /* Add extra info */
2438 ast_str_append(&buf, 0, "Status: %s\r\n",
2440 if (!status || status->status != AVAILABLE) {
2441 ast_str_append(&buf, 0, "RoundtripUsec: N/A\r\n");
2442 } else {
2443 ast_str_append(&buf, 0, "RoundtripUsec: %" PRId64 "\r\n", status->rtt);
2444 }
2446
2447 astman_append(ami->s, "%s\r\n", ast_str_buffer(buf));
2448
2449 ami->count++;
2450
2451 ast_free(buf);
2452
2453 return 0;
2454}
2455
2456static int ami_show_contacts(struct mansession *s, const struct message *m)
2457{
2458 struct ast_sip_ami ami = { .s = s, .m = m, .action_id = astman_get_header(m, "ActionID"), };
2459 struct ao2_container *contacts;
2460
2461 contacts = get_all_contacts();
2462 if (!contacts) {
2463 astman_send_error(s, m, "Could not get Contacts\n");
2464 return 0;
2465 }
2466
2467 if (!ao2_container_count(contacts)) {
2468 astman_send_error(s, m, "No Contacts found\n");
2469 ao2_ref(contacts, -1);
2470 return 0;
2471 }
2472
2473 astman_send_listack(s, m, "A listing of Contacts follows, presented as ContactList events",
2474 "start");
2475
2477
2478 astman_send_list_complete_start(s, m, "ContactListComplete", ami.count);
2480
2481 ao2_ref(contacts, -1);
2482
2483 return 0;
2484}
2485
2486static char *cli_show_qualify_endpoint(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2487{
2488 RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
2489 const char *endpoint_name;
2490 char *aors;
2491 char *aor_name;
2492
2493 switch (cmd) {
2494 case CLI_INIT:
2495 e->command = "pjsip show qualify endpoint";
2496 e->usage =
2497 "Usage: pjsip show qualify endpoint <id>\n"
2498 " Show the current qualify options for all Aors on the PJSIP endpoint.\n";
2499 return NULL;
2500 case CLI_GENERATE:
2501 return NULL;
2502 }
2503
2504 if (a->argc != 5) {
2505 return CLI_SHOWUSAGE;
2506 }
2507
2508 endpoint_name = a->argv[4];
2509
2510 endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint",
2511 endpoint_name);
2512 if (!endpoint) {
2513 ast_cli(a->fd, "Unable to retrieve endpoint %s\n", endpoint_name);
2514 return CLI_FAILURE;
2515 }
2516
2517 if (ast_strlen_zero(endpoint->aors)) {
2518 ast_cli(a->fd, "No AORs configured for endpoint '%s'\n", endpoint_name);
2519 return CLI_FAILURE;
2520 }
2521
2522 aors = ast_strdupa(endpoint->aors);
2523 while ((aor_name = ast_strip(strsep(&aors, ",")))) {
2524 struct sip_options_aor *aor_options;
2525
2526 aor_options = ao2_find(sip_options_aors, aor_name, OBJ_SEARCH_KEY);
2527 if (!aor_options) {
2528 continue;
2529 }
2530
2531 ast_cli(a->fd, " * AOR '%s' on endpoint '%s'\n", aor_name, endpoint_name);
2532 ast_cli(a->fd, " Qualify frequency : %d sec\n", aor_options->qualify_frequency);
2533 ast_cli(a->fd, " Qualify timeout : %d ms\n", (int)(aor_options->qualify_timeout / 1000));
2534 ast_cli(a->fd, " Qualify 2xx only : %s\n", aor_options->qualify_2xx_only ? "yes" : "no");
2535 ast_cli(a->fd, " Authenticate qualify : %s\n", aor_options->authenticate_qualify?"yes":"no");
2536 ast_cli(a->fd, "\n");
2537 ao2_ref(aor_options, -1);
2538 }
2539
2540 return CLI_SUCCESS;
2541}
2542
2543static char *cli_show_qualify_aor(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2544{
2545 struct sip_options_aor *aor_options;
2546 const char *aor_name;
2547
2548 switch (cmd) {
2549 case CLI_INIT:
2550 e->command = "pjsip show qualify aor";
2551 e->usage =
2552 "Usage: pjsip show qualify aor <id>\n"
2553 " Show the PJSIP Aor current qualify options.\n";
2554 return NULL;
2555 case CLI_GENERATE:
2556 return NULL;
2557 }
2558
2559 if (a->argc != 5) {
2560 return CLI_SHOWUSAGE;
2561 }
2562
2563 aor_name = a->argv[4];
2564
2565 aor_options = ao2_find(sip_options_aors, aor_name, OBJ_SEARCH_KEY);
2566 if (!aor_options) {
2567 ast_cli(a->fd, "Unable to retrieve aor '%s' qualify options\n", aor_name);
2568 return CLI_FAILURE;
2569 }
2570
2571 ast_cli(a->fd, " * AOR '%s'\n", aor_name);
2572 ast_cli(a->fd, " Qualify frequency : %d sec\n", aor_options->qualify_frequency);
2573 ast_cli(a->fd, " Qualify timeout : %d ms\n", (int)(aor_options->qualify_timeout / 1000));
2574 ast_cli(a->fd, " Qualify 2xx only : %s\n", aor_options->qualify_2xx_only ? "yes" : "no");
2575 ast_cli(a->fd, " Authenticate qualify : %s\n", aor_options->authenticate_qualify?"yes":"no");
2576 ao2_ref(aor_options, -1);
2577
2578 return CLI_SUCCESS;
2579}
2580
2581static char *cli_reload_qualify_endpoint(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2582{
2583 RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
2584 const char *endpoint_name;
2585 char *aors;
2586 char *aor_name;
2587
2588 switch (cmd) {
2589 case CLI_INIT:
2590 e->command = "pjsip reload qualify endpoint";
2591 e->usage =
2592 "Usage: pjsip reload qualify endpoint <id>\n"
2593 " Synchronize the qualify options for all Aors on the PJSIP endpoint.\n";
2594 return NULL;
2595 case CLI_GENERATE:
2596 return NULL;
2597 }
2598
2599 if (a->argc != 5) {
2600 return CLI_SHOWUSAGE;
2601 }
2602
2603 endpoint_name = a->argv[4];
2604
2605 endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint",
2606 endpoint_name);
2607 if (!endpoint) {
2608 ast_cli(a->fd, "Unable to retrieve endpoint %s\n", endpoint_name);
2609 return CLI_FAILURE;
2610 }
2611
2612 if (ast_strlen_zero(endpoint->aors)) {
2613 ast_cli(a->fd, "No AORs configured for endpoint '%s'\n", endpoint_name);
2614 return CLI_FAILURE;
2615 }
2616
2617 aors = ast_strdupa(endpoint->aors);
2618 while ((aor_name = ast_strip(strsep(&aors, ",")))) {
2619 struct ast_sip_aor *aor;
2620
2621 aor = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "aor", aor_name);
2622 if (!aor) {
2623 continue;
2624 }
2625
2626 ast_cli(a->fd, "Synchronizing AOR '%s' on endpoint '%s'\n", aor_name, endpoint_name);
2629 ao2_ref(aor, -1);
2630 }
2631
2632 return CLI_SUCCESS;
2633}
2634
2635static char *cli_reload_qualify_aor(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2636{
2637 struct ast_sip_aor *aor;
2638 const char *aor_name;
2639
2640 switch (cmd) {
2641 case CLI_INIT:
2642 e->command = "pjsip reload qualify aor";
2643 e->usage =
2644 "Usage: pjsip reload qualify aor <id>\n"
2645 " Synchronize the PJSIP Aor qualify options.\n";
2646 return NULL;
2647 case CLI_GENERATE:
2648 return NULL;
2649 }
2650
2651 if (a->argc != 5) {
2652 return CLI_SHOWUSAGE;
2653 }
2654
2655 aor_name = a->argv[4];
2656
2657 aor = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "aor", aor_name);
2658 if (!aor) {
2659 ast_cli(a->fd, "Unable to retrieve aor '%s'\n", aor_name);
2660 return CLI_FAILURE;
2661 }
2662
2663 ast_cli(a->fd, "Synchronizing AOR '%s'\n", aor_name);
2666 ao2_ref(aor, -1);
2667
2668 return CLI_SUCCESS;
2669}
2670
2671static int ami_sip_qualify(struct mansession *s, const struct message *m)
2672{
2673 const char *endpoint_name = astman_get_header(m, "Endpoint");
2674 RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
2675 char *aors;
2676 char *aor_name;
2677
2678 if (ast_strlen_zero(endpoint_name)) {
2679 astman_send_error(s, m, "Endpoint parameter missing.");
2680 return 0;
2681 }
2682
2683 endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint",
2684 endpoint_name);
2685 if (!endpoint) {
2686 astman_send_error(s, m, "Unable to retrieve endpoint\n");
2687 return 0;
2688 }
2689
2690 /* send a qualify for all contacts registered with the endpoint */
2691 if (ast_strlen_zero(endpoint->aors)) {
2692 astman_send_error(s, m, "No AoRs configured for endpoint\n");
2693 return 0;
2694 }
2695
2696 aors = ast_strdupa(endpoint->aors);
2697 while ((aor_name = ast_strip(strsep(&aors, ",")))) {
2698 struct sip_options_aor *aor_options;
2699
2700 aor_options = ao2_find(sip_options_aors, aor_name, OBJ_SEARCH_KEY);
2701 if (!aor_options) {
2702 continue;
2703 }
2704
2706 aor_options);
2707 ao2_ref(aor_options, -1);
2708 }
2709
2710 astman_send_ack(s, m, "Endpoint found, will qualify");
2711 return 0;
2712}
2713
2714static struct ast_cli_entry cli_options[] = {
2715 AST_CLI_DEFINE(cli_qualify, "Send an OPTIONS request to a PJSIP endpoint"),
2716 AST_CLI_DEFINE(cli_show_qualify_endpoint, "Show the current qualify options for all Aors on the PJSIP endpoint"),
2717 AST_CLI_DEFINE(cli_show_qualify_aor, "Show the PJSIP Aor current qualify options"),
2718 AST_CLI_DEFINE(cli_reload_qualify_endpoint, "Synchronize the qualify options for all Aors on the PJSIP endpoint"),
2719 AST_CLI_DEFINE(cli_reload_qualify_aor, "Synchronize the PJSIP Aor qualify options"),
2720};
2721
2722int ast_sip_format_contact_ami(void *obj, void *arg, int flags)
2723{
2724 struct ast_sip_contact_wrapper *wrapper = obj;
2725 struct ast_sip_contact *contact = wrapper->contact;
2726 struct ast_sip_ami *ami = arg;
2728 struct ast_str *buf;
2729 const struct ast_sip_endpoint *endpoint = ami->arg;
2730 char secs[AST_TIME_T_LEN];
2731
2732 buf = ast_sip_create_ami_event("ContactStatusDetail", ami);
2733 if (!buf) {
2734 return -1;
2735 }
2736
2738
2739 ast_str_append(&buf, 0, "AOR: %s\r\n", wrapper->aor_id);
2740 ast_str_append(&buf, 0, "URI: %s\r\n", contact->uri);
2741 ast_str_append(&buf, 0, "UserAgent: %s\r\n", contact->user_agent);
2742 ast_time_t_to_string(contact->expiration_time.tv_sec, secs, sizeof(secs));
2743 ast_str_append(&buf, 0, "RegExpire: %s\r\n", secs);
2744 if (!ast_strlen_zero(contact->via_addr)) {
2745 ast_str_append(&buf, 0, "ViaAddress: %s", contact->via_addr);
2746 if (contact->via_port) {
2747 ast_str_append(&buf, 0, ":%d", contact->via_port);
2748 }
2749 ast_str_append(&buf, 0, "\r\n");
2750 }
2751 if (!ast_strlen_zero(contact->call_id)) {
2752 ast_str_append(&buf, 0, "CallID: %s\r\n", contact->call_id);
2753 }
2754 ast_str_append(&buf, 0, "Status: %s\r\n",
2756 if (!status || status->status != AVAILABLE) {
2757 ast_str_append(&buf, 0, "RoundtripUsec: N/A\r\n");
2758 } else {
2759 ast_str_append(&buf, 0, "RoundtripUsec: %" PRId64 "\r\n", status->rtt);
2760 }
2761 ast_str_append(&buf, 0, "EndpointName: %s\r\n",
2762 endpoint ? ast_sorcery_object_get_id(endpoint) : S_OR(contact->endpoint_name, ""));
2763
2764 ast_str_append(&buf, 0, "ID: %s\r\n", ast_sorcery_object_get_id(contact));
2765 ast_str_append(&buf, 0, "AuthenticateQualify: %d\r\n", contact->authenticate_qualify);
2766 ast_str_append(&buf, 0, "OutboundProxy: %s\r\n", contact->outbound_proxy);
2767 ast_str_append(&buf, 0, "Path: %s\r\n", contact->path);
2768 ast_str_append(&buf, 0, "QualifyFrequency: %u\r\n", contact->qualify_frequency);
2769 ast_str_append(&buf, 0, "QualifyTimeout: %.3f\r\n", contact->qualify_timeout);
2770 ast_str_append(&buf, 0, "Qualify2xxOnly: %d\r\n", contact->qualify_2xx_only);
2771
2772 astman_append(ami->s, "%s\r\n", ast_str_buffer(buf));
2773 ami->count++;
2774
2775 ast_free(buf);
2777 return 0;
2778}
2779
2780static int format_contact_status_for_aor(void *obj, void *arg, int flags)
2781{
2782 struct ast_sip_aor *aor = obj;
2783
2785}
2786
2787static int format_ami_contact_status(const struct ast_sip_endpoint *endpoint,
2788 struct ast_sip_ami *ami)
2789{
2790 ami->arg = (void *)endpoint;
2792}
2793
2797
2798/*!
2799 * \brief Management task to clean up an AOR
2800 * \note Run by aor_options->serializer
2801 */
2802static int sip_options_cleanup_aor_task(void *obj)
2803{
2804 struct sip_options_aor *aor_options = obj;
2805
2806 ast_debug(2, "Cleaning up AOR '%s' for shutdown\n", aor_options->name);
2807
2808 aor_options->qualify_frequency = 0;
2809 if (aor_options->sched_task) {
2811 ao2_ref(aor_options->sched_task, -1);
2812 aor_options->sched_task = NULL;
2813 }
2815
2816 return 0;
2817}
2818
2819/*!
2820 * \brief Management task to clean up the environment
2821 * \note Run by management_serializer
2822 */
2823static int sip_options_cleanup_task(void *obj)
2824{
2825 struct ao2_iterator it_aor;
2826 struct sip_options_aor *aor_options;
2827
2828 if (!sip_options_aors) {
2829 /* Nothing to do */
2830 return 0;
2831 }
2832
2834 for (; (aor_options = ao2_iterator_next(&it_aor)); ao2_ref(aor_options, -1)) {
2836 sip_options_cleanup_aor_task, aor_options);
2837 }
2838 ao2_iterator_destroy(&it_aor);
2839
2840 return 0;
2841}
2842
2875
2876/*!
2877 * \brief Management task to finish setting up the environment.
2878 * \note Run by management_serializer
2879 */
2880static int sip_options_init_task(void *mgmt_serializer)
2881{
2882 management_serializer = mgmt_serializer;
2883
2886 return -1;
2887 }
2890 return -1;
2891 }
2894 return -1;
2895 }
2896
2898
2899 return 0;
2900}
2901
2907
2909{
2910 struct ast_taskprocessor *mgmt_serializer;
2911
2912 static const pj_str_t STR_OPTIONS = { "OPTIONS", 7 };
2913
2914 if (reload) {
2916 return 0;
2917 }
2918
2919 if (pjsip_endpt_register_module(ast_sip_get_pjsip_endpoint(), &options_module)
2920 != PJ_SUCCESS) {
2921 return -1;
2922 }
2923
2924 if (pjsip_endpt_add_capability(ast_sip_get_pjsip_endpoint(), NULL, PJSIP_H_ALLOW,
2925 NULL, 1, &STR_OPTIONS) != PJ_SUCCESS) {
2927 return -1;
2928 }
2929
2931 sip_options_aor_hash_fn, NULL, sip_options_aor_cmp_fn);
2932 if (!sip_options_aors) {
2934 return -1;
2935 }
2939 sip_options_endpoint_state_compositor_hash_fn, NULL,
2940 sip_options_endpoint_state_compositor_cmp_fn);
2943 return -1;
2944 }
2945
2946 mgmt_serializer = ast_sip_create_serializer("pjsip/options/manage");
2947 if (!mgmt_serializer) {
2949 return -1;
2950 }
2951
2952 /*
2953 * Set the water mark levels high because we can get a flood of
2954 * contact status updates from sip_options_synchronize() that
2955 * quickly clears on initial load or reload.
2956 */
2957 ast_taskprocessor_alert_set_levels(mgmt_serializer, -1,
2959
2960 /*
2961 * We make sure that the environment is completely setup before we allow
2962 * any other threads to post contact_status updates to the
2963 * management_serializer.
2964 */
2966 mgmt_serializer)) {
2967 /* Set management_serializer in case pushing the task actually failed. */
2968 management_serializer = mgmt_serializer;
2970 return -1;
2971 }
2972
2978
2979 return 0;
2980}
void ast_cli_unregister_multiple(void)
Definition ael_main.c:408
jack_status_t status
Definition app_jack.c:149
char * strsep(char **str, const char *delims)
Asterisk main include file. File version handling, generic pbx functions.
int ast_shutting_down(void)
Definition asterisk.c:1889
#define ast_free(a)
Definition astmm.h:180
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition astmm.h:298
#define ast_malloc(len)
A wrapper for malloc()
Definition astmm.h:191
#define ast_log
Definition astobj2.c:42
int ao2_container_dup(struct ao2_container *dest, struct ao2_container *src, enum search_flags flags)
Copy all object references in the src container into the dest container.
#define ao2_iterator_next(iter)
Definition astobj2.h:1911
#define ao2_link(container, obj)
Add an object to a container.
Definition astobj2.h:1532
@ CMP_MATCH
Definition astobj2.h:1027
@ CMP_STOP
Definition astobj2.h:1028
@ AO2_ALLOC_OPT_LOCK_NOLOCK
Definition astobj2.h:367
@ AO2_ALLOC_OPT_LOCK_RWLOCK
Definition astobj2.h:365
@ AO2_ALLOC_OPT_LOCK_MUTEX
Definition astobj2.h:363
#define ao2_callback(c, flags, cb_fn, arg)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container,...
Definition astobj2.h:1693
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
#define AO2_STRING_FIELD_CMP_FN(stype, field)
Creates a compare function for a structure string field.
Definition astobj2.h:2048
#define ao2_cleanup(obj)
Definition astobj2.h:1934
#define ao2_unlink(container, obj)
Remove an object from a container.
Definition astobj2.h:1578
@ AO2_ITERATOR_UNLINK
Definition astobj2.h:1863
#define ao2_link_flags(container, obj, flags)
Add an object to a container.
Definition astobj2.h:1554
#define ao2_find(container, arg, flags)
Definition astobj2.h:1736
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
#define AO2_STRING_FIELD_SORT_FN(stype, field)
Creates a sort function for a structure string field.
Definition astobj2.h:2064
#define ao2_unlock(a)
Definition astobj2.h:729
#define ao2_lock(a)
Definition astobj2.h:717
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition astobj2.h:459
#define ao2_alloc_options(data_size, destructor_fn, options)
Definition astobj2.h:404
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
Definition astobj2.h:480
#define AO2_STRING_FIELD_HASH_FN(stype, field)
Creates a hash function for a structure string field.
Definition astobj2.h:2032
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
@ OBJ_SEARCH_OBJECT
The arg parameter is an object of the same type.
Definition astobj2.h:1087
@ OBJ_NOLOCK
Assume that the ao2_container is already locked.
Definition astobj2.h:1063
@ OBJ_NODATA
Definition astobj2.h:1044
@ OBJ_MULTIPLE
Definition astobj2.h:1049
@ OBJ_UNLINK
Definition astobj2.h:1039
@ OBJ_SEARCH_KEY
The arg parameter is a search key, but is not an object.
Definition astobj2.h:1101
#define ao2_alloc(data_size, destructor_fn)
Definition astobj2.h:409
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Allocate and initialize a hash container with the desired number of buckets.
Definition astobj2.h:1303
#define ao2_container_clone(orig, flags)
Create a clone/copy of the given container.
Definition astobj2.h:1419
@ AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT
Reject objects with duplicate keys in container.
Definition astobj2.h:1188
@ AO2_CONTAINER_ALLOC_OPT_DUPS_REPLACE
Replace objects with duplicate keys in container.
Definition astobj2.h:1211
static int available(struct dahdi_pvt **pvt, int is_specific_channel)
General Asterisk PBX channel definitions.
#define AST_MAX_EXTENSION
Definition channel.h:134
Standard Command Line Interface.
#define CLI_SHOWUSAGE
Definition cli.h:45
#define CLI_SUCCESS
Definition cli.h:44
#define AST_CLI_DEFINE(fn, txt,...)
Definition cli.h:197
void ast_cli(int fd, const char *fmt,...)
Definition clicompat.c:6
@ CLI_INIT
Definition cli.h:152
@ CLI_GENERATE
Definition cli.h:153
#define CLI_FAILURE
Definition cli.h:46
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition cli.h:265
char buf[BUFSIZE]
Definition eagi_proxy.c:66
ast_endpoint_state
Valid states for an endpoint.
Definition endpoints.h:51
@ AST_ENDPOINT_OFFLINE
Definition endpoints.h:55
@ AST_ENDPOINT_ONLINE
Definition endpoints.h:57
static const char name[]
Definition format_mp3.c:68
void astman_send_listack(struct mansession *s, const struct message *m, char *msg, char *listflag)
Send ack in manager transaction to begin a list.
Definition manager.c:1963
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Definition manager.c:1921
void astman_send_list_complete_start(struct mansession *s, const struct message *m, const char *event_name, int count)
Start the list complete event.
Definition manager.c:1999
void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
Send ack in manager transaction.
Definition manager.c:1953
const char * astman_get_header(const struct message *m, char *var)
Get header from manager transaction.
Definition manager.c:1582
void astman_send_list_complete_end(struct mansession *s)
End the list complete event.
Definition manager.c:2007
void astman_append(struct mansession *s, const char *fmt,...)
Definition manager.c:1842
int ast_manager_unregister(const char *action)
Unregister a registered manager command.
Definition manager.c:7782
struct ast_taskprocessor * ast_sip_get_distributor_serializer_hash(int hash)
Determine the distributor serializer for a given hash.
#define ast_sip_push_task(serializer, sip_task, task_data)
Definition res_pjsip.h:2126
struct ast_taskprocessor * ast_sip_create_serializer(const char *name)
Create a new serializer for SIP tasks.
Definition res_pjsip.c:2092
struct ast_sip_sched_task * ast_sip_schedule_task(struct ast_taskprocessor *serializer, int interval, ast_sip_task sip_task, const char *name, void *task_data, enum ast_sip_scheduler_task_flags flags)
Schedule a task to run in the res_pjsip taskpool.
int ast_sip_sched_task_cancel(struct ast_sip_sched_task *schtd)
Cancels the next invocation of a task.
#define ast_sip_push_task_wait_serializer(serializer, sip_task, task_data)
Definition res_pjsip.h:2221
@ AST_SIP_SCHED_TASK_DATA_AO2
Definition res_pjsip.h:2274
@ AST_SIP_SCHED_TASK_VARIABLE
Definition res_pjsip.h:2257
static char prefix[MAX_PREFIX]
Definition http.c:145
#define ast_debug(level,...)
Log a DEBUG message.
#define LOG_ERROR
#define ast_verb(level,...)
#define LOG_WARNING
static struct ao2_container * endpoints
#define EVENT_FLAG_REPORTING
Definition manager.h:84
#define EVENT_FLAG_SYSTEM
Definition manager.h:75
#define ast_manager_register_xml(action, authority, func)
Register a manager callback using XML documentation to describe the manager.
Definition manager.h:193
Core PBX routines and definitions.
int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
Determine whether an extension exists.
Definition pbx.c:2735
static pjsip_module options_module
static void aor_observer_deleted(const void *obj)
Observer callback invoked on AOR deletion.
static pj_status_t send_options_response(pjsip_rx_data *rdata, int code)
int ast_res_pjsip_preinit_options_handling(void)
static struct ao2_container * sip_options_aors
static int sip_options_contact_status_available_count(void *obj, void *arg, int flags)
Count AVAILABLE qualified contacts.
#define ENDPOINT_STATE_COMPOSITOR_INITIAL_SIZE
The initial vector size for the endpoint state compositors on an AOR.
static void sip_contact_status_dtor(void *obj)
Destructor for contact statuses.
static int sip_options_synchronize_aor_task(void *obj)
Task to synchronize an AOR with our local state.
static void sip_options_endpoint_unlink_aor_feeders(struct ast_sip_endpoint *endpoint, struct sip_options_endpoint_state_compositor *endpoint_state_compositor)
Unlink AORs feeding the endpoint status compositor.
static char * cli_reload_qualify_endpoint(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static void sip_options_aor_dtor(void *obj)
Destructor function for SIP OPTIONS AORs.
static char * cli_qualify(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static int sip_options_endpoint_observer_modified_task(void *obj)
Task to synchronize the endpoint.
static int sip_options_aor_observer_deleted_task(void *obj)
Task to delete an AOR from the known universe.
static struct ast_taskprocessor * management_serializer
static int sip_options_contact_update_task(void *obj)
Task which updates a dynamic contact to an AOR.
#define DEFAULT_ENCODING
static void endpoint_observer_modified(const void *obj)
Observer callback invoked on endpoint creation or modification.
static void aor_observer_modified(const void *obj)
Observer callback invoked on AOR creation or modification.
#define DEFAULT_LANGUAGE
static void sip_options_synchronize(int reload)
Synchronize our local container of AORs and endpoint state compositors with the current configuration...
static struct ao2_container * get_all_contacts(void)
static void contact_observer_created(const void *obj)
Observer callback invoked on contact creation.
static void contact_observer_deleted(const void *obj)
Observer callback invoked on contact deletion.
static void sip_options_endpoint_state_compositor_dtor(void *obj)
Destructor for endpoint state compositors.
static struct sip_options_endpoint_state_compositor * sip_options_endpoint_state_compositor_find_or_alloc(const struct ast_sip_endpoint *endpoint)
Find (or create) an endpoint state compositor.
#define AOR_STATUS_BUCKETS
These are the number of buckets (per endpoint state compositor) to use to store AOR statuses.
static void qualify_contact_cb(void *token, pjsip_event *e)
Callback for when we get a result from a SIP OPTIONS request (a response or a timeout)
static struct sip_options_contact_callback_data * sip_options_contact_callback_data_alloc(struct ast_sip_contact *contact, struct sip_options_aor *aor_options)
Contact callback data allocator.
static int sip_options_set_contact_status_unqualified(void *obj, void *arg, int flags)
Transition the contact status to unqualified mode.
int ast_res_pjsip_init_options_handling(int reload)
static void contact_observer_updated(const void *obj)
Observer callback invoked on contact update.
static int sip_options_endpoint_observer_deleted_task(void *obj)
Task to delete an endpoint from the known universe.
static int sip_contact_to_ami(const struct ast_sip_contact *contact, struct ast_str **buf)
static int sip_options_aor_observer_modified_task(void *obj)
Task to synchronize the AOR.
static const struct ast_sorcery_observer endpoint_observer_callbacks
Observer callbacks for endpoints.
static int sip_options_contact_add_management_task(void *obj)
Task to add a dynamic contact to an AOR in its serializer.
static const char * short_status_map[]
static int sip_options_aor_remove_task(void *obj)
Task which removes an AOR from all of the ESCs it is reporting to.
static struct ao2_container * sip_options_contact_statuses
static int sip_options_cleanup_aor_task(void *obj)
Management task to clean up an AOR.
#define CONTACT_STATUS_BUCKETS
These are the number of contact status buckets.
static int format_ami_contactlist_handler(void *obj, void *arg, int flags)
static int sip_options_unused_aor(void *obj, void *arg, int flags)
Callback which removes any unused AORs that remained after reloading.
static char * cli_reload_qualify_aor(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static int ami_sip_qualify(struct mansession *s, const struct message *m)
static char * cli_show_qualify_endpoint(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static struct ao2_container * sip_options_contact_statuses_alloc(void)
Helper function to allocate a contact statuses container.
const char * ast_sip_get_contact_short_status_label(const enum ast_sip_contact_status_type status)
static int sip_options_qualify_aor(void *obj)
Task to qualify contacts of an AOR.
static int sip_options_unused_endpoint_state_compositor(void *obj, void *arg, int flags)
Callback function used to unlink and remove event state compositors that have no AORs feeding them.
static int sip_options_endpoint_compositor_remove_task(void *obj)
Task which adds removes an AOR from an endpoint state compositor.
int ast_sip_format_contact_ami(void *obj, void *arg, int flags)
Formats the contact and sends over AMI.
static int sip_options_endpoint_compositor_add_task(void *obj)
Task which adds an AOR to an endpoint state compositor.
void ast_res_pjsip_cleanup_options_handling(void)
static int sip_options_contact_delete_management_task(void *obj)
Task to delete a contact from an AOR in its serializer.
#define ENDPOINT_STATE_COMPOSITOR_BUCKETS
These are the number of buckets to store endpoint state compositors.
static struct ao2_container * sip_options_endpoint_state_compositors
static void sip_options_apply_aor_configuration(struct sip_options_aor *aor_options, struct ast_sip_aor *aor, int is_new)
Function which applies configuration to an AOR options structure.
static int sip_options_synchronize_endpoint(void *obj, void *arg, int flags)
Synchronize an endpoint with our local state.
static int sip_options_contact_status_notify_task(void *obj)
Task to notify an AOR of a contact status change.
static pj_bool_t options_on_rx_request(pjsip_rx_data *rdata)
#define AOR_BUCKETS
These are the number of buckets to store AORs in.
static int format_contact_status_for_aor(void *obj, void *arg, int flags)
static int sip_options_set_contact_status_qualified(void *obj, void *arg, int flags)
Transition the contact status to qualified mode.
static int sip_options_qualify_contact(void *obj, void *arg, int flags)
Send a SIP OPTIONS request for a contact.
static void sip_options_remove_contact_status(struct sip_options_aor *aor_options, struct ast_sip_contact *contact)
Remove contact status for a hint.
static char * cli_show_qualify_aor(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static struct sip_options_aor * sip_options_aor_alloc(struct ast_sip_aor *aor)
Allocator for AOR OPTIONS.
static void endpoint_observer_deleted(const void *obj)
Observer callback invoked on endpoint deletion.
static struct ast_cli_entry cli_options[]
static int sip_options_cleanup_task(void *obj)
Management task to clean up the environment.
static int sip_options_remove_contact(void *obj, void *arg, int flags)
Forward declaration of this helpful function.
static void sip_options_notify_endpoint_state_compositors(struct sip_options_aor *aor_options, enum ast_sip_contact_status_type status)
Function which notifies endpoint state compositors of a state change of an AOR.
static int sip_options_synchronize_task(void *obj)
Task to synchronize our local container of AORs and endpoint state compositors with the current confi...
static void sip_options_contact_callback_data_dtor(void *obj)
Destructor for contact callback data.
static void sip_options_publish_contact_state(const struct sip_options_aor *aor_options, const struct ast_sip_contact_status *contact_status)
Function which publishes a contact status update to all interested endpoints.
static const struct ast_sorcery_observer aor_observer_callbacks
Observer callbacks for AORs.
static enum ast_endpoint_state sip_options_get_endpoint_state_compositor_state(const struct sip_options_endpoint_state_compositor *endpoint_state_compositor)
Return the current state of an endpoint state compositor.
static void sip_options_contact_status_update(struct ast_sip_contact_status *contact_status)
static void sip_options_set_contact_status(struct ast_sip_contact_status *contact_status, enum ast_sip_contact_status_type status)
Set the contact status for a contact.
static int sip_options_synchronize_aor(void *obj, void *arg, int flags)
Synchronize an AOR with our local state.
static int sip_options_contact_delete_task(void *obj)
Task which deletes a dynamic contact from an AOR.
static int ami_show_contacts(struct mansession *s, const struct message *m)
static void sip_options_update_endpoint_state_compositor_aor(struct sip_options_endpoint_state_compositor *endpoint_state_compositor, const char *name, enum ast_sip_contact_status_type status)
Update the AOR status on an endpoint state compositor.
static int sip_options_determine_initial_qualify_time(int qualify_frequency)
Determine an initial time for scheduling AOR qualifying.
struct ast_sip_contact_status * ast_res_pjsip_find_or_create_contact_status(const struct ast_sip_contact *contact)
static int contact_status_publish_update_task(void *obj)
Task to notify endpoints of a contact status change.
static int format_ami_contact_status(const struct ast_sip_endpoint *endpoint, struct ast_sip_ami *ami)
struct ast_sip_contact_status * ast_sip_get_contact_status(const struct ast_sip_contact *contact)
Retrieve the current status for a contact.
static int sip_options_contact_add_task(void *obj)
Task which adds a dynamic contact to an AOR.
static const struct ast_sorcery_observer contact_observer_callbacks
Observer callbacks for contacts.
const char * ast_sip_get_contact_status_label(const enum ast_sip_contact_status_type status)
translate ast_sip_contact_status_type to character string.
static struct ast_sip_endpoint_formatter contact_status_formatter
static int has_qualify_changed(const struct ast_sip_contact *contact, const struct sip_options_aor *aor_options)
Check if the contact qualify options are different than local aor qualify options.
static int sip_options_update_aor_task(void *obj)
Task to synchronize an AOR with our local state.
#define CONTACT_BUCKETS
These are the number of buckets (per AOR) to use to store contacts.
static struct ast_sip_contact_status * sip_contact_status_copy(const struct ast_sip_contact_status *src)
static int sip_options_init_task(void *mgmt_serializer)
Management task to finish setting up the environment.
static struct ast_sip_contact_status * sip_contact_status_alloc(const char *name)
static int reload(void)
const pj_str_t * ast_sip_pjsip_uri_get_username(pjsip_uri *uri)
Get the user portion of the pjsip_uri.
Definition res_pjsip.c:3452
unsigned int ast_sip_get_max_initial_qualify_time(void)
Retrieve the system max initial qualify time.
void ast_sip_persistent_endpoint_publish_contact_state(const char *endpoint_name, const struct ast_sip_contact_status *contact_status)
Publish the change of state for a contact.
void ast_sip_security_mechanisms_vector_copy(struct ast_sip_security_mechanism_vector *dst, const struct ast_sip_security_mechanism_vector *src)
Duplicate a security mechanism.
int ast_sip_create_response(const pjsip_rx_data *rdata, int st_code, struct ast_sip_contact *contact, pjsip_tx_data **p_tdata)
General purpose method for creating a SIP response.
Definition res_pjsip.c:2443
int ast_sip_is_allowed_uri(pjsip_uri *uri)
Check whether a pjsip_uri is allowed or not.
Definition res_pjsip.c:3447
int ast_sip_for_each_contact(const struct ast_sip_aor *aor, ao2_callback_fn on_contact, void *arg)
For every contact on an AOR call the given 'on_contact' handler.
Definition location.c:723
int ast_sip_for_each_aor(const char *aors, ao2_callback_fn on_aor, void *arg)
For every aor in the comma separated aors string call the given 'on_aor' handler.
Definition location.c:688
pjsip_endpoint * ast_sip_get_pjsip_endpoint(void)
Get a pointer to the PJSIP endpoint.
Definition res_pjsip.c:518
unsigned int ast_sip_get_send_contact_status_on_update_registration(void)
Retrieve the global setting 'send_contact_status_on_update_registration'.
#define AST_SIP_USER_OPTIONS_TRUNCATE_CHECK(str)
Truncate the URI user field options string if enabled.
Definition res_pjsip.h:3561
struct ast_sip_endpoint * ast_pjsip_rdata_get_endpoint(pjsip_rx_data *rdata)
Get the looked-up endpoint on an out-of dialog request or response.
void ast_copy_pj_str(char *dest, const pj_str_t *src, size_t size)
Copy a pj_str_t into a standard character buffer.
Definition res_pjsip.c:2176
void ast_sip_security_mechanisms_vector_destroy(struct ast_sip_security_mechanism_vector *security_mechanisms)
Free contents of a security mechanism vector.
int ast_sip_send_out_of_dialog_request(pjsip_tx_data *tdata, struct ast_sip_endpoint *endpoint, int timeout, void *token, void(*callback)(void *token, pjsip_event *e))
General purpose method for sending an Out-Of-Dialog SIP request.
Definition res_pjsip.c:1936
int ast_sip_persistent_endpoint_update_state(const char *endpoint_name, enum ast_endpoint_state state)
Change state of a persistent endpoint.
void ast_sip_register_endpoint_formatter(struct ast_sip_endpoint_formatter *obj)
Register an endpoint formatter.
Definition res_pjsip.c:479
void ast_sip_unregister_endpoint_formatter(struct ast_sip_endpoint_formatter *obj)
Unregister an endpoint formatter.
Definition res_pjsip.c:485
int ast_sip_sorcery_object_to_ami(const void *obj, struct ast_str **buf)
Converts a sorcery object to a string of object properties.
int ast_sip_set_outbound_proxy(pjsip_tx_data *tdata, const char *proxy)
Set the outbound proxy for an outbound SIP message.
Definition res_pjsip.c:1990
int ast_sip_create_request(const char *method, struct pjsip_dialog *dlg, struct ast_sip_endpoint *endpoint, const char *uri, struct ast_sip_contact *contact, pjsip_tx_data **tdata)
General purpose method for creating a SIP request.
Definition res_pjsip.c:1433
struct ast_str * ast_sip_create_ami_event(const char *event, struct ast_sip_ami *ami)
Creates a string to store AMI event data in.
int ast_sip_add_header(pjsip_tx_data *tdata, const char *name, const char *value)
Add a header to an outbound SIP message.
Definition res_pjsip.c:2006
struct ast_sorcery * ast_sip_get_sorcery(void)
Get a pointer to the SIP sorcery structure.
int ast_sip_send_stateful_response(pjsip_rx_data *rdata, pjsip_tx_data *tdata, struct ast_sip_endpoint *sip_endpoint)
Send a stateful response to an out of dialog request.
Definition res_pjsip.c:2399
ast_sip_contact_status_type
Status type for a contact.
Definition res_pjsip.h:436
@ AVAILABLE
Definition res_pjsip.h:440
@ UNAVAILABLE
Definition res_pjsip.h:438
@ REMOVED
Definition res_pjsip.h:445
@ UNKNOWN
Definition res_pjsip.h:442
@ CREATED
Definition res_pjsip.h:444
#define NULL
Definition resample.c:96
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition sorcery.c:2381
void ast_sorcery_observer_remove(const struct ast_sorcery *sorcery, const char *type, const struct ast_sorcery_observer *callbacks)
Remove an observer from a specific object type.
Definition sorcery.c:2487
@ AST_RETRIEVE_FLAG_MULTIPLE
Return all matching objects.
Definition sorcery.h:120
@ AST_RETRIEVE_FLAG_ALL
Perform no matching, return all objects.
Definition sorcery.h:123
void * ast_sorcery_retrieve_by_id(const struct ast_sorcery *sorcery, const char *type, const char *id)
Retrieve an object using its unique identifier.
Definition sorcery.c:1917
int ast_sorcery_observer_add(const struct ast_sorcery *sorcery, const char *type, const struct ast_sorcery_observer *callbacks)
Add an observer to a specific object type.
Definition sorcery.c:2455
int ast_sorcery_object_id_compare(void *obj, void *arg, int flags)
ao2 object comparator based on sorcery id.
Definition sorcery.c:2528
int ast_sorcery_object_id_sort(const void *obj, const void *arg, int flags)
ao2 object sorter based on sorcery id.
Definition sorcery.c:2504
int ast_sorcery_object_id_hash(const void *obj, int flags)
ao2 object hasher based on sorcery id.
Definition sorcery.c:2539
void * ast_sorcery_retrieve_by_fields(const struct ast_sorcery *sorcery, const char *type, unsigned int flags, struct ast_variable *fields)
Retrieve an object or multiple objects using specific fields.
Definition sorcery.c:1961
struct ao2_container * ast_sorcery_retrieve_by_prefix(const struct ast_sorcery *sorcery, const char *type, const char *prefix, const size_t prefix_len)
Retrieve multiple objects whose id begins with the specified prefix.
Definition sorcery.c:2053
void AST_OPTIONAL_API_NAME() ast_statsd_log_string_va(const char *metric_name, const char *metric_type, const char *value, double sample_rate,...)
Send a stat to the configured statsd server.
Definition res_statsd.c:205
#define AST_STATSD_TIMER
Definition statsd.h:41
#define AST_STATSD_GAUGE
Support for publishing to a statsd server.
Definition statsd.h:32
void AST_OPTIONAL_API_NAME() ast_statsd_log_full_va(const char *metric_name, const char *metric_type, intmax_t value, double sample_rate,...)
Send a stat to the configured statsd server.
Definition res_statsd.c:228
#define ast_string_fields_copy(copy, orig)
Copy all string fields from one instance to another of the same structure.
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition strings.h:1139
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one.
Definition strings.h:80
static force_inline int attribute_pure ast_str_hash(const char *str)
Compute a hash value on a string.
Definition strings.h:1259
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition strings.h:65
char *attribute_pure ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition strings.h:761
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
Definition strings.h:223
Generic container type.
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition astobj2.h:1821
descriptor for a cli entry.
Definition cli.h:171
char * command
Definition cli.h:186
const char * usage
Definition cli.h:177
AMI variable container.
Definition res_pjsip.h:3257
struct mansession * s
Definition res_pjsip.h:3259
const struct message * m
Definition res_pjsip.h:3261
A SIP address of record.
Definition res_pjsip.h:480
double qualify_timeout
Definition res_pjsip.h:508
int qualify_2xx_only
Definition res_pjsip.h:514
struct ao2_container * permanent_contacts
Definition res_pjsip.h:504
int authenticate_qualify
Definition res_pjsip.h:498
unsigned int qualify_frequency
Definition res_pjsip.h:496
A contact's status.
Definition res_pjsip.h:453
const ast_string_field uri
Definition res_pjsip.h:459
enum ast_sip_contact_status_type status
Definition res_pjsip.h:470
enum ast_sip_contact_status_type last_status
Definition res_pjsip.h:472
const ast_string_field aor
Definition res_pjsip.h:459
struct ast_sip_security_mechanism_vector security_mechanisms
Definition res_pjsip.h:468
A wrapper for contact that adds the aor_id and a consistent contact id. Used by ast_sip_for_each_cont...
Definition res_pjsip.h:521
struct ast_sip_contact * contact
Definition res_pjsip.h:527
Contact associated with an address of record.
Definition res_pjsip.h:392
const ast_string_field uri
Definition res_pjsip.h:414
double qualify_timeout
Definition res_pjsip.h:422
const ast_string_field via_addr
Definition res_pjsip.h:414
const ast_string_field call_id
Definition res_pjsip.h:414
const ast_string_field aor
Definition res_pjsip.h:414
const ast_string_field outbound_proxy
Definition res_pjsip.h:414
struct timeval expiration_time
Definition res_pjsip.h:416
const ast_string_field path
Definition res_pjsip.h:414
const ast_string_field endpoint_name
Definition res_pjsip.h:414
int authenticate_qualify
Definition res_pjsip.h:420
const ast_string_field user_agent
Definition res_pjsip.h:414
unsigned int qualify_frequency
Definition res_pjsip.h:418
An entity responsible formatting endpoint information.
Definition res_pjsip.h:3283
int(* format_ami)(const struct ast_sip_endpoint *endpoint, struct ast_sip_ami *ami)
Callback used to format endpoint information over AMI.
Definition res_pjsip.h:3287
An entity with which Asterisk communicates.
Definition res_pjsip.h:1067
const ast_string_field aors
Definition res_pjsip.h:1096
Interface for a sorcery object type observer.
Definition sorcery.h:332
void(* created)(const void *object)
Callback for when an object is created.
Definition sorcery.h:334
Support for dynamic strings.
Definition strings.h:623
A ast_taskprocessor structure is a singleton by name.
In case you didn't read that giant block of text above the mansession_session struct,...
Definition manager.c:314
Structure which contains an AOR and contacts for qualifying purposes.
double qualify_timeout
Qualify timeout. 0 is diabled.
struct ao2_container * contacts
All contacts associated with this AOR.
int qualify_2xx_only
If true only authenticate if OPTIONS response is 2XX.
struct sip_options_aor::@491 compositors
The endpoint state compositors we are feeding, a reference is held to each.
struct ao2_container * dynamic_contacts
Only dynamic contacts associated with this AOR.
struct ast_taskprocessor * serializer
The serializer for this AOR.
struct ast_sip_sched_task * sched_task
The scheduler task for this AOR.
unsigned int available
The number of available contacts on this AOR.
unsigned int qualify_frequency
Frequency to send OPTIONS requests to AOR contacts. 0 is disabled.
char name[0]
The name of the AOR.
Structure used to contain information for an OPTIONS callback.
struct ast_sip_contact * contact
The contact we qualified.
struct timeval rtt_start
The time at which this OPTIONS attempt was started.
enum ast_sip_contact_status_type status
The new status of the contact.
struct sip_options_aor * aor_options
The AOR options.
Task details for adding an AOR to an endpoint state compositor.
struct ast_sip_contact * contact
The contact itself.
struct sip_options_aor * aor_options
The AOR options that the contact is referring to.
Structure which contains status information for an AOR feeding an endpoint state compositor.
char available
The last contributed available status of the named AOR (1 if available, 0 if not available)
char name[0]
The name of the AOR.
Task details for adding an AOR to an endpoint state compositor.
struct sip_options_endpoint_state_compositor * endpoint_state_compositor
The endpoint state compositor.
struct sip_options_aor * aor_options
The AOR options that the endpoint state compositor should be added to.
Structure which contains composites information for endpoint state.
char active
Non-zero if the compositor is in normal operation. i.e. Not being setup/reconfigured.
struct ao2_container * aor_statuses
The last contributed available status of the AORs feeding this compositor.
char name[0]
The name of the endpoint.
Task data for AOR creation or updating.
struct sip_options_aor * aor_options
The AOR options for this AOR.
int added
Whether this AOR is being added.
struct ast_sip_aor * aor
The AOR which contains the new configuraton.
struct ao2_container * existing
Optional container of existing AOR s.
Structure which contains information required to synchronize.
int reload
Whether this is a reload or not.
userdata associated with baseline taskprocessor test
An API for managing task processing threads that can be shared across modules.
void * ast_taskprocessor_unreference(struct ast_taskprocessor *tps)
Unreference the specified taskprocessor and its reference count will decrement.
const char * ast_taskprocessor_name(struct ast_taskprocessor *tps)
Return the name of the taskprocessor singleton.
#define AST_TASKPROCESSOR_HIGH_WATER_LEVEL
int ast_taskprocessor_alert_set_levels(struct ast_taskprocessor *tps, long low_water, long high_water)
Set the high and low alert water marks of the given taskprocessor queue.
Test Framework API.
#define ast_test_suite_event_notify(s, f,...)
Definition test.h:189
static struct test_val a
Time-related functions and macros.
int64_t ast_tvdiff_us(struct timeval end, struct timeval start)
Computes the difference (in microseconds) between two struct timeval instances.
Definition time.h:87
int ast_time_t_to_string(time_t time, char *buf, size_t length)
Converts to a string representation of a time_t as decimal seconds since the epoch....
Definition time.c:152
#define AST_TIME_T_LEN
Definition time.h:45
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition time.h:159
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition utils.h:981
#define ast_assert(a)
Definition utils.h:779
#define ARRAY_LEN(a)
Definition utils.h:706
#define ast_random_double()
Returns a random number between 0.0 and 1.0, inclusive.
Definition utils.h:664
#define AST_VECTOR_RESET(vec, cleanup)
Reset vector.
Definition vector.h:653
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition vector.h:637
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
Definition vector.h:185
#define AST_VECTOR_REMOVE(vec, idx, preserve_ordered)
Remove an element from a vector by index.
Definition vector.h:440
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
Definition vector.h:124
#define AST_VECTOR_APPEND(vec, elem)
Append an element to a vector, growing the vector if needed.
Definition vector.h:267
#define AST_VECTOR(name, type)
Define a vector structure.
Definition vector.h:44
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition vector.h:708