Asterisk - The Open Source Telephony Project GIT-master-754dea3
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros Modules Pages
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 /*! \brief If true only authenticate if OPTIONS response is 2XX */
185 /*! If true authenticate the qualify challenge response if needed */
187 /*! \brief Qualify timeout. 0 is diabled. */
189 /*! \brief The name of the AOR */
190 char name[0];
191};
192
193/*!
194 * \internal
195 * \brief Container of active SIP AORs for qualifying
196 */
198
199/*!
200 * \internal
201 * \brief Container of contact statuses
202 */
204
205/*!
206 * \internal
207 * \brief Container of endpoint state compositors
208 */
210
211/*!
212 * \internal
213 * \brief Serializer for AOR, endpoint state compositor, and contact existence management
214 */
216
217static pj_status_t send_options_response(pjsip_rx_data *rdata, int code)
218{
219 pjsip_endpoint *endpt = ast_sip_get_pjsip_endpoint();
220 pjsip_dialog *dlg = pjsip_rdata_get_dlg(rdata);
221 pjsip_transaction *trans = pjsip_rdata_get_tsx(rdata);
222 pjsip_tx_data *tdata;
223 const pjsip_hdr *hdr;
224 pj_status_t status;
225
226 /* Make the response object */
227 status = ast_sip_create_response(rdata, code, NULL, &tdata);
228 if (status != PJ_SUCCESS) {
229 ast_log(LOG_ERROR, "Unable to create response (%d)\n", status);
230 return status;
231 }
232
233 /* Add appropriate headers */
234 if ((hdr = pjsip_endpt_get_capability(endpt, PJSIP_H_ACCEPT, NULL))) {
235 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)pjsip_hdr_clone(tdata->pool, hdr));
236 }
237 if ((hdr = pjsip_endpt_get_capability(endpt, PJSIP_H_ALLOW, NULL))) {
238 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)pjsip_hdr_clone(tdata->pool, hdr));
239 }
240 if ((hdr = pjsip_endpt_get_capability(endpt, PJSIP_H_SUPPORTED, NULL))) {
241 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)pjsip_hdr_clone(tdata->pool, hdr));
242 }
243
244 /*
245 * XXX TODO: pjsip doesn't care a lot about either of these headers -
246 * while it provides specific methods to create them, they are defined
247 * to be the standard string header creation. Hard coded here.
248 */
249 ast_sip_add_header(tdata, "Accept-Encoding", DEFAULT_ENCODING);
250 ast_sip_add_header(tdata, "Accept-Language", DEFAULT_LANGUAGE);
251
252 if (dlg && trans) {
253 status = pjsip_dlg_send_response(dlg, trans, tdata);
254 } else {
255 struct ast_sip_endpoint *endpoint;
256
257 endpoint = ast_pjsip_rdata_get_endpoint(rdata);
258 status = ast_sip_send_stateful_response(rdata, tdata, endpoint);
259 ao2_cleanup(endpoint);
260 }
261
262 if (status != PJ_SUCCESS) {
263 ast_log(LOG_ERROR, "Unable to send response (%d)\n", status);
264 }
265
266 return status;
267}
268
269static pj_bool_t options_on_rx_request(pjsip_rx_data *rdata)
270{
271 RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
272 pjsip_uri *ruri;
273 char exten[AST_MAX_EXTENSION];
274
275 if (pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_options_method)) {
276 return PJ_FALSE;
277 }
278
279 if (!(endpoint = ast_pjsip_rdata_get_endpoint(rdata))) {
280 return PJ_FALSE;
281 }
282
283 ruri = rdata->msg_info.msg->line.req.uri;
284 if (!ast_sip_is_allowed_uri(ruri)) {
285 send_options_response(rdata, 416);
286 return PJ_TRUE;
287 }
288
289 ast_copy_pj_str(exten, ast_sip_pjsip_uri_get_username(ruri), sizeof(exten));
290
291 /*
292 * We may want to match in the dialplan without any user
293 * options getting in the way.
294 */
296
297 if (ast_shutting_down()) {
298 /*
299 * Not taking any new calls at this time.
300 * Likely a server availability OPTIONS poll.
301 */
302 send_options_response(rdata, 503);
303 } else if (!ast_strlen_zero(exten)
304 && !ast_exists_extension(NULL, endpoint->context, exten, 1, NULL)) {
305 send_options_response(rdata, 404);
306 } else {
307 send_options_response(rdata, 200);
308 }
309 return PJ_TRUE;
310}
311
312static pjsip_module options_module = {
313 .name = {"Options Module", 14},
314 .id = -1,
315 .priority = PJSIP_MOD_PRIORITY_APPLICATION,
316 .on_rx_request = options_on_rx_request,
317};
318
319static const char *status_map[] = {
320 [UNAVAILABLE] = "Unreachable",
321 [AVAILABLE] = "Reachable",
322 [UNKNOWN] = "Unknown",
323 [CREATED] = "NonQualified",
324 [REMOVED] = "Removed",
325};
326
327static const char *short_status_map[] = {
328 [UNAVAILABLE] = "Unavail",
329 [AVAILABLE] = "Avail",
330 [UNKNOWN] = "Unknown",
331 [CREATED] = "NonQual",
332 [REMOVED] = "Removed",
333};
334
336{
338 return status_map[status];
339}
340
342{
344 return short_status_map[status];
345}
346
347/*! \brief Destructor for contact statuses */
348static void sip_contact_status_dtor(void *obj)
349{
350 struct ast_sip_contact_status *contact_status = obj;
351
353
354 ast_string_field_free_memory(contact_status);
355}
356
358{
359 struct ast_sip_contact_status *contact_status;
360 size_t size = sizeof(*contact_status) + strlen(name) + 1;
361
362 contact_status = ao2_alloc_options(size, sip_contact_status_dtor,
364 if (!contact_status) {
365 return NULL;
366 }
367 if (ast_string_field_init(contact_status, 256)) {
368 ao2_ref(contact_status, -1);
369 return NULL;
370 }
371 AST_VECTOR_INIT(&contact_status->security_mechanisms, 0);
372 strcpy(contact_status->name, name); /* SAFE */
373 return contact_status;
374}
375
377{
378 struct ast_sip_contact_status *dst;
379
380 dst = sip_contact_status_alloc(src->name);
381 if (!dst) {
382 return NULL;
383 }
384
385 if (ast_string_fields_copy(dst, src)) {
386 ao2_ref(dst, -1);
387 return NULL;
388 }
389 dst->rtt = src->rtt;
390 dst->status = src->status;
391 dst->last_status = src->last_status;
392
394 return dst;
395}
396
397/*! \brief Hashing function for contact statuses */
399
400/*! \brief Sort function for contact statuses */
402
403/*! \brief Comparator function for contact statuses */
405
406/*! \brief Helper function to allocate a contact statuses container */
408{
409 /*
410 * Replace duplicate objects so we can update the immutable
411 * contact status objects by simply linking in a new object.
412 */
415 ast_sip_contact_status_hash_fn, ast_sip_contact_status_sort_fn,
416 ast_sip_contact_status_cmp_fn);
417}
418
419/*! \brief Function which publishes a contact status update to all interested endpoints */
420static void sip_options_publish_contact_state(const struct sip_options_aor *aor_options,
421 const struct ast_sip_contact_status *contact_status)
422{
423 int i;
424
425 for (i = 0; i < AST_VECTOR_SIZE(&aor_options->compositors); ++i) {
426 const struct sip_options_endpoint_state_compositor *endpoint_state_compositor;
427
428 endpoint_state_compositor = AST_VECTOR_GET(&aor_options->compositors, i);
430 contact_status);
431 }
432}
433
434/*!
435 * \brief Task to notify endpoints of a contact status change
436 * \note Run by management_serializer
437 */
439{
440 struct ast_sip_contact_status *contact_status = obj;
441 struct sip_options_aor *aor_options;
442
443 aor_options = ao2_find(sip_options_aors, contact_status->aor, OBJ_SEARCH_KEY);
444 if (aor_options) {
445 sip_options_publish_contact_state(aor_options, contact_status);
446 ao2_ref(aor_options, -1);
447 }
448 ao2_ref(contact_status, -1);
449
450 return 0;
451}
452
454{
455 struct ast_taskprocessor *mgmt_serializer = management_serializer;
456
457 if (mgmt_serializer) {
458 ao2_ref(contact_status, +1);
460 contact_status)) {
461 ao2_ref(contact_status, -1);
462 }
463 }
464}
465
467{
468 struct ast_sip_contact_status *contact_status;
469 int res;
470
471 /*
472 * At startup a contact status can be retrieved when static contacts
473 * are themselves being setup. This happens before we are fully setup.
474 * Since we don't actually trigger qualify or anything as a result it
475 * is safe to do so. They'll just get back a contact status that will
476 * be updated later. At this time they only care that the contact
477 * status gets created for the static contact anyway.
478 */
480 /*
481 * We haven't been pre-initialized or we are shutting down.
482 * Neither situation should happen.
483 */
484 ast_assert(0);
485 return NULL;
486 }
487
489
490 /* If contact status for this contact already exists just return it */
491 contact_status = ao2_find(sip_options_contact_statuses,
493 if (contact_status) {
495 return contact_status;
496 }
497
498 /* Otherwise we have to create and store a new contact status */
499 contact_status = sip_contact_status_alloc(ast_sorcery_object_get_id(contact));
500 if (!contact_status) {
502 return NULL;
503 }
504
505 contact_status->rtt = 0;
506 contact_status->status = CREATED;
507 contact_status->last_status = CREATED;
508 res = ast_string_field_set(contact_status, uri, contact->uri);
509 res |= ast_string_field_set(contact_status, aor, contact->aor);
510 if (res) {
512 ao2_ref(contact_status, -1);
513 return NULL;
514 }
515
518
519 ast_statsd_log_string_va("PJSIP.contacts.states.%s", AST_STATSD_GAUGE,
520 "+1", 1.0, ast_sip_get_contact_status_label(contact_status->status));
521
522 sip_options_contact_status_update(contact_status);
523
524 return contact_status;
525}
526
528{
531}
532
533/*! \brief Hashing function for OPTIONS AORs */
535
536/*! \brief Comparator function for SIP OPTIONS AORs */
538
539/*! \brief Hashing function for endpoint state compositors */
541
542/*! \brief Comparator function for endpoint state compositors */
544
545/*! \brief Structure used to contain information for an OPTIONS callback */
547 /*! \brief The contact we qualified */
549 /*! \brief The AOR options */
551 /*! \brief The time at which this OPTIONS attempt was started */
552 struct timeval rtt_start;
553 /*! \brief The new status of the contact */
555};
556
557/*!
558 * \brief Return the current state of an endpoint state compositor
559 * \pre The endpoint_state_compositor lock must be held.
560 */
562 const struct sip_options_endpoint_state_compositor *endpoint_state_compositor)
563{
564 struct ao2_iterator it_aor_statuses;
565 struct sip_options_endpoint_aor_status *aor_status;
567
568 it_aor_statuses = ao2_iterator_init(endpoint_state_compositor->aor_statuses, 0);
569 for (; (aor_status = ao2_iterator_next(&it_aor_statuses)); ao2_ref(aor_status, -1)) {
570 if (aor_status->available) {
572 ao2_ref(aor_status, -1);
573 break;
574 }
575 }
576 ao2_iterator_destroy(&it_aor_statuses);
577
578 return state;
579}
580
581/*!
582 * \brief Update the AOR status on an endpoint state compositor
583 * \pre The endpoint_state_compositor lock must be held.
584 */
586 const char *name, enum ast_sip_contact_status_type status)
587{
588 struct sip_options_endpoint_aor_status *aor_status;
589 enum ast_endpoint_state endpoint_state;
590
591 aor_status = ao2_find(endpoint_state_compositor->aor_statuses, name,
593 if (!aor_status) {
594 /* The AOR status doesn't exist already so we don't need to go any further */
595 if (status == REMOVED) {
596 return;
597 }
598
599 aor_status = ao2_alloc_options(sizeof(*aor_status) + strlen(name) + 1, NULL,
601 if (!aor_status) {
602 return;
603 }
604
605 strcpy(aor_status->name, name); /* SAFE */
606 ao2_link(endpoint_state_compositor->aor_statuses, aor_status);
607 }
608
609 if (status == REMOVED) {
610 /*
611 * If the AOR is being removed then remove its AOR status
612 * from the endpoint compositor.
613 */
614 ao2_unlink(endpoint_state_compositor->aor_statuses, aor_status);
615 } else {
616 aor_status->available = (status == AVAILABLE ? 1 : 0);
617 }
618 ao2_ref(aor_status, -1);
619
620 if (!endpoint_state_compositor->active) {
621 return;
622 }
623
624 /* If this AOR is available then the endpoint itself has to be online */
625 if (status == AVAILABLE) {
626 ast_debug(3, "Endpoint state compositor '%s' is online as AOR '%s' is available\n",
627 endpoint_state_compositor->name, name);
628 endpoint_state = AST_ENDPOINT_ONLINE;
629 } else {
630 endpoint_state =
631 sip_options_get_endpoint_state_compositor_state(endpoint_state_compositor);
632 }
633
634 ast_sip_persistent_endpoint_update_state(endpoint_state_compositor->name,
635 endpoint_state);
636}
637
638/*! \brief Function which notifies endpoint state compositors of a state change of an AOR */
641{
642 int i;
643
644 /* Iterate through the associated endpoint state compositors updating them */
645 for (i = 0; i < AST_VECTOR_SIZE(&aor_options->compositors); ++i) {
646 struct sip_options_endpoint_state_compositor *endpoint_state_compositor;
647
648 endpoint_state_compositor = AST_VECTOR_GET(&aor_options->compositors, i);
649
650 ao2_lock(endpoint_state_compositor);
651 sip_options_update_endpoint_state_compositor_aor(endpoint_state_compositor,
652 aor_options->name, status);
653 ao2_unlock(endpoint_state_compositor);
654 }
655
656 if (status == REMOVED) {
658 }
659}
660
661/*!
662 * \brief Task to notify an AOR of a contact status change
663 * \note Run by aor_options->serializer
664 */
666{
667 struct sip_options_contact_callback_data *contact_callback_data = obj;
668 struct ast_sip_contact *contact;
669 struct ast_sip_contact_status *cs_old;
670 struct ast_sip_contact_status *cs_new;
671
672 /*
673 * Determine if this is a late arriving notification, as it is
674 * possible that we get a callback from PJSIP giving us contact
675 * status but in the mean time said contact has been removed
676 * from the controlling AOR.
677 */
678
679 if (!contact_callback_data->aor_options->qualify_frequency) {
680 /* Contact qualify response is late */
681 ao2_ref(contact_callback_data, -1);
682 return 0;
683 }
684
685 contact = ao2_find(contact_callback_data->aor_options->contacts,
686 contact_callback_data->contact, OBJ_SEARCH_OBJECT);
687 if (!contact) {
688 /* Contact qualify response is late */
689 ao2_ref(contact_callback_data, -1);
690 return 0;
691 }
692 ao2_ref(contact, -1);
693
695 ast_sorcery_object_get_id(contact_callback_data->contact), OBJ_SEARCH_KEY);
696 if (!cs_old) {
697 /* Contact qualify response is late */
698 ao2_ref(contact_callback_data, -1);
699 return 0;
700 }
701
702 /* Update the contact specific status information */
703 cs_new = sip_contact_status_copy(cs_old);
704 ao2_ref(cs_old, -1);
705 if (!cs_new) {
706 ao2_ref(contact_callback_data, -1);
707 return 0;
708 }
709 cs_new->last_status = cs_new->status;
710 cs_new->status = contact_callback_data->status;
711 cs_new->rtt =
712 cs_new->status == AVAILABLE
713 ? ast_tvdiff_us(ast_tvnow(), contact_callback_data->rtt_start)
714 : 0;
716
717 /*
718 * If the status has changed then notify the endpoint state compositors
719 * and publish our events.
720 */
721 if (cs_new->last_status != cs_new->status) {
722 if (cs_new->status == AVAILABLE) {
723 /* If this is the first available contact then the AOR has become available */
724 ++contact_callback_data->aor_options->available;
725 if (contact_callback_data->aor_options->available == 1) {
727 contact_callback_data->aor_options, AVAILABLE);
728 }
729 } else if (cs_new->last_status == AVAILABLE) {
730 ast_assert(cs_new->status == UNAVAILABLE);
731
732 /* If there are no more available contacts then this AOR is unavailable */
733 --contact_callback_data->aor_options->available;
734 if (!contact_callback_data->aor_options->available) {
736 contact_callback_data->aor_options, UNAVAILABLE);
737 }
738 }
739
740 ast_verb(3, "Contact %s/%s is now %s. RTT: %.3f msec\n",
741 cs_new->aor,
742 cs_new->uri,
744 cs_new->rtt / 1000.0);
745
746 ast_statsd_log_string_va("PJSIP.contacts.states.%s", AST_STATSD_GAUGE,
748 ast_statsd_log_string_va("PJSIP.contacts.states.%s", AST_STATSD_GAUGE,
749 "+1", 1.0, ast_sip_get_contact_status_label(cs_new->status));
750
752
753 ast_test_suite_event_notify("AOR_CONTACT_UPDATE",
754 "Contact: %s\r\n"
755 "Status: %s",
756 cs_new->name,
758 } else {
759 ast_debug(3, "Contact %s/%s status didn't change: %s, RTT: %.3f msec\n",
760 cs_new->aor,
761 cs_new->uri,
763 cs_new->rtt / 1000.0);
764 }
765
766 ast_statsd_log_full_va("PJSIP.contacts.%s.rtt", AST_STATSD_TIMER,
767 cs_new->status != AVAILABLE ? -1 : cs_new->rtt / 1000,
768 1.0,
769 cs_new->name);
770
771 ast_test_suite_event_notify("AOR_CONTACT_QUALIFY_RESULT",
772 "Contact: %s\r\n"
773 "Status: %s\r\n"
774 "RTT: %" PRId64,
775 cs_new->name,
777 cs_new->rtt);
778
779 ast_debug(3, "AOR '%s' now has %d available contacts\n",
780 contact_callback_data->aor_options->name,
781 contact_callback_data->aor_options->available);
782
783 ao2_ref(cs_new, -1);
784 ao2_ref(contact_callback_data, -1);
785
786 return 0;
787}
788
789/*! \brief Callback for when we get a result from a SIP OPTIONS request (a response or a timeout) */
790static void qualify_contact_cb(void *token, pjsip_event *e)
791{
792 struct sip_options_contact_callback_data *contact_callback_data = token;
794
795 switch(e->body.tsx_state.type) {
796 default:
797 ast_log(LOG_ERROR, "Unexpected PJSIP event %u\n", e->body.tsx_state.type);
798 /* Fall through */
799 case PJSIP_EVENT_TRANSPORT_ERROR:
800 case PJSIP_EVENT_TIMER:
802 break;
803 case PJSIP_EVENT_RX_MSG:
804 if (contact_callback_data->aor_options->qualify_2xx_only &&
805 (e->body.tsx_state.tsx->status_code < 200 || e->body.tsx_state.tsx->status_code >= 300)) {
807 } else {
809 }
810 break;
811 }
812
813 /* Update the callback data with the new status, this will get handled in the AOR serializer */
814 contact_callback_data->status = status;
815
816 if (ast_sip_push_task(contact_callback_data->aor_options->serializer,
817 sip_options_contact_status_notify_task, contact_callback_data)) {
818 ast_log(LOG_WARNING, "Unable to queue contact status update for '%s' on AOR '%s', state will be incorrect\n",
819 ast_sorcery_object_get_id(contact_callback_data->contact),
820 contact_callback_data->aor_options->name);
821 ao2_ref(contact_callback_data, -1);
822 }
823
824 /* The task inherited our reference so we don't unreference here */
825}
826
827/*! \brief Destructor for contact callback data */
829{
830 struct sip_options_contact_callback_data *contact_callback_data = obj;
831
832 ao2_cleanup(contact_callback_data->contact);
833 ao2_cleanup(contact_callback_data->aor_options);
834}
835
836/*! \brief Contact callback data allocator */
839{
840 struct sip_options_contact_callback_data *contact_callback_data;
841
842 contact_callback_data = ao2_alloc_options(sizeof(*contact_callback_data),
844 if (!contact_callback_data) {
845 return NULL;
846 }
847
848 contact_callback_data->contact = ao2_bump(contact);
849 contact_callback_data->aor_options = ao2_bump(aor_options);
850 contact_callback_data->rtt_start = ast_tvnow();
851
852 return contact_callback_data;
853}
854
855/*! \brief Send a SIP OPTIONS request for a contact */
856static int sip_options_qualify_contact(void *obj, void *arg, int flags)
857{
858 struct ast_sip_contact *contact = obj;
859 struct sip_options_aor *aor_options = arg;
860 RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
861 pjsip_tx_data *tdata;
862 struct ast_sip_contact_status *contact_status;
863 struct sip_options_contact_callback_data *contact_callback_data;
864
865 ast_debug(3, "Qualifying contact '%s' on AOR '%s'\n",
867
869 endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint",
871 }
872 if (!endpoint && AST_VECTOR_SIZE(&aor_options->compositors)) {
873 struct sip_options_endpoint_state_compositor *endpoint_state_compositor;
874
875 endpoint_state_compositor = AST_VECTOR_GET(&aor_options->compositors, 0);
876 endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint",
877 endpoint_state_compositor->name);
878 }
879 if (!endpoint) {
880 ast_debug(3, "Could not find an endpoint to qualify contact '%s' on AOR '%s'\n",
881 ast_sorcery_object_get_id(contact), aor_options->name);
882 return 0;
883 }
884
885 if (ast_sip_create_request("OPTIONS", NULL, endpoint, NULL, contact, &tdata)) {
886 ast_log(LOG_ERROR, "Unable to create request to qualify contact %s on AOR %s\n",
887 contact->uri, aor_options->name);
888 return 0;
889 }
890
891 /* If an outbound proxy is specified set it on this request */
892 if (!ast_strlen_zero(contact->outbound_proxy) &&
894 ast_log(LOG_ERROR, "Unable to apply outbound proxy on request to qualify contact %s\n",
895 contact->uri);
896 pjsip_tx_data_dec_ref(tdata);
897 return 0;
898 }
899
900 contact_status = ast_res_pjsip_find_or_create_contact_status(contact);
901 if (!contact_status) {
902 ast_log(LOG_ERROR, "Unable to retrieve contact status information for contact %s on AOR %s\n",
903 contact->uri, aor_options->name);
904 pjsip_tx_data_dec_ref(tdata);
905 return 0;
906 }
907 ao2_ref(contact_status, -1);
908
909 contact_callback_data = sip_options_contact_callback_data_alloc(contact, aor_options);
910 if (!contact_callback_data) {
911 ast_log(LOG_ERROR, "Unable to create object to contain callback data for contact %s on AOR %s\n",
912 contact->uri, aor_options->name);
913 pjsip_tx_data_dec_ref(tdata);
914 return 0;
915 }
916
917 if (ast_sip_send_out_of_dialog_request(tdata, endpoint,
918 (int)(aor_options->qualify_timeout * 1000), contact_callback_data,
920 ast_log(LOG_ERROR, "Unable to send request to qualify contact %s on AOR %s\n",
921 contact->uri, aor_options->name);
922 ao2_ref(contact_callback_data, -1);
923 }
924
925 return 0;
926}
927
928/*!
929 * \brief Task to qualify contacts of an AOR
930 * \note Run by aor_options->serializer
931 */
932static int sip_options_qualify_aor(void *obj)
933{
934 struct sip_options_aor *aor_options = obj;
935
936 ast_debug(3, "Qualifying all contacts on AOR '%s'\n", aor_options->name);
937
938 /* Attempt to send an OPTIONS request to every contact on this AOR */
940 (struct sip_options_aor *) aor_options);
941
942 /* Always reschedule to the frequency we should go */
943 return aor_options->qualify_frequency * 1000;
944}
945
946/*! \brief Forward declaration of this helpful function */
947static int sip_options_remove_contact(void *obj, void *arg, int flags);
948
949/*! \brief Destructor function for SIP OPTIONS AORs */
950static void sip_options_aor_dtor(void *obj)
951{
952 struct sip_options_aor *aor_options = obj;
953
954 /*
955 * Any contacts are unreachable since the AOR is being destroyed
956 * so remove their contact status
957 */
958 if (aor_options->contacts) {
960 sip_options_remove_contact, aor_options);
961 ao2_ref(aor_options->contacts, -1);
962 }
963 ao2_cleanup(aor_options->dynamic_contacts);
964
966
967 ast_assert(AST_VECTOR_SIZE(&aor_options->compositors) == 0);
968 AST_VECTOR_FREE(&aor_options->compositors);
969}
970
971/*! \brief Allocator for AOR OPTIONS */
973{
974 struct sip_options_aor *aor_options;
975 char tps_name[AST_TASKPROCESSOR_MAX_NAME + 1];
976
977 aor_options = ao2_alloc_options(sizeof(*aor_options) + strlen(ast_sorcery_object_get_id(aor)) + 1,
979 if (!aor_options) {
980 return NULL;
981 }
982
983 strcpy(aor_options->name, ast_sorcery_object_get_id(aor)); /* SAFE */
984
985 ast_taskprocessor_build_name(tps_name, sizeof(tps_name), "pjsip/options/%s",
987 aor_options->serializer = ast_sip_create_serializer_group(tps_name,
989 if (!aor_options->serializer) {
990 ao2_ref(aor_options, -1);
991 return NULL;
992 }
993
995 ao2_ref(aor_options, -1);
996 return NULL;
997 }
998
1002 if (!aor_options->contacts) {
1003 ao2_ref(aor_options, -1);
1004 return NULL;
1005 }
1006
1010 if (!aor_options->dynamic_contacts) {
1011 ao2_ref(aor_options, -1);
1012 return NULL;
1013 }
1014
1015 return aor_options;
1016}
1017
1018/*! \brief Remove contact status for a hint */
1020 struct ast_sip_contact *contact)
1021{
1022 struct ast_sip_contact_status *cs_new;
1023 struct ast_sip_contact_status *cs_old;
1024
1027 if (!cs_old) {
1028 ast_debug(3, "Attempted to remove contact status for '%s' but it does not exist\n",
1029 ast_sorcery_object_get_id(contact));
1030 return;
1031 }
1032
1033 ast_verb(2, "Contact %s/%s has been deleted\n", contact->aor, contact->uri);
1034
1035 /* Update the contact status to reflect its new state */
1036 cs_new = sip_contact_status_copy(cs_old);
1037 if (!cs_new) {
1038 /*
1039 * We'll have to violate the immutable property because we
1040 * couldn't create a new one to modify and we are deleting
1041 * the contact status anyway.
1042 */
1043 cs_new = cs_old;
1044 } else {
1045 ao2_ref(cs_old, -1);
1046 }
1047 cs_new->last_status = cs_new->status;
1048 cs_new->status = REMOVED;
1049 cs_new->rtt = 0;
1050
1051 ast_statsd_log_string_va("PJSIP.contacts.states.%s", AST_STATSD_GAUGE,
1052 "-1", 1.0, ast_sip_get_contact_status_label(cs_new->last_status));
1053 ast_statsd_log_string_va("PJSIP.contacts.states.%s", AST_STATSD_GAUGE,
1054 "+1", 1.0, ast_sip_get_contact_status_label(cs_new->status));
1055
1057
1058 /*
1059 * The only time we need to update the AOR is if this contact was
1060 * available and qualify is in use, otherwise we can just stop
1061 * early.
1062 */
1063 if (!aor_options->qualify_frequency || cs_new->last_status != AVAILABLE) {
1064 ao2_ref(cs_new, -1);
1065 return;
1066 }
1067
1068 --aor_options->available;
1069 if (!aor_options->available) {
1071 }
1072
1073 ast_debug(3, "AOR '%s' now has %d available contacts\n", aor_options->name,
1074 aor_options->available);
1075
1076 ao2_ref(cs_new, -1);
1077}
1078
1079/*! \brief Task data for AOR creation or updating */
1081 /*! \brief The AOR options for this AOR */
1083 /*! \brief The AOR which contains the new configuraton */
1085 /*! \brief Optional container of existing AOR s*/
1087 /*! \brief Whether this AOR is being added */
1089};
1090
1091/*! \brief Callback function to remove a contact and its contact status from an AOR */
1092static int sip_options_remove_contact(void *obj, void *arg, int flags)
1093{
1094 struct ast_sip_contact *contact = obj;
1095 struct sip_options_aor *aor_options = arg;
1096
1097 sip_options_remove_contact_status(aor_options, contact);
1098
1099 return CMP_MATCH;
1100}
1101
1102/*! \brief Determine an initial time for scheduling AOR qualifying */
1104{
1105 int initial_interval;
1106 int max_time = ast_sip_get_max_initial_qualify_time();
1107
1108 if (max_time && max_time < qualify_frequency) {
1109 initial_interval = max_time;
1110 } else {
1111 initial_interval = qualify_frequency;
1112 }
1113
1114 initial_interval = (int)((initial_interval * 1000) * ast_random_double());
1115 return 0 < initial_interval ? initial_interval : 1;
1116}
1117
1118/*! \brief Set the contact status for a contact */
1121{
1122 struct ast_sip_contact_status *cs_new;
1123
1124 /* Update the contact specific status information */
1125 cs_new = sip_contact_status_copy(contact_status);
1126 if (!cs_new) {
1127 return;
1128 }
1129 cs_new->last_status = cs_new->status;
1130 cs_new->status = status;
1131
1132 /*
1133 * We need to always set the RTT to zero because we haven't completed
1134 * an OPTIONS ping so RTT is unknown. If the OPTIONS ping were still
1135 * running it will be refreshed on the next go round anyway.
1136 */
1137 cs_new->rtt = 0;
1138
1140
1141 if (cs_new->status != cs_new->last_status) {
1142 ast_verb(3, "Contact %s/%s is now %s.\n",
1143 cs_new->aor, cs_new->uri,
1145
1146 ast_statsd_log_string_va("PJSIP.contacts.states.%s", AST_STATSD_GAUGE,
1147 "-1", 1.0, ast_sip_get_contact_status_label(cs_new->last_status));
1148 ast_statsd_log_string_va("PJSIP.contacts.states.%s", AST_STATSD_GAUGE,
1149 "+1", 1.0, ast_sip_get_contact_status_label(cs_new->status));
1150
1152
1153 ast_test_suite_event_notify("AOR_CONTACT_UPDATE",
1154 "Contact: %s\r\n"
1155 "Status: %s",
1156 cs_new->name,
1158 }
1159 ao2_ref(cs_new, -1);
1160}
1161
1162/*! \brief Transition the contact status to unqualified mode */
1163static int sip_options_set_contact_status_unqualified(void *obj, void *arg, int flags)
1164{
1165 struct ast_sip_contact *contact = obj;
1166 struct ast_sip_contact_status *contact_status;
1167
1168 contact_status = ast_res_pjsip_find_or_create_contact_status(contact);
1169 if (!contact_status) {
1170 return 0;
1171 }
1172
1173 switch (contact_status->status) {
1174 case AVAILABLE:
1175 case UNAVAILABLE:
1176 case UNKNOWN:
1177 sip_options_set_contact_status(contact_status, CREATED);
1178 break;
1179 case CREATED:
1180 case REMOVED:
1181 break;
1182 }
1183
1184 ao2_ref(contact_status, -1);
1185
1186 return 0;
1187}
1188
1189/*! \brief Transition the contact status to qualified mode */
1190static int sip_options_set_contact_status_qualified(void *obj, void *arg, int flags)
1191{
1192 struct ast_sip_contact *contact = obj;
1193 struct ast_sip_contact_status *contact_status;
1194
1195 contact_status = ast_res_pjsip_find_or_create_contact_status(contact);
1196 if (!contact_status) {
1197 return 0;
1198 }
1199
1200 switch (contact_status->status) {
1201 case AVAILABLE:
1203 break;
1204 case UNAVAILABLE:
1205 case UNKNOWN:
1206 case CREATED:
1207 case REMOVED:
1208 break;
1209 }
1210
1211 ao2_ref(contact_status, -1);
1212
1213 return 0;
1214}
1215
1216/*! \brief Count AVAILABLE qualified contacts. */
1217static int sip_options_contact_status_available_count(void *obj, void *arg, int flags)
1218{
1219 struct ast_sip_contact *contact = obj;
1220 unsigned int *available = arg;
1221 struct ast_sip_contact_status *contact_status;
1222
1223 contact_status = ast_res_pjsip_find_or_create_contact_status(contact);
1224 if (!contact_status) {
1225 return 0;
1226 }
1227
1228 /* Count qualified available contacts. */
1229 switch (contact_status->status) {
1230 case AVAILABLE:
1231 ++*available;
1232 break;
1233 case UNAVAILABLE:
1234 case UNKNOWN:
1235 case CREATED:
1236 case REMOVED:
1237 break;
1238 }
1239
1240 ao2_ref(contact_status, -1);
1241
1242 return 0;
1243}
1244
1245/*!
1246 * \brief Function which applies configuration to an AOR options structure
1247 * \note Run by aor_options->serializer (or management_serializer on aor_options creation)
1248 */
1250 struct ast_sip_aor *aor, int is_new)
1251{
1252 struct ao2_container *existing_contacts;
1253 struct ast_sip_contact *contact;
1254 struct ao2_iterator iter;
1255
1256 ast_debug(3, "Configuring AOR '%s' with current state of configuration and world\n",
1257 aor_options->name);
1258
1259 /*
1260 * Permanent contacts, since we receive no notification that they
1261 * are gone, follow the same approach as AORs. We create a copy
1262 * of the existing container and any reused contacts are removed
1263 * from it. Any contacts remaining in the container after
1264 * processing no longer exist so we need to remove their state.
1265 */
1266 existing_contacts = ao2_container_clone(aor_options->contacts, 0);
1267 if (!existing_contacts) {
1268 ast_log(LOG_WARNING, "Synchronization of AOR '%s' failed for qualify, retaining existing state\n",
1269 aor_options->name);
1270 return;
1271 }
1272
1274 NULL, NULL);
1275
1276 /* Process permanent contacts */
1277 if (aor->permanent_contacts) {
1278 iter = ao2_iterator_init(aor->permanent_contacts, 0);
1279 for (; (contact = ao2_iterator_next(&iter)); ao2_ref(contact, -1)) {
1280 ao2_find(existing_contacts, ast_sorcery_object_get_id(contact),
1282 ao2_link(aor_options->contacts, contact);
1283 }
1284 ao2_iterator_destroy(&iter);
1285 }
1286
1287 /*
1288 * If this is newly added we need to see if there are any
1289 * existing dynamic contacts to add. Ones that are added
1290 * after creation will occur as a result of the contact
1291 * observer creation callback.
1292 */
1293 if (is_new) {
1294 size_t prefix_len = strlen(ast_sorcery_object_get_id(aor)) + sizeof(";@") - 1;
1295 char prefix[prefix_len + 1];
1296 struct ao2_container *contacts;
1297
1298 sprintf(prefix, "%s;@", ast_sorcery_object_get_id(aor)); /* Safe */
1300 prefix, prefix_len);
1301 if (contacts) {
1302 ao2_container_dup(aor_options->dynamic_contacts, contacts, 0);
1303 ao2_ref(contacts, -1);
1304 }
1305 }
1306
1307 /* Process dynamic contacts */
1308 iter = ao2_iterator_init(aor_options->dynamic_contacts, 0);
1309 for (; (contact = ao2_iterator_next(&iter)); ao2_ref(contact, -1)) {
1310 ao2_find(existing_contacts, ast_sorcery_object_get_id(contact),
1312 ao2_link(aor_options->contacts, contact);
1313 }
1314 ao2_iterator_destroy(&iter);
1315
1316 /* Any contacts left no longer exist, so raise events and make them disappear */
1317 ao2_callback(existing_contacts, OBJ_NODATA | OBJ_UNLINK,
1318 sip_options_remove_contact, aor_options);
1319 ao2_ref(existing_contacts, -1);
1320
1321 /*
1322 * Update the available count if we transition between qualified
1323 * and unqualified. In the qualified case we need to start with
1324 * 0 available as the qualify process will take care of it. In
1325 * the unqualified case it is based on the number of contacts
1326 * present.
1327 */
1328 if (!aor->qualify_frequency) {
1329 ao2_callback(aor_options->contacts, OBJ_NODATA,
1331 aor_options->available = ao2_container_count(aor_options->contacts);
1332 ast_debug(3, "AOR '%s' is unqualified, number of available contacts is therefore '%d'\n",
1333 aor_options->name, aor_options->available);
1334 } else if (!aor_options->qualify_frequency) {
1335 ao2_callback(aor_options->contacts, OBJ_NODATA,
1337 aor_options->available = 0;
1338 ast_debug(3, "AOR '%s' has transitioned from unqualified to qualified, reset available contacts to 0\n",
1339 aor_options->name);
1340 } else {
1341 /*
1342 * Count the number of AVAILABLE qualified contacts to ensure
1343 * the count is in sync with reality.
1344 */
1345 aor_options->available = 0;
1346 ao2_callback(aor_options->contacts, OBJ_NODATA,
1348 }
1349
1350 aor_options->authenticate_qualify = aor->authenticate_qualify;
1351 aor_options->qualify_2xx_only = aor->qualify_2xx_only;
1352 aor_options->qualify_timeout = aor->qualify_timeout;
1353
1354 /*
1355 * If we need to stop or start the scheduled callback then do so.
1356 * This occurs due to the following:
1357 * 1. The qualify frequency has changed
1358 * 2. Contacts were added when previously there were none
1359 * 3. There are no contacts but previously there were some
1360 */
1361 if (aor_options->qualify_frequency != aor->qualify_frequency
1362 || (!aor_options->sched_task && ao2_container_count(aor_options->contacts))
1363 || (aor_options->sched_task && !ao2_container_count(aor_options->contacts))) {
1364 if (aor_options->sched_task) {
1366 ao2_ref(aor_options->sched_task, -1);
1367 aor_options->sched_task = NULL;
1368 }
1369
1370 /* If there is still a qualify frequency then schedule this */
1371 aor_options->qualify_frequency = aor->qualify_frequency;
1372 if (aor_options->qualify_frequency
1373 && ao2_container_count(aor_options->contacts)) {
1374 aor_options->sched_task = ast_sip_schedule_task(aor_options->serializer,
1378 if (!aor_options->sched_task) {
1379 ast_log(LOG_ERROR, "Unable to schedule qualify for contacts of AOR '%s'\n",
1380 aor_options->name);
1381 }
1382 }
1383 }
1384
1385 ast_debug(3, "AOR '%s' now has %d available contacts\n", aor_options->name,
1386 aor_options->available);
1387}
1388
1389/*!
1390 * \brief Task to synchronize an AOR with our local state
1391 * \note Run by aor_options->serializer (or management_serializer on aor_options creation)
1392 */
1394{
1396 int i;
1397
1398 ast_debug(3, "Synchronizing AOR '%s' with current state of configuration and world\n",
1399 task_data->aor_options->name);
1400
1402 task_data->added);
1403
1404 /*
1405 * Endpoint state compositors are removed in this operation but not
1406 * added. To reduce the amount of work done they are done later. In
1407 * the mean time things can still qualify and once an endpoint state
1408 * compositor is added to the AOR it will be updated with the current
1409 * state.
1410 */
1411 for (i = 0; i < AST_VECTOR_SIZE(&task_data->aor_options->compositors); ++i) {
1412 struct sip_options_endpoint_state_compositor *endpoint_state_compositor;
1413
1414 endpoint_state_compositor = AST_VECTOR_GET(&task_data->aor_options->compositors, i);
1415
1416 ao2_lock(endpoint_state_compositor);
1417 endpoint_state_compositor->active = 0;
1418 sip_options_update_endpoint_state_compositor_aor(endpoint_state_compositor,
1419 task_data->aor_options->name, REMOVED);
1420 ao2_unlock(endpoint_state_compositor);
1421 }
1422 AST_VECTOR_RESET(&task_data->aor_options->compositors, ao2_cleanup);
1423
1424 return 0;
1425}
1426
1427/*!
1428 * \brief Synchronize an AOR with our local state
1429 * \note Run by management_serializer
1430 */
1431static int sip_options_synchronize_aor(void *obj, void *arg, int flags)
1432{
1434 .aor = obj,
1435 .existing = arg,
1436 };
1437
1438 task_data.aor_options = ao2_find(sip_options_aors,
1440 if (!task_data.aor_options) {
1441 task_data.aor_options = sip_options_aor_alloc(task_data.aor);
1442 if (!task_data.aor_options) {
1443 return 0;
1444 }
1445
1446 task_data.added = 1;
1447
1448 /* Nothing is aware of this AOR yet so we can just update it in this thread */
1450 ao2_link(sip_options_aors, task_data.aor_options);
1451 } else {
1452 /* This AOR already exists so we have to do manipulation in its serializer */
1453 ast_sip_push_task_wait_serializer(task_data.aor_options->serializer,
1455 }
1456
1457 ao2_ref(task_data.aor_options, -1);
1458
1459 if (task_data.existing) {
1462 }
1463
1464 return 0;
1465}
1466
1467/*! \brief Destructor for endpoint state compositors */
1469{
1470 struct sip_options_endpoint_state_compositor *endpoint_state_compositor = obj;
1471
1472 ao2_cleanup(endpoint_state_compositor->aor_statuses);
1473}
1474
1475/*! \brief Hashing function for endpoint AOR status */
1477
1478/*! \brief Comparator function for endpoint AOR status */
1480
1481/*! \brief Find (or create) an endpoint state compositor */
1483{
1484 struct sip_options_endpoint_state_compositor *endpoint_state_compositor;
1485
1487 endpoint_state_compositor = ao2_find(sip_options_endpoint_state_compositors,
1489 if (endpoint_state_compositor) {
1491 return endpoint_state_compositor;
1492 }
1493
1494 endpoint_state_compositor = ao2_alloc(sizeof(*endpoint_state_compositor)
1495 + strlen(ast_sorcery_object_get_id(endpoint)) + 1,
1497 if (!endpoint_state_compositor) {
1499 return NULL;
1500 }
1501
1502 /*
1503 * NOTE: The endpoint_state_compositor->aor_statuses container is
1504 * externally protected by the endpoint_state_compositor lock.
1505 */
1506 endpoint_state_compositor->aor_statuses = ao2_container_alloc_hash(
1508 sip_options_endpoint_aor_status_hash_fn, NULL,
1509 sip_options_endpoint_aor_status_cmp_fn);
1510 if (!endpoint_state_compositor->aor_statuses) {
1512 ao2_ref(endpoint_state_compositor, -1);
1513 return NULL;
1514 }
1515
1516 strcpy(endpoint_state_compositor->name, ast_sorcery_object_get_id(endpoint)); /* SAFE */
1517
1518 ao2_link_flags(sip_options_endpoint_state_compositors, endpoint_state_compositor,
1519 OBJ_NOLOCK);
1521
1522 return endpoint_state_compositor;
1523}
1524
1525/*! \brief Task details for adding an AOR to an endpoint state compositor */
1527 /*! \brief The AOR options that the endpoint state compositor should be added to */
1529 /*! \brief The endpoint state compositor */
1531};
1532
1533/*!
1534 * \brief Task which adds an AOR to an endpoint state compositor
1535 * \note Run by aor_options->serializer
1536 */
1538{
1540
1541 ast_debug(3, "Adding endpoint compositor '%s' to AOR '%s'\n",
1542 task_data->endpoint_state_compositor->name, task_data->aor_options->name);
1543
1544 ao2_ref(task_data->endpoint_state_compositor, +1);
1545 if (AST_VECTOR_APPEND(&task_data->aor_options->compositors,
1546 task_data->endpoint_state_compositor)) {
1547 /* Failed to add so no need to update the endpoint status. Nothing changed. */
1548 ao2_ref(task_data->endpoint_state_compositor, -1);
1549 return 0;
1550 }
1551
1552 ao2_lock(task_data->endpoint_state_compositor);
1554 task_data->aor_options->name,
1555 task_data->aor_options->available ? AVAILABLE : UNAVAILABLE);
1556 ao2_unlock(task_data->endpoint_state_compositor);
1557
1558 return 0;
1559}
1560
1561/*!
1562 * \brief Task which adds removes an AOR from an endpoint state compositor
1563 * \note Run by aor_options->serializer
1564 */
1566{
1568 int i;
1569
1570 ast_debug(3, "Removing endpoint compositor '%s' from AOR '%s'\n",
1571 task_data->endpoint_state_compositor->name,
1572 task_data->aor_options->name);
1573
1574 for (i = 0; i < AST_VECTOR_SIZE(&task_data->aor_options->compositors); ++i) {
1575 struct sip_options_endpoint_state_compositor *endpoint_state_compositor;
1576
1577 endpoint_state_compositor = AST_VECTOR_GET(&task_data->aor_options->compositors, i);
1578 if (endpoint_state_compositor != task_data->endpoint_state_compositor) {
1579 continue;
1580 }
1581
1582 AST_VECTOR_REMOVE(&task_data->aor_options->compositors, i, 0);
1583 ao2_ref(endpoint_state_compositor, -1);
1584 break;
1585 }
1586
1587 return 0;
1588}
1589
1590/*!
1591 * \brief Synchronize an endpoint with our local state
1592 * \note Run by management_serializer
1593 */
1594static int sip_options_synchronize_endpoint(void *obj, void *arg, int flags)
1595{
1596 struct ast_sip_endpoint *endpoint = obj;
1597 struct ast_sip_aor *aor = arg;
1598 char *aors;
1599 char *aor_name;
1601
1602 if (ast_strlen_zero(endpoint->aors)) {
1603 /* There are no AORs, so really... who the heck knows */
1604 ast_debug(3, "Endpoint '%s' is not interested in any AORs so not creating endpoint state compositor\n",
1605 ast_sorcery_object_get_id(endpoint));
1606 return 0;
1607 }
1608
1609 ast_debug(3, "Synchronizing endpoint '%s' with AORs '%s'\n",
1610 ast_sorcery_object_get_id(endpoint), endpoint->aors);
1611
1612 aors = ast_strdupa(endpoint->aors);
1613 while ((aor_name = ast_strip(strsep(&aors, ",")))) {
1614 if (ast_strlen_zero(aor_name)) {
1615 continue;
1616 }
1617 if (aor && strcasecmp(ast_sorcery_object_get_id(aor), aor_name)) {
1618 ast_debug(3, "Filtered AOR '%s' on endpoint '%s' as we are looking for '%s'\n",
1619 aor_name, ast_sorcery_object_get_id(endpoint),
1621 continue;
1622 }
1623
1624 task_data.aor_options = ao2_find(sip_options_aors, aor_name, OBJ_SEARCH_KEY);
1625 if (!task_data.aor_options) {
1626 /*
1627 * They have referenced an invalid AOR. If that's all they've
1628 * done we will set them to offline at the end.
1629 */
1630 ast_debug(3, "Endpoint '%s' referenced invalid AOR '%s'\n",
1631 ast_sorcery_object_get_id(endpoint), aor_name);
1632 continue;
1633 }
1634
1635 if (!task_data.endpoint_state_compositor) {
1636 /*
1637 * We create an endpoint state compositor only after we know
1638 * for sure we need it.
1639 */
1640 task_data.endpoint_state_compositor =
1642 if (!task_data.endpoint_state_compositor) {
1644 "Could not create endpoint state compositor for '%s', endpoint state will be incorrect\n",
1645 ast_sorcery_object_get_id(endpoint));
1646 ao2_ref(task_data.aor_options, -1);
1649 return 0;
1650 }
1651 }
1652
1653 /* We use a synchronous task so that we don't flood the system */
1654 ast_sip_push_task_wait_serializer(task_data.aor_options->serializer,
1656
1657 ao2_ref(task_data.aor_options, -1);
1658
1659 /*
1660 * If we filtered on a specific AOR name then the endpoint can
1661 * only reference it once so break early.
1662 */
1663 if (aor) {
1664 break;
1665 }
1666 }
1667
1668 if (task_data.endpoint_state_compositor) {
1669 /*
1670 * If an endpoint state compositor is present determine the current state
1671 * of the endpoint and update it.
1672 */
1673 ao2_lock(task_data.endpoint_state_compositor);
1674 task_data.endpoint_state_compositor->active = 1;
1677 ao2_unlock(task_data.endpoint_state_compositor);
1678
1679 ao2_ref(task_data.endpoint_state_compositor, -1);
1680 } else if (!aor) {
1681 /* If no explicit AOR is specified we are updating the endpoint itself, so then set
1682 * it to offline if no endpoint compositor exists as they referenced an invalid AOR
1683 * or none at all
1684 */
1685 ast_debug(3, "Endpoint '%s' has no AORs feeding it, setting it to offline state as default\n",
1686 ast_sorcery_object_get_id(endpoint));
1689 }
1690
1691 return 0;
1692}
1693
1694/*!
1695 * \brief Task which removes an AOR from all of the ESCs it is reporting to
1696 * \note Run by aor_options->serializer
1697 */
1698static int sip_options_aor_remove_task(void *obj)
1699{
1700 struct sip_options_aor *aor_options = obj;
1701
1703
1704 if (aor_options->sched_task) {
1706 ao2_ref(aor_options->sched_task, -1);
1707 aor_options->sched_task = NULL;
1708 }
1709
1710 return 0;
1711}
1712
1713/*!
1714 * \brief Callback which removes any unused AORs that remained after reloading
1715 * \note Run by management_serializer
1716 */
1717static int sip_options_unused_aor(void *obj, void *arg, int flags)
1718{
1719 struct sip_options_aor *aor_options = obj;
1720
1721 ast_debug(3, "AOR '%s' is no longer configured, removing it\n", aor_options->name);
1722
1724 aor_options);
1725 ao2_unlink(sip_options_aors, aor_options);
1726
1727 return CMP_MATCH;
1728}
1729
1730/*!
1731 * \brief Callback function used to unlink and remove event state compositors that have no AORs feeding them
1732 * \note Run by management_serializer
1733 */
1734static int sip_options_unused_endpoint_state_compositor(void *obj, void *arg, int flags)
1735{
1736 struct sip_options_endpoint_state_compositor *endpoint_state_compositor = obj;
1737
1738 if (ao2_container_count(endpoint_state_compositor->aor_statuses)) {
1739 return 0;
1740 }
1741
1742 /* No AORs are feeding this endpoint state compositor */
1743 ast_sip_persistent_endpoint_update_state(endpoint_state_compositor->name,
1745
1746 return CMP_MATCH;
1747}
1748
1749/*! \brief Structure which contains information required to synchronize */
1751 /*! \brief Whether this is a reload or not */
1753};
1754
1755/*!
1756 * \brief Task to synchronize our local container of AORs and endpoint state compositors with the current configuration
1757 * \note Run by management_serializer
1758 */
1759static int sip_options_synchronize_task(void *obj)
1760{
1762 struct ao2_container *existing = NULL;
1763 struct ao2_container *objects;
1764
1765 /*
1766 * When reloading we keep track of the existing AORs so we can
1767 * terminate old ones that are no longer referenced or used.
1768 */
1769 if (task_data->reload) {
1771 if (!existing) {
1772 return 0;
1773 }
1774 }
1775
1778 if (objects) {
1779 /* Go through the returned AORs and synchronize with our local state */
1781 ao2_ref(objects, -1);
1782 }
1783
1784 /*
1785 * Any AORs remaining in existing are no longer referenced by
1786 * the current container of AORs we retrieved, so remove them.
1787 */
1788 if (existing) {
1791 ao2_ref(existing, -1);
1792 }
1793
1796 if (objects) {
1797 /* Go through the provided endpoints and update AORs */
1799 ao2_ref(objects, -1);
1800 }
1801
1802 /*
1803 * All endpoint state compositors that don't have any AORs
1804 * feeding them information can be removed. If they end
1805 * up getting needed later they'll just be recreated.
1806 */
1810
1811 return 0;
1812}
1813
1814/*! \brief Synchronize our local container of AORs and endpoint state compositors with the current configuration */
1816{
1818 .reload = reload,
1819 };
1820
1822 &task_data);
1823}
1824
1825/*!
1826 * \brief Unlink AORs feeding the endpoint status compositor
1827 * \note Run by management_serializer
1828 */
1830 struct sip_options_endpoint_state_compositor *endpoint_state_compositor)
1831{
1832 struct ao2_iterator it_aor_statuses;
1833 struct sip_options_endpoint_aor_status *aor_status;
1835 .endpoint_state_compositor = endpoint_state_compositor,
1836 };
1837
1840
1841 /* Unlink AOR feeders pointing to endpoint */
1843 for (; (aor_status = ao2_iterator_next(&it_aor_statuses)); ao2_ref(aor_status, -1)) {
1844 task_data.aor_options = ao2_find(sip_options_aors, aor_status->name,
1846 if (!task_data.aor_options) {
1847 continue;
1848 }
1849
1850 ast_debug(3, "Removing endpoint state compositor '%s' from AOR '%s'\n",
1851 ast_sorcery_object_get_id(endpoint), aor_status->name);
1853 ast_sip_push_task_wait_serializer(task_data.aor_options->serializer,
1856 ao2_ref(task_data.aor_options, -1);
1857 }
1858 ao2_iterator_destroy(&it_aor_statuses);
1859
1860 /*
1861 * We do not need to remove the AOR feeder status memory from the
1862 * aor_statuses container. The endpoint_state_compositor is about
1863 * to die and do it for us.
1864 */
1865
1867}
1868
1869/*!
1870 * \brief Task to delete an endpoint from the known universe
1871 * \note Run by management_serializer
1872 */
1874{
1875 struct ast_sip_endpoint *endpoint = obj;
1876 struct sip_options_endpoint_state_compositor *endpoint_state_compositor;
1877
1878 endpoint_state_compositor = ao2_find(sip_options_endpoint_state_compositors,
1880 if (!endpoint_state_compositor) {
1881 return 0;
1882 }
1883
1884 ast_debug(3, "Endpoint '%s' has been deleted, removing endpoint state compositor from AORs\n",
1885 ast_sorcery_object_get_id(endpoint));
1886 sip_options_endpoint_unlink_aor_feeders(endpoint, endpoint_state_compositor);
1887 ao2_ref(endpoint_state_compositor, -1);
1888
1889 return 0;
1890}
1891
1892/*! \brief Observer callback invoked on endpoint deletion */
1893static void endpoint_observer_deleted(const void *obj)
1894{
1897}
1898
1899/*!
1900 * \brief Task to synchronize the endpoint
1901 * \note Run by management_serializer
1902 */
1904{
1905 struct ast_sip_endpoint *endpoint = obj;
1906 struct sip_options_endpoint_state_compositor *endpoint_state_compositor;
1907
1908 ast_debug(3, "Endpoint '%s' has been created or modified, updating state\n",
1909 ast_sorcery_object_get_id(endpoint));
1910
1911 endpoint_state_compositor = ao2_find(sip_options_endpoint_state_compositors,
1913 if (endpoint_state_compositor) {
1914 /* Unlink the AORs currently feeding the endpoint. */
1915 sip_options_endpoint_unlink_aor_feeders(endpoint, endpoint_state_compositor);
1916 ao2_ref(endpoint_state_compositor, -1);
1917 }
1918
1919 /* Connect the AORs that now feed the endpoint. */
1921 return 0;
1922}
1923
1924/*! \brief Observer callback invoked on endpoint creation or modification */
1925static void endpoint_observer_modified(const void *obj)
1926{
1929}
1930
1931/*! \brief Observer callbacks for endpoints */
1934 .updated = endpoint_observer_modified,
1935 .deleted = endpoint_observer_deleted,
1936};
1937
1938/*!
1939 * \brief Task to synchronize an AOR with our local state
1940 * \note Run by aor_options->serializer
1941 */
1942static int sip_options_update_aor_task(void *obj)
1943{
1945 int available = task_data->aor_options->available;
1946
1947 ast_debug(3, "Individually updating AOR '%s' with current state of configuration and world\n",
1948 task_data->aor_options->name);
1949
1951 task_data->added);
1952
1953 if (!available && task_data->aor_options->available) {
1954 ast_debug(3, "After modifying AOR '%s' it has now become available\n",
1955 task_data->aor_options->name);
1957 } else if (available && !task_data->aor_options->available) {
1958 ast_debug(3, "After modifying AOR '%s' it has become unavailable\n",
1959 task_data->aor_options->name);
1961 }
1962
1963 return 0;
1964}
1965
1966/*!
1967 * \brief Task to synchronize the AOR
1968 * \note Run by management_serializer
1969 */
1971{
1972 struct ast_sip_aor *aor = obj;
1973 struct sip_options_aor *aor_options;
1974
1977 if (!aor_options) {
1978 struct ao2_container *endpoints;
1979
1980 aor_options = sip_options_aor_alloc(aor);
1981 if (!aor_options) {
1982 return 0;
1983 }
1984
1985 /*
1986 * This is a newly added AOR and we need to establish any
1987 * endpoint state compositors that may reference only the
1988 * AOR. If these need to be updated later then they'll
1989 * be done by modifying the endpoint or issuing a reload.
1990 */
1991 sip_options_apply_aor_configuration(aor_options, aor, 1);
1992 ao2_link(sip_options_aors, aor_options);
1993
1994 /*
1995 * Using LIKE doesn't seem to work very well with non-realtime so we
1996 * fetch everything right now and do a filter on our side.
1997 */
2000 if (endpoints) {
2002 ao2_ref(endpoints, -1);
2003 }
2004 } else {
2006 .aor_options = aor_options,
2007 .aor = aor,
2008 };
2009
2010 /*
2011 * If this AOR was modified we have to do our work in its serializer
2012 * instead of this thread to ensure that things aren't modified by
2013 * multiple threads.
2014 */
2017 }
2018
2019 ao2_ref(aor_options, -1);
2020
2021 return 0;
2022}
2023
2024/*! \brief Observer callback invoked on AOR creation or modification */
2025static void aor_observer_modified(const void *obj)
2026{
2029}
2030
2031/*!
2032 * \brief Task to delete an AOR from the known universe
2033 * \note Run by management_serializer
2034 */
2036{
2037 struct ast_sip_aor *aor = obj;
2038 struct sip_options_aor *aor_options;
2039
2042 if (!aor_options) {
2043 return 0;
2044 }
2045
2046 ast_debug(3, "AOR '%s' has been deleted, removing it\n", aor_options->name);
2047
2049 aor_options);
2050 ao2_ref(aor_options, -1);
2051
2052 return 0;
2053}
2054
2055/*! \brief Observer callback invoked on AOR deletion */
2056static void aor_observer_deleted(const void *obj)
2057{
2060}
2061
2062/*! \brief Observer callbacks for AORs */
2065 .updated = aor_observer_modified,
2066 .deleted = aor_observer_deleted,
2067};
2068
2069/*! \brief Task details for adding an AOR to an endpoint state compositor */
2071 /*! \brief The AOR options that the contact is referring to */
2073 /*! \brief The contact itself */
2075};
2076
2077
2078/*!
2079 * \brief Check if the contact qualify options are different than local aor qualify options
2080 */
2081static int has_qualify_changed (const struct ast_sip_contact *contact, const struct sip_options_aor *aor_options)
2082{
2083 if (!contact) {
2084 return 0;
2085 }
2086
2087 if (!aor_options) {
2088 if (contact->qualify_frequency) {
2089 return 1;
2090 }
2091 } else if (contact->qualify_frequency != aor_options->qualify_frequency
2092 || contact->authenticate_qualify != aor_options->authenticate_qualify
2093 || contact->qualify_2xx_only != aor_options->qualify_2xx_only
2094 || ((int)(contact->qualify_timeout * 1000)) != ((int)(aor_options->qualify_timeout * 1000))) {
2095 return 1;
2096 }
2097
2098 return 0;
2099}
2100
2101/*!
2102 * \brief Task which adds a dynamic contact to an AOR
2103 * \note Run by aor_options->serializer
2104 */
2105static int sip_options_contact_add_task(void *obj)
2106{
2108 struct ast_sip_contact_status *contact_status;
2109
2110 ao2_link(task_data->aor_options->dynamic_contacts, task_data->contact);
2111 ao2_link(task_data->aor_options->contacts, task_data->contact);
2112
2113 contact_status = ast_res_pjsip_find_or_create_contact_status(task_data->contact);
2114 ao2_cleanup(contact_status);
2115
2116 if (task_data->aor_options->qualify_frequency) {
2117 /* There will always be a contact here, and we need to immediately schedule
2118 * a qualify so that contacts are not waiting for the qualify_frequency
2119 * timer duration before qualifying.
2120 */
2121 ast_debug(3, "Starting scheduled callback on AOR '%s' for qualifying as there is now a contact on it\n",
2122 task_data->aor_options->name);
2123 /*
2124 * We immediately schedule the initial qualify so that we get
2125 * reachable/unreachable as soon as possible. Realistically
2126 * since they pretty much just registered they should be
2127 * reachable.
2128 */
2129 if (task_data->aor_options->sched_task) {
2130 ast_sip_sched_task_cancel(task_data->aor_options->sched_task);
2131 ao2_ref(task_data->aor_options->sched_task, -1);
2132 task_data->aor_options->sched_task = NULL;
2133 }
2134 task_data->aor_options->sched_task = ast_sip_schedule_task(
2135 task_data->aor_options->serializer, 1, sip_options_qualify_aor,
2136 ast_taskprocessor_name(task_data->aor_options->serializer),
2137 task_data->aor_options,
2139 if (!task_data->aor_options->sched_task) {
2140 ast_log(LOG_ERROR, "Unable to schedule qualify for contacts of AOR '%s'\n",
2141 task_data->aor_options->name);
2142 }
2143 } else {
2144 /*
2145 * If this was the first contact added to a non-qualified AOR then
2146 * it should become available.
2147 */
2148 task_data->aor_options->available =
2149 ao2_container_count(task_data->aor_options->contacts);
2150 if (task_data->aor_options->available == 1) {
2151 ast_debug(3, "An unqualified contact has been added to AOR '%s' so it is now available\n",
2152 task_data->aor_options->name);
2154 AVAILABLE);
2155 }
2156 }
2157
2158 return 0;
2159}
2160
2161/*!
2162 * \brief Task to add a dynamic contact to an AOR in its serializer
2163 * \note Run by management_serializer
2164 */
2166{
2168
2169 task_data.contact = obj;
2170 task_data.aor_options = ao2_find(sip_options_aors, task_data.contact->aor,
2172
2173 if (has_qualify_changed(task_data.contact, task_data.aor_options)) {
2174 struct ast_sip_aor *aor;
2175
2177 task_data.contact->aor);
2178 if (aor) {
2179 ast_debug(3, "AOR '%s' qualify options have been modified. Synchronize an AOR local state\n",
2180 task_data.contact->aor);
2182 ao2_ref(aor, -1);
2183 }
2184 }
2185
2186 if (!task_data.aor_options) {
2187 return 0;
2188 }
2189
2190 ast_sip_push_task_wait_serializer(task_data.aor_options->serializer,
2192 ao2_ref(task_data.aor_options, -1);
2193
2194 return 0;
2195}
2196
2197/*! \brief Observer callback invoked on contact creation */
2198static void contact_observer_created(const void *obj)
2199{
2202}
2203
2204/*!
2205 * \brief Task which updates a dynamic contact to an AOR
2206 * \note Run by aor_options->serializer
2207 */
2209{
2211 struct ast_sip_contact_status *contact_status;
2212
2213 contact_status = ast_sip_get_contact_status(task_data->contact);
2214 if (contact_status) {
2215 switch (contact_status->status) {
2216 case CREATED:
2217 case UNAVAILABLE:
2218 case AVAILABLE:
2219 case UNKNOWN:
2220 /* Refresh the ContactStatus AMI events. */
2221 sip_options_contact_status_update(contact_status);
2222 break;
2223 case REMOVED:
2224 break;
2225 }
2226 ao2_ref(contact_status, -1);
2227 }
2228
2229 ao2_ref(task_data->contact, -1);
2230 ao2_ref(task_data->aor_options, -1);
2232 return 0;
2233}
2234
2235/*! \brief Observer callback invoked on contact update */
2236static void contact_observer_updated(const void *obj)
2237{
2238 const struct ast_sip_contact *contact = obj;
2239 struct sip_options_aor *aor_options = ao2_find(sip_options_aors, contact->aor, OBJ_SEARCH_KEY);
2240
2241 if (has_qualify_changed(contact, aor_options)) {
2242 struct ast_sip_aor *aor;
2243
2245 contact->aor);
2246 if (aor) {
2247 ast_debug(3, "AOR '%s' qualify options have been modified. Synchronize an AOR local state\n",
2248 contact->aor);
2251 ao2_ref(aor, -1);
2252 }
2253 }
2254
2257
2258 task_data = ast_malloc(sizeof(*task_data));
2259 if (!task_data) {
2260 ao2_ref(aor_options, -1);
2261 return;
2262 }
2263
2264 task_data->contact = (struct ast_sip_contact *) contact;
2265 /* task_data takes ownership of aor_options and will take care of releasing the ref */
2266 task_data->aor_options = aor_options;
2267
2268 ao2_ref(task_data->contact, +1);
2269 if (ast_sip_push_task(task_data->aor_options->serializer,
2271 ao2_ref(task_data->contact, -1);
2272 ao2_ref(task_data->aor_options, -1);
2274 }
2275 } else {
2276 ao2_cleanup(aor_options);
2277 }
2278}
2279
2280/*!
2281 * \brief Task which deletes a dynamic contact from an AOR
2282 * \note Run by aor_options->serializer
2283 */
2285{
2287
2288 ao2_find(task_data->aor_options->dynamic_contacts, task_data->contact,
2290 ao2_find(task_data->aor_options->contacts, task_data->contact,
2292
2294
2295 if (task_data->aor_options->qualify_frequency) {
2296 /* If this is the last contact then we need to stop the scheduled callback */
2297 if (!ao2_container_count(task_data->aor_options->contacts)) {
2298 ast_debug(3, "Terminating scheduled callback on AOR '%s' as there are no contacts to qualify\n",
2299 task_data->aor_options->name);
2300 if (task_data->aor_options->sched_task) {
2301 ast_sip_sched_task_cancel(task_data->aor_options->sched_task);
2302 ao2_ref(task_data->aor_options->sched_task, -1);
2303 task_data->aor_options->sched_task = NULL;
2304 }
2305 }
2306 } else {
2307 task_data->aor_options->available =
2308 ao2_container_count(task_data->aor_options->contacts);
2309 if (!task_data->aor_options->available) {
2310 ast_debug(3, "An unqualified contact has been removed from AOR '%s' leaving no remaining contacts\n",
2311 task_data->aor_options->name);
2313 UNAVAILABLE);
2314 }
2315 }
2316
2317 return 0;
2318}
2319
2320/*!
2321 * \brief Task to delete a contact from an AOR in its serializer
2322 * \note Run by management_serializer
2323 */
2325{
2327
2328 task_data.contact = obj;
2329 task_data.aor_options = ao2_find(sip_options_aors, task_data.contact->aor,
2331 if (!task_data.aor_options) {
2332 /* For contacts that are deleted we don't really care if there is no AOR locally */
2333 return 0;
2334 }
2335
2336 ast_sip_push_task_wait_serializer(task_data.aor_options->serializer,
2338 ao2_ref(task_data.aor_options, -1);
2339
2340 return 0;
2341}
2342
2343/*! \brief Observer callback invoked on contact deletion */
2344static void contact_observer_deleted(const void *obj)
2345{
2348}
2349
2350/*! \brief Observer callbacks for contacts */
2353 .updated = contact_observer_updated,
2354 .deleted = contact_observer_deleted,
2355};
2356
2357static char *cli_qualify(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2358{
2359 RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
2360 const char *endpoint_name;
2361 char *aors;
2362 char *aor_name;
2363
2364 switch (cmd) {
2365 case CLI_INIT:
2366 e->command = "pjsip qualify";
2367 e->usage =
2368 "Usage: pjsip qualify <endpoint>\n"
2369 " Send a SIP OPTIONS request to all contacts on the endpoint.\n";
2370 return NULL;
2371 case CLI_GENERATE:
2372 return NULL;
2373 }
2374
2375 if (a->argc != 3) {
2376 return CLI_SHOWUSAGE;
2377 }
2378
2379 endpoint_name = a->argv[2];
2380
2381 endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint",
2382 endpoint_name);
2383 if (!endpoint) {
2384 ast_cli(a->fd, "Unable to retrieve endpoint %s\n", endpoint_name);
2385 return CLI_FAILURE;
2386 }
2387
2388 if (ast_strlen_zero(endpoint->aors)) {
2389 ast_cli(a->fd, "No AORs configured for endpoint '%s'\n", endpoint_name);
2390 return CLI_FAILURE;
2391 }
2392
2393 aors = ast_strdupa(endpoint->aors);
2394 while ((aor_name = ast_strip(strsep(&aors, ",")))) {
2395 struct sip_options_aor *aor_options;
2396
2397 aor_options = ao2_find(sip_options_aors, aor_name, OBJ_SEARCH_KEY);
2398 if (!aor_options) {
2399 continue;
2400 }
2401
2402 ast_cli(a->fd, "Qualifying AOR '%s' on endpoint '%s'\n", aor_name, endpoint_name);
2404 aor_options);
2405 ao2_ref(aor_options, -1);
2406 }
2407
2408 return CLI_SUCCESS;
2409}
2410
2412{
2413 struct ao2_container *contacts;
2414
2417
2418 return contacts;
2419}
2420
2421static int sip_contact_to_ami(const struct ast_sip_contact *contact,
2422 struct ast_str **buf)
2423{
2424 return ast_sip_sorcery_object_to_ami(contact, buf);
2425}
2426
2427static int format_ami_contactlist_handler(void *obj, void *arg, int flags)
2428{
2429 struct ast_sip_contact *contact = obj;
2430 struct ast_sip_ami *ami = arg;
2431 struct ast_str *buf;
2433
2434 buf = ast_sip_create_ami_event("ContactList", ami);
2435 if (!buf) {
2436 return CMP_STOP;
2437 }
2438
2439 if (sip_contact_to_ami(contact, &buf)) {
2440 ast_free(buf);
2441 return CMP_STOP;
2442 }
2443
2444 /* Add extra info */
2446 ast_str_append(&buf, 0, "Status: %s\r\n",
2448 if (!status || status->status != AVAILABLE) {
2449 ast_str_append(&buf, 0, "RoundtripUsec: N/A\r\n");
2450 } else {
2451 ast_str_append(&buf, 0, "RoundtripUsec: %" PRId64 "\r\n", status->rtt);
2452 }
2454
2455 astman_append(ami->s, "%s\r\n", ast_str_buffer(buf));
2456
2457 ami->count++;
2458
2459 ast_free(buf);
2460
2461 return 0;
2462}
2463
2464static int ami_show_contacts(struct mansession *s, const struct message *m)
2465{
2466 struct ast_sip_ami ami = { .s = s, .m = m, .action_id = astman_get_header(m, "ActionID"), };
2467 struct ao2_container *contacts;
2468
2469 contacts = get_all_contacts();
2470 if (!contacts) {
2471 astman_send_error(s, m, "Could not get Contacts\n");
2472 return 0;
2473 }
2474
2475 if (!ao2_container_count(contacts)) {
2476 astman_send_error(s, m, "No Contacts found\n");
2477 ao2_ref(contacts, -1);
2478 return 0;
2479 }
2480
2481 astman_send_listack(s, m, "A listing of Contacts follows, presented as ContactList events",
2482 "start");
2483
2485
2486 astman_send_list_complete_start(s, m, "ContactListComplete", ami.count);
2488
2489 ao2_ref(contacts, -1);
2490
2491 return 0;
2492}
2493
2494static char *cli_show_qualify_endpoint(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2495{
2496 RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
2497 const char *endpoint_name;
2498 char *aors;
2499 char *aor_name;
2500
2501 switch (cmd) {
2502 case CLI_INIT:
2503 e->command = "pjsip show qualify endpoint";
2504 e->usage =
2505 "Usage: pjsip show qualify endpoint <id>\n"
2506 " Show the current qualify options for all Aors on the PJSIP endpoint.\n";
2507 return NULL;
2508 case CLI_GENERATE:
2509 return NULL;
2510 }
2511
2512 if (a->argc != 5) {
2513 return CLI_SHOWUSAGE;
2514 }
2515
2516 endpoint_name = a->argv[4];
2517
2518 endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint",
2519 endpoint_name);
2520 if (!endpoint) {
2521 ast_cli(a->fd, "Unable to retrieve endpoint %s\n", endpoint_name);
2522 return CLI_FAILURE;
2523 }
2524
2525 if (ast_strlen_zero(endpoint->aors)) {
2526 ast_cli(a->fd, "No AORs configured for endpoint '%s'\n", endpoint_name);
2527 return CLI_FAILURE;
2528 }
2529
2530 aors = ast_strdupa(endpoint->aors);
2531 while ((aor_name = ast_strip(strsep(&aors, ",")))) {
2532 struct sip_options_aor *aor_options;
2533
2534 aor_options = ao2_find(sip_options_aors, aor_name, OBJ_SEARCH_KEY);
2535 if (!aor_options) {
2536 continue;
2537 }
2538
2539 ast_cli(a->fd, " * AOR '%s' on endpoint '%s'\n", aor_name, endpoint_name);
2540 ast_cli(a->fd, " Qualify frequency : %d sec\n", aor_options->qualify_frequency);
2541 ast_cli(a->fd, " Qualify timeout : %d ms\n", (int)(aor_options->qualify_timeout / 1000));
2542 ast_cli(a->fd, " Qualify 2xx only : %s\n", aor_options->qualify_2xx_only ? "yes" : "no");
2543 ast_cli(a->fd, " Authenticate qualify : %s\n", aor_options->authenticate_qualify?"yes":"no");
2544 ast_cli(a->fd, "\n");
2545 ao2_ref(aor_options, -1);
2546 }
2547
2548 return CLI_SUCCESS;
2549}
2550
2551static char *cli_show_qualify_aor(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2552{
2553 struct sip_options_aor *aor_options;
2554 const char *aor_name;
2555
2556 switch (cmd) {
2557 case CLI_INIT:
2558 e->command = "pjsip show qualify aor";
2559 e->usage =
2560 "Usage: pjsip show qualify aor <id>\n"
2561 " Show the PJSIP Aor current qualify options.\n";
2562 return NULL;
2563 case CLI_GENERATE:
2564 return NULL;
2565 }
2566
2567 if (a->argc != 5) {
2568 return CLI_SHOWUSAGE;
2569 }
2570
2571 aor_name = a->argv[4];
2572
2573 aor_options = ao2_find(sip_options_aors, aor_name, OBJ_SEARCH_KEY);
2574 if (!aor_options) {
2575 ast_cli(a->fd, "Unable to retrieve aor '%s' qualify options\n", aor_name);
2576 return CLI_FAILURE;
2577 }
2578
2579 ast_cli(a->fd, " * AOR '%s'\n", aor_name);
2580 ast_cli(a->fd, " Qualify frequency : %d sec\n", aor_options->qualify_frequency);
2581 ast_cli(a->fd, " Qualify timeout : %d ms\n", (int)(aor_options->qualify_timeout / 1000));
2582 ast_cli(a->fd, " Qualify 2xx only : %s\n", aor_options->qualify_2xx_only ? "yes" : "no");
2583 ast_cli(a->fd, " Authenticate qualify : %s\n", aor_options->authenticate_qualify?"yes":"no");
2584 ao2_ref(aor_options, -1);
2585
2586 return CLI_SUCCESS;
2587}
2588
2589static char *cli_reload_qualify_endpoint(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2590{
2591 RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
2592 const char *endpoint_name;
2593 char *aors;
2594 char *aor_name;
2595
2596 switch (cmd) {
2597 case CLI_INIT:
2598 e->command = "pjsip reload qualify endpoint";
2599 e->usage =
2600 "Usage: pjsip reload qualify endpoint <id>\n"
2601 " Synchronize the qualify options for all Aors on the PJSIP endpoint.\n";
2602 return NULL;
2603 case CLI_GENERATE:
2604 return NULL;
2605 }
2606
2607 if (a->argc != 5) {
2608 return CLI_SHOWUSAGE;
2609 }
2610
2611 endpoint_name = a->argv[4];
2612
2613 endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint",
2614 endpoint_name);
2615 if (!endpoint) {
2616 ast_cli(a->fd, "Unable to retrieve endpoint %s\n", endpoint_name);
2617 return CLI_FAILURE;
2618 }
2619
2620 if (ast_strlen_zero(endpoint->aors)) {
2621 ast_cli(a->fd, "No AORs configured for endpoint '%s'\n", endpoint_name);
2622 return CLI_FAILURE;
2623 }
2624
2625 aors = ast_strdupa(endpoint->aors);
2626 while ((aor_name = ast_strip(strsep(&aors, ",")))) {
2627 struct ast_sip_aor *aor;
2628
2629 aor = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "aor", aor_name);
2630 if (!aor) {
2631 continue;
2632 }
2633
2634 ast_cli(a->fd, "Synchronizing AOR '%s' on endpoint '%s'\n", aor_name, endpoint_name);
2637 ao2_ref(aor, -1);
2638 }
2639
2640 return CLI_SUCCESS;
2641}
2642
2643static char *cli_reload_qualify_aor(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2644{
2645 struct ast_sip_aor *aor;
2646 const char *aor_name;
2647
2648 switch (cmd) {
2649 case CLI_INIT:
2650 e->command = "pjsip reload qualify aor";
2651 e->usage =
2652 "Usage: pjsip reload qualify aor <id>\n"
2653 " Synchronize the PJSIP Aor qualify options.\n";
2654 return NULL;
2655 case CLI_GENERATE:
2656 return NULL;
2657 }
2658
2659 if (a->argc != 5) {
2660 return CLI_SHOWUSAGE;
2661 }
2662
2663 aor_name = a->argv[4];
2664
2665 aor = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "aor", aor_name);
2666 if (!aor) {
2667 ast_cli(a->fd, "Unable to retrieve aor '%s'\n", aor_name);
2668 return CLI_FAILURE;
2669 }
2670
2671 ast_cli(a->fd, "Synchronizing AOR '%s'\n", aor_name);
2674 ao2_ref(aor, -1);
2675
2676 return CLI_SUCCESS;
2677}
2678
2679static int ami_sip_qualify(struct mansession *s, const struct message *m)
2680{
2681 const char *endpoint_name = astman_get_header(m, "Endpoint");
2682 RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
2683 char *aors;
2684 char *aor_name;
2685
2686 if (ast_strlen_zero(endpoint_name)) {
2687 astman_send_error(s, m, "Endpoint parameter missing.");
2688 return 0;
2689 }
2690
2691 endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint",
2692 endpoint_name);
2693 if (!endpoint) {
2694 astman_send_error(s, m, "Unable to retrieve endpoint\n");
2695 return 0;
2696 }
2697
2698 /* send a qualify for all contacts registered with the endpoint */
2699 if (ast_strlen_zero(endpoint->aors)) {
2700 astman_send_error(s, m, "No AoRs configured for endpoint\n");
2701 return 0;
2702 }
2703
2704 aors = ast_strdupa(endpoint->aors);
2705 while ((aor_name = ast_strip(strsep(&aors, ",")))) {
2706 struct sip_options_aor *aor_options;
2707
2708 aor_options = ao2_find(sip_options_aors, aor_name, OBJ_SEARCH_KEY);
2709 if (!aor_options) {
2710 continue;
2711 }
2712
2714 aor_options);
2715 ao2_ref(aor_options, -1);
2716 }
2717
2718 astman_send_ack(s, m, "Endpoint found, will qualify");
2719 return 0;
2720}
2721
2722static struct ast_cli_entry cli_options[] = {
2723 AST_CLI_DEFINE(cli_qualify, "Send an OPTIONS request to a PJSIP endpoint"),
2724 AST_CLI_DEFINE(cli_show_qualify_endpoint, "Show the current qualify options for all Aors on the PJSIP endpoint"),
2725 AST_CLI_DEFINE(cli_show_qualify_aor, "Show the PJSIP Aor current qualify options"),
2726 AST_CLI_DEFINE(cli_reload_qualify_endpoint, "Synchronize the qualify options for all Aors on the PJSIP endpoint"),
2727 AST_CLI_DEFINE(cli_reload_qualify_aor, "Synchronize the PJSIP Aor qualify options"),
2728};
2729
2730int ast_sip_format_contact_ami(void *obj, void *arg, int flags)
2731{
2732 struct ast_sip_contact_wrapper *wrapper = obj;
2733 struct ast_sip_contact *contact = wrapper->contact;
2734 struct ast_sip_ami *ami = arg;
2736 struct ast_str *buf;
2737 const struct ast_sip_endpoint *endpoint = ami->arg;
2738 char secs[AST_TIME_T_LEN];
2739
2740 buf = ast_sip_create_ami_event("ContactStatusDetail", ami);
2741 if (!buf) {
2742 return -1;
2743 }
2744
2746
2747 ast_str_append(&buf, 0, "AOR: %s\r\n", wrapper->aor_id);
2748 ast_str_append(&buf, 0, "URI: %s\r\n", contact->uri);
2749 ast_str_append(&buf, 0, "UserAgent: %s\r\n", contact->user_agent);
2750 ast_time_t_to_string(contact->expiration_time.tv_sec, secs, sizeof(secs));
2751 ast_str_append(&buf, 0, "RegExpire: %s\r\n", secs);
2752 if (!ast_strlen_zero(contact->via_addr)) {
2753 ast_str_append(&buf, 0, "ViaAddress: %s", contact->via_addr);
2754 if (contact->via_port) {
2755 ast_str_append(&buf, 0, ":%d", contact->via_port);
2756 }
2757 ast_str_append(&buf, 0, "\r\n");
2758 }
2759 if (!ast_strlen_zero(contact->call_id)) {
2760 ast_str_append(&buf, 0, "CallID: %s\r\n", contact->call_id);
2761 }
2762 ast_str_append(&buf, 0, "Status: %s\r\n",
2764 if (!status || status->status != AVAILABLE) {
2765 ast_str_append(&buf, 0, "RoundtripUsec: N/A\r\n");
2766 } else {
2767 ast_str_append(&buf, 0, "RoundtripUsec: %" PRId64 "\r\n", status->rtt);
2768 }
2769 ast_str_append(&buf, 0, "EndpointName: %s\r\n",
2770 endpoint ? ast_sorcery_object_get_id(endpoint) : S_OR(contact->endpoint_name, ""));
2771
2772 ast_str_append(&buf, 0, "ID: %s\r\n", ast_sorcery_object_get_id(contact));
2773 ast_str_append(&buf, 0, "AuthenticateQualify: %d\r\n", contact->authenticate_qualify);
2774 ast_str_append(&buf, 0, "OutboundProxy: %s\r\n", contact->outbound_proxy);
2775 ast_str_append(&buf, 0, "Path: %s\r\n", contact->path);
2776 ast_str_append(&buf, 0, "QualifyFrequency: %u\r\n", contact->qualify_frequency);
2777 ast_str_append(&buf, 0, "QualifyTimeout: %.3f\r\n", contact->qualify_timeout);
2778 ast_str_append(&buf, 0, "Qualify2xxOnly: %d\r\n", contact->qualify_2xx_only);
2779
2780 astman_append(ami->s, "%s\r\n", ast_str_buffer(buf));
2781 ami->count++;
2782
2783 ast_free(buf);
2785 return 0;
2786}
2787
2788static int format_contact_status_for_aor(void *obj, void *arg, int flags)
2789{
2790 struct ast_sip_aor *aor = obj;
2791
2793}
2794
2795static int format_ami_contact_status(const struct ast_sip_endpoint *endpoint,
2796 struct ast_sip_ami *ami)
2797{
2798 ami->arg = (void *)endpoint;
2800}
2801
2804};
2805
2806/*!
2807 * \brief Management task to clean up an AOR
2808 * \note Run by aor_options->serializer
2809 */
2810static int sip_options_cleanup_aor_task(void *obj)
2811{
2812 struct sip_options_aor *aor_options = obj;
2813
2814 ast_debug(2, "Cleaning up AOR '%s' for shutdown\n", aor_options->name);
2815
2816 aor_options->qualify_frequency = 0;
2817 if (aor_options->sched_task) {
2819 ao2_ref(aor_options->sched_task, -1);
2820 aor_options->sched_task = NULL;
2821 }
2823
2824 return 0;
2825}
2826
2827/*!
2828 * \brief Management task to clean up the environment
2829 * \note Run by management_serializer
2830 */
2831static int sip_options_cleanup_task(void *obj)
2832{
2833 struct ao2_iterator it_aor;
2834 struct sip_options_aor *aor_options;
2835
2836 if (!sip_options_aors) {
2837 /* Nothing to do */
2838 return 0;
2839 }
2840
2842 for (; (aor_options = ao2_iterator_next(&it_aor)); ao2_ref(aor_options, -1)) {
2844 sip_options_cleanup_aor_task, aor_options);
2845 }
2846 ao2_iterator_destroy(&it_aor);
2847
2848 return 0;
2849}
2850
2852{
2853 int remaining;
2854 struct ast_taskprocessor *mgmt_serializer;
2855
2857 ast_manager_unregister("PJSIPQualify");
2858 ast_manager_unregister("PJSIPShowContacts");
2860
2867
2868 mgmt_serializer = management_serializer;
2870 if (mgmt_serializer) {
2872 }
2873
2876 if (remaining) {
2877 ast_log(LOG_WARNING, "Cleanup incomplete. Could not stop %d AORs.\n",
2878 remaining);
2879 }
2882
2883 if (mgmt_serializer) {
2884 ast_taskprocessor_unreference(mgmt_serializer);
2885 }
2886
2893
2894 pjsip_endpt_unregister_module(ast_sip_get_pjsip_endpoint(), &options_module);
2895}
2896
2897/*!
2898 * \brief Management task to finish setting up the environment.
2899 * \note Run by management_serializer
2900 */
2901static int sip_options_init_task(void *mgmt_serializer)
2902{
2903 management_serializer = mgmt_serializer;
2904
2906 if (!shutdown_group) {
2907 return -1;
2908 }
2909
2912 return -1;
2913 }
2916 return -1;
2917 }
2920 return -1;
2921 }
2922
2924
2925 return 0;
2926}
2927
2929{
2931 return sip_options_contact_statuses ? 0 : -1;
2932}
2933
2935{
2936 struct ast_taskprocessor *mgmt_serializer;
2937
2938 static const pj_str_t STR_OPTIONS = { "OPTIONS", 7 };
2939
2940 if (reload) {
2942 return 0;
2943 }
2944
2945 if (pjsip_endpt_register_module(ast_sip_get_pjsip_endpoint(), &options_module)
2946 != PJ_SUCCESS) {
2947 return -1;
2948 }
2949
2950 if (pjsip_endpt_add_capability(ast_sip_get_pjsip_endpoint(), NULL, PJSIP_H_ALLOW,
2951 NULL, 1, &STR_OPTIONS) != PJ_SUCCESS) {
2953 return -1;
2954 }
2955
2957 sip_options_aor_hash_fn, NULL, sip_options_aor_cmp_fn);
2958 if (!sip_options_aors) {
2960 return -1;
2961 }
2965 sip_options_endpoint_state_compositor_hash_fn, NULL,
2966 sip_options_endpoint_state_compositor_cmp_fn);
2969 return -1;
2970 }
2971
2972 mgmt_serializer = ast_sip_create_serializer("pjsip/options/manage");
2973 if (!mgmt_serializer) {
2975 return -1;
2976 }
2977
2978 /*
2979 * Set the water mark levels high because we can get a flood of
2980 * contact status updates from sip_options_synchronize() that
2981 * quickly clears on initial load or reload.
2982 */
2983 ast_taskprocessor_alert_set_levels(mgmt_serializer, -1,
2985
2986 /*
2987 * We make sure that the environment is completely setup before we allow
2988 * any other threads to post contact_status updates to the
2989 * management_serializer.
2990 */
2992 mgmt_serializer)) {
2993 /* Set management_serializer in case pushing the task actually failed. */
2994 management_serializer = mgmt_serializer;
2996 return -1;
2997 }
2998
3004
3005 return 0;
3006}
jack_status_t status
Definition: app_jack.c:149
char * strsep(char **str, const char *delims)
Asterisk main include file. File version handling, generic pbx functions.
int ast_shutting_down(void)
Definition: asterisk.c:1883
#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:399
static int available(struct dahdi_pvt **pvt, int is_specific_channel)
Definition: chan_dahdi.c:13552
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:2028
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Definition: manager.c:1986
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:2064
void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
Send ack in manager transaction.
Definition: manager.c:2018
const char * astman_get_header(const struct message *m, char *var)
Get header from manager transaction.
Definition: manager.c:1647
void astman_send_list_complete_end(struct mansession *s)
End the list complete event.
Definition: manager.c:2072
void astman_append(struct mansession *s, const char *fmt,...)
Definition: manager.c:1907
int ast_manager_unregister(const char *action)
Unregister a registered manager command.
Definition: manager.c:7697
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:2217
@ AST_SIP_SCHED_TASK_VARIABLE
Definition: res_pjsip.h:2200
static char prefix[MAX_PREFIX]
Definition: http.c:144
#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:192
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:4190
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:723
int ast_sip_for_each_aor(const char *aors, ao2_callback_fn on_aor, void *arg)
For every aor in the comma separated aors string call the given 'on_aor' handler.
Definition: location.c:688
pjsip_endpoint * ast_sip_get_pjsip_endpoint(void)
Get a pointer to the PJSIP endpoint.
Definition: res_pjsip.c: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:3504
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:434
@ AVAILABLE
Definition: res_pjsip.h:438
@ UNAVAILABLE
Definition: res_pjsip.h:436
@ REMOVED
Definition: res_pjsip.h:443
@ UNKNOWN
Definition: res_pjsip.h:440
@ CREATED
Definition: res_pjsip.h:442
#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:205
#define AST_STATSD_TIMER
Definition: statsd.h:41
#define AST_STATSD_GAUGE
Support for publishing to a statsd server.
Definition: statsd.h:32
void ast_statsd_log_full_va(const char *metric_name, const char *metric_type, intmax_t value, double sample_rate,...)
Send a stat to the configured statsd server.
Definition: res_statsd.c:228
#define ast_string_fields_copy(copy, orig)
Copy all string fields from one instance to another of the same structure.
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:3200
struct mansession * s
Definition: res_pjsip.h:3202
void * arg
Definition: res_pjsip.h:3208
const struct message * m
Definition: res_pjsip.h:3204
A SIP address of record.
Definition: res_pjsip.h:478
double qualify_timeout
Definition: res_pjsip.h:506
int qualify_2xx_only
Definition: res_pjsip.h:512
struct ao2_container * permanent_contacts
Definition: res_pjsip.h:502
int authenticate_qualify
Definition: res_pjsip.h:496
unsigned int qualify_frequency
Definition: res_pjsip.h:494
A contact's status.
Definition: res_pjsip.h:451
const ast_string_field uri
Definition: res_pjsip.h:457
enum ast_sip_contact_status_type status
Definition: res_pjsip.h:468
enum ast_sip_contact_status_type last_status
Definition: res_pjsip.h:470
const ast_string_field aor
Definition: res_pjsip.h:457
struct ast_sip_security_mechanism_vector security_mechanisms
Definition: res_pjsip.h:466
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:519
struct ast_sip_contact * contact
Definition: res_pjsip.h:525
Contact associated with an address of record.
Definition: res_pjsip.h:390
const ast_string_field uri
Definition: res_pjsip.h:412
double qualify_timeout
Definition: res_pjsip.h:420
const ast_string_field via_addr
Definition: res_pjsip.h:412
int qualify_2xx_only
Definition: res_pjsip.h:428
const ast_string_field call_id
Definition: res_pjsip.h:412
const ast_string_field aor
Definition: res_pjsip.h:412
const ast_string_field outbound_proxy
Definition: res_pjsip.h:412
struct timeval expiration_time
Definition: res_pjsip.h:414
const ast_string_field path
Definition: res_pjsip.h:412
const ast_string_field endpoint_name
Definition: res_pjsip.h:412
int authenticate_qualify
Definition: res_pjsip.h:418
const ast_string_field user_agent
Definition: res_pjsip.h:412
unsigned int qualify_frequency
Definition: res_pjsip.h:416
An entity responsible formatting endpoint information.
Definition: res_pjsip.h:3226
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:3230
An entity with which Asterisk communicates.
Definition: res_pjsip.h:1051
const ast_string_field aors
Definition: res_pjsip.h:1080
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:327
Structure which contains an AOR and contacts for qualifying purposes.
struct sip_options_aor::@457 compositors
The endpoint state compositors we are feeding, a reference is held to each.
double qualify_timeout
Qualify timeout. 0 is diabled.
struct ao2_container * contacts
All contacts associated with this AOR.
int qualify_2xx_only
If true only authenticate if OPTIONS response is 2XX.
struct ao2_container * dynamic_contacts
Only dynamic contacts associated with this AOR.
struct ast_taskprocessor * serializer
The serializer for this AOR.
struct ast_sip_sched_task * sched_task
The scheduler task for this AOR.
unsigned int available
The number of available contacts on this AOR.
unsigned int qualify_frequency
Frequency to send OPTIONS requests to AOR contacts. 0 is disabled.
char name[0]
The name of the AOR.
Structure used to contain information for an OPTIONS callback.
struct ast_sip_contact * contact
The contact we qualified.
struct timeval rtt_start
The time at which this OPTIONS attempt was started.
enum ast_sip_contact_status_type status
The new status of the contact.
struct sip_options_aor * aor_options
The AOR options.
Task details for adding an AOR to an endpoint state compositor.
struct ast_sip_contact * contact
The contact itself.
struct sip_options_aor * aor_options
The AOR options that the contact is referring to.
Structure which contains status information for an AOR feeding an endpoint state compositor.
char available
The last contributed available status of the named AOR (1 if available, 0 if not available)
char name[0]
The name of the AOR.
Task details for adding an AOR to an endpoint state compositor.
struct sip_options_endpoint_state_compositor * endpoint_state_compositor
The endpoint state compositor.
struct sip_options_aor * aor_options
The AOR options that the endpoint state compositor should be added to.
Structure which contains composites information for endpoint state.
char active
Non-zero if the compositor is in normal operation. i.e. Not being setup/reconfigured.
struct ao2_container * aor_statuses
The last contributed available status of the AORs feeding this compositor.
char name[0]
The name of the endpoint.
Task data for AOR creation or updating.
struct sip_options_aor * aor_options
The AOR options for this AOR.
int added
Whether this AOR is being added.
struct ast_sip_aor * aor
The AOR which contains the new configuraton.
struct ao2_container * existing
Optional container of existing AOR s.
Structure which contains information required to synchronize.
int reload
Whether this is a reload or not.
userdata associated with baseline taskprocessor test
An API for managing task processing threads that can be shared across modules.
void * ast_taskprocessor_unreference(struct ast_taskprocessor *tps)
Unreference the specified taskprocessor and its reference count will decrement.
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