Asterisk - The Open Source Telephony Project GIT-master-3dae2cf
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#include "asterisk/threadpool.h"
37
38/*
39 * This implementation for OPTIONS support is based around the idea
40 * that realistically an AOR generally has very few contacts and is
41 * referenced by only a few endpoints. While it is perfectly fine for
42 * use in opposite scenarios it works best in the above case. It is
43 * also not shy to keeping state but it is reactive to outside changes
44 * so it can be updated.
45 *
46 * The lowest level object in here is a contact and its associated
47 * contact status. The result of an OPTIONS request to a contact is
48 * reflected in the contact status. The scheduling of these OPTIONS
49 * request is driven by the AOR. The AOR periodicially (according to
50 * configuration) sends OPTIONS requests out to any contacts
51 * associated with it. Contacts themselves are not individually
52 * scheduled. Contacts can be added or deleted as appropriate with no
53 * requirement to reschedule.
54 *
55 * The next level object up is the AOR itself. The result of a contact
56 * status change is fed into it and the result composited with all
57 * other contacts. This may result in the AOR itself changing state
58 * (it can be either AVAILABLE or UNAVAILABLE).
59 *
60 * The highest level object up is the endpoint state compositor (ESC).
61 * The result of AOR state changes is fed into it and the result
62 * composited with all other referenced AORs. This may result in the
63 * endpoint itself changing state (it can be either ONLINE or
64 * OFFLINE). If this occurs the permanent endpoint is updated to
65 * reflect it.
66 *
67 * The threading model errs on the side of a world where things are
68 * not constantly changing. That is: A world where AORs and endpoints
69 * are not being constantly added/removed. This more closely mirrors
70 * the usage of the vast majority of people. This scenario can still
71 * be done but it may not be applied immediately.
72 *
73 * Manipulation of which AORs, endpoint state compositors, and
74 * contacts exist is done within a single serializer. This ensures
75 * that no matter the source threads order is preserved and you won't
76 * get into a weird situation where things are referencing other
77 * things that should have already been destroyed.
78 *
79 * Operations which impact the state of an AOR are done within a
80 * serializer that is specific to the AOR. This includes the result of
81 * a contact status change. This change is queued and executed on the
82 * AOR serializer afterwards.
83 *
84 * Operations which impact an endpoint state compositor are protected
85 * by a lock. This is done as the endpoint state compositor usage is
86 * minimal and the overhead of using a serializer and queueing things
87 * is not warranted.
88 *
89 * AORs which do not have a qualify frequency are also kept in here
90 * but do not require the same criteria as qualified AORs to be
91 * considered available. In their case as long as at least 1 contact
92 * is configured on the AOR (or added to it by registration) it is
93 * considered available.
94 */
95
96#define DEFAULT_LANGUAGE "en"
97#define DEFAULT_ENCODING "identity"
98
99/*! \brief These are the number of buckets to store AORs in */
100#ifdef LOW_MEMORY
101#define AOR_BUCKETS 61
102#else
103#define AOR_BUCKETS 1567
104#endif
105
106/*! \brief These are the number of contact status buckets */
107#ifdef LOW_MEMORY
108#define CONTACT_STATUS_BUCKETS 61
109#else
110#define CONTACT_STATUS_BUCKETS 1567
111#endif
112
113/*! \brief These are the number of buckets (per AOR) to use to store contacts */
114#define CONTACT_BUCKETS 13
115
116/*! \brief These are the number of buckets to store endpoint state compositors */
117#define ENDPOINT_STATE_COMPOSITOR_BUCKETS 13
118
119/*! \brief The initial vector size for the endpoint state compositors on an AOR */
120#define ENDPOINT_STATE_COMPOSITOR_INITIAL_SIZE 1
121
122/*! \brief These are the number of buckets (per endpoint state compositor) to use to store AOR statuses */
123#define AOR_STATUS_BUCKETS 3
124
125/*! \brief Maximum wait time to join the below shutdown group */
126#define MAX_UNLOAD_TIMEOUT_TIME 10 /* Seconds */
127
128/*! \brief Shutdown group for options serializers */
130
131/*!
132 * \brief Structure which contains status information for an AOR feeding an endpoint state compositor
133 */
135 /*! \brief The last contributed available status of the named AOR (1 if available, 0 if not available) */
137 /*! \brief The name of the AOR */
138 char name[0];
139};
140
141/*!
142 * \brief Structure which contains composites information for endpoint state
143 */
145 /*! \brief The last contributed available status of the AORs feeding this compositor */
147 /*!
148 * \brief Non-zero if the compositor is in normal operation. i.e. Not being setup/reconfigured.
149 *
150 * \details
151 * The aor layer can only update its aor_statuses record when not active.
152 * When active the aor layer can update its aor_statuses record, calculate the new
153 * number of available aors, determine if the endpoint compositor changed state,
154 * and report it.
155 */
156 char active;
157 /*! \brief The name of the endpoint */
158 char name[0];
159};
160
161/*!
162 * \brief Structure which contains an AOR and contacts for qualifying purposes
163 */
165 /*! \brief The scheduler task for this AOR */
167 /*! \brief The serializer for this AOR */
169 /*! \brief All contacts associated with this AOR */
171 /*!
172 * \brief Only dynamic contacts associated with this AOR
173 * \note Used to speed up applying AOR configuration by
174 * minimizing wild card sorcery access.
175 */
177 /*! \brief The endpoint state compositors we are feeding, a reference is held to each */
179 /*! \brief The number of available contacts on this AOR */
180 unsigned int available;
181 /*! \brief Frequency to send OPTIONS requests to AOR contacts. 0 is disabled. */
182 unsigned int qualify_frequency;
183 /*! If true authenticate the qualify challenge response if needed */
185 /*! \brief Qualify timeout. 0 is diabled. */
187 /*! \brief The name of the AOR */
188 char name[0];
189};
190
191/*!
192 * \internal
193 * \brief Container of active SIP AORs for qualifying
194 */
196
197/*!
198 * \internal
199 * \brief Container of contact statuses
200 */
202
203/*!
204 * \internal
205 * \brief Container of endpoint state compositors
206 */
208
209/*!
210 * \internal
211 * \brief Serializer for AOR, endpoint state compositor, and contact existence management
212 */
214
215static pj_status_t send_options_response(pjsip_rx_data *rdata, int code)
216{
217 pjsip_endpoint *endpt = ast_sip_get_pjsip_endpoint();
218 pjsip_dialog *dlg = pjsip_rdata_get_dlg(rdata);
219 pjsip_transaction *trans = pjsip_rdata_get_tsx(rdata);
220 pjsip_tx_data *tdata;
221 const pjsip_hdr *hdr;
222 pj_status_t status;
223
224 /* Make the response object */
225 status = ast_sip_create_response(rdata, code, NULL, &tdata);
226 if (status != PJ_SUCCESS) {
227 ast_log(LOG_ERROR, "Unable to create response (%d)\n", status);
228 return status;
229 }
230
231 /* Add appropriate headers */
232 if ((hdr = pjsip_endpt_get_capability(endpt, PJSIP_H_ACCEPT, NULL))) {
233 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)pjsip_hdr_clone(tdata->pool, hdr));
234 }
235 if ((hdr = pjsip_endpt_get_capability(endpt, PJSIP_H_ALLOW, NULL))) {
236 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)pjsip_hdr_clone(tdata->pool, hdr));
237 }
238 if ((hdr = pjsip_endpt_get_capability(endpt, PJSIP_H_SUPPORTED, NULL))) {
239 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)pjsip_hdr_clone(tdata->pool, hdr));
240 }
241
242 /*
243 * XXX TODO: pjsip doesn't care a lot about either of these headers -
244 * while it provides specific methods to create them, they are defined
245 * to be the standard string header creation. Hard coded here.
246 */
247 ast_sip_add_header(tdata, "Accept-Encoding", DEFAULT_ENCODING);
248 ast_sip_add_header(tdata, "Accept-Language", DEFAULT_LANGUAGE);
249
250 if (dlg && trans) {
251 status = pjsip_dlg_send_response(dlg, trans, tdata);
252 } else {
253 struct ast_sip_endpoint *endpoint;
254
255 endpoint = ast_pjsip_rdata_get_endpoint(rdata);
256 status = ast_sip_send_stateful_response(rdata, tdata, endpoint);
257 ao2_cleanup(endpoint);
258 }
259
260 if (status != PJ_SUCCESS) {
261 ast_log(LOG_ERROR, "Unable to send response (%d)\n", status);
262 }
263
264 return status;
265}
266
267static pj_bool_t options_on_rx_request(pjsip_rx_data *rdata)
268{
269 RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
270 pjsip_uri *ruri;
271 char exten[AST_MAX_EXTENSION];
272
273 if (pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_options_method)) {
274 return PJ_FALSE;
275 }
276
277 if (!(endpoint = ast_pjsip_rdata_get_endpoint(rdata))) {
278 return PJ_FALSE;
279 }
280
281 ruri = rdata->msg_info.msg->line.req.uri;
282 if (!ast_sip_is_allowed_uri(ruri)) {
283 send_options_response(rdata, 416);
284 return PJ_TRUE;
285 }
286
287 ast_copy_pj_str(exten, ast_sip_pjsip_uri_get_username(ruri), sizeof(exten));
288
289 /*
290 * We may want to match in the dialplan without any user
291 * options getting in the way.
292 */
294
295 if (ast_shutting_down()) {
296 /*
297 * Not taking any new calls at this time.
298 * Likely a server availability OPTIONS poll.
299 */
300 send_options_response(rdata, 503);
301 } else if (!ast_strlen_zero(exten)
302 && !ast_exists_extension(NULL, endpoint->context, exten, 1, NULL)) {
303 send_options_response(rdata, 404);
304 } else {
305 send_options_response(rdata, 200);
306 }
307 return PJ_TRUE;
308}
309
310static pjsip_module options_module = {
311 .name = {"Options Module", 14},
312 .id = -1,
313 .priority = PJSIP_MOD_PRIORITY_APPLICATION,
314 .on_rx_request = options_on_rx_request,
315};
316
317static const char *status_map[] = {
318 [UNAVAILABLE] = "Unreachable",
319 [AVAILABLE] = "Reachable",
320 [UNKNOWN] = "Unknown",
321 [CREATED] = "NonQualified",
322 [REMOVED] = "Removed",
323};
324
325static const char *short_status_map[] = {
326 [UNAVAILABLE] = "Unavail",
327 [AVAILABLE] = "Avail",
328 [UNKNOWN] = "Unknown",
329 [CREATED] = "NonQual",
330 [REMOVED] = "Removed",
331};
332
334{
336 return status_map[status];
337}
338
340{
342 return short_status_map[status];
343}
344
345/*! \brief Destructor for contact statuses */
346static void sip_contact_status_dtor(void *obj)
347{
348 struct ast_sip_contact_status *contact_status = obj;
349
351
352 ast_string_field_free_memory(contact_status);
353}
354
356{
357 struct ast_sip_contact_status *contact_status;
358 size_t size = sizeof(*contact_status) + strlen(name) + 1;
359
360 contact_status = ao2_alloc_options(size, sip_contact_status_dtor,
362 if (!contact_status) {
363 return NULL;
364 }
365 if (ast_string_field_init(contact_status, 256)) {
366 ao2_ref(contact_status, -1);
367 return NULL;
368 }
369 AST_VECTOR_INIT(&contact_status->security_mechanisms, 0);
370 strcpy(contact_status->name, name); /* SAFE */
371 return contact_status;
372}
373
375{
376 struct ast_sip_contact_status *dst;
377
378 dst = sip_contact_status_alloc(src->name);
379 if (!dst) {
380 return NULL;
381 }
382
383 if (ast_string_fields_copy(dst, src)) {
384 ao2_ref(dst, -1);
385 return NULL;
386 }
387 dst->rtt = src->rtt;
388 dst->status = src->status;
389 dst->last_status = src->last_status;
390
392 return dst;
393}
394
395/*! \brief Hashing function for contact statuses */
397
398/*! \brief Sort function for contact statuses */
400
401/*! \brief Comparator function for contact statuses */
403
404/*! \brief Helper function to allocate a contact statuses container */
406{
407 /*
408 * Replace duplicate objects so we can update the immutable
409 * contact status objects by simply linking in a new object.
410 */
413 ast_sip_contact_status_hash_fn, ast_sip_contact_status_sort_fn,
414 ast_sip_contact_status_cmp_fn);
415}
416
417/*! \brief Function which publishes a contact status update to all interested endpoints */
418static void sip_options_publish_contact_state(const struct sip_options_aor *aor_options,
419 const struct ast_sip_contact_status *contact_status)
420{
421 int i;
422
423 for (i = 0; i < AST_VECTOR_SIZE(&aor_options->compositors); ++i) {
424 const struct sip_options_endpoint_state_compositor *endpoint_state_compositor;
425
426 endpoint_state_compositor = AST_VECTOR_GET(&aor_options->compositors, i);
428 contact_status);
429 }
430}
431
432/*!
433 * \brief Task to notify endpoints of a contact status change
434 * \note Run by management_serializer
435 */
437{
438 struct ast_sip_contact_status *contact_status = obj;
439 struct sip_options_aor *aor_options;
440
441 aor_options = ao2_find(sip_options_aors, contact_status->aor, OBJ_SEARCH_KEY);
442 if (aor_options) {
443 sip_options_publish_contact_state(aor_options, contact_status);
444 ao2_ref(aor_options, -1);
445 }
446 ao2_ref(contact_status, -1);
447
448 return 0;
449}
450
452{
453 struct ast_taskprocessor *mgmt_serializer = management_serializer;
454
455 if (mgmt_serializer) {
456 ao2_ref(contact_status, +1);
458 contact_status)) {
459 ao2_ref(contact_status, -1);
460 }
461 }
462}
463
465{
466 struct ast_sip_contact_status *contact_status;
467 int res;
468
469 /*
470 * At startup a contact status can be retrieved when static contacts
471 * are themselves being setup. This happens before we are fully setup.
472 * Since we don't actually trigger qualify or anything as a result it
473 * is safe to do so. They'll just get back a contact status that will
474 * be updated later. At this time they only care that the contact
475 * status gets created for the static contact anyway.
476 */
478 /*
479 * We haven't been pre-initialized or we are shutting down.
480 * Neither situation should happen.
481 */
482 ast_assert(0);
483 return NULL;
484 }
485
487
488 /* If contact status for this contact already exists just return it */
489 contact_status = ao2_find(sip_options_contact_statuses,
491 if (contact_status) {
493 return contact_status;
494 }
495
496 /* Otherwise we have to create and store a new contact status */
497 contact_status = sip_contact_status_alloc(ast_sorcery_object_get_id(contact));
498 if (!contact_status) {
500 return NULL;
501 }
502
503 contact_status->rtt = 0;
504 contact_status->status = CREATED;
505 contact_status->last_status = CREATED;
506 res = ast_string_field_set(contact_status, uri, contact->uri);
507 res |= ast_string_field_set(contact_status, aor, contact->aor);
508 if (res) {
510 ao2_ref(contact_status, -1);
511 return NULL;
512 }
513
516
517 ast_statsd_log_string_va("PJSIP.contacts.states.%s", AST_STATSD_GAUGE,
518 "+1", 1.0, ast_sip_get_contact_status_label(contact_status->status));
519
520 sip_options_contact_status_update(contact_status);
521
522 return contact_status;
523}
524
526{
529}
530
531/*! \brief Hashing function for OPTIONS AORs */
533
534/*! \brief Comparator function for SIP OPTIONS AORs */
536
537/*! \brief Hashing function for endpoint state compositors */
539
540/*! \brief Comparator function for endpoint state compositors */
542
543/*! \brief Structure used to contain information for an OPTIONS callback */
545 /*! \brief The contact we qualified */
547 /*! \brief The AOR options */
549 /*! \brief The time at which this OPTIONS attempt was started */
550 struct timeval rtt_start;
551 /*! \brief The new status of the contact */
553};
554
555/*!
556 * \brief Return the current state of an endpoint state compositor
557 * \pre The endpoint_state_compositor lock must be held.
558 */
560 const struct sip_options_endpoint_state_compositor *endpoint_state_compositor)
561{
562 struct ao2_iterator it_aor_statuses;
563 struct sip_options_endpoint_aor_status *aor_status;
565
566 it_aor_statuses = ao2_iterator_init(endpoint_state_compositor->aor_statuses, 0);
567 for (; (aor_status = ao2_iterator_next(&it_aor_statuses)); ao2_ref(aor_status, -1)) {
568 if (aor_status->available) {
570 ao2_ref(aor_status, -1);
571 break;
572 }
573 }
574 ao2_iterator_destroy(&it_aor_statuses);
575
576 return state;
577}
578
579/*!
580 * \brief Update the AOR status on an endpoint state compositor
581 * \pre The endpoint_state_compositor lock must be held.
582 */
584 const char *name, enum ast_sip_contact_status_type status)
585{
586 struct sip_options_endpoint_aor_status *aor_status;
587 enum ast_endpoint_state endpoint_state;
588
589 aor_status = ao2_find(endpoint_state_compositor->aor_statuses, name,
591 if (!aor_status) {
592 /* The AOR status doesn't exist already so we don't need to go any further */
593 if (status == REMOVED) {
594 return;
595 }
596
597 aor_status = ao2_alloc_options(sizeof(*aor_status) + strlen(name) + 1, NULL,
599 if (!aor_status) {
600 return;
601 }
602
603 strcpy(aor_status->name, name); /* SAFE */
604 ao2_link(endpoint_state_compositor->aor_statuses, aor_status);
605 }
606
607 if (status == REMOVED) {
608 /*
609 * If the AOR is being removed then remove its AOR status
610 * from the endpoint compositor.
611 */
612 ao2_unlink(endpoint_state_compositor->aor_statuses, aor_status);
613 } else {
614 aor_status->available = (status == AVAILABLE ? 1 : 0);
615 }
616 ao2_ref(aor_status, -1);
617
618 if (!endpoint_state_compositor->active) {
619 return;
620 }
621
622 /* If this AOR is available then the endpoint itself has to be online */
623 if (status == AVAILABLE) {
624 ast_debug(3, "Endpoint state compositor '%s' is online as AOR '%s' is available\n",
625 endpoint_state_compositor->name, name);
626 endpoint_state = AST_ENDPOINT_ONLINE;
627 } else {
628 endpoint_state =
629 sip_options_get_endpoint_state_compositor_state(endpoint_state_compositor);
630 }
631
632 ast_sip_persistent_endpoint_update_state(endpoint_state_compositor->name,
633 endpoint_state);
634}
635
636/*! \brief Function which notifies endpoint state compositors of a state change of an AOR */
639{
640 int i;
641
642 /* Iterate through the associated endpoint state compositors updating them */
643 for (i = 0; i < AST_VECTOR_SIZE(&aor_options->compositors); ++i) {
644 struct sip_options_endpoint_state_compositor *endpoint_state_compositor;
645
646 endpoint_state_compositor = AST_VECTOR_GET(&aor_options->compositors, i);
647
648 ao2_lock(endpoint_state_compositor);
649 sip_options_update_endpoint_state_compositor_aor(endpoint_state_compositor,
650 aor_options->name, status);
651 ao2_unlock(endpoint_state_compositor);
652 }
653
654 if (status == REMOVED) {
656 }
657}
658
659/*!
660 * \brief Task to notify an AOR of a contact status change
661 * \note Run by aor_options->serializer
662 */
664{
665 struct sip_options_contact_callback_data *contact_callback_data = obj;
666 struct ast_sip_contact *contact;
667 struct ast_sip_contact_status *cs_old;
668 struct ast_sip_contact_status *cs_new;
669
670 /*
671 * Determine if this is a late arriving notification, as it is
672 * possible that we get a callback from PJSIP giving us contact
673 * status but in the mean time said contact has been removed
674 * from the controlling AOR.
675 */
676
677 if (!contact_callback_data->aor_options->qualify_frequency) {
678 /* Contact qualify response is late */
679 ao2_ref(contact_callback_data, -1);
680 return 0;
681 }
682
683 contact = ao2_find(contact_callback_data->aor_options->contacts,
684 contact_callback_data->contact, OBJ_SEARCH_OBJECT);
685 if (!contact) {
686 /* Contact qualify response is late */
687 ao2_ref(contact_callback_data, -1);
688 return 0;
689 }
690 ao2_ref(contact, -1);
691
693 ast_sorcery_object_get_id(contact_callback_data->contact), OBJ_SEARCH_KEY);
694 if (!cs_old) {
695 /* Contact qualify response is late */
696 ao2_ref(contact_callback_data, -1);
697 return 0;
698 }
699
700 /* Update the contact specific status information */
701 cs_new = sip_contact_status_copy(cs_old);
702 ao2_ref(cs_old, -1);
703 if (!cs_new) {
704 ao2_ref(contact_callback_data, -1);
705 return 0;
706 }
707 cs_new->last_status = cs_new->status;
708 cs_new->status = contact_callback_data->status;
709 cs_new->rtt =
710 cs_new->status == AVAILABLE
711 ? ast_tvdiff_us(ast_tvnow(), contact_callback_data->rtt_start)
712 : 0;
714
715 /*
716 * If the status has changed then notify the endpoint state compositors
717 * and publish our events.
718 */
719 if (cs_new->last_status != cs_new->status) {
720 if (cs_new->status == AVAILABLE) {
721 /* If this is the first available contact then the AOR has become available */
722 ++contact_callback_data->aor_options->available;
723 if (contact_callback_data->aor_options->available == 1) {
725 contact_callback_data->aor_options, AVAILABLE);
726 }
727 } else if (cs_new->last_status == AVAILABLE) {
728 ast_assert(cs_new->status == UNAVAILABLE);
729
730 /* If there are no more available contacts then this AOR is unavailable */
731 --contact_callback_data->aor_options->available;
732 if (!contact_callback_data->aor_options->available) {
734 contact_callback_data->aor_options, UNAVAILABLE);
735 }
736 }
737
738 ast_verb(3, "Contact %s/%s is now %s. RTT: %.3f msec\n",
739 cs_new->aor,
740 cs_new->uri,
742 cs_new->rtt / 1000.0);
743
744 ast_statsd_log_string_va("PJSIP.contacts.states.%s", AST_STATSD_GAUGE,
746 ast_statsd_log_string_va("PJSIP.contacts.states.%s", AST_STATSD_GAUGE,
747 "+1", 1.0, ast_sip_get_contact_status_label(cs_new->status));
748
750
751 ast_test_suite_event_notify("AOR_CONTACT_UPDATE",
752 "Contact: %s\r\n"
753 "Status: %s",
754 cs_new->name,
756 } else {
757 ast_debug(3, "Contact %s/%s status didn't change: %s, RTT: %.3f msec\n",
758 cs_new->aor,
759 cs_new->uri,
761 cs_new->rtt / 1000.0);
762 }
763
764 ast_statsd_log_full_va("PJSIP.contacts.%s.rtt", AST_STATSD_TIMER,
765 cs_new->status != AVAILABLE ? -1 : cs_new->rtt / 1000,
766 1.0,
767 cs_new->name);
768
769 ast_test_suite_event_notify("AOR_CONTACT_QUALIFY_RESULT",
770 "Contact: %s\r\n"
771 "Status: %s\r\n"
772 "RTT: %" PRId64,
773 cs_new->name,
775 cs_new->rtt);
776
777 ast_debug(3, "AOR '%s' now has %d available contacts\n",
778 contact_callback_data->aor_options->name,
779 contact_callback_data->aor_options->available);
780
781 ao2_ref(cs_new, -1);
782 ao2_ref(contact_callback_data, -1);
783
784 return 0;
785}
786
787/*! \brief Callback for when we get a result from a SIP OPTIONS request (a response or a timeout) */
788static void qualify_contact_cb(void *token, pjsip_event *e)
789{
790 struct sip_options_contact_callback_data *contact_callback_data = token;
792
793 switch(e->body.tsx_state.type) {
794 default:
795 ast_log(LOG_ERROR, "Unexpected PJSIP event %u\n", e->body.tsx_state.type);
796 /* Fall through */
797 case PJSIP_EVENT_TRANSPORT_ERROR:
798 case PJSIP_EVENT_TIMER:
800 break;
801 case PJSIP_EVENT_RX_MSG:
803 break;
804 }
805
806 /* Update the callback data with the new status, this will get handled in the AOR serializer */
807 contact_callback_data->status = status;
808
809 if (ast_sip_push_task(contact_callback_data->aor_options->serializer,
810 sip_options_contact_status_notify_task, contact_callback_data)) {
811 ast_log(LOG_WARNING, "Unable to queue contact status update for '%s' on AOR '%s', state will be incorrect\n",
812 ast_sorcery_object_get_id(contact_callback_data->contact),
813 contact_callback_data->aor_options->name);
814 ao2_ref(contact_callback_data, -1);
815 }
816
817 /* The task inherited our reference so we don't unreference here */
818}
819
820/*! \brief Destructor for contact callback data */
822{
823 struct sip_options_contact_callback_data *contact_callback_data = obj;
824
825 ao2_cleanup(contact_callback_data->contact);
826 ao2_cleanup(contact_callback_data->aor_options);
827}
828
829/*! \brief Contact callback data allocator */
832{
833 struct sip_options_contact_callback_data *contact_callback_data;
834
835 contact_callback_data = ao2_alloc_options(sizeof(*contact_callback_data),
837 if (!contact_callback_data) {
838 return NULL;
839 }
840
841 contact_callback_data->contact = ao2_bump(contact);
842 contact_callback_data->aor_options = ao2_bump(aor_options);
843 contact_callback_data->rtt_start = ast_tvnow();
844
845 return contact_callback_data;
846}
847
848/*! \brief Send a SIP OPTIONS request for a contact */
849static int sip_options_qualify_contact(void *obj, void *arg, int flags)
850{
851 struct ast_sip_contact *contact = obj;
852 struct sip_options_aor *aor_options = arg;
853 RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
854 pjsip_tx_data *tdata;
855 struct ast_sip_contact_status *contact_status;
856 struct sip_options_contact_callback_data *contact_callback_data;
857
858 ast_debug(3, "Qualifying contact '%s' on AOR '%s'\n",
860
862 endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint",
864 }
865 if (!endpoint && AST_VECTOR_SIZE(&aor_options->compositors)) {
866 struct sip_options_endpoint_state_compositor *endpoint_state_compositor;
867
868 endpoint_state_compositor = AST_VECTOR_GET(&aor_options->compositors, 0);
869 endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint",
870 endpoint_state_compositor->name);
871 }
872 if (!endpoint) {
873 ast_debug(3, "Could not find an endpoint to qualify contact '%s' on AOR '%s'\n",
874 ast_sorcery_object_get_id(contact), aor_options->name);
875 return 0;
876 }
877
878 if (ast_sip_create_request("OPTIONS", NULL, endpoint, NULL, contact, &tdata)) {
879 ast_log(LOG_ERROR, "Unable to create request to qualify contact %s on AOR %s\n",
880 contact->uri, aor_options->name);
881 return 0;
882 }
883
884 /* If an outbound proxy is specified set it on this request */
885 if (!ast_strlen_zero(contact->outbound_proxy) &&
887 ast_log(LOG_ERROR, "Unable to apply outbound proxy on request to qualify contact %s\n",
888 contact->uri);
889 pjsip_tx_data_dec_ref(tdata);
890 return 0;
891 }
892
893 contact_status = ast_res_pjsip_find_or_create_contact_status(contact);
894 if (!contact_status) {
895 ast_log(LOG_ERROR, "Unable to retrieve contact status information for contact %s on AOR %s\n",
896 contact->uri, aor_options->name);
897 pjsip_tx_data_dec_ref(tdata);
898 return 0;
899 }
900 ao2_ref(contact_status, -1);
901
902 contact_callback_data = sip_options_contact_callback_data_alloc(contact, aor_options);
903 if (!contact_callback_data) {
904 ast_log(LOG_ERROR, "Unable to create object to contain callback data for contact %s on AOR %s\n",
905 contact->uri, aor_options->name);
906 pjsip_tx_data_dec_ref(tdata);
907 return 0;
908 }
909
910 if (ast_sip_send_out_of_dialog_request(tdata, endpoint,
911 (int)(aor_options->qualify_timeout * 1000), contact_callback_data,
913 ast_log(LOG_ERROR, "Unable to send request to qualify contact %s on AOR %s\n",
914 contact->uri, aor_options->name);
915 ao2_ref(contact_callback_data, -1);
916 }
917
918 return 0;
919}
920
921/*!
922 * \brief Task to qualify contacts of an AOR
923 * \note Run by aor_options->serializer
924 */
925static int sip_options_qualify_aor(void *obj)
926{
927 struct sip_options_aor *aor_options = obj;
928
929 ast_debug(3, "Qualifying all contacts on AOR '%s'\n", aor_options->name);
930
931 /* Attempt to send an OPTIONS request to every contact on this AOR */
933 (struct sip_options_aor *) aor_options);
934
935 /* Always reschedule to the frequency we should go */
936 return aor_options->qualify_frequency * 1000;
937}
938
939/*! \brief Forward declaration of this helpful function */
940static int sip_options_remove_contact(void *obj, void *arg, int flags);
941
942/*! \brief Destructor function for SIP OPTIONS AORs */
943static void sip_options_aor_dtor(void *obj)
944{
945 struct sip_options_aor *aor_options = obj;
946
947 /*
948 * Any contacts are unreachable since the AOR is being destroyed
949 * so remove their contact status
950 */
951 if (aor_options->contacts) {
953 sip_options_remove_contact, aor_options);
954 ao2_ref(aor_options->contacts, -1);
955 }
956 ao2_cleanup(aor_options->dynamic_contacts);
957
959
960 ast_assert(AST_VECTOR_SIZE(&aor_options->compositors) == 0);
961 AST_VECTOR_FREE(&aor_options->compositors);
962}
963
964/*! \brief Allocator for AOR OPTIONS */
966{
967 struct sip_options_aor *aor_options;
968 char tps_name[AST_TASKPROCESSOR_MAX_NAME + 1];
969
970 aor_options = ao2_alloc_options(sizeof(*aor_options) + strlen(ast_sorcery_object_get_id(aor)) + 1,
972 if (!aor_options) {
973 return NULL;
974 }
975
976 strcpy(aor_options->name, ast_sorcery_object_get_id(aor)); /* SAFE */
977
978 ast_taskprocessor_build_name(tps_name, sizeof(tps_name), "pjsip/options/%s",
980 aor_options->serializer = ast_sip_create_serializer_group(tps_name,
982 if (!aor_options->serializer) {
983 ao2_ref(aor_options, -1);
984 return NULL;
985 }
986
988 ao2_ref(aor_options, -1);
989 return NULL;
990 }
991
995 if (!aor_options->contacts) {
996 ao2_ref(aor_options, -1);
997 return NULL;
998 }
999
1003 if (!aor_options->dynamic_contacts) {
1004 ao2_ref(aor_options, -1);
1005 return NULL;
1006 }
1007
1008 return aor_options;
1009}
1010
1011/*! \brief Remove contact status for a hint */
1013 struct ast_sip_contact *contact)
1014{
1015 struct ast_sip_contact_status *cs_new;
1016 struct ast_sip_contact_status *cs_old;
1017
1020 if (!cs_old) {
1021 ast_debug(3, "Attempted to remove contact status for '%s' but it does not exist\n",
1022 ast_sorcery_object_get_id(contact));
1023 return;
1024 }
1025
1026 ast_verb(2, "Contact %s/%s has been deleted\n", contact->aor, contact->uri);
1027
1028 /* Update the contact status to reflect its new state */
1029 cs_new = sip_contact_status_copy(cs_old);
1030 if (!cs_new) {
1031 /*
1032 * We'll have to violate the immutable property because we
1033 * couldn't create a new one to modify and we are deleting
1034 * the contact status anyway.
1035 */
1036 cs_new = cs_old;
1037 } else {
1038 ao2_ref(cs_old, -1);
1039 }
1040 cs_new->last_status = cs_new->status;
1041 cs_new->status = REMOVED;
1042 cs_new->rtt = 0;
1043
1044 ast_statsd_log_string_va("PJSIP.contacts.states.%s", AST_STATSD_GAUGE,
1045 "-1", 1.0, ast_sip_get_contact_status_label(cs_new->last_status));
1046 ast_statsd_log_string_va("PJSIP.contacts.states.%s", AST_STATSD_GAUGE,
1047 "+1", 1.0, ast_sip_get_contact_status_label(cs_new->status));
1048
1050
1051 /*
1052 * The only time we need to update the AOR is if this contact was
1053 * available and qualify is in use, otherwise we can just stop
1054 * early.
1055 */
1056 if (!aor_options->qualify_frequency || cs_new->last_status != AVAILABLE) {
1057 ao2_ref(cs_new, -1);
1058 return;
1059 }
1060
1061 --aor_options->available;
1062 if (!aor_options->available) {
1064 }
1065
1066 ast_debug(3, "AOR '%s' now has %d available contacts\n", aor_options->name,
1067 aor_options->available);
1068
1069 ao2_ref(cs_new, -1);
1070}
1071
1072/*! \brief Task data for AOR creation or updating */
1074 /*! \brief The AOR options for this AOR */
1076 /*! \brief The AOR which contains the new configuraton */
1078 /*! \brief Optional container of existing AOR s*/
1080 /*! \brief Whether this AOR is being added */
1082};
1083
1084/*! \brief Callback function to remove a contact and its contact status from an AOR */
1085static int sip_options_remove_contact(void *obj, void *arg, int flags)
1086{
1087 struct ast_sip_contact *contact = obj;
1088 struct sip_options_aor *aor_options = arg;
1089
1090 sip_options_remove_contact_status(aor_options, contact);
1091
1092 return CMP_MATCH;
1093}
1094
1095/*! \brief Determine an initial time for scheduling AOR qualifying */
1097{
1098 int initial_interval;
1099 int max_time = ast_sip_get_max_initial_qualify_time();
1100
1101 if (max_time && max_time < qualify_frequency) {
1102 initial_interval = max_time;
1103 } else {
1104 initial_interval = qualify_frequency;
1105 }
1106
1107 initial_interval = (int)((initial_interval * 1000) * ast_random_double());
1108 return 0 < initial_interval ? initial_interval : 1;
1109}
1110
1111/*! \brief Set the contact status for a contact */
1114{
1115 struct ast_sip_contact_status *cs_new;
1116
1117 /* Update the contact specific status information */
1118 cs_new = sip_contact_status_copy(contact_status);
1119 if (!cs_new) {
1120 return;
1121 }
1122 cs_new->last_status = cs_new->status;
1123 cs_new->status = status;
1124
1125 /*
1126 * We need to always set the RTT to zero because we haven't completed
1127 * an OPTIONS ping so RTT is unknown. If the OPTIONS ping were still
1128 * running it will be refreshed on the next go round anyway.
1129 */
1130 cs_new->rtt = 0;
1131
1133
1134 if (cs_new->status != cs_new->last_status) {
1135 ast_verb(3, "Contact %s/%s is now %s.\n",
1136 cs_new->aor, cs_new->uri,
1138
1139 ast_statsd_log_string_va("PJSIP.contacts.states.%s", AST_STATSD_GAUGE,
1140 "-1", 1.0, ast_sip_get_contact_status_label(cs_new->last_status));
1141 ast_statsd_log_string_va("PJSIP.contacts.states.%s", AST_STATSD_GAUGE,
1142 "+1", 1.0, ast_sip_get_contact_status_label(cs_new->status));
1143
1145
1146 ast_test_suite_event_notify("AOR_CONTACT_UPDATE",
1147 "Contact: %s\r\n"
1148 "Status: %s",
1149 cs_new->name,
1151 }
1152 ao2_ref(cs_new, -1);
1153}
1154
1155/*! \brief Transition the contact status to unqualified mode */
1156static int sip_options_set_contact_status_unqualified(void *obj, void *arg, int flags)
1157{
1158 struct ast_sip_contact *contact = obj;
1159 struct ast_sip_contact_status *contact_status;
1160
1161 contact_status = ast_res_pjsip_find_or_create_contact_status(contact);
1162 if (!contact_status) {
1163 return 0;
1164 }
1165
1166 switch (contact_status->status) {
1167 case AVAILABLE:
1168 case UNAVAILABLE:
1169 case UNKNOWN:
1170 sip_options_set_contact_status(contact_status, CREATED);
1171 break;
1172 case CREATED:
1173 case REMOVED:
1174 break;
1175 }
1176
1177 ao2_ref(contact_status, -1);
1178
1179 return 0;
1180}
1181
1182/*! \brief Transition the contact status to qualified mode */
1183static int sip_options_set_contact_status_qualified(void *obj, void *arg, int flags)
1184{
1185 struct ast_sip_contact *contact = obj;
1186 struct ast_sip_contact_status *contact_status;
1187
1188 contact_status = ast_res_pjsip_find_or_create_contact_status(contact);
1189 if (!contact_status) {
1190 return 0;
1191 }
1192
1193 switch (contact_status->status) {
1194 case AVAILABLE:
1196 break;
1197 case UNAVAILABLE:
1198 case UNKNOWN:
1199 case CREATED:
1200 case REMOVED:
1201 break;
1202 }
1203
1204 ao2_ref(contact_status, -1);
1205
1206 return 0;
1207}
1208
1209/*! \brief Count AVAILABLE qualified contacts. */
1210static int sip_options_contact_status_available_count(void *obj, void *arg, int flags)
1211{
1212 struct ast_sip_contact *contact = obj;
1213 unsigned int *available = arg;
1214 struct ast_sip_contact_status *contact_status;
1215
1216 contact_status = ast_res_pjsip_find_or_create_contact_status(contact);
1217 if (!contact_status) {
1218 return 0;
1219 }
1220
1221 /* Count qualified available contacts. */
1222 switch (contact_status->status) {
1223 case AVAILABLE:
1224 ++*available;
1225 break;
1226 case UNAVAILABLE:
1227 case UNKNOWN:
1228 case CREATED:
1229 case REMOVED:
1230 break;
1231 }
1232
1233 ao2_ref(contact_status, -1);
1234
1235 return 0;
1236}
1237
1238/*!
1239 * \brief Function which applies configuration to an AOR options structure
1240 * \note Run by aor_options->serializer (or management_serializer on aor_options creation)
1241 */
1243 struct ast_sip_aor *aor, int is_new)
1244{
1245 struct ao2_container *existing_contacts;
1246 struct ast_sip_contact *contact;
1247 struct ao2_iterator iter;
1248
1249 ast_debug(3, "Configuring AOR '%s' with current state of configuration and world\n",
1250 aor_options->name);
1251
1252 /*
1253 * Permanent contacts, since we receive no notification that they
1254 * are gone, follow the same approach as AORs. We create a copy
1255 * of the existing container and any reused contacts are removed
1256 * from it. Any contacts remaining in the container after
1257 * processing no longer exist so we need to remove their state.
1258 */
1259 existing_contacts = ao2_container_clone(aor_options->contacts, 0);
1260 if (!existing_contacts) {
1261 ast_log(LOG_WARNING, "Synchronization of AOR '%s' failed for qualify, retaining existing state\n",
1262 aor_options->name);
1263 return;
1264 }
1265
1267 NULL, NULL);
1268
1269 /* Process permanent contacts */
1270 if (aor->permanent_contacts) {
1271 iter = ao2_iterator_init(aor->permanent_contacts, 0);
1272 for (; (contact = ao2_iterator_next(&iter)); ao2_ref(contact, -1)) {
1273 ao2_find(existing_contacts, ast_sorcery_object_get_id(contact),
1275 ao2_link(aor_options->contacts, contact);
1276 }
1277 ao2_iterator_destroy(&iter);
1278 }
1279
1280 /*
1281 * If this is newly added we need to see if there are any
1282 * existing dynamic contacts to add. Ones that are added
1283 * after creation will occur as a result of the contact
1284 * observer creation callback.
1285 */
1286 if (is_new) {
1287 size_t prefix_len = strlen(ast_sorcery_object_get_id(aor)) + sizeof(";@") - 1;
1288 char prefix[prefix_len + 1];
1289 struct ao2_container *contacts;
1290
1291 sprintf(prefix, "%s;@", ast_sorcery_object_get_id(aor)); /* Safe */
1293 prefix, prefix_len);
1294 if (contacts) {
1295 ao2_container_dup(aor_options->dynamic_contacts, contacts, 0);
1296 ao2_ref(contacts, -1);
1297 }
1298 }
1299
1300 /* Process dynamic contacts */
1301 iter = ao2_iterator_init(aor_options->dynamic_contacts, 0);
1302 for (; (contact = ao2_iterator_next(&iter)); ao2_ref(contact, -1)) {
1303 ao2_find(existing_contacts, ast_sorcery_object_get_id(contact),
1305 ao2_link(aor_options->contacts, contact);
1306 }
1307 ao2_iterator_destroy(&iter);
1308
1309 /* Any contacts left no longer exist, so raise events and make them disappear */
1310 ao2_callback(existing_contacts, OBJ_NODATA | OBJ_UNLINK,
1311 sip_options_remove_contact, aor_options);
1312 ao2_ref(existing_contacts, -1);
1313
1314 /*
1315 * Update the available count if we transition between qualified
1316 * and unqualified. In the qualified case we need to start with
1317 * 0 available as the qualify process will take care of it. In
1318 * the unqualified case it is based on the number of contacts
1319 * present.
1320 */
1321 if (!aor->qualify_frequency) {
1322 ao2_callback(aor_options->contacts, OBJ_NODATA,
1324 aor_options->available = ao2_container_count(aor_options->contacts);
1325 ast_debug(3, "AOR '%s' is unqualified, number of available contacts is therefore '%d'\n",
1326 aor_options->name, aor_options->available);
1327 } else if (!aor_options->qualify_frequency) {
1328 ao2_callback(aor_options->contacts, OBJ_NODATA,
1330 aor_options->available = 0;
1331 ast_debug(3, "AOR '%s' has transitioned from unqualified to qualified, reset available contacts to 0\n",
1332 aor_options->name);
1333 } else {
1334 /*
1335 * Count the number of AVAILABLE qualified contacts to ensure
1336 * the count is in sync with reality.
1337 */
1338 aor_options->available = 0;
1339 ao2_callback(aor_options->contacts, OBJ_NODATA,
1341 }
1342
1343 aor_options->authenticate_qualify = aor->authenticate_qualify;
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 */
1808{
1810 .reload = reload,
1811 };
1812
1814 &task_data);
1815}
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 */
1885static void endpoint_observer_deleted(const void *obj)
1886{
1889}
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 */
1917static void endpoint_observer_modified(const void *obj)
1918{
1921}
1922
1923/*! \brief Observer callbacks for endpoints */
1926 .updated = endpoint_observer_modified,
1927 .deleted = endpoint_observer_deleted,
1928};
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 */
2017static void aor_observer_modified(const void *obj)
2018{
2021}
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 */
2048static void aor_observer_deleted(const void *obj)
2049{
2052}
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 || ((int)(contact->qualify_timeout * 1000)) != ((int)(aor_options->qualify_timeout * 1000))) {
2086 return 1;
2087 }
2088
2089 return 0;
2090}
2091
2092/*!
2093 * \brief Task which adds a dynamic contact to an AOR
2094 * \note Run by aor_options->serializer
2095 */
2096static int sip_options_contact_add_task(void *obj)
2097{
2099 struct ast_sip_contact_status *contact_status;
2100
2101 ao2_link(task_data->aor_options->dynamic_contacts, task_data->contact);
2102 ao2_link(task_data->aor_options->contacts, task_data->contact);
2103
2104 contact_status = ast_res_pjsip_find_or_create_contact_status(task_data->contact);
2105 ao2_cleanup(contact_status);
2106
2107 if (task_data->aor_options->qualify_frequency) {
2108 /* There will always be a contact here, and we need to immediately schedule
2109 * a qualify so that contacts are not waiting for the qualify_frequency
2110 * timer duration before qualifying.
2111 */
2112 ast_debug(3, "Starting scheduled callback on AOR '%s' for qualifying as there is now a contact on it\n",
2113 task_data->aor_options->name);
2114 /*
2115 * We immediately schedule the initial qualify so that we get
2116 * reachable/unreachable as soon as possible. Realistically
2117 * since they pretty much just registered they should be
2118 * reachable.
2119 */
2120 if (task_data->aor_options->sched_task) {
2121 ast_sip_sched_task_cancel(task_data->aor_options->sched_task);
2122 ao2_ref(task_data->aor_options->sched_task, -1);
2123 task_data->aor_options->sched_task = NULL;
2124 }
2125 task_data->aor_options->sched_task = ast_sip_schedule_task(
2126 task_data->aor_options->serializer, 1, sip_options_qualify_aor,
2127 ast_taskprocessor_name(task_data->aor_options->serializer),
2128 task_data->aor_options,
2130 if (!task_data->aor_options->sched_task) {
2131 ast_log(LOG_ERROR, "Unable to schedule qualify for contacts of AOR '%s'\n",
2132 task_data->aor_options->name);
2133 }
2134 } else {
2135 /*
2136 * If this was the first contact added to a non-qualified AOR then
2137 * it should become available.
2138 */
2139 task_data->aor_options->available =
2140 ao2_container_count(task_data->aor_options->contacts);
2141 if (task_data->aor_options->available == 1) {
2142 ast_debug(3, "An unqualified contact has been added to AOR '%s' so it is now available\n",
2143 task_data->aor_options->name);
2145 AVAILABLE);
2146 }
2147 }
2148
2149 return 0;
2150}
2151
2152/*!
2153 * \brief Task to add a dynamic contact to an AOR in its serializer
2154 * \note Run by management_serializer
2155 */
2157{
2159
2160 task_data.contact = obj;
2161 task_data.aor_options = ao2_find(sip_options_aors, task_data.contact->aor,
2163
2164 if (has_qualify_changed(task_data.contact, task_data.aor_options)) {
2165 struct ast_sip_aor *aor;
2166
2168 task_data.contact->aor);
2169 if (aor) {
2170 ast_debug(3, "AOR '%s' qualify options have been modified. Synchronize an AOR local state\n",
2171 task_data.contact->aor);
2173 ao2_ref(aor, -1);
2174 }
2175 }
2176
2177 if (!task_data.aor_options) {
2178 return 0;
2179 }
2180
2181 ast_sip_push_task_wait_serializer(task_data.aor_options->serializer,
2183 ao2_ref(task_data.aor_options, -1);
2184
2185 return 0;
2186}
2187
2188/*! \brief Observer callback invoked on contact creation */
2189static void contact_observer_created(const void *obj)
2190{
2193}
2194
2195/*!
2196 * \brief Task which updates a dynamic contact to an AOR
2197 * \note Run by aor_options->serializer
2198 */
2200{
2202 struct ast_sip_contact_status *contact_status;
2203
2204 contact_status = ast_sip_get_contact_status(task_data->contact);
2205 if (contact_status) {
2206 switch (contact_status->status) {
2207 case CREATED:
2208 case UNAVAILABLE:
2209 case AVAILABLE:
2210 case UNKNOWN:
2211 /* Refresh the ContactStatus AMI events. */
2212 sip_options_contact_status_update(contact_status);
2213 break;
2214 case REMOVED:
2215 break;
2216 }
2217 ao2_ref(contact_status, -1);
2218 }
2219
2220 ao2_ref(task_data->contact, -1);
2221 ao2_ref(task_data->aor_options, -1);
2223 return 0;
2224}
2225
2226/*! \brief Observer callback invoked on contact update */
2227static void contact_observer_updated(const void *obj)
2228{
2229 const struct ast_sip_contact *contact = obj;
2230 struct sip_options_aor *aor_options = ao2_find(sip_options_aors, contact->aor, OBJ_SEARCH_KEY);
2231
2232 if (has_qualify_changed(contact, aor_options)) {
2233 struct ast_sip_aor *aor;
2234
2236 contact->aor);
2237 if (aor) {
2238 ast_debug(3, "AOR '%s' qualify options have been modified. Synchronize an AOR local state\n",
2239 contact->aor);
2242 ao2_ref(aor, -1);
2243 }
2244 }
2245
2248
2249 task_data = ast_malloc(sizeof(*task_data));
2250 if (!task_data) {
2251 ao2_ref(aor_options, -1);
2252 return;
2253 }
2254
2255 task_data->contact = (struct ast_sip_contact *) contact;
2256 /* task_data takes ownership of aor_options and will take care of releasing the ref */
2257 task_data->aor_options = aor_options;
2258
2259 ao2_ref(task_data->contact, +1);
2260 if (ast_sip_push_task(task_data->aor_options->serializer,
2262 ao2_ref(task_data->contact, -1);
2263 ao2_ref(task_data->aor_options, -1);
2265 }
2266 } else {
2267 ao2_cleanup(aor_options);
2268 }
2269}
2270
2271/*!
2272 * \brief Task which deletes a dynamic contact from an AOR
2273 * \note Run by aor_options->serializer
2274 */
2276{
2278
2279 ao2_find(task_data->aor_options->dynamic_contacts, task_data->contact,
2281 ao2_find(task_data->aor_options->contacts, task_data->contact,
2283
2285
2286 if (task_data->aor_options->qualify_frequency) {
2287 /* If this is the last contact then we need to stop the scheduled callback */
2288 if (!ao2_container_count(task_data->aor_options->contacts)) {
2289 ast_debug(3, "Terminating scheduled callback on AOR '%s' as there are no contacts to qualify\n",
2290 task_data->aor_options->name);
2291 if (task_data->aor_options->sched_task) {
2292 ast_sip_sched_task_cancel(task_data->aor_options->sched_task);
2293 ao2_ref(task_data->aor_options->sched_task, -1);
2294 task_data->aor_options->sched_task = NULL;
2295 }
2296 }
2297 } else {
2298 task_data->aor_options->available =
2299 ao2_container_count(task_data->aor_options->contacts);
2300 if (!task_data->aor_options->available) {
2301 ast_debug(3, "An unqualified contact has been removed from AOR '%s' leaving no remaining contacts\n",
2302 task_data->aor_options->name);
2304 UNAVAILABLE);
2305 }
2306 }
2307
2308 return 0;
2309}
2310
2311/*!
2312 * \brief Task to delete a contact from an AOR in its serializer
2313 * \note Run by management_serializer
2314 */
2316{
2318
2319 task_data.contact = obj;
2320 task_data.aor_options = ao2_find(sip_options_aors, task_data.contact->aor,
2322 if (!task_data.aor_options) {
2323 /* For contacts that are deleted we don't really care if there is no AOR locally */
2324 return 0;
2325 }
2326
2327 ast_sip_push_task_wait_serializer(task_data.aor_options->serializer,
2329 ao2_ref(task_data.aor_options, -1);
2330
2331 return 0;
2332}
2333
2334/*! \brief Observer callback invoked on contact deletion */
2335static void contact_observer_deleted(const void *obj)
2336{
2339}
2340
2341/*! \brief Observer callbacks for contacts */
2344 .updated = contact_observer_updated,
2345 .deleted = contact_observer_deleted,
2346};
2347
2348static char *cli_qualify(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2349{
2350 RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
2351 const char *endpoint_name;
2352 char *aors;
2353 char *aor_name;
2354
2355 switch (cmd) {
2356 case CLI_INIT:
2357 e->command = "pjsip qualify";
2358 e->usage =
2359 "Usage: pjsip qualify <endpoint>\n"
2360 " Send a SIP OPTIONS request to all contacts on the endpoint.\n";
2361 return NULL;
2362 case CLI_GENERATE:
2363 return NULL;
2364 }
2365
2366 if (a->argc != 3) {
2367 return CLI_SHOWUSAGE;
2368 }
2369
2370 endpoint_name = a->argv[2];
2371
2372 endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint",
2373 endpoint_name);
2374 if (!endpoint) {
2375 ast_cli(a->fd, "Unable to retrieve endpoint %s\n", endpoint_name);
2376 return CLI_FAILURE;
2377 }
2378
2379 if (ast_strlen_zero(endpoint->aors)) {
2380 ast_cli(a->fd, "No AORs configured for endpoint '%s'\n", endpoint_name);
2381 return CLI_FAILURE;
2382 }
2383
2384 aors = ast_strdupa(endpoint->aors);
2385 while ((aor_name = ast_strip(strsep(&aors, ",")))) {
2386 struct sip_options_aor *aor_options;
2387
2388 aor_options = ao2_find(sip_options_aors, aor_name, OBJ_SEARCH_KEY);
2389 if (!aor_options) {
2390 continue;
2391 }
2392
2393 ast_cli(a->fd, "Qualifying AOR '%s' on endpoint '%s'\n", aor_name, endpoint_name);
2395 aor_options);
2396 ao2_ref(aor_options, -1);
2397 }
2398
2399 return CLI_SUCCESS;
2400}
2401
2403{
2404 struct ao2_container *contacts;
2405
2408
2409 return contacts;
2410}
2411
2412static int sip_contact_to_ami(const struct ast_sip_contact *contact,
2413 struct ast_str **buf)
2414{
2415 return ast_sip_sorcery_object_to_ami(contact, buf);
2416}
2417
2418static int format_ami_contactlist_handler(void *obj, void *arg, int flags)
2419{
2420 struct ast_sip_contact *contact = obj;
2421 struct ast_sip_ami *ami = arg;
2422 struct ast_str *buf;
2424
2425 buf = ast_sip_create_ami_event("ContactList", ami);
2426 if (!buf) {
2427 return CMP_STOP;
2428 }
2429
2430 if (sip_contact_to_ami(contact, &buf)) {
2431 ast_free(buf);
2432 return CMP_STOP;
2433 }
2434
2435 /* Add extra info */
2437 ast_str_append(&buf, 0, "Status: %s\r\n",
2439 if (!status || status->status != AVAILABLE) {
2440 ast_str_append(&buf, 0, "RoundtripUsec: N/A\r\n");
2441 } else {
2442 ast_str_append(&buf, 0, "RoundtripUsec: %" PRId64 "\r\n", status->rtt);
2443 }
2445
2446 astman_append(ami->s, "%s\r\n", ast_str_buffer(buf));
2447
2448 ami->count++;
2449
2450 ast_free(buf);
2451
2452 return 0;
2453}
2454
2455static int ami_show_contacts(struct mansession *s, const struct message *m)
2456{
2457 struct ast_sip_ami ami = { .s = s, .m = m, .action_id = astman_get_header(m, "ActionID"), };
2458 struct ao2_container *contacts;
2459
2460 contacts = get_all_contacts();
2461 if (!contacts) {
2462 astman_send_error(s, m, "Could not get Contacts\n");
2463 return 0;
2464 }
2465
2466 if (!ao2_container_count(contacts)) {
2467 astman_send_error(s, m, "No Contacts found\n");
2468 ao2_ref(contacts, -1);
2469 return 0;
2470 }
2471
2472 astman_send_listack(s, m, "A listing of Contacts follows, presented as ContactList events",
2473 "start");
2474
2476
2477 astman_send_list_complete_start(s, m, "ContactListComplete", ami.count);
2479
2480 ao2_ref(contacts, -1);
2481
2482 return 0;
2483}
2484
2485static char *cli_show_qualify_endpoint(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2486{
2487 RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
2488 const char *endpoint_name;
2489 char *aors;
2490 char *aor_name;
2491
2492 switch (cmd) {
2493 case CLI_INIT:
2494 e->command = "pjsip show qualify endpoint";
2495 e->usage =
2496 "Usage: pjsip show qualify endpoint <id>\n"
2497 " Show the current qualify options for all Aors on the PJSIP endpoint.\n";
2498 return NULL;
2499 case CLI_GENERATE:
2500 return NULL;
2501 }
2502
2503 if (a->argc != 5) {
2504 return CLI_SHOWUSAGE;
2505 }
2506
2507 endpoint_name = a->argv[4];
2508
2509 endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint",
2510 endpoint_name);
2511 if (!endpoint) {
2512 ast_cli(a->fd, "Unable to retrieve endpoint %s\n", endpoint_name);
2513 return CLI_FAILURE;
2514 }
2515
2516 if (ast_strlen_zero(endpoint->aors)) {
2517 ast_cli(a->fd, "No AORs configured for endpoint '%s'\n", endpoint_name);
2518 return CLI_FAILURE;
2519 }
2520
2521 aors = ast_strdupa(endpoint->aors);
2522 while ((aor_name = ast_strip(strsep(&aors, ",")))) {
2523 struct sip_options_aor *aor_options;
2524
2525 aor_options = ao2_find(sip_options_aors, aor_name, OBJ_SEARCH_KEY);
2526 if (!aor_options) {
2527 continue;
2528 }
2529
2530 ast_cli(a->fd, " * AOR '%s' on endpoint '%s'\n", aor_name, endpoint_name);
2531 ast_cli(a->fd, " Qualify frequency : %d sec\n", aor_options->qualify_frequency);
2532 ast_cli(a->fd, " Qualify timeout : %d ms\n", (int)(aor_options->qualify_timeout / 1000));
2533 ast_cli(a->fd, " Authenticate qualify : %s\n", aor_options->authenticate_qualify?"yes":"no");
2534 ast_cli(a->fd, "\n");
2535 ao2_ref(aor_options, -1);
2536 }
2537
2538 return CLI_SUCCESS;
2539}
2540
2541static char *cli_show_qualify_aor(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2542{
2543 struct sip_options_aor *aor_options;
2544 const char *aor_name;
2545
2546 switch (cmd) {
2547 case CLI_INIT:
2548 e->command = "pjsip show qualify aor";
2549 e->usage =
2550 "Usage: pjsip show qualify aor <id>\n"
2551 " Show the PJSIP Aor current qualify options.\n";
2552 return NULL;
2553 case CLI_GENERATE:
2554 return NULL;
2555 }
2556
2557 if (a->argc != 5) {
2558 return CLI_SHOWUSAGE;
2559 }
2560
2561 aor_name = a->argv[4];
2562
2563 aor_options = ao2_find(sip_options_aors, aor_name, OBJ_SEARCH_KEY);
2564 if (!aor_options) {
2565 ast_cli(a->fd, "Unable to retrieve aor '%s' qualify options\n", aor_name);
2566 return CLI_FAILURE;
2567 }
2568
2569 ast_cli(a->fd, " * AOR '%s'\n", aor_name);
2570 ast_cli(a->fd, " Qualify frequency : %d sec\n", aor_options->qualify_frequency);
2571 ast_cli(a->fd, " Qualify timeout : %d ms\n", (int)(aor_options->qualify_timeout / 1000));
2572 ast_cli(a->fd, " Authenticate qualify : %s\n", aor_options->authenticate_qualify?"yes":"no");
2573 ao2_ref(aor_options, -1);
2574
2575 return CLI_SUCCESS;
2576}
2577
2578static char *cli_reload_qualify_endpoint(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2579{
2580 RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
2581 const char *endpoint_name;
2582 char *aors;
2583 char *aor_name;
2584
2585 switch (cmd) {
2586 case CLI_INIT:
2587 e->command = "pjsip reload qualify endpoint";
2588 e->usage =
2589 "Usage: pjsip reload qualify endpoint <id>\n"
2590 " Synchronize the qualify options for all Aors on the PJSIP endpoint.\n";
2591 return NULL;
2592 case CLI_GENERATE:
2593 return NULL;
2594 }
2595
2596 if (a->argc != 5) {
2597 return CLI_SHOWUSAGE;
2598 }
2599
2600 endpoint_name = a->argv[4];
2601
2602 endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint",
2603 endpoint_name);
2604 if (!endpoint) {
2605 ast_cli(a->fd, "Unable to retrieve endpoint %s\n", endpoint_name);
2606 return CLI_FAILURE;
2607 }
2608
2609 if (ast_strlen_zero(endpoint->aors)) {
2610 ast_cli(a->fd, "No AORs configured for endpoint '%s'\n", endpoint_name);
2611 return CLI_FAILURE;
2612 }
2613
2614 aors = ast_strdupa(endpoint->aors);
2615 while ((aor_name = ast_strip(strsep(&aors, ",")))) {
2616 struct ast_sip_aor *aor;
2617
2618 aor = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "aor", aor_name);
2619 if (!aor) {
2620 continue;
2621 }
2622
2623 ast_cli(a->fd, "Synchronizing AOR '%s' on endpoint '%s'\n", aor_name, endpoint_name);
2626 ao2_ref(aor, -1);
2627 }
2628
2629 return CLI_SUCCESS;
2630}
2631
2632static char *cli_reload_qualify_aor(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2633{
2634 struct ast_sip_aor *aor;
2635 const char *aor_name;
2636
2637 switch (cmd) {
2638 case CLI_INIT:
2639 e->command = "pjsip reload qualify aor";
2640 e->usage =
2641 "Usage: pjsip reload qualify aor <id>\n"
2642 " Synchronize the PJSIP Aor qualify options.\n";
2643 return NULL;
2644 case CLI_GENERATE:
2645 return NULL;
2646 }
2647
2648 if (a->argc != 5) {
2649 return CLI_SHOWUSAGE;
2650 }
2651
2652 aor_name = a->argv[4];
2653
2654 aor = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "aor", aor_name);
2655 if (!aor) {
2656 ast_cli(a->fd, "Unable to retrieve aor '%s'\n", aor_name);
2657 return CLI_FAILURE;
2658 }
2659
2660 ast_cli(a->fd, "Synchronizing AOR '%s'\n", aor_name);
2663 ao2_ref(aor, -1);
2664
2665 return CLI_SUCCESS;
2666}
2667
2668static int ami_sip_qualify(struct mansession *s, const struct message *m)
2669{
2670 const char *endpoint_name = astman_get_header(m, "Endpoint");
2671 RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
2672 char *aors;
2673 char *aor_name;
2674
2675 if (ast_strlen_zero(endpoint_name)) {
2676 astman_send_error(s, m, "Endpoint parameter missing.");
2677 return 0;
2678 }
2679
2680 endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint",
2681 endpoint_name);
2682 if (!endpoint) {
2683 astman_send_error(s, m, "Unable to retrieve endpoint\n");
2684 return 0;
2685 }
2686
2687 /* send a qualify for all contacts registered with the endpoint */
2688 if (ast_strlen_zero(endpoint->aors)) {
2689 astman_send_error(s, m, "No AoRs configured for endpoint\n");
2690 return 0;
2691 }
2692
2693 aors = ast_strdupa(endpoint->aors);
2694 while ((aor_name = ast_strip(strsep(&aors, ",")))) {
2695 struct sip_options_aor *aor_options;
2696
2697 aor_options = ao2_find(sip_options_aors, aor_name, OBJ_SEARCH_KEY);
2698 if (!aor_options) {
2699 continue;
2700 }
2701
2703 aor_options);
2704 ao2_ref(aor_options, -1);
2705 }
2706
2707 astman_send_ack(s, m, "Endpoint found, will qualify");
2708 return 0;
2709}
2710
2711static struct ast_cli_entry cli_options[] = {
2712 AST_CLI_DEFINE(cli_qualify, "Send an OPTIONS request to a PJSIP endpoint"),
2713 AST_CLI_DEFINE(cli_show_qualify_endpoint, "Show the current qualify options for all Aors on the PJSIP endpoint"),
2714 AST_CLI_DEFINE(cli_show_qualify_aor, "Show the PJSIP Aor current qualify options"),
2715 AST_CLI_DEFINE(cli_reload_qualify_endpoint, "Synchronize the qualify options for all Aors on the PJSIP endpoint"),
2716 AST_CLI_DEFINE(cli_reload_qualify_aor, "Synchronize the PJSIP Aor qualify options"),
2717};
2718
2719int ast_sip_format_contact_ami(void *obj, void *arg, int flags)
2720{
2721 struct ast_sip_contact_wrapper *wrapper = obj;
2722 struct ast_sip_contact *contact = wrapper->contact;
2723 struct ast_sip_ami *ami = arg;
2725 struct ast_str *buf;
2726 const struct ast_sip_endpoint *endpoint = ami->arg;
2727 char secs[AST_TIME_T_LEN];
2728
2729 buf = ast_sip_create_ami_event("ContactStatusDetail", ami);
2730 if (!buf) {
2731 return -1;
2732 }
2733
2735
2736 ast_str_append(&buf, 0, "AOR: %s\r\n", wrapper->aor_id);
2737 ast_str_append(&buf, 0, "URI: %s\r\n", contact->uri);
2738 ast_str_append(&buf, 0, "UserAgent: %s\r\n", contact->user_agent);
2739 ast_time_t_to_string(contact->expiration_time.tv_sec, secs, sizeof(secs));
2740 ast_str_append(&buf, 0, "RegExpire: %s\r\n", secs);
2741 if (!ast_strlen_zero(contact->via_addr)) {
2742 ast_str_append(&buf, 0, "ViaAddress: %s", contact->via_addr);
2743 if (contact->via_port) {
2744 ast_str_append(&buf, 0, ":%d", contact->via_port);
2745 }
2746 ast_str_append(&buf, 0, "\r\n");
2747 }
2748 if (!ast_strlen_zero(contact->call_id)) {
2749 ast_str_append(&buf, 0, "CallID: %s\r\n", contact->call_id);
2750 }
2751 ast_str_append(&buf, 0, "Status: %s\r\n",
2753 if (!status || status->status != AVAILABLE) {
2754 ast_str_append(&buf, 0, "RoundtripUsec: N/A\r\n");
2755 } else {
2756 ast_str_append(&buf, 0, "RoundtripUsec: %" PRId64 "\r\n", status->rtt);
2757 }
2758 ast_str_append(&buf, 0, "EndpointName: %s\r\n",
2759 endpoint ? ast_sorcery_object_get_id(endpoint) : S_OR(contact->endpoint_name, ""));
2760
2761 ast_str_append(&buf, 0, "ID: %s\r\n", ast_sorcery_object_get_id(contact));
2762 ast_str_append(&buf, 0, "AuthenticateQualify: %d\r\n", contact->authenticate_qualify);
2763 ast_str_append(&buf, 0, "OutboundProxy: %s\r\n", contact->outbound_proxy);
2764 ast_str_append(&buf, 0, "Path: %s\r\n", contact->path);
2765 ast_str_append(&buf, 0, "QualifyFrequency: %u\r\n", contact->qualify_frequency);
2766 ast_str_append(&buf, 0, "QualifyTimeout: %.3f\r\n", contact->qualify_timeout);
2767
2768 astman_append(ami->s, "%s\r\n", ast_str_buffer(buf));
2769 ami->count++;
2770
2771 ast_free(buf);
2773 return 0;
2774}
2775
2776static int format_contact_status_for_aor(void *obj, void *arg, int flags)
2777{
2778 struct ast_sip_aor *aor = obj;
2779
2781}
2782
2783static int format_ami_contact_status(const struct ast_sip_endpoint *endpoint,
2784 struct ast_sip_ami *ami)
2785{
2786 ami->arg = (void *)endpoint;
2788}
2789
2792};
2793
2794/*!
2795 * \brief Management task to clean up an AOR
2796 * \note Run by aor_options->serializer
2797 */
2798static int sip_options_cleanup_aor_task(void *obj)
2799{
2800 struct sip_options_aor *aor_options = obj;
2801
2802 ast_debug(2, "Cleaning up AOR '%s' for shutdown\n", aor_options->name);
2803
2804 aor_options->qualify_frequency = 0;
2805 if (aor_options->sched_task) {
2807 ao2_ref(aor_options->sched_task, -1);
2808 aor_options->sched_task = NULL;
2809 }
2811
2812 return 0;
2813}
2814
2815/*!
2816 * \brief Management task to clean up the environment
2817 * \note Run by management_serializer
2818 */
2819static int sip_options_cleanup_task(void *obj)
2820{
2821 struct ao2_iterator it_aor;
2822 struct sip_options_aor *aor_options;
2823
2824 if (!sip_options_aors) {
2825 /* Nothing to do */
2826 return 0;
2827 }
2828
2830 for (; (aor_options = ao2_iterator_next(&it_aor)); ao2_ref(aor_options, -1)) {
2832 sip_options_cleanup_aor_task, aor_options);
2833 }
2834 ao2_iterator_destroy(&it_aor);
2835
2836 return 0;
2837}
2838
2840{
2841 int remaining;
2842 struct ast_taskprocessor *mgmt_serializer;
2843
2845 ast_manager_unregister("PJSIPQualify");
2846 ast_manager_unregister("PJSIPShowContacts");
2848
2855
2856 mgmt_serializer = management_serializer;
2858 if (mgmt_serializer) {
2860 }
2861
2864 if (remaining) {
2865 ast_log(LOG_WARNING, "Cleanup incomplete. Could not stop %d AORs.\n",
2866 remaining);
2867 }
2870
2871 if (mgmt_serializer) {
2872 ast_taskprocessor_unreference(mgmt_serializer);
2873 }
2874
2881
2882 pjsip_endpt_unregister_module(ast_sip_get_pjsip_endpoint(), &options_module);
2883}
2884
2885/*!
2886 * \brief Management task to finish setting up the environment.
2887 * \note Run by management_serializer
2888 */
2889static int sip_options_init_task(void *mgmt_serializer)
2890{
2891 management_serializer = mgmt_serializer;
2892
2894 if (!shutdown_group) {
2895 return -1;
2896 }
2897
2900 return -1;
2901 }
2904 return -1;
2905 }
2908 return -1;
2909 }
2910
2912
2913 return 0;
2914}
2915
2917{
2919 return sip_options_contact_statuses ? 0 : -1;
2920}
2921
2923{
2924 struct ast_taskprocessor *mgmt_serializer;
2925
2926 static const pj_str_t STR_OPTIONS = { "OPTIONS", 7 };
2927
2928 if (reload) {
2930 return 0;
2931 }
2932
2933 if (pjsip_endpt_register_module(ast_sip_get_pjsip_endpoint(), &options_module)
2934 != PJ_SUCCESS) {
2935 return -1;
2936 }
2937
2938 if (pjsip_endpt_add_capability(ast_sip_get_pjsip_endpoint(), NULL, PJSIP_H_ALLOW,
2939 NULL, 1, &STR_OPTIONS) != PJ_SUCCESS) {
2941 return -1;
2942 }
2943
2945 sip_options_aor_hash_fn, NULL, sip_options_aor_cmp_fn);
2946 if (!sip_options_aors) {
2948 return -1;
2949 }
2953 sip_options_endpoint_state_compositor_hash_fn, NULL,
2954 sip_options_endpoint_state_compositor_cmp_fn);
2957 return -1;
2958 }
2959
2960 mgmt_serializer = ast_sip_create_serializer("pjsip/options/manage");
2961 if (!mgmt_serializer) {
2963 return -1;
2964 }
2965
2966 /*
2967 * Set the water mark levels high because we can get a flood of
2968 * contact status updates from sip_options_synchronize() that
2969 * quickly clears on initial load or reload.
2970 */
2971 ast_taskprocessor_alert_set_levels(mgmt_serializer, -1,
2973
2974 /*
2975 * We make sure that the environment is completely setup before we allow
2976 * any other threads to post contact_status updates to the
2977 * management_serializer.
2978 */
2980 mgmt_serializer)) {
2981 /* Set management_serializer in case pushing the task actually failed. */
2982 management_serializer = mgmt_serializer;
2984 return -1;
2985 }
2986
2992
2993 return 0;
2994}
jack_status_t status
Definition: app_jack.c:146
Asterisk main include file. File version handling, generic pbx functions.
int ast_shutting_down(void)
Definition: asterisk.c:1877
#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_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_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
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
enum cc_state state
Definition: ccss.c:393
static int available(struct dahdi_pvt **pvt, int is_specific_channel)
Definition: chan_dahdi.c:13477
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
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
#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:2011
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Definition: manager.c:1969
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:2047
void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
Send ack in manager transaction.
Definition: manager.c:2001
const char * astman_get_header(const struct message *m, char *var)
Get header from manager transaction.
Definition: manager.c:1630
void astman_send_list_complete_end(struct mansession *s)
End the list complete event.
Definition: manager.c:2055
void astman_append(struct mansession *s, const char *fmt,...)
Definition: manager.c:1890
int ast_manager_unregister(const char *action)
Unregister a registered manager command.
Definition: manager.c:7606
int ast_sip_push_task(struct ast_taskprocessor *serializer, int(*sip_task)(void *), void *task_data)
Pushes a task to SIP servants.
Definition: res_pjsip.c:2099
struct ast_taskprocessor * ast_sip_create_serializer(const char *name)
Create a new serializer for SIP tasks.
Definition: res_pjsip.c:2094
struct ast_taskprocessor * ast_sip_create_serializer_group(const char *name, struct ast_serializer_shutdown_group *shutdown_group)
Create a new serializer for SIP tasks.
Definition: res_pjsip.c:2089
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 thread pool.
int ast_sip_sched_task_cancel(struct ast_sip_sched_task *schtd)
Cancels the next invocation of a task.
int ast_sip_push_task_wait_serializer(struct ast_taskprocessor *serializer, int(*sip_task)(void *), void *task_data)
Push a task to the serializer and wait for it to complete.
Definition: res_pjsip.c:2179
@ AST_SIP_SCHED_TASK_DATA_AO2
Definition: res_pjsip.h:2097
@ AST_SIP_SCHED_TASK_VARIABLE
Definition: res_pjsip.h:2080
static char prefix[MAX_PREFIX]
Definition: http.c:144
char * strsep(char **str, const char *delims)
#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:191
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:4175
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
Definition: pjsip_options.c:97
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
Definition: pjsip_options.c:96
static const char * status_map[]
static struct ast_serializer_shutdown_group * shutdown_group
Shutdown group for options serializers.
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.
#define MAX_UNLOAD_TIMEOUT_TIME
Maximum wait time to join the below shutdown group.
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.
AO2_STRING_FIELD_HASH_FN(ast_sip_contact_status, name)
Hashing function for contact statuses.
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.
AO2_STRING_FIELD_SORT_FN(ast_sip_contact_status, name)
Sort function for contact statuses.
AO2_STRING_FIELD_CMP_FN(ast_sip_contact_status, name)
Comparator function for contact statuses.
#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:3477
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:2468
int ast_sip_is_allowed_uri(pjsip_uri *uri)
Check whether a pjsip_uri is allowed or not.
Definition: res_pjsip.c:3472
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:722
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:687
pjsip_endpoint * ast_sip_get_pjsip_endpoint(void)
Get a pointer to the PJSIP endpoint.
Definition: res_pjsip.c:520
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:3350
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:2201
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:1938
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:481
void ast_sip_unregister_endpoint_formatter(struct ast_sip_endpoint_formatter *obj)
Unregister an endpoint formatter.
Definition: res_pjsip.c:487
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:1992
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:1435
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:2008
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:2424
ast_sip_contact_status_type
Status type for a contact.
Definition: res_pjsip.h:431
@ AVAILABLE
Definition: res_pjsip.h:435
@ UNAVAILABLE
Definition: res_pjsip.h:433
@ REMOVED
Definition: res_pjsip.h:440
@ UNKNOWN
Definition: res_pjsip.h:437
@ CREATED
Definition: res_pjsip.h:439
#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:2317
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:2423
@ 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:1853
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:2391
int ast_sorcery_object_id_compare(void *obj, void *arg, int flags)
ao2 object comparator based on sorcery id.
Definition: sorcery.c:2464
int ast_sorcery_object_id_sort(const void *obj, const void *arg, int flags)
ao2 object sorter based on sorcery id.
Definition: sorcery.c:2440
int ast_sorcery_object_id_hash(const void *obj, int flags)
ao2 object hasher based on sorcery id.
Definition: sorcery.c:2475
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:1897
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:1989
void 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:186
#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_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:209
#define ast_string_fields_copy(copy, orig)
Copy all string fields from one instance to another of the same structure.
Definition: stringfields.h:630
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:521
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
Definition: stringfields.h:359
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Definition: stringfields.h:374
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
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:761
#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_strlen_zero(const char *s)
Definition: strings.h:65
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:3046
struct mansession * s
Definition: res_pjsip.h:3048
void * arg
Definition: res_pjsip.h:3054
const struct message * m
Definition: res_pjsip.h:3050
A SIP address of record.
Definition: res_pjsip.h:475
double qualify_timeout
Definition: res_pjsip.h:503
struct ao2_container * permanent_contacts
Definition: res_pjsip.h:499
int authenticate_qualify
Definition: res_pjsip.h:493
unsigned int qualify_frequency
Definition: res_pjsip.h:491
A contact's status.
Definition: res_pjsip.h:448
const ast_string_field uri
Definition: res_pjsip.h:454
enum ast_sip_contact_status_type status
Definition: res_pjsip.h:465
enum ast_sip_contact_status_type last_status
Definition: res_pjsip.h:467
const ast_string_field aor
Definition: res_pjsip.h:454
struct ast_sip_security_mechanism_vector security_mechanisms
Definition: res_pjsip.h:463
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:514
struct ast_sip_contact * contact
Definition: res_pjsip.h:520
Contact associated with an address of record.
Definition: res_pjsip.h:389
const ast_string_field uri
Definition: res_pjsip.h:411
double qualify_timeout
Definition: res_pjsip.h:419
const ast_string_field via_addr
Definition: res_pjsip.h:411
const ast_string_field call_id
Definition: res_pjsip.h:411
const ast_string_field aor
Definition: res_pjsip.h:411
const ast_string_field outbound_proxy
Definition: res_pjsip.h:411
struct timeval expiration_time
Definition: res_pjsip.h:413
const ast_string_field path
Definition: res_pjsip.h:411
const ast_string_field endpoint_name
Definition: res_pjsip.h:411
int authenticate_qualify
Definition: res_pjsip.h:417
const ast_string_field user_agent
Definition: res_pjsip.h:411
unsigned int qualify_frequency
Definition: res_pjsip.h:415
An entity responsible formatting endpoint information.
Definition: res_pjsip.h:3072
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:3076
An entity with which Asterisk communicates.
Definition: res_pjsip.h:958
const ast_string_field aors
Definition: res_pjsip.h:987
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.
Definition: taskprocessor.c:69
In case you didn't read that giant block of text above the mansession_session struct,...
Definition: manager.c:326
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.
struct ao2_container * dynamic_contacts
Only dynamic contacts associated with this AOR.
struct sip_options_aor::@454 compositors
The endpoint state compositors we are feeding, a reference is held to each.
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.
void ast_taskprocessor_build_name(char *buf, unsigned int size, const char *format,...)
Build a taskprocessor name with a sequence number on the end.
const char * ast_taskprocessor_name(struct ast_taskprocessor *tps)
Return the name of the taskprocessor singleton.
#define AST_TASKPROCESSOR_HIGH_WATER_LEVEL
Definition: taskprocessor.h:64
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.
#define AST_TASKPROCESSOR_MAX_NAME
Suggested maximum taskprocessor name length (less null terminator).
Definition: taskprocessor.h:61
Test Framework API.
#define ast_test_suite_event_notify(s, f,...)
Definition: test.h:189
static struct test_val a
int ast_serializer_shutdown_group_join(struct ast_serializer_shutdown_group *shutdown_group, int timeout)
Wait for the serializers in the group to shutdown with timeout.
Definition: threadpool.c:1241
struct ast_serializer_shutdown_group * ast_serializer_shutdown_group_alloc(void)
Create a serializer group shutdown control object.
Definition: threadpool.c:1229
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:941
#define ast_assert(a)
Definition: utils.h:739
#define ARRAY_LEN(a)
Definition: utils.h:666
#define ast_random_double()
Returns a random number between 0.0 and 1.0, inclusive.
Definition: utils.h:624
#define AST_VECTOR_RESET(vec, cleanup)
Reset vector.
Definition: vector.h:625
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:609
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
Definition: vector.h:174
#define AST_VECTOR_REMOVE(vec, idx, preserve_ordered)
Remove an element from a vector by index.
Definition: vector.h:412
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
Definition: vector.h:113
#define AST_VECTOR_APPEND(vec, elem)
Append an element to a vector, growing the vector if needed.
Definition: vector.h:256
#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:680