Asterisk - The Open Source Telephony Project GIT-master-545c459
Loading...
Searching...
No Matches
pjsip_options.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 2018, Digium, Inc.
5 *
6 * Joshua Colp <jcolp@digium.com>
7 * Richard Mudgett <rmudgett@digium.com>
8 *
9 * See http://www.asterisk.org for more information about
10 * the Asterisk project. Please do not directly contact
11 * any of the maintainers of this project for assistance;
12 * the project provides a web site, mailing lists and IRC
13 * channels for your use.
14 *
15 * This program is free software, distributed under the terms of
16 * the GNU General Public License Version 2. See the LICENSE file
17 * at the top of the source tree.
18 */
19
20#include "asterisk.h"
21
22#include <pjsip.h>
23#include <pjsip_ua.h>
24#include <pjlib.h>
25
26#include "asterisk/res_pjsip.h"
27#include "asterisk/channel.h"
28#include "asterisk/pbx.h"
29#include "asterisk/astobj2.h"
30#include "asterisk/cli.h"
31#include "asterisk/time.h"
32#include "asterisk/test.h"
33#include "asterisk/statsd.h"
36#include "asterisk/taskpool.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/*!
129 * \brief Structure which contains status information for an AOR feeding an endpoint state compositor
130 */
132 /*! \brief The last contributed available status of the named AOR (1 if available, 0 if not available) */
134 /*! \brief The name of the AOR */
135 char name[0];
136};
137
138/*!
139 * \brief Structure which contains composites information for endpoint state
140 */
142 /*! \brief The last contributed available status of the AORs feeding this compositor */
144 /*!
145 * \brief Non-zero if the compositor is in normal operation. i.e. Not being setup/reconfigured.
146 *
147 * \details
148 * The aor layer can only update its aor_statuses record when not active.
149 * When active the aor layer can update its aor_statuses record, calculate the new
150 * number of available aors, determine if the endpoint compositor changed state,
151 * and report it.
152 */
153 char active;
154 /*! \brief The name of the endpoint */
155 char name[0];
156};
157
158/*!
159 * \brief Structure which contains an AOR and contacts for qualifying purposes
160 */
162 /*! \brief The scheduler task for this AOR */
164 /*! \brief The serializer for this AOR */
166 /*! \brief All contacts associated with this AOR */
168 /*!
169 * \brief Only dynamic contacts associated with this AOR
170 * \note Used to speed up applying AOR configuration by
171 * minimizing wild card sorcery access.
172 */
174 /*! \brief The endpoint state compositors we are feeding, a reference is held to each */
176 /*! \brief The number of available contacts on this AOR */
177 unsigned int available;
178 /*! \brief Frequency to send OPTIONS requests to AOR contacts. 0 is disabled. */
179 unsigned int qualify_frequency;
180 /*! \brief If true only authenticate if OPTIONS response is 2XX */
182 /*! If true authenticate the qualify challenge response if needed */
184 /*! \brief Qualify timeout. 0 is diabled. */
186 /*! \brief The name of the AOR */
187 char name[0];
188};
189
190/*!
191 * \internal
192 * \brief Container of active SIP AORs for qualifying
193 */
195
196/*!
197 * \internal
198 * \brief Container of contact statuses
199 */
201
202/*!
203 * \internal
204 * \brief Container of endpoint state compositors
205 */
207
208/*!
209 * \internal
210 * \brief Serializer for AOR, endpoint state compositor, and contact existence management
211 */
213
214static pj_status_t send_options_response(pjsip_rx_data *rdata, int code)
215{
216 pjsip_endpoint *endpt = ast_sip_get_pjsip_endpoint();
217 pjsip_dialog *dlg = pjsip_rdata_get_dlg(rdata);
218 pjsip_transaction *trans = pjsip_rdata_get_tsx(rdata);
219 pjsip_tx_data *tdata;
220 const pjsip_hdr *hdr;
221 pj_status_t status;
222
223 /* Make the response object */
224 status = ast_sip_create_response(rdata, code, NULL, &tdata);
225 if (status != PJ_SUCCESS) {
226 ast_log(LOG_ERROR, "Unable to create response (%d)\n", status);
227 return status;
228 }
229
230 /* Add appropriate headers */
231 if ((hdr = pjsip_endpt_get_capability(endpt, PJSIP_H_ACCEPT, NULL))) {
232 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)pjsip_hdr_clone(tdata->pool, hdr));
233 }
234 if ((hdr = pjsip_endpt_get_capability(endpt, PJSIP_H_ALLOW, 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_SUPPORTED, NULL))) {
238 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)pjsip_hdr_clone(tdata->pool, hdr));
239 }
240
241 /*
242 * XXX TODO: pjsip doesn't care a lot about either of these headers -
243 * while it provides specific methods to create them, they are defined
244 * to be the standard string header creation. Hard coded here.
245 */
246 ast_sip_add_header(tdata, "Accept-Encoding", DEFAULT_ENCODING);
247 ast_sip_add_header(tdata, "Accept-Language", DEFAULT_LANGUAGE);
248
249 if (dlg && trans) {
250 status = pjsip_dlg_send_response(dlg, trans, tdata);
251 } else {
252 struct ast_sip_endpoint *endpoint;
253
254 endpoint = ast_pjsip_rdata_get_endpoint(rdata);
255 status = ast_sip_send_stateful_response(rdata, tdata, endpoint);
256 ao2_cleanup(endpoint);
257 }
258
259 if (status != PJ_SUCCESS) {
260 ast_log(LOG_ERROR, "Unable to send response (%d)\n", status);
261 }
262
263 return status;
264}
265
266static pj_bool_t options_on_rx_request(pjsip_rx_data *rdata)
267{
268 RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
269 pjsip_uri *ruri;
270 char exten[AST_MAX_EXTENSION];
271
272 if (pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_options_method)) {
273 return PJ_FALSE;
274 }
275
276 if (!(endpoint = ast_pjsip_rdata_get_endpoint(rdata))) {
277 return PJ_FALSE;
278 }
279
280 ruri = rdata->msg_info.msg->line.req.uri;
281 if (!ast_sip_is_allowed_uri(ruri)) {
282 send_options_response(rdata, 416);
283 return PJ_TRUE;
284 }
285
286 ast_copy_pj_str(exten, ast_sip_pjsip_uri_get_username(ruri), sizeof(exten));
287
288 /*
289 * We may want to match in the dialplan without any user
290 * options getting in the way.
291 */
293
294 if (ast_shutting_down()) {
295 /*
296 * Not taking any new calls at this time.
297 * Likely a server availability OPTIONS poll.
298 */
299 send_options_response(rdata, 503);
300 } else if (!ast_strlen_zero(exten)
301 && !ast_exists_extension(NULL, endpoint->context, exten, 1, NULL)) {
302 send_options_response(rdata, 404);
303 } else {
304 send_options_response(rdata, 200);
305 }
306 return PJ_TRUE;
307}
308
309static pjsip_module options_module = {
310 .name = {"Options Module", 14},
311 .id = -1,
312 .priority = PJSIP_MOD_PRIORITY_APPLICATION,
313 .on_rx_request = options_on_rx_request,
314};
315
316static const char *status_map[] = {
317 [UNAVAILABLE] = "Unreachable",
318 [AVAILABLE] = "Reachable",
319 [UNKNOWN] = "Unknown",
320 [CREATED] = "NonQualified",
321 [REMOVED] = "Removed",
322};
323
324static const char *short_status_map[] = {
325 [UNAVAILABLE] = "Unavail",
326 [AVAILABLE] = "Avail",
327 [UNKNOWN] = "Unknown",
328 [CREATED] = "NonQual",
329 [REMOVED] = "Removed",
330};
331
337
343
344/*! \brief Destructor for contact statuses */
345static void sip_contact_status_dtor(void *obj)
346{
347 struct ast_sip_contact_status *contact_status = obj;
348
350
351 ast_string_field_free_memory(contact_status);
352}
353
355{
356 struct ast_sip_contact_status *contact_status;
357 size_t size = sizeof(*contact_status) + strlen(name) + 1;
358
359 contact_status = ao2_alloc_options(size, sip_contact_status_dtor,
361 if (!contact_status) {
362 return NULL;
363 }
364 if (ast_string_field_init(contact_status, 256)) {
365 ao2_ref(contact_status, -1);
366 return NULL;
367 }
368 AST_VECTOR_INIT(&contact_status->security_mechanisms, 0);
369 strcpy(contact_status->name, name); /* SAFE */
370 return contact_status;
371}
372
374{
375 struct ast_sip_contact_status *dst;
376
377 dst = sip_contact_status_alloc(src->name);
378 if (!dst) {
379 return NULL;
380 }
381
382 if (ast_string_fields_copy(dst, src)) {
383 ao2_ref(dst, -1);
384 return NULL;
385 }
386 dst->rtt = src->rtt;
387 dst->status = src->status;
388 dst->last_status = src->last_status;
389
391 return dst;
392}
393
394/*! \brief Hashing function for contact statuses */
396
397/*! \brief Sort function for contact statuses */
399
400/*! \brief Comparator function for contact statuses */
402
403/*! \brief Helper function to allocate a contact statuses container */
405{
406 /*
407 * Replace duplicate objects so we can update the immutable
408 * contact status objects by simply linking in a new object.
409 */
412 ast_sip_contact_status_hash_fn, ast_sip_contact_status_sort_fn,
413 ast_sip_contact_status_cmp_fn);
414}
415
416/*! \brief Function which publishes a contact status update to all interested endpoints */
417static void sip_options_publish_contact_state(const struct sip_options_aor *aor_options,
418 const struct ast_sip_contact_status *contact_status)
419{
420 int i;
421
422 for (i = 0; i < AST_VECTOR_SIZE(&aor_options->compositors); ++i) {
423 const struct sip_options_endpoint_state_compositor *endpoint_state_compositor;
424
425 endpoint_state_compositor = AST_VECTOR_GET(&aor_options->compositors, i);
427 contact_status);
428 }
429}
430
431/*!
432 * \brief Task to notify endpoints of a contact status change
433 * \note Run by management_serializer
434 */
436{
437 struct ast_sip_contact_status *contact_status = obj;
438 struct sip_options_aor *aor_options;
439
440 aor_options = ao2_find(sip_options_aors, contact_status->aor, OBJ_SEARCH_KEY);
441 if (aor_options) {
442 sip_options_publish_contact_state(aor_options, contact_status);
443 ao2_ref(aor_options, -1);
444 }
445 ao2_ref(contact_status, -1);
446
447 return 0;
448}
449
451{
452 struct ast_taskprocessor *mgmt_serializer = management_serializer;
453
454 if (mgmt_serializer) {
455 ao2_ref(contact_status, +1);
457 contact_status)) {
458 ao2_ref(contact_status, -1);
459 }
460 }
461}
462
464{
465 struct ast_sip_contact_status *contact_status;
466 int res;
467
468 /*
469 * At startup a contact status can be retrieved when static contacts
470 * are themselves being setup. This happens before we are fully setup.
471 * Since we don't actually trigger qualify or anything as a result it
472 * is safe to do so. They'll just get back a contact status that will
473 * be updated later. At this time they only care that the contact
474 * status gets created for the static contact anyway.
475 */
477 /*
478 * We haven't been pre-initialized or we are shutting down.
479 * Neither situation should happen.
480 */
481 ast_assert(0);
482 return NULL;
483 }
484
486
487 /* If contact status for this contact already exists just return it */
488 contact_status = ao2_find(sip_options_contact_statuses,
490 if (contact_status) {
492 return contact_status;
493 }
494
495 /* Otherwise we have to create and store a new contact status */
496 contact_status = sip_contact_status_alloc(ast_sorcery_object_get_id(contact));
497 if (!contact_status) {
499 return NULL;
500 }
501
502 contact_status->rtt = 0;
503 contact_status->status = CREATED;
504 contact_status->last_status = CREATED;
505 res = ast_string_field_set(contact_status, uri, contact->uri);
506 res |= ast_string_field_set(contact_status, aor, contact->aor);
507 if (res) {
509 ao2_ref(contact_status, -1);
510 return NULL;
511 }
512
515
516 ast_statsd_log_string_va("PJSIP.contacts.states.%s", AST_STATSD_GAUGE,
517 "+1", 1.0, ast_sip_get_contact_status_label(contact_status->status));
518
519 sip_options_contact_status_update(contact_status);
520
521 return contact_status;
522}
523
529
530/*! \brief Hashing function for OPTIONS AORs */
532
533/*! \brief Comparator function for SIP OPTIONS AORs */
535
536/*! \brief Hashing function for endpoint state compositors */
538
539/*! \brief Comparator function for endpoint state compositors */
541
542/*! \brief Structure used to contain information for an OPTIONS callback */
544 /*! \brief The contact we qualified */
546 /*! \brief The AOR options */
548 /*! \brief The time at which this OPTIONS attempt was started */
549 struct timeval rtt_start;
550 /*! \brief The new status of the contact */
552 /*! \brief Whether the OPTIONS request(s) have been completed */
553 unsigned int completed;
554 /*! \brief Number of resolved targets waiting for a response */
555 unsigned int pending;
556 /*! \brief Transaction data for the resolve request */
557 pjsip_tx_data *resolve_tdata;
558 /*! \brief Endpoint used to create and send each target request */
560 /*! \brief Transactions for all target OPTIONS requests in this batch */
561 AST_VECTOR(, pjsip_transaction *) target_transactions;
562};
563
566 pj_status_t status;
567 unsigned int count;
568 pjsip_server_addresses addresses;
569 char *names[PJSIP_MAX_RESOLVED_ADDRESSES];
570};
571
575static void qualify_contact_cb(void *token, pjsip_event *e);
576
578{
580 unsigned int idx;
581
582 for (idx = 0; idx < task_data->count; ++idx) {
583 ast_free(task_data->names[idx]);
584 }
585
586 ao2_ref(task_data->batch, -1);
587}
588
589/*! \brief Process a DNS resolution result on the AOR serializer */
591{
594 unsigned int idx;
595
596 if (task_data->status != PJ_SUCCESS || !task_data->count) {
597 /* This failure is a de facto single pending result. */
598 batch->pending = 1;
600 ao2_ref(task_data, -1);
601 return 0;
602 }
603
604 /* Each resolved address must contribute exactly one batch result. */
605 batch->pending = task_data->count;
606
607 for (idx = 0; idx < task_data->count; ++idx) {
608 pjsip_tx_data *tdata;
609 pjsip_via_hdr *via;
610 pjsip_transaction *tsx = NULL;
611
612 if (ast_sip_create_request("OPTIONS", NULL, batch->endpoint, NULL,
613 batch->contact, &tdata)) {
615 continue;
616 }
617
618 if (!ast_strlen_zero(batch->contact->outbound_proxy) &&
619 ast_sip_set_outbound_proxy(tdata, batch->contact->outbound_proxy)) {
620 pjsip_tx_data_dec_ref(tdata);
622 continue;
623 }
624
625 /*
626 * Build a new request per resolved target so each send gets its own
627 * transaction and Via branch. Setting exactly one pre-resolved
628 * destination here avoids PJSIP re-resolving and choosing only the
629 * first DNS result.
630 */
631 tdata->dest_info.addr.count = 1;
632 tdata->dest_info.cur_addr = 0;
633 tdata->dest_info.addr.entry[0].type = task_data->addresses.entry[idx].type;
634 tdata->dest_info.addr.entry[0].priority = task_data->addresses.entry[idx].priority;
635 tdata->dest_info.addr.entry[0].weight = task_data->addresses.entry[idx].weight;
636 tdata->dest_info.addr.entry[0].addr_len = task_data->addresses.entry[idx].addr_len;
637 pj_sockaddr_cp(&tdata->dest_info.addr.entry[0].addr,
638 &task_data->addresses.entry[idx].addr);
639 pj_strdup(tdata->pool, &tdata->dest_info.addr.entry[0].name,
640 &task_data->addresses.entry[idx].name);
641 via = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL);
642 if (via) {
643 via->branch_param.slen = 0;
644 }
645
646 /* ast_sip_send_out_of_dialog_request_with_tsx consumes the tdata reference. */
648 (int)(batch->aor_options->qualify_timeout * 1000),
650 ao2_ref(batch, -1);
652 } else if (tsx) {
653 /*
654 * It is possible that we will not get back a transaction under two circumstances:
655 * 1. The send failed.
656 * 2. The build of PJPROJECT used does not contain pjsip_endpt_send_request2() so
657 * there is no way to get an in-flight transaction reference for the OPTIONS.
658 *
659 * With no transaction references, we can not cancel in-flight OPTIONS requests when
660 * an endpoint responds with a 2xx response to one of the requests. This is not ideal
661 * and will result in unnecessary OPTIONS retransmissions being sent.
662 *
663 * The Append should never fail as we init the vector to PJSIP_MAX_RESOLVED_ADDRESSES
664 * and also limit the count of resolved addresses in sip_options_qualify_resolve_cb.
665 */
666 AST_VECTOR_APPEND(&batch->target_transactions, tsx);
667 }
668 }
669
670 ao2_ref(task_data, -1);
671 return 0;
672}
673
674static void sip_options_transaction_free(pjsip_transaction *tsx)
675{
676 if (tsx) {
677 pj_grp_lock_dec_ref(tsx->grp_lock);
678 }
679}
680
681/*! \brief Result of qualifying an individual address belonging to a contact resolved
682 from an A, AAAA or SRV record. */
687
688/*! \brief Terminate all in-flight target transactions for a batch */
691{
692 unsigned int idx;
693
694 for (idx = 0; idx < AST_VECTOR_SIZE(&batch->target_transactions); ++idx) {
695 pjsip_transaction *tsx = AST_VECTOR_GET(&batch->target_transactions, idx);
696
697 if (tsx) {
698 pjsip_tsx_terminate_async(tsx, PJSIP_SC_REQUEST_TERMINATED);
699 }
700 }
701}
702
703/*!
704 * \brief Return the current state of an endpoint state compositor
705 * \pre The endpoint_state_compositor lock must be held.
706 */
708 const struct sip_options_endpoint_state_compositor *endpoint_state_compositor)
709{
710 struct ao2_iterator it_aor_statuses;
711 struct sip_options_endpoint_aor_status *aor_status;
713
714 it_aor_statuses = ao2_iterator_init(endpoint_state_compositor->aor_statuses, 0);
715 for (; (aor_status = ao2_iterator_next(&it_aor_statuses)); ao2_ref(aor_status, -1)) {
716 if (aor_status->available) {
718 ao2_ref(aor_status, -1);
719 break;
720 }
721 }
722 ao2_iterator_destroy(&it_aor_statuses);
723
724 return state;
725}
726
727/*!
728 * \brief Update the AOR status on an endpoint state compositor
729 * \pre The endpoint_state_compositor lock must be held.
730 */
732 const char *name, enum ast_sip_contact_status_type status)
733{
734 struct sip_options_endpoint_aor_status *aor_status;
735 enum ast_endpoint_state endpoint_state;
736
737 aor_status = ao2_find(endpoint_state_compositor->aor_statuses, name,
739 if (!aor_status) {
740 /* The AOR status doesn't exist already so we don't need to go any further */
741 if (status == REMOVED) {
742 return;
743 }
744
745 aor_status = ao2_alloc_options(sizeof(*aor_status) + strlen(name) + 1, NULL,
747 if (!aor_status) {
748 return;
749 }
750
751 strcpy(aor_status->name, name); /* SAFE */
752 ao2_link(endpoint_state_compositor->aor_statuses, aor_status);
753 }
754
755 if (status == REMOVED) {
756 /*
757 * If the AOR is being removed then remove its AOR status
758 * from the endpoint compositor.
759 */
760 ao2_unlink(endpoint_state_compositor->aor_statuses, aor_status);
761 } else {
762 aor_status->available = (status == AVAILABLE ? 1 : 0);
763 }
764 ao2_ref(aor_status, -1);
765
766 if (!endpoint_state_compositor->active) {
767 return;
768 }
769
770 /* If this AOR is available then the endpoint itself has to be online */
771 if (status == AVAILABLE) {
772 ast_debug(3, "Endpoint state compositor '%s' is online as AOR '%s' is available\n",
773 endpoint_state_compositor->name, name);
774 endpoint_state = AST_ENDPOINT_ONLINE;
775 } else {
776 endpoint_state =
777 sip_options_get_endpoint_state_compositor_state(endpoint_state_compositor);
778 }
779
780 ast_sip_persistent_endpoint_update_state(endpoint_state_compositor->name,
781 endpoint_state);
782}
783
784/*! \brief Function which notifies endpoint state compositors of a state change of an AOR */
787{
788 int i;
789
790 /* Iterate through the associated endpoint state compositors updating them */
791 for (i = 0; i < AST_VECTOR_SIZE(&aor_options->compositors); ++i) {
792 struct sip_options_endpoint_state_compositor *endpoint_state_compositor;
793
794 endpoint_state_compositor = AST_VECTOR_GET(&aor_options->compositors, i);
795
796 ao2_lock(endpoint_state_compositor);
797 sip_options_update_endpoint_state_compositor_aor(endpoint_state_compositor,
798 aor_options->name, status);
799 ao2_unlock(endpoint_state_compositor);
800 }
801
802 if (status == REMOVED) {
804 }
805}
806
807/*!
808 * \brief Task to notify an AOR of a contact status change
809 * \note Run by aor_options->serializer
810 */
812{
813 struct sip_options_contact_callback_data *contact_callback_data = obj;
814 struct ast_sip_contact *contact;
815 struct ast_sip_contact_status *cs_old;
816 struct ast_sip_contact_status *cs_new;
817
818 /*
819 * Determine if this is a late arriving notification, as it is
820 * possible that we get a callback from PJSIP giving us contact
821 * status but in the mean time said contact has been removed
822 * from the controlling AOR.
823 */
824
825 if (!contact_callback_data->aor_options->qualify_frequency) {
826 /* Contact qualify response is late */
827 ao2_ref(contact_callback_data, -1);
828 return 0;
829 }
830
831 contact = ao2_find(contact_callback_data->aor_options->contacts,
832 contact_callback_data->contact, OBJ_SEARCH_OBJECT);
833 if (!contact) {
834 /* Contact qualify response is late */
835 ao2_ref(contact_callback_data, -1);
836 return 0;
837 }
838 ao2_ref(contact, -1);
839
841 ast_sorcery_object_get_id(contact_callback_data->contact), OBJ_SEARCH_KEY);
842 if (!cs_old) {
843 /* Contact qualify response is late */
844 ao2_ref(contact_callback_data, -1);
845 return 0;
846 }
847
848 /* Update the contact specific status information */
849 cs_new = sip_contact_status_copy(cs_old);
850 ao2_ref(cs_old, -1);
851 if (!cs_new) {
852 ao2_ref(contact_callback_data, -1);
853 return 0;
854 }
855 cs_new->last_status = cs_new->status;
856 cs_new->status = contact_callback_data->status;
857 cs_new->rtt =
858 cs_new->status == AVAILABLE
859 ? ast_tvdiff_us(ast_tvnow(), contact_callback_data->rtt_start)
860 : 0;
862
863 /*
864 * If the status has changed then notify the endpoint state compositors
865 * and publish our events.
866 */
867 if (cs_new->last_status != cs_new->status) {
868 if (cs_new->status == AVAILABLE) {
869 /* If this is the first available contact then the AOR has become available */
870 ++contact_callback_data->aor_options->available;
871 if (contact_callback_data->aor_options->available == 1) {
873 contact_callback_data->aor_options, AVAILABLE);
874 }
875 } else if (cs_new->last_status == AVAILABLE) {
876 ast_assert(cs_new->status == UNAVAILABLE);
877
878 /* If there are no more available contacts then this AOR is unavailable */
879 --contact_callback_data->aor_options->available;
880 if (!contact_callback_data->aor_options->available) {
882 contact_callback_data->aor_options, UNAVAILABLE);
883 }
884 }
885
886 ast_verb(3, "Contact %s/%s is now %s. RTT: %.3f msec\n",
887 cs_new->aor,
888 cs_new->uri,
890 cs_new->rtt / 1000.0);
891
892 ast_statsd_log_string_va("PJSIP.contacts.states.%s", AST_STATSD_GAUGE,
894 ast_statsd_log_string_va("PJSIP.contacts.states.%s", AST_STATSD_GAUGE,
895 "+1", 1.0, ast_sip_get_contact_status_label(cs_new->status));
896
898
899 ast_test_suite_event_notify("AOR_CONTACT_UPDATE",
900 "Contact: %s\r\n"
901 "Status: %s",
902 cs_new->name,
904 } else {
905 ast_debug(3, "Contact %s/%s status didn't change: %s, RTT: %.3f msec\n",
906 cs_new->aor,
907 cs_new->uri,
909 cs_new->rtt / 1000.0);
910 }
911
912 ast_statsd_log_full_va("PJSIP.contacts.%s.rtt", AST_STATSD_TIMER,
913 cs_new->status != AVAILABLE ? -1 : cs_new->rtt / 1000,
914 1.0,
915 cs_new->name);
916
917 ast_test_suite_event_notify("AOR_CONTACT_QUALIFY_RESULT",
918 "Contact: %s\r\n"
919 "Status: %s\r\n"
920 "RTT: %" PRId64,
921 cs_new->name,
923 cs_new->rtt);
924
925 ast_debug(3, "AOR '%s' now has %d available contacts\n",
926 contact_callback_data->aor_options->name,
927 contact_callback_data->aor_options->available);
928
929 ao2_ref(cs_new, -1);
930 ao2_ref(contact_callback_data, -1);
931
932 return 0;
933}
934
935/*! \brief Destructor for a resolved target's qualification result */
936static void sip_options_target_result_dtor(void *obj)
937{
938 struct sip_options_target_result *result = obj;
939 ao2_cleanup(result->batch);
940}
941
942/*!
943 * \brief Combine the result of one resolved target with the other targets
944 * \note Run by aor_options->serializer
945 */
947{
948 struct sip_options_target_result *result = obj;
950
951 if (!batch->completed) {
952 /* If the result is available then we can mark the batch as completed
953 and notify the AOR */
954 ast_assert(batch->pending);
955 --batch->pending;
956
957 if (result->status == AVAILABLE) {
958 /* At least one resolved target was available. */
959 batch->completed = 1;
960 batch->status = AVAILABLE;
962 /* The notify task inherits this reference. */
964 } else if (!batch->pending) {
965 /* Every resolved target failed. */
966 batch->completed = 1;
967 batch->status = UNAVAILABLE;
969 }
970 }
971
972 ao2_ref(result, -1);
973 return 0;
974}
975
976/*! \brief Queue a resolved target's qualification result to be combined with the other targets */
980{
982
985 if (!result) {
986 ast_log(LOG_WARNING, "Unable to allocate qualify target result for '%s'\n",
988 return;
989 }
990
991 result->batch = ao2_bump(batch);
992 result->status = status;
993 /*
994 * Callbacks may arrive on non-serializer threads, so they queue one result per
995 * target onto the AOR serializer, the single owner of the batch's processing.
996 *
997 * Sends and callbacks can execute synchronously while we are already
998 * running on that serializer thread. Re-queueing to the same serializer in
999 * that case would defer updates and can break processing.
1000 *
1001 * Process inline when already on the same taskpool serializer to preserve
1002 * immediate, in-order state transitions.
1003 */
1004 if (batch->aor_options->serializer == ast_taskpool_serializer_get_current()) {
1006 return;
1007 }
1008
1009 if (ast_sip_push_task(batch->aor_options->serializer,
1011 ast_log(LOG_WARNING, "Unable to queue qualify target result for '%s'\n",
1013 ao2_ref(result, -1);
1014 }
1015}
1016
1017/*! \brief Callback for an OPTIONS response, timeout, or transport error */
1018static void qualify_contact_cb(void *token, pjsip_event *e)
1019{
1020 struct sip_options_contact_callback_data *contact_callback_data = token;
1022
1023 switch(e->body.tsx_state.type) {
1024 default:
1025 ast_log(LOG_ERROR, "Unexpected PJSIP event %u\n", e->body.tsx_state.type);
1026 /* Fall through */
1027 case PJSIP_EVENT_TRANSPORT_ERROR:
1028 case PJSIP_EVENT_TIMER:
1030 break;
1031 case PJSIP_EVENT_RX_MSG:
1032 if (contact_callback_data->aor_options->qualify_2xx_only &&
1033 (e->body.tsx_state.tsx->status_code < 200 || e->body.tsx_state.tsx->status_code >= 300)) {
1035 } else {
1036 status = AVAILABLE;
1037 }
1038 break;
1039 case PJSIP_EVENT_USER:
1040 /*
1041 * When one resolved target responds, we know the endpoint is available and we cancel the other
1042 * outstanding transactions. The cancelled transactions will trigger this user event, which we
1043 * can ignore as we already have a result for the contact.
1044 */
1045 ast_debug(3, "Received user event for contact '%s', ignoring\n",
1046 ast_sorcery_object_get_id(contact_callback_data->contact));
1047 /* Decrement reference count for the contact callback data and return as we have no result */
1048 ao2_ref(contact_callback_data, -1);
1049 return;
1050 }
1051
1052 sip_options_queue_target_result(contact_callback_data, status);
1053 ao2_ref(contact_callback_data, -1);
1054}
1055
1056/*! \brief Destructor for contact callback data */
1058{
1059 struct sip_options_contact_callback_data *contact_callback_data = obj;
1060
1061 ao2_cleanup(contact_callback_data->contact);
1062 ao2_cleanup(contact_callback_data->aor_options);
1063 ao2_cleanup(contact_callback_data->endpoint);
1064 /*
1065 * sip_options_qualify_resolve_cb should handle cleaning the resolve_tdata, but
1066 * keep this fallback just in case.
1067 */
1068 if (contact_callback_data->resolve_tdata) {
1069 pjsip_tx_data_dec_ref(contact_callback_data->resolve_tdata);
1070 contact_callback_data->resolve_tdata = NULL;
1071 }
1072 AST_VECTOR_RESET(&contact_callback_data->target_transactions,
1074 AST_VECTOR_FREE(&contact_callback_data->target_transactions);
1075}
1076
1077/*! \brief Contact callback data allocator */
1080 struct ast_sip_endpoint *endpoint, pjsip_tx_data *resolve_tdata)
1081{
1082 struct sip_options_contact_callback_data *contact_callback_data;
1083
1084 contact_callback_data = ao2_alloc_options(sizeof(*contact_callback_data),
1086 if (!contact_callback_data) {
1087 return NULL;
1088 }
1089
1090 if (AST_VECTOR_INIT(&contact_callback_data->target_transactions, PJSIP_MAX_RESOLVED_ADDRESSES)) {
1091 ao2_ref(contact_callback_data, -1);
1092 return NULL;
1093 }
1094
1095 contact_callback_data->contact = ao2_bump(contact);
1096 contact_callback_data->aor_options = ao2_bump(aor_options);
1097 contact_callback_data->endpoint = ao2_bump(endpoint);
1098 contact_callback_data->resolve_tdata = resolve_tdata;
1099 contact_callback_data->rtt_start = ast_tvnow();
1100
1101 return contact_callback_data;
1102}
1103
1104/*!
1105 * \brief Apply a request's transport selector to its DNS destination
1106 *
1107 * pjsip_get_request_dest builds the destination from the Request-URI and
1108 * may miss an outbound transport/listener.
1109 * Before manual DNS resolution, apply the selected transport to the
1110 * destination and check for mismatches so we use the correct transport
1111 * for the request.
1112 */
1114 const pjsip_tx_data *tdata, pjsip_host_info *destination)
1115{
1116 pjsip_transport_type_e transport_type = PJSIP_TRANSPORT_UNSPECIFIED;
1117
1118 if ((tdata->tp_sel.type != PJSIP_TPSELECTOR_TRANSPORT
1119 && tdata->tp_sel.type != PJSIP_TPSELECTOR_LISTENER)
1120 || !tdata->tp_sel.u.ptr) {
1121 return PJ_SUCCESS;
1122 }
1123
1124 if (tdata->tp_sel.type == PJSIP_TPSELECTOR_TRANSPORT) {
1125 transport_type = tdata->tp_sel.u.transport->key.type;
1126 } else {
1127 transport_type = tdata->tp_sel.u.listener->type;
1128 }
1129
1130 if (destination->type != PJSIP_TRANSPORT_UNSPECIFIED
1131 && ((destination->type | PJSIP_TRANSPORT_IPV6)
1132 != (transport_type | PJSIP_TRANSPORT_IPV6))) {
1133 return PJSIP_ETPNOTSUITABLE;
1134 }
1135
1136 destination->type = transport_type;
1137 return PJ_SUCCESS;
1138}
1139
1140/*! \brief DNS callback used to fan out a qualify to every resolved target */
1141static void sip_options_qualify_resolve_cb(pj_status_t status, void *token,
1142 const pjsip_server_addresses *addresses)
1143{
1146 unsigned int idx;
1147
1150 if (!task_data) {
1151 /*
1152 * Resolver callbacks are not guaranteed to run on the AOR serializer,
1153 * so on allocation failure we must log and drop to avoid potential state
1154 * issues.
1155 */
1157 "Unable to allocate qualify resolve task for '%s'\n",
1159 ao2_ref(batch, -1);
1160 return;
1161 }
1162
1163 memset(task_data, 0, sizeof(*task_data));
1164 task_data->batch = ao2_bump(batch);
1165 task_data->status = status;
1166
1167 if (status != PJ_SUCCESS || !addresses || !addresses->count) {
1168 if (batch->resolve_tdata) {
1169 pjsip_tx_data_dec_ref(batch->resolve_tdata);
1170 batch->resolve_tdata = NULL;
1171 }
1172
1173 if (ast_sip_push_task(batch->aor_options->serializer,
1176 "Unable to queue qualify resolve task for '%s'\n",
1178 ao2_ref(task_data, -1);
1179 }
1180 ao2_ref(batch, -1);
1181 return;
1182 }
1183
1184 /* Each resolved address must contribute exactly one batch result. */
1185 task_data->count = addresses->count;
1186 if (task_data->count > PJSIP_MAX_RESOLVED_ADDRESSES) {
1187 task_data->count = PJSIP_MAX_RESOLVED_ADDRESSES;
1188 }
1189
1190 for (idx = 0; idx < task_data->count; ++idx) {
1191 char *name_copy;
1192
1193 name_copy = ast_malloc(addresses->entry[idx].name.slen + 1);
1194 if (!name_copy) {
1195 task_data->status = PJ_ENOMEM;
1196 task_data->count = idx;
1197 break;
1198 }
1199
1200 ast_copy_pj_str(name_copy, &addresses->entry[idx].name,
1201 addresses->entry[idx].name.slen + 1);
1202 task_data->names[idx] = name_copy;
1203 task_data->addresses.entry[idx] = addresses->entry[idx];
1204 task_data->addresses.entry[idx].name.ptr = name_copy;
1205 task_data->addresses.entry[idx].name.slen = addresses->entry[idx].name.slen;
1206 }
1207
1208 if (task_data->status == PJ_SUCCESS) {
1209 task_data->addresses.count = task_data->count;
1210 }
1211
1212 if (batch->resolve_tdata) {
1213 pjsip_tx_data_dec_ref(batch->resolve_tdata);
1214 batch->resolve_tdata = NULL;
1215 }
1216
1217 /*
1218 * Push the qualify resolve task to the AOR serializer to avoid potential race
1219 * conditions between the resolve callback and the qualify contact task.
1220 */
1221 if (ast_sip_push_task(batch->aor_options->serializer,
1224 "Unable to queue qualify resolve task for '%s'\n",
1226 ao2_ref(task_data, -1);
1227 } else {
1228 ao2_ref(batch, -1);
1229 return;
1230 }
1231
1232 ao2_ref(batch, -1);
1233}
1234
1235/*! \brief Send a SIP OPTIONS request for a contact */
1236static int sip_options_qualify_contact(void *obj, void *arg, int flags)
1237{
1238 struct ast_sip_contact *contact = obj;
1239 struct sip_options_aor *aor_options = arg;
1240 RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
1241 pjsip_tx_data *tdata;
1242 pjsip_host_info destination;
1243 struct ast_sip_contact_status *contact_status;
1244 struct sip_options_contact_callback_data *contact_callback_data;
1245
1246 ast_debug(3, "Qualifying contact '%s' on AOR '%s'\n",
1248
1252 }
1254 struct sip_options_endpoint_state_compositor *endpoint_state_compositor;
1255
1256 endpoint_state_compositor = AST_VECTOR_GET(&aor_options->compositors, 0);
1257 endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint",
1258 endpoint_state_compositor->name);
1259 }
1260 if (!endpoint) {
1261 ast_debug(3, "Could not find an endpoint to qualify contact '%s' on AOR '%s'\n",
1262 ast_sorcery_object_get_id(contact), aor_options->name);
1263 return 0;
1264 }
1265
1266 /*
1267 * Create a request solely for DNS resolution. Its pool keeps the resolver strings alive,
1268 * and passing a URI with no contact avoids leaving a contact reference behind in case
1269 * resolution fails before it can send.
1270 */
1271 if (ast_sip_create_request("OPTIONS", NULL, endpoint, contact->uri, NULL,
1272 &tdata)) {
1273 ast_log(LOG_ERROR, "Unable to create request to qualify contact %s on AOR %s\n",
1274 contact->uri, aor_options->name);
1275 return 0;
1276 }
1277
1278 /* If an outbound proxy is specified set it on this request */
1279 if (!ast_strlen_zero(contact->outbound_proxy) &&
1280 ast_sip_set_outbound_proxy(tdata, contact->outbound_proxy)) {
1281 ast_log(LOG_ERROR, "Unable to apply outbound proxy on request to qualify contact %s\n",
1282 contact->uri);
1283 pjsip_tx_data_dec_ref(tdata);
1284 return 0;
1285 }
1286
1287 contact_status = ast_res_pjsip_find_or_create_contact_status(contact);
1288 if (!contact_status) {
1289 ast_log(LOG_ERROR, "Unable to retrieve contact status information for contact %s on AOR %s\n",
1290 contact->uri, aor_options->name);
1291 pjsip_tx_data_dec_ref(tdata);
1292 return 0;
1293 }
1294 ao2_ref(contact_status, -1);
1295
1296 contact_callback_data = sip_options_contact_callback_data_alloc(contact,
1297 aor_options, endpoint, tdata);
1298 if (!contact_callback_data) {
1299 ast_log(LOG_ERROR, "Unable to create object to contain callback data for contact %s on AOR %s\n",
1300 contact->uri, aor_options->name);
1301 pjsip_tx_data_dec_ref(tdata);
1302 return 0;
1303 }
1304
1305
1306 /*
1307 * Resolve the contact destination explicitly via DNS, then create and send
1308 * an independent OPTIONS for each returned transport/address/port tuple.
1309 * Keep the resolver-only tdata alive because its pool owns strings used
1310 * by the asynchronous resolver.
1311 */
1312 if (pjsip_get_request_dest(tdata, &destination) != PJ_SUCCESS
1313 || sip_options_apply_transport_to_destination(tdata, &destination)
1314 != PJ_SUCCESS) {
1315 ast_log(LOG_ERROR, "Unable to resolve destination to qualify contact %s on AOR %s\n",
1316 contact->uri, aor_options->name);
1317 ao2_ref(contact_callback_data, -1);
1318 return 0;
1319 }
1320
1321 pjsip_endpt_resolve(ast_sip_get_pjsip_endpoint(), tdata->pool, &destination,
1322 contact_callback_data, sip_options_qualify_resolve_cb);
1323
1324 return 0;
1325}
1326
1327/*!
1328 * \brief Task to qualify contacts of an AOR
1329 * \note Run by aor_options->serializer
1330 */
1331static int sip_options_qualify_aor(void *obj)
1332{
1333 struct sip_options_aor *aor_options = obj;
1334
1335 ast_debug(3, "Qualifying all contacts on AOR '%s'\n", aor_options->name);
1336
1337 /* Attempt to send an OPTIONS request to every contact on this AOR */
1339 (struct sip_options_aor *) aor_options);
1340
1341 /* Always reschedule to the frequency we should go */
1342 return aor_options->qualify_frequency * 1000;
1343}
1344
1345/*! \brief Forward declaration of this helpful function */
1346static int sip_options_remove_contact(void *obj, void *arg, int flags);
1347
1348/*! \brief Destructor function for SIP OPTIONS AORs */
1349static void sip_options_aor_dtor(void *obj)
1350{
1351 struct sip_options_aor *aor_options = obj;
1352
1353 /*
1354 * Any contacts are unreachable since the AOR is being destroyed
1355 * so remove their contact status
1356 */
1357 if (aor_options->contacts) {
1359 sip_options_remove_contact, aor_options);
1360 ao2_ref(aor_options->contacts, -1);
1361 }
1362 ao2_cleanup(aor_options->dynamic_contacts);
1363
1365
1366 ast_assert(AST_VECTOR_SIZE(&aor_options->compositors) == 0);
1367 AST_VECTOR_FREE(&aor_options->compositors);
1368}
1369
1370/*! \brief Allocator for AOR OPTIONS */
1372{
1373 struct sip_options_aor *aor_options;
1374
1375 aor_options = ao2_alloc_options(sizeof(*aor_options) + strlen(ast_sorcery_object_get_id(aor)) + 1,
1377 if (!aor_options) {
1378 return NULL;
1379 }
1380
1381 strcpy(aor_options->name, ast_sorcery_object_get_id(aor)); /* SAFE */
1382
1384 if (!aor_options->serializer) {
1385 ao2_ref(aor_options, -1);
1386 return NULL;
1387 }
1388
1390 ao2_ref(aor_options, -1);
1391 return NULL;
1392 }
1393
1397 if (!aor_options->contacts) {
1398 ao2_ref(aor_options, -1);
1399 return NULL;
1400 }
1401
1405 if (!aor_options->dynamic_contacts) {
1406 ao2_ref(aor_options, -1);
1407 return NULL;
1408 }
1409
1410 return aor_options;
1411}
1412
1413/*! \brief Remove contact status for a hint */
1415 struct ast_sip_contact *contact)
1416{
1417 struct ast_sip_contact_status *cs_new;
1418 struct ast_sip_contact_status *cs_old;
1419
1422 if (!cs_old) {
1423 ast_debug(3, "Attempted to remove contact status for '%s' but it does not exist\n",
1424 ast_sorcery_object_get_id(contact));
1425 return;
1426 }
1427
1428 ast_verb(2, "Contact %s/%s has been deleted\n", contact->aor, contact->uri);
1429
1430 /* Update the contact status to reflect its new state */
1431 cs_new = sip_contact_status_copy(cs_old);
1432 if (!cs_new) {
1433 /*
1434 * We'll have to violate the immutable property because we
1435 * couldn't create a new one to modify and we are deleting
1436 * the contact status anyway.
1437 */
1438 cs_new = cs_old;
1439 } else {
1440 ao2_ref(cs_old, -1);
1441 }
1442 cs_new->last_status = cs_new->status;
1443 cs_new->status = REMOVED;
1444 cs_new->rtt = 0;
1445
1446 ast_statsd_log_string_va("PJSIP.contacts.states.%s", AST_STATSD_GAUGE,
1447 "-1", 1.0, ast_sip_get_contact_status_label(cs_new->last_status));
1448 ast_statsd_log_string_va("PJSIP.contacts.states.%s", AST_STATSD_GAUGE,
1449 "+1", 1.0, ast_sip_get_contact_status_label(cs_new->status));
1450
1452
1453 /*
1454 * The only time we need to update the AOR is if this contact was
1455 * available and qualify is in use, otherwise we can just stop
1456 * early.
1457 */
1458 if (!aor_options->qualify_frequency || cs_new->last_status != AVAILABLE) {
1459 ao2_ref(cs_new, -1);
1460 return;
1461 }
1462
1463 --aor_options->available;
1464 if (!aor_options->available) {
1466 }
1467
1468 ast_debug(3, "AOR '%s' now has %d available contacts\n", aor_options->name,
1469 aor_options->available);
1470
1471 ao2_ref(cs_new, -1);
1472}
1473
1474/*! \brief Task data for AOR creation or updating */
1476 /*! \brief The AOR options for this AOR */
1478 /*! \brief The AOR which contains the new configuraton */
1480 /*! \brief Optional container of existing AOR s*/
1482 /*! \brief Whether this AOR is being added */
1484};
1485
1486/*! \brief Callback function to remove a contact and its contact status from an AOR */
1487static int sip_options_remove_contact(void *obj, void *arg, int flags)
1488{
1489 struct ast_sip_contact *contact = obj;
1490 struct sip_options_aor *aor_options = arg;
1491
1492 sip_options_remove_contact_status(aor_options, contact);
1493
1494 return CMP_MATCH;
1495}
1496
1497/*! \brief Determine an initial time for scheduling AOR qualifying */
1499{
1500 int initial_interval;
1501 int max_time = ast_sip_get_max_initial_qualify_time();
1502
1503 if (max_time && max_time < qualify_frequency) {
1504 initial_interval = max_time;
1505 } else {
1506 initial_interval = qualify_frequency;
1507 }
1508
1509 initial_interval = (int)((initial_interval * 1000) * ast_random_double());
1510 return 0 < initial_interval ? initial_interval : 1;
1511}
1512
1513/*! \brief Set the contact status for a contact */
1516{
1517 struct ast_sip_contact_status *cs_new;
1518
1519 /* Update the contact specific status information */
1520 cs_new = sip_contact_status_copy(contact_status);
1521 if (!cs_new) {
1522 return;
1523 }
1524 cs_new->last_status = cs_new->status;
1525 cs_new->status = status;
1526
1527 /*
1528 * We need to always set the RTT to zero because we haven't completed
1529 * an OPTIONS ping so RTT is unknown. If the OPTIONS ping were still
1530 * running it will be refreshed on the next go round anyway.
1531 */
1532 cs_new->rtt = 0;
1533
1535
1536 if (cs_new->status != cs_new->last_status) {
1537 ast_verb(3, "Contact %s/%s is now %s.\n",
1538 cs_new->aor, cs_new->uri,
1540
1541 ast_statsd_log_string_va("PJSIP.contacts.states.%s", AST_STATSD_GAUGE,
1542 "-1", 1.0, ast_sip_get_contact_status_label(cs_new->last_status));
1543 ast_statsd_log_string_va("PJSIP.contacts.states.%s", AST_STATSD_GAUGE,
1544 "+1", 1.0, ast_sip_get_contact_status_label(cs_new->status));
1545
1547
1548 ast_test_suite_event_notify("AOR_CONTACT_UPDATE",
1549 "Contact: %s\r\n"
1550 "Status: %s",
1551 cs_new->name,
1553 }
1554 ao2_ref(cs_new, -1);
1555}
1556
1557/*! \brief Transition the contact status to unqualified mode */
1558static int sip_options_set_contact_status_unqualified(void *obj, void *arg, int flags)
1559{
1560 struct ast_sip_contact *contact = obj;
1561 struct ast_sip_contact_status *contact_status;
1562
1563 contact_status = ast_res_pjsip_find_or_create_contact_status(contact);
1564 if (!contact_status) {
1565 return 0;
1566 }
1567
1568 switch (contact_status->status) {
1569 case AVAILABLE:
1570 case UNAVAILABLE:
1571 case UNKNOWN:
1572 sip_options_set_contact_status(contact_status, CREATED);
1573 break;
1574 case CREATED:
1575 case REMOVED:
1576 break;
1577 }
1578
1579 ao2_ref(contact_status, -1);
1580
1581 return 0;
1582}
1583
1584/*! \brief Transition the contact status to qualified mode */
1585static int sip_options_set_contact_status_qualified(void *obj, void *arg, int flags)
1586{
1587 struct ast_sip_contact *contact = obj;
1588 struct ast_sip_contact_status *contact_status;
1589
1590 contact_status = ast_res_pjsip_find_or_create_contact_status(contact);
1591 if (!contact_status) {
1592 return 0;
1593 }
1594
1595 switch (contact_status->status) {
1596 case AVAILABLE:
1598 break;
1599 case UNAVAILABLE:
1600 case UNKNOWN:
1601 case CREATED:
1602 case REMOVED:
1603 break;
1604 }
1605
1606 ao2_ref(contact_status, -1);
1607
1608 return 0;
1609}
1610
1611/*! \brief Count AVAILABLE qualified contacts. */
1612static int sip_options_contact_status_available_count(void *obj, void *arg, int flags)
1613{
1614 struct ast_sip_contact *contact = obj;
1615 unsigned int *available = arg;
1616 struct ast_sip_contact_status *contact_status;
1617
1618 contact_status = ast_res_pjsip_find_or_create_contact_status(contact);
1619 if (!contact_status) {
1620 return 0;
1621 }
1622
1623 /* Count qualified available contacts. */
1624 switch (contact_status->status) {
1625 case AVAILABLE:
1626 ++*available;
1627 break;
1628 case UNAVAILABLE:
1629 case UNKNOWN:
1630 case CREATED:
1631 case REMOVED:
1632 break;
1633 }
1634
1635 ao2_ref(contact_status, -1);
1636
1637 return 0;
1638}
1639
1640/*!
1641 * \brief Function which applies configuration to an AOR options structure
1642 * \note Run by aor_options->serializer (or management_serializer on aor_options creation)
1643 */
1645 struct ast_sip_aor *aor, int is_new)
1646{
1647 struct ao2_container *existing_contacts;
1648 struct ast_sip_contact *contact;
1649 struct ao2_iterator iter;
1650
1651 ast_debug(3, "Configuring AOR '%s' with current state of configuration and world\n",
1652 aor_options->name);
1653
1654 /*
1655 * Permanent contacts, since we receive no notification that they
1656 * are gone, follow the same approach as AORs. We create a copy
1657 * of the existing container and any reused contacts are removed
1658 * from it. Any contacts remaining in the container after
1659 * processing no longer exist so we need to remove their state.
1660 */
1661 existing_contacts = ao2_container_clone(aor_options->contacts, 0);
1662 if (!existing_contacts) {
1663 ast_log(LOG_WARNING, "Synchronization of AOR '%s' failed for qualify, retaining existing state\n",
1664 aor_options->name);
1665 return;
1666 }
1667
1669 NULL, NULL);
1670
1671 /* Process permanent contacts */
1672 if (aor->permanent_contacts) {
1673 iter = ao2_iterator_init(aor->permanent_contacts, 0);
1674 for (; (contact = ao2_iterator_next(&iter)); ao2_ref(contact, -1)) {
1675 ao2_find(existing_contacts, ast_sorcery_object_get_id(contact),
1677 ao2_link(aor_options->contacts, contact);
1678 }
1679 ao2_iterator_destroy(&iter);
1680 }
1681
1682 /*
1683 * If this is newly added we need to see if there are any
1684 * existing dynamic contacts to add. Ones that are added
1685 * after creation will occur as a result of the contact
1686 * observer creation callback.
1687 */
1688 if (is_new) {
1689 size_t prefix_len = strlen(ast_sorcery_object_get_id(aor)) + sizeof(";@") - 1;
1690 char prefix[prefix_len + 1];
1691 struct ao2_container *contacts;
1692
1693 sprintf(prefix, "%s;@", ast_sorcery_object_get_id(aor)); /* Safe */
1695 prefix, prefix_len);
1696 if (contacts) {
1697 ao2_container_dup(aor_options->dynamic_contacts, contacts, 0);
1698 ao2_ref(contacts, -1);
1699 }
1700 }
1701
1702 /* Process dynamic contacts */
1703 iter = ao2_iterator_init(aor_options->dynamic_contacts, 0);
1704 for (; (contact = ao2_iterator_next(&iter)); ao2_ref(contact, -1)) {
1705 ao2_find(existing_contacts, ast_sorcery_object_get_id(contact),
1707 ao2_link(aor_options->contacts, contact);
1708 }
1709 ao2_iterator_destroy(&iter);
1710
1711 /* Any contacts left no longer exist, so raise events and make them disappear */
1712 ao2_callback(existing_contacts, OBJ_NODATA | OBJ_UNLINK,
1713 sip_options_remove_contact, aor_options);
1714 ao2_ref(existing_contacts, -1);
1715
1716 /*
1717 * Update the available count if we transition between qualified
1718 * and unqualified. In the qualified case we need to start with
1719 * 0 available as the qualify process will take care of it. In
1720 * the unqualified case it is based on the number of contacts
1721 * present.
1722 */
1723 if (!aor->qualify_frequency) {
1724 ao2_callback(aor_options->contacts, OBJ_NODATA,
1726 aor_options->available = ao2_container_count(aor_options->contacts);
1727 ast_debug(3, "AOR '%s' is unqualified, number of available contacts is therefore '%d'\n",
1728 aor_options->name, aor_options->available);
1729 } else if (!aor_options->qualify_frequency) {
1730 ao2_callback(aor_options->contacts, OBJ_NODATA,
1732 aor_options->available = 0;
1733 ast_debug(3, "AOR '%s' has transitioned from unqualified to qualified, reset available contacts to 0\n",
1734 aor_options->name);
1735 } else {
1736 /*
1737 * Count the number of AVAILABLE qualified contacts to ensure
1738 * the count is in sync with reality.
1739 */
1740 aor_options->available = 0;
1741 ao2_callback(aor_options->contacts, OBJ_NODATA,
1743 }
1744
1745 aor_options->authenticate_qualify = aor->authenticate_qualify;
1746 aor_options->qualify_2xx_only = aor->qualify_2xx_only;
1747 aor_options->qualify_timeout = aor->qualify_timeout;
1748
1749 /*
1750 * If we need to stop or start the scheduled callback then do so.
1751 * This occurs due to the following:
1752 * 1. The qualify frequency has changed
1753 * 2. Contacts were added when previously there were none
1754 * 3. There are no contacts but previously there were some
1755 */
1756 if (aor_options->qualify_frequency != aor->qualify_frequency
1757 || (!aor_options->sched_task && ao2_container_count(aor_options->contacts))
1758 || (aor_options->sched_task && !ao2_container_count(aor_options->contacts))) {
1759 if (aor_options->sched_task) {
1761 ao2_ref(aor_options->sched_task, -1);
1762 aor_options->sched_task = NULL;
1763 }
1764
1765 /* If there is still a qualify frequency then schedule this */
1766 aor_options->qualify_frequency = aor->qualify_frequency;
1767 if (aor_options->qualify_frequency
1768 && ao2_container_count(aor_options->contacts)) {
1769 aor_options->sched_task = ast_sip_schedule_task(aor_options->serializer,
1773 if (!aor_options->sched_task) {
1774 ast_log(LOG_ERROR, "Unable to schedule qualify for contacts of AOR '%s'\n",
1775 aor_options->name);
1776 }
1777 }
1778 }
1779
1780 ast_debug(3, "AOR '%s' now has %d available contacts\n", aor_options->name,
1781 aor_options->available);
1782}
1783
1784/*!
1785 * \brief Task to synchronize an AOR with our local state
1786 * \note Run by aor_options->serializer (or management_serializer on aor_options creation)
1787 */
1789{
1791 int i;
1792
1793 ast_debug(3, "Synchronizing AOR '%s' with current state of configuration and world\n",
1794 task_data->aor_options->name);
1795
1797 task_data->added);
1798
1799 /*
1800 * Endpoint state compositors are removed in this operation but not
1801 * added. To reduce the amount of work done they are done later. In
1802 * the mean time things can still qualify and once an endpoint state
1803 * compositor is added to the AOR it will be updated with the current
1804 * state.
1805 */
1806 for (i = 0; i < AST_VECTOR_SIZE(&task_data->aor_options->compositors); ++i) {
1807 struct sip_options_endpoint_state_compositor *endpoint_state_compositor;
1808
1809 endpoint_state_compositor = AST_VECTOR_GET(&task_data->aor_options->compositors, i);
1810
1811 ao2_lock(endpoint_state_compositor);
1812 endpoint_state_compositor->active = 0;
1813 sip_options_update_endpoint_state_compositor_aor(endpoint_state_compositor,
1814 task_data->aor_options->name, REMOVED);
1815 ao2_unlock(endpoint_state_compositor);
1816 }
1817 AST_VECTOR_RESET(&task_data->aor_options->compositors, ao2_cleanup);
1818
1819 return 0;
1820}
1821
1822/*!
1823 * \brief Synchronize an AOR with our local state
1824 * \note Run by management_serializer
1825 */
1826static int sip_options_synchronize_aor(void *obj, void *arg, int flags)
1827{
1829 .aor = obj,
1830 .existing = arg,
1831 };
1832
1833 task_data.aor_options = ao2_find(sip_options_aors,
1835 if (!task_data.aor_options) {
1836 task_data.aor_options = sip_options_aor_alloc(task_data.aor);
1837 if (!task_data.aor_options) {
1838 return 0;
1839 }
1840
1841 task_data.added = 1;
1842
1843 /* Nothing is aware of this AOR yet so we can just update it in this thread */
1845 ao2_link(sip_options_aors, task_data.aor_options);
1846 } else {
1847 /* This AOR already exists so we have to do manipulation in its serializer */
1848 ast_sip_push_task_wait_serializer(task_data.aor_options->serializer,
1850 }
1851
1852 ao2_ref(task_data.aor_options, -1);
1853
1854 if (task_data.existing) {
1857 }
1858
1859 return 0;
1860}
1861
1862/*! \brief Destructor for endpoint state compositors */
1864{
1865 struct sip_options_endpoint_state_compositor *endpoint_state_compositor = obj;
1866
1867 ao2_cleanup(endpoint_state_compositor->aor_statuses);
1868}
1869
1870/*! \brief Hashing function for endpoint AOR status */
1872
1873/*! \brief Comparator function for endpoint AOR status */
1875
1876/*! \brief Find (or create) an endpoint state compositor */
1878{
1879 struct sip_options_endpoint_state_compositor *endpoint_state_compositor;
1880
1882 endpoint_state_compositor = ao2_find(sip_options_endpoint_state_compositors,
1884 if (endpoint_state_compositor) {
1886 return endpoint_state_compositor;
1887 }
1888
1889 endpoint_state_compositor = ao2_alloc(sizeof(*endpoint_state_compositor)
1890 + strlen(ast_sorcery_object_get_id(endpoint)) + 1,
1892 if (!endpoint_state_compositor) {
1894 return NULL;
1895 }
1896
1897 /*
1898 * NOTE: The endpoint_state_compositor->aor_statuses container is
1899 * externally protected by the endpoint_state_compositor lock.
1900 */
1901 endpoint_state_compositor->aor_statuses = ao2_container_alloc_hash(
1903 sip_options_endpoint_aor_status_hash_fn, NULL,
1904 sip_options_endpoint_aor_status_cmp_fn);
1905 if (!endpoint_state_compositor->aor_statuses) {
1907 ao2_ref(endpoint_state_compositor, -1);
1908 return NULL;
1909 }
1910
1911 strcpy(endpoint_state_compositor->name, ast_sorcery_object_get_id(endpoint)); /* SAFE */
1912
1913 ao2_link_flags(sip_options_endpoint_state_compositors, endpoint_state_compositor,
1914 OBJ_NOLOCK);
1916
1917 return endpoint_state_compositor;
1918}
1919
1920/*! \brief Task details for adding an AOR to an endpoint state compositor */
1922 /*! \brief The AOR options that the endpoint state compositor should be added to */
1924 /*! \brief The endpoint state compositor */
1926};
1927
1928/*!
1929 * \brief Task which adds an AOR to an endpoint state compositor
1930 * \note Run by aor_options->serializer
1931 */
1933{
1935
1936 ast_debug(3, "Adding endpoint compositor '%s' to AOR '%s'\n",
1937 task_data->endpoint_state_compositor->name, task_data->aor_options->name);
1938
1939 ao2_ref(task_data->endpoint_state_compositor, +1);
1940 if (AST_VECTOR_APPEND(&task_data->aor_options->compositors,
1941 task_data->endpoint_state_compositor)) {
1942 /* Failed to add so no need to update the endpoint status. Nothing changed. */
1943 ao2_ref(task_data->endpoint_state_compositor, -1);
1944 return 0;
1945 }
1946
1947 ao2_lock(task_data->endpoint_state_compositor);
1949 task_data->aor_options->name,
1950 task_data->aor_options->available ? AVAILABLE : UNAVAILABLE);
1951 ao2_unlock(task_data->endpoint_state_compositor);
1952
1953 return 0;
1954}
1955
1956/*!
1957 * \brief Task which adds removes an AOR from an endpoint state compositor
1958 * \note Run by aor_options->serializer
1959 */
1961{
1963 int i;
1964
1965 ast_debug(3, "Removing endpoint compositor '%s' from AOR '%s'\n",
1966 task_data->endpoint_state_compositor->name,
1967 task_data->aor_options->name);
1968
1969 for (i = 0; i < AST_VECTOR_SIZE(&task_data->aor_options->compositors); ++i) {
1970 struct sip_options_endpoint_state_compositor *endpoint_state_compositor;
1971
1972 endpoint_state_compositor = AST_VECTOR_GET(&task_data->aor_options->compositors, i);
1973 if (endpoint_state_compositor != task_data->endpoint_state_compositor) {
1974 continue;
1975 }
1976
1977 AST_VECTOR_REMOVE(&task_data->aor_options->compositors, i, 0);
1978 ao2_ref(endpoint_state_compositor, -1);
1979 break;
1980 }
1981
1982 return 0;
1983}
1984
1985/*!
1986 * \brief Synchronize an endpoint with our local state
1987 * \note Run by management_serializer
1988 */
1989static int sip_options_synchronize_endpoint(void *obj, void *arg, int flags)
1990{
1991 struct ast_sip_endpoint *endpoint = obj;
1992 struct ast_sip_aor *aor = arg;
1993 char *aors;
1994 char *aor_name;
1996
1997 if (ast_strlen_zero(endpoint->aors)) {
1998 /* There are no AORs, so really... who the heck knows */
1999 ast_debug(3, "Endpoint '%s' is not interested in any AORs so not creating endpoint state compositor\n",
2000 ast_sorcery_object_get_id(endpoint));
2001 return 0;
2002 }
2003
2004 ast_debug(3, "Synchronizing endpoint '%s' with AORs '%s'\n",
2005 ast_sorcery_object_get_id(endpoint), endpoint->aors);
2006
2007 aors = ast_strdupa(endpoint->aors);
2008 while ((aor_name = ast_strip(strsep(&aors, ",")))) {
2009 if (ast_strlen_zero(aor_name)) {
2010 continue;
2011 }
2012 if (aor && strcasecmp(ast_sorcery_object_get_id(aor), aor_name)) {
2013 ast_debug(3, "Filtered AOR '%s' on endpoint '%s' as we are looking for '%s'\n",
2014 aor_name, ast_sorcery_object_get_id(endpoint),
2016 continue;
2017 }
2018
2019 task_data.aor_options = ao2_find(sip_options_aors, aor_name, OBJ_SEARCH_KEY);
2020 if (!task_data.aor_options) {
2021 /*
2022 * They have referenced an invalid AOR. If that's all they've
2023 * done we will set them to offline at the end.
2024 */
2025 ast_debug(3, "Endpoint '%s' referenced invalid AOR '%s'\n",
2026 ast_sorcery_object_get_id(endpoint), aor_name);
2027 continue;
2028 }
2029
2030 if (!task_data.endpoint_state_compositor) {
2031 /*
2032 * We create an endpoint state compositor only after we know
2033 * for sure we need it.
2034 */
2035 task_data.endpoint_state_compositor =
2037 if (!task_data.endpoint_state_compositor) {
2039 "Could not create endpoint state compositor for '%s', endpoint state will be incorrect\n",
2040 ast_sorcery_object_get_id(endpoint));
2041 ao2_ref(task_data.aor_options, -1);
2044 return 0;
2045 }
2046 }
2047
2048 /* We use a synchronous task so that we don't flood the system */
2049 ast_sip_push_task_wait_serializer(task_data.aor_options->serializer,
2051
2052 ao2_ref(task_data.aor_options, -1);
2053
2054 /*
2055 * If we filtered on a specific AOR name then the endpoint can
2056 * only reference it once so break early.
2057 */
2058 if (aor) {
2059 break;
2060 }
2061 }
2062
2063 if (task_data.endpoint_state_compositor) {
2064 /*
2065 * If an endpoint state compositor is present determine the current state
2066 * of the endpoint and update it.
2067 */
2068 ao2_lock(task_data.endpoint_state_compositor);
2069 task_data.endpoint_state_compositor->active = 1;
2072 ao2_unlock(task_data.endpoint_state_compositor);
2073
2074 ao2_ref(task_data.endpoint_state_compositor, -1);
2075 } else if (!aor) {
2076 /* If no explicit AOR is specified we are updating the endpoint itself, so then set
2077 * it to offline if no endpoint compositor exists as they referenced an invalid AOR
2078 * or none at all
2079 */
2080 ast_debug(3, "Endpoint '%s' has no AORs feeding it, setting it to offline state as default\n",
2081 ast_sorcery_object_get_id(endpoint));
2084 }
2085
2086 return 0;
2087}
2088
2089/*!
2090 * \brief Task which removes an AOR from all of the ESCs it is reporting to
2091 * \note Run by aor_options->serializer
2092 */
2093static int sip_options_aor_remove_task(void *obj)
2094{
2095 struct sip_options_aor *aor_options = obj;
2096
2098
2099 if (aor_options->sched_task) {
2101 ao2_ref(aor_options->sched_task, -1);
2102 aor_options->sched_task = NULL;
2103 }
2104
2105 return 0;
2106}
2107
2108/*!
2109 * \brief Callback which removes any unused AORs that remained after reloading
2110 * \note Run by management_serializer
2111 */
2112static int sip_options_unused_aor(void *obj, void *arg, int flags)
2113{
2114 struct sip_options_aor *aor_options = obj;
2115
2116 ast_debug(3, "AOR '%s' is no longer configured, removing it\n", aor_options->name);
2117
2119 aor_options);
2120 ao2_unlink(sip_options_aors, aor_options);
2121
2122 return CMP_MATCH;
2123}
2124
2125/*!
2126 * \brief Callback function used to unlink and remove event state compositors that have no AORs feeding them
2127 * \note Run by management_serializer
2128 */
2129static int sip_options_unused_endpoint_state_compositor(void *obj, void *arg, int flags)
2130{
2131 struct sip_options_endpoint_state_compositor *endpoint_state_compositor = obj;
2132
2133 if (ao2_container_count(endpoint_state_compositor->aor_statuses)) {
2134 return 0;
2135 }
2136
2137 /* No AORs are feeding this endpoint state compositor */
2138 ast_sip_persistent_endpoint_update_state(endpoint_state_compositor->name,
2140
2141 return CMP_MATCH;
2142}
2143
2144/*! \brief Structure which contains information required to synchronize */
2146 /*! \brief Whether this is a reload or not */
2148};
2149
2150/*!
2151 * \brief Task to synchronize our local container of AORs and endpoint state compositors with the current configuration
2152 * \note Run by management_serializer
2153 */
2154static int sip_options_synchronize_task(void *obj)
2155{
2157 struct ao2_container *existing = NULL;
2158 struct ao2_container *objects;
2159
2160 /*
2161 * When reloading we keep track of the existing AORs so we can
2162 * terminate old ones that are no longer referenced or used.
2163 */
2164 if (task_data->reload) {
2166 if (!existing) {
2167 return 0;
2168 }
2169 }
2170
2173 if (objects) {
2174 /* Go through the returned AORs and synchronize with our local state */
2176 ao2_ref(objects, -1);
2177 }
2178
2179 /*
2180 * Any AORs remaining in existing are no longer referenced by
2181 * the current container of AORs we retrieved, so remove them.
2182 */
2183 if (existing) {
2186 ao2_ref(existing, -1);
2187 }
2188
2191 if (objects) {
2192 /* Go through the provided endpoints and update AORs */
2194 ao2_ref(objects, -1);
2195 }
2196
2197 /*
2198 * All endpoint state compositors that don't have any AORs
2199 * feeding them information can be removed. If they end
2200 * up getting needed later they'll just be recreated.
2201 */
2205
2206 return 0;
2207}
2208
2209/*! \brief Synchronize our local container of AORs and endpoint state compositors with the current configuration */
2219
2220/*!
2221 * \brief Unlink AORs feeding the endpoint status compositor
2222 * \note Run by management_serializer
2223 */
2225 struct sip_options_endpoint_state_compositor *endpoint_state_compositor)
2226{
2227 struct ao2_iterator it_aor_statuses;
2228 struct sip_options_endpoint_aor_status *aor_status;
2230 .endpoint_state_compositor = endpoint_state_compositor,
2231 };
2232
2235
2236 /* Unlink AOR feeders pointing to endpoint */
2238 for (; (aor_status = ao2_iterator_next(&it_aor_statuses)); ao2_ref(aor_status, -1)) {
2239 task_data.aor_options = ao2_find(sip_options_aors, aor_status->name,
2241 if (!task_data.aor_options) {
2242 continue;
2243 }
2244
2245 ast_debug(3, "Removing endpoint state compositor '%s' from AOR '%s'\n",
2246 ast_sorcery_object_get_id(endpoint), aor_status->name);
2248 ast_sip_push_task_wait_serializer(task_data.aor_options->serializer,
2251 ao2_ref(task_data.aor_options, -1);
2252 }
2253 ao2_iterator_destroy(&it_aor_statuses);
2254
2255 /*
2256 * We do not need to remove the AOR feeder status memory from the
2257 * aor_statuses container. The endpoint_state_compositor is about
2258 * to die and do it for us.
2259 */
2260
2262}
2263
2264/*!
2265 * \brief Task to delete an endpoint from the known universe
2266 * \note Run by management_serializer
2267 */
2269{
2270 struct ast_sip_endpoint *endpoint = obj;
2271 struct sip_options_endpoint_state_compositor *endpoint_state_compositor;
2272
2273 endpoint_state_compositor = ao2_find(sip_options_endpoint_state_compositors,
2275 if (!endpoint_state_compositor) {
2276 return 0;
2277 }
2278
2279 ast_debug(3, "Endpoint '%s' has been deleted, removing endpoint state compositor from AORs\n",
2280 ast_sorcery_object_get_id(endpoint));
2281 sip_options_endpoint_unlink_aor_feeders(endpoint, endpoint_state_compositor);
2282 ao2_ref(endpoint_state_compositor, -1);
2283
2284 return 0;
2285}
2286
2287/*! \brief Observer callback invoked on endpoint deletion */
2293
2294/*!
2295 * \brief Task to synchronize the endpoint
2296 * \note Run by management_serializer
2297 */
2299{
2300 struct ast_sip_endpoint *endpoint = obj;
2301 struct sip_options_endpoint_state_compositor *endpoint_state_compositor;
2302
2303 ast_debug(3, "Endpoint '%s' has been created or modified, updating state\n",
2304 ast_sorcery_object_get_id(endpoint));
2305
2306 endpoint_state_compositor = ao2_find(sip_options_endpoint_state_compositors,
2308 if (endpoint_state_compositor) {
2309 /* Unlink the AORs currently feeding the endpoint. */
2310 sip_options_endpoint_unlink_aor_feeders(endpoint, endpoint_state_compositor);
2311 ao2_ref(endpoint_state_compositor, -1);
2312 }
2313
2314 /* Connect the AORs that now feed the endpoint. */
2316 return 0;
2317}
2318
2319/*! \brief Observer callback invoked on endpoint creation or modification */
2325
2326/*! \brief Observer callbacks for endpoints */
2332
2333/*!
2334 * \brief Task to synchronize an AOR with our local state
2335 * \note Run by aor_options->serializer
2336 */
2337static int sip_options_update_aor_task(void *obj)
2338{
2340 int available = task_data->aor_options->available;
2341
2342 ast_debug(3, "Individually updating AOR '%s' with current state of configuration and world\n",
2343 task_data->aor_options->name);
2344
2346 task_data->added);
2347
2348 if (!available && task_data->aor_options->available) {
2349 ast_debug(3, "After modifying AOR '%s' it has now become available\n",
2350 task_data->aor_options->name);
2352 } else if (available && !task_data->aor_options->available) {
2353 ast_debug(3, "After modifying AOR '%s' it has become unavailable\n",
2354 task_data->aor_options->name);
2356 }
2357
2358 return 0;
2359}
2360
2361/*!
2362 * \brief Task to synchronize the AOR
2363 * \note Run by management_serializer
2364 */
2366{
2367 struct ast_sip_aor *aor = obj;
2368 struct sip_options_aor *aor_options;
2369
2372 if (!aor_options) {
2373 struct ao2_container *endpoints;
2374
2375 aor_options = sip_options_aor_alloc(aor);
2376 if (!aor_options) {
2377 return 0;
2378 }
2379
2380 /*
2381 * This is a newly added AOR and we need to establish any
2382 * endpoint state compositors that may reference only the
2383 * AOR. If these need to be updated later then they'll
2384 * be done by modifying the endpoint or issuing a reload.
2385 */
2386 sip_options_apply_aor_configuration(aor_options, aor, 1);
2387 ao2_link(sip_options_aors, aor_options);
2388
2389 /*
2390 * Using LIKE doesn't seem to work very well with non-realtime so we
2391 * fetch everything right now and do a filter on our side.
2392 */
2395 if (endpoints) {
2397 ao2_ref(endpoints, -1);
2398 }
2399 } else {
2401 .aor_options = aor_options,
2402 .aor = aor,
2403 };
2404
2405 /*
2406 * If this AOR was modified we have to do our work in its serializer
2407 * instead of this thread to ensure that things aren't modified by
2408 * multiple threads.
2409 */
2412 }
2413
2414 ao2_ref(aor_options, -1);
2415
2416 return 0;
2417}
2418
2419/*! \brief Observer callback invoked on AOR creation or modification */
2425
2426/*!
2427 * \brief Task to delete an AOR from the known universe
2428 * \note Run by management_serializer
2429 */
2431{
2432 struct ast_sip_aor *aor = obj;
2433 struct sip_options_aor *aor_options;
2434
2437 if (!aor_options) {
2438 return 0;
2439 }
2440
2441 ast_debug(3, "AOR '%s' has been deleted, removing it\n", aor_options->name);
2442
2444 aor_options);
2445 ao2_ref(aor_options, -1);
2446
2447 return 0;
2448}
2449
2450/*! \brief Observer callback invoked on AOR deletion */
2456
2457/*! \brief Observer callbacks for AORs */
2460 .updated = aor_observer_modified,
2461 .deleted = aor_observer_deleted,
2462};
2463
2464/*! \brief Task details for adding an AOR to an endpoint state compositor */
2466 /*! \brief The AOR options that the contact is referring to */
2468 /*! \brief The contact itself */
2470};
2471
2472
2473/*!
2474 * \brief Check if the contact qualify options are different than local aor qualify options
2475 */
2476static int has_qualify_changed (const struct ast_sip_contact *contact, const struct sip_options_aor *aor_options)
2477{
2478 if (!contact) {
2479 return 0;
2480 }
2481
2482 if (!aor_options) {
2483 if (contact->qualify_frequency) {
2484 return 1;
2485 }
2486 } else if (contact->qualify_frequency != aor_options->qualify_frequency
2487 || contact->authenticate_qualify != aor_options->authenticate_qualify
2488 || contact->qualify_2xx_only != aor_options->qualify_2xx_only
2489 || ((int)(contact->qualify_timeout * 1000)) != ((int)(aor_options->qualify_timeout * 1000))) {
2490 return 1;
2491 }
2492
2493 return 0;
2494}
2495
2496/*!
2497 * \brief Task which adds a dynamic contact to an AOR
2498 * \note Run by aor_options->serializer
2499 */
2500static int sip_options_contact_add_task(void *obj)
2501{
2503 struct ast_sip_contact_status *contact_status;
2504
2505 ao2_link(task_data->aor_options->dynamic_contacts, task_data->contact);
2506 ao2_link(task_data->aor_options->contacts, task_data->contact);
2507
2508 contact_status = ast_res_pjsip_find_or_create_contact_status(task_data->contact);
2509 ao2_cleanup(contact_status);
2510
2511 if (task_data->aor_options->qualify_frequency) {
2512 /* There will always be a contact here, and we need to immediately schedule
2513 * a qualify so that contacts are not waiting for the qualify_frequency
2514 * timer duration before qualifying.
2515 */
2516 ast_debug(3, "Starting scheduled callback on AOR '%s' for qualifying as there is now a contact on it\n",
2517 task_data->aor_options->name);
2518 /*
2519 * We immediately schedule the initial qualify so that we get
2520 * reachable/unreachable as soon as possible. Realistically
2521 * since they pretty much just registered they should be
2522 * reachable.
2523 */
2524 if (task_data->aor_options->sched_task) {
2525 ast_sip_sched_task_cancel(task_data->aor_options->sched_task);
2526 ao2_ref(task_data->aor_options->sched_task, -1);
2527 task_data->aor_options->sched_task = NULL;
2528 }
2529 task_data->aor_options->sched_task = ast_sip_schedule_task(
2530 task_data->aor_options->serializer, 1, sip_options_qualify_aor,
2531 ast_taskprocessor_name(task_data->aor_options->serializer),
2532 task_data->aor_options,
2534 if (!task_data->aor_options->sched_task) {
2535 ast_log(LOG_ERROR, "Unable to schedule qualify for contacts of AOR '%s'\n",
2536 task_data->aor_options->name);
2537 }
2538 } else {
2539 /*
2540 * If this was the first contact added to a non-qualified AOR then
2541 * it should become available.
2542 */
2543 task_data->aor_options->available =
2544 ao2_container_count(task_data->aor_options->contacts);
2545 if (task_data->aor_options->available == 1) {
2546 ast_debug(3, "An unqualified contact has been added to AOR '%s' so it is now available\n",
2547 task_data->aor_options->name);
2549 AVAILABLE);
2550 }
2551 }
2552
2553 return 0;
2554}
2555
2556/*!
2557 * \brief Task to add a dynamic contact to an AOR in its serializer
2558 * \note Run by management_serializer
2559 */
2561{
2563
2564 task_data.contact = obj;
2565 task_data.aor_options = ao2_find(sip_options_aors, task_data.contact->aor,
2567
2568 if (has_qualify_changed(task_data.contact, task_data.aor_options)) {
2569 struct ast_sip_aor *aor;
2570
2572 task_data.contact->aor);
2573 if (aor) {
2574 ast_debug(3, "AOR '%s' qualify options have been modified. Synchronize an AOR local state\n",
2575 task_data.contact->aor);
2577 ao2_ref(aor, -1);
2578 }
2579 }
2580
2581 if (!task_data.aor_options) {
2582 return 0;
2583 }
2584
2585 ast_sip_push_task_wait_serializer(task_data.aor_options->serializer,
2587 ao2_ref(task_data.aor_options, -1);
2588
2589 return 0;
2590}
2591
2592/*! \brief Observer callback invoked on contact creation */
2598
2599/*!
2600 * \brief Task which updates a dynamic contact to an AOR
2601 * \note Run by aor_options->serializer
2602 */
2604{
2606 struct ast_sip_contact_status *contact_status;
2607
2608 contact_status = ast_sip_get_contact_status(task_data->contact);
2609 if (contact_status) {
2610 switch (contact_status->status) {
2611 case CREATED:
2612 case UNAVAILABLE:
2613 case AVAILABLE:
2614 case UNKNOWN:
2615 /* Refresh the ContactStatus AMI events. */
2616 sip_options_contact_status_update(contact_status);
2617 break;
2618 case REMOVED:
2619 break;
2620 }
2621 ao2_ref(contact_status, -1);
2622 }
2623
2624 ao2_ref(task_data->contact, -1);
2625 ao2_ref(task_data->aor_options, -1);
2627 return 0;
2628}
2629
2630/*! \brief Observer callback invoked on contact update */
2631static void contact_observer_updated(const void *obj)
2632{
2633 const struct ast_sip_contact *contact = obj;
2634 struct sip_options_aor *aor_options = ao2_find(sip_options_aors, contact->aor, OBJ_SEARCH_KEY);
2635
2636 if (has_qualify_changed(contact, aor_options)) {
2637 struct ast_sip_aor *aor;
2638
2640 contact->aor);
2641 if (aor) {
2642 ast_debug(3, "AOR '%s' qualify options have been modified. Synchronize an AOR local state\n",
2643 contact->aor);
2646 ao2_ref(aor, -1);
2647 }
2648 }
2649
2652
2653 task_data = ast_malloc(sizeof(*task_data));
2654 if (!task_data) {
2655 ao2_ref(aor_options, -1);
2656 return;
2657 }
2658
2659 task_data->contact = (struct ast_sip_contact *) contact;
2660 /* task_data takes ownership of aor_options and will take care of releasing the ref */
2661 task_data->aor_options = aor_options;
2662
2663 ao2_ref(task_data->contact, +1);
2664 if (ast_sip_push_task(task_data->aor_options->serializer,
2666 ao2_ref(task_data->contact, -1);
2667 ao2_ref(task_data->aor_options, -1);
2669 }
2670 } else {
2671 ao2_cleanup(aor_options);
2672 }
2673}
2674
2675/*!
2676 * \brief Task which deletes a dynamic contact from an AOR
2677 * \note Run by aor_options->serializer
2678 */
2680{
2682
2683 ao2_find(task_data->aor_options->dynamic_contacts, task_data->contact,
2685 ao2_find(task_data->aor_options->contacts, task_data->contact,
2687
2689
2690 if (task_data->aor_options->qualify_frequency) {
2691 /* If this is the last contact then we need to stop the scheduled callback */
2692 if (!ao2_container_count(task_data->aor_options->contacts)) {
2693 ast_debug(3, "Terminating scheduled callback on AOR '%s' as there are no contacts to qualify\n",
2694 task_data->aor_options->name);
2695 if (task_data->aor_options->sched_task) {
2696 ast_sip_sched_task_cancel(task_data->aor_options->sched_task);
2697 ao2_ref(task_data->aor_options->sched_task, -1);
2698 task_data->aor_options->sched_task = NULL;
2699 }
2700 }
2701 } else {
2702 task_data->aor_options->available =
2703 ao2_container_count(task_data->aor_options->contacts);
2704 if (!task_data->aor_options->available) {
2705 ast_debug(3, "An unqualified contact has been removed from AOR '%s' leaving no remaining contacts\n",
2706 task_data->aor_options->name);
2708 UNAVAILABLE);
2709 }
2710 }
2711
2712 return 0;
2713}
2714
2715/*!
2716 * \brief Task to delete a contact from an AOR in its serializer
2717 * \note Run by management_serializer
2718 */
2720{
2722
2723 task_data.contact = obj;
2724 task_data.aor_options = ao2_find(sip_options_aors, task_data.contact->aor,
2726 if (!task_data.aor_options) {
2727 /* For contacts that are deleted we don't really care if there is no AOR locally */
2728 return 0;
2729 }
2730
2731 ast_sip_push_task_wait_serializer(task_data.aor_options->serializer,
2733 ao2_ref(task_data.aor_options, -1);
2734
2735 return 0;
2736}
2737
2738/*! \brief Observer callback invoked on contact deletion */
2744
2745/*! \brief Observer callbacks for contacts */
2751
2752static char *cli_qualify(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2753{
2754 RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
2755 const char *endpoint_name;
2756 char *aors;
2757 char *aor_name;
2758
2759 switch (cmd) {
2760 case CLI_INIT:
2761 e->command = "pjsip qualify";
2762 e->usage =
2763 "Usage: pjsip qualify <endpoint>\n"
2764 " Send a SIP OPTIONS request to all contacts on the endpoint.\n";
2765 return NULL;
2766 case CLI_GENERATE:
2767 return NULL;
2768 }
2769
2770 if (a->argc != 3) {
2771 return CLI_SHOWUSAGE;
2772 }
2773
2774 endpoint_name = a->argv[2];
2775
2776 endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint",
2777 endpoint_name);
2778 if (!endpoint) {
2779 ast_cli(a->fd, "Unable to retrieve endpoint %s\n", endpoint_name);
2780 return CLI_FAILURE;
2781 }
2782
2783 if (ast_strlen_zero(endpoint->aors)) {
2784 ast_cli(a->fd, "No AORs configured for endpoint '%s'\n", endpoint_name);
2785 return CLI_FAILURE;
2786 }
2787
2788 aors = ast_strdupa(endpoint->aors);
2789 while ((aor_name = ast_strip(strsep(&aors, ",")))) {
2790 struct sip_options_aor *aor_options;
2791
2792 aor_options = ao2_find(sip_options_aors, aor_name, OBJ_SEARCH_KEY);
2793 if (!aor_options) {
2794 continue;
2795 }
2796
2797 ast_cli(a->fd, "Qualifying AOR '%s' on endpoint '%s'\n", aor_name, endpoint_name);
2799 aor_options);
2800 ao2_ref(aor_options, -1);
2801 }
2802
2803 return CLI_SUCCESS;
2804}
2805
2807{
2808 struct ao2_container *contacts;
2809
2812
2813 return contacts;
2814}
2815
2816static int sip_contact_to_ami(const struct ast_sip_contact *contact,
2817 struct ast_str **buf)
2818{
2819 return ast_sip_sorcery_object_to_ami(contact, buf);
2820}
2821
2822static int format_ami_contactlist_handler(void *obj, void *arg, int flags)
2823{
2824 struct ast_sip_contact *contact = obj;
2825 struct ast_sip_ami *ami = arg;
2826 struct ast_str *buf;
2828
2829 buf = ast_sip_create_ami_event("ContactList", ami);
2830 if (!buf) {
2831 return CMP_STOP;
2832 }
2833
2834 if (sip_contact_to_ami(contact, &buf)) {
2835 ast_free(buf);
2836 return CMP_STOP;
2837 }
2838
2839 /* Add extra info */
2841 ast_str_append(&buf, 0, "Status: %s\r\n",
2843 if (!status || status->status != AVAILABLE) {
2844 ast_str_append(&buf, 0, "RoundtripUsec: N/A\r\n");
2845 } else {
2846 ast_str_append(&buf, 0, "RoundtripUsec: %" PRId64 "\r\n", status->rtt);
2847 }
2849
2850 astman_append(ami->s, "%s\r\n", ast_str_buffer(buf));
2851
2852 ami->count++;
2853
2854 ast_free(buf);
2855
2856 return 0;
2857}
2858
2859static int ami_show_contacts(struct mansession *s, const struct message *m)
2860{
2861 struct ast_sip_ami ami = { .s = s, .m = m, .action_id = astman_get_header(m, "ActionID"), };
2862 struct ao2_container *contacts;
2863
2864 contacts = get_all_contacts();
2865 if (!contacts) {
2866 astman_send_error(s, m, "Could not get Contacts\n");
2867 return 0;
2868 }
2869
2870 if (!ao2_container_count(contacts)) {
2871 astman_send_error(s, m, "No Contacts found\n");
2872 ao2_ref(contacts, -1);
2873 return 0;
2874 }
2875
2876 astman_send_listack(s, m, "A listing of Contacts follows, presented as ContactList events",
2877 "start");
2878
2880
2881 astman_send_list_complete_start(s, m, "ContactListComplete", ami.count);
2883
2884 ao2_ref(contacts, -1);
2885
2886 return 0;
2887}
2888
2889static char *cli_show_qualify_endpoint(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2890{
2891 RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
2892 const char *endpoint_name;
2893 char *aors;
2894 char *aor_name;
2895
2896 switch (cmd) {
2897 case CLI_INIT:
2898 e->command = "pjsip show qualify endpoint";
2899 e->usage =
2900 "Usage: pjsip show qualify endpoint <id>\n"
2901 " Show the current qualify options for all Aors on the PJSIP endpoint.\n";
2902 return NULL;
2903 case CLI_GENERATE:
2904 return NULL;
2905 }
2906
2907 if (a->argc != 5) {
2908 return CLI_SHOWUSAGE;
2909 }
2910
2911 endpoint_name = a->argv[4];
2912
2913 endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint",
2914 endpoint_name);
2915 if (!endpoint) {
2916 ast_cli(a->fd, "Unable to retrieve endpoint %s\n", endpoint_name);
2917 return CLI_FAILURE;
2918 }
2919
2920 if (ast_strlen_zero(endpoint->aors)) {
2921 ast_cli(a->fd, "No AORs configured for endpoint '%s'\n", endpoint_name);
2922 return CLI_FAILURE;
2923 }
2924
2925 aors = ast_strdupa(endpoint->aors);
2926 while ((aor_name = ast_strip(strsep(&aors, ",")))) {
2927 struct sip_options_aor *aor_options;
2928
2929 aor_options = ao2_find(sip_options_aors, aor_name, OBJ_SEARCH_KEY);
2930 if (!aor_options) {
2931 continue;
2932 }
2933
2934 ast_cli(a->fd, " * AOR '%s' on endpoint '%s'\n", aor_name, endpoint_name);
2935 ast_cli(a->fd, " Qualify frequency : %d sec\n", aor_options->qualify_frequency);
2936 ast_cli(a->fd, " Qualify timeout : %d ms\n", (int)(aor_options->qualify_timeout / 1000));
2937 ast_cli(a->fd, " Qualify 2xx only : %s\n", aor_options->qualify_2xx_only ? "yes" : "no");
2938 ast_cli(a->fd, " Authenticate qualify : %s\n", aor_options->authenticate_qualify?"yes":"no");
2939 ast_cli(a->fd, "\n");
2940 ao2_ref(aor_options, -1);
2941 }
2942
2943 return CLI_SUCCESS;
2944}
2945
2946static char *cli_show_qualify_aor(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2947{
2948 struct sip_options_aor *aor_options;
2949 const char *aor_name;
2950
2951 switch (cmd) {
2952 case CLI_INIT:
2953 e->command = "pjsip show qualify aor";
2954 e->usage =
2955 "Usage: pjsip show qualify aor <id>\n"
2956 " Show the PJSIP Aor current qualify options.\n";
2957 return NULL;
2958 case CLI_GENERATE:
2959 return NULL;
2960 }
2961
2962 if (a->argc != 5) {
2963 return CLI_SHOWUSAGE;
2964 }
2965
2966 aor_name = a->argv[4];
2967
2968 aor_options = ao2_find(sip_options_aors, aor_name, OBJ_SEARCH_KEY);
2969 if (!aor_options) {
2970 ast_cli(a->fd, "Unable to retrieve aor '%s' qualify options\n", aor_name);
2971 return CLI_FAILURE;
2972 }
2973
2974 ast_cli(a->fd, " * AOR '%s'\n", aor_name);
2975 ast_cli(a->fd, " Qualify frequency : %d sec\n", aor_options->qualify_frequency);
2976 ast_cli(a->fd, " Qualify timeout : %d ms\n", (int)(aor_options->qualify_timeout / 1000));
2977 ast_cli(a->fd, " Qualify 2xx only : %s\n", aor_options->qualify_2xx_only ? "yes" : "no");
2978 ast_cli(a->fd, " Authenticate qualify : %s\n", aor_options->authenticate_qualify?"yes":"no");
2979 ao2_ref(aor_options, -1);
2980
2981 return CLI_SUCCESS;
2982}
2983
2984static char *cli_reload_qualify_endpoint(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2985{
2986 RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
2987 const char *endpoint_name;
2988 char *aors;
2989 char *aor_name;
2990
2991 switch (cmd) {
2992 case CLI_INIT:
2993 e->command = "pjsip reload qualify endpoint";
2994 e->usage =
2995 "Usage: pjsip reload qualify endpoint <id>\n"
2996 " Synchronize the qualify options for all Aors on the PJSIP endpoint.\n";
2997 return NULL;
2998 case CLI_GENERATE:
2999 return NULL;
3000 }
3001
3002 if (a->argc != 5) {
3003 return CLI_SHOWUSAGE;
3004 }
3005
3006 endpoint_name = a->argv[4];
3007
3008 endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint",
3009 endpoint_name);
3010 if (!endpoint) {
3011 ast_cli(a->fd, "Unable to retrieve endpoint %s\n", endpoint_name);
3012 return CLI_FAILURE;
3013 }
3014
3015 if (ast_strlen_zero(endpoint->aors)) {
3016 ast_cli(a->fd, "No AORs configured for endpoint '%s'\n", endpoint_name);
3017 return CLI_FAILURE;
3018 }
3019
3020 aors = ast_strdupa(endpoint->aors);
3021 while ((aor_name = ast_strip(strsep(&aors, ",")))) {
3022 struct ast_sip_aor *aor;
3023
3024 aor = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "aor", aor_name);
3025 if (!aor) {
3026 continue;
3027 }
3028
3029 ast_cli(a->fd, "Synchronizing AOR '%s' on endpoint '%s'\n", aor_name, endpoint_name);
3032 ao2_ref(aor, -1);
3033 }
3034
3035 return CLI_SUCCESS;
3036}
3037
3038static char *cli_reload_qualify_aor(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
3039{
3040 struct ast_sip_aor *aor;
3041 const char *aor_name;
3042
3043 switch (cmd) {
3044 case CLI_INIT:
3045 e->command = "pjsip reload qualify aor";
3046 e->usage =
3047 "Usage: pjsip reload qualify aor <id>\n"
3048 " Synchronize the PJSIP Aor qualify options.\n";
3049 return NULL;
3050 case CLI_GENERATE:
3051 return NULL;
3052 }
3053
3054 if (a->argc != 5) {
3055 return CLI_SHOWUSAGE;
3056 }
3057
3058 aor_name = a->argv[4];
3059
3060 aor = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "aor", aor_name);
3061 if (!aor) {
3062 ast_cli(a->fd, "Unable to retrieve aor '%s'\n", aor_name);
3063 return CLI_FAILURE;
3064 }
3065
3066 ast_cli(a->fd, "Synchronizing AOR '%s'\n", aor_name);
3069 ao2_ref(aor, -1);
3070
3071 return CLI_SUCCESS;
3072}
3073
3074static int ami_sip_qualify(struct mansession *s, const struct message *m)
3075{
3076 const char *endpoint_name = astman_get_header(m, "Endpoint");
3077 RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
3078 char *aors;
3079 char *aor_name;
3080
3081 if (ast_strlen_zero(endpoint_name)) {
3082 astman_send_error(s, m, "Endpoint parameter missing.");
3083 return 0;
3084 }
3085
3086 endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint",
3087 endpoint_name);
3088 if (!endpoint) {
3089 astman_send_error(s, m, "Unable to retrieve endpoint\n");
3090 return 0;
3091 }
3092
3093 /* send a qualify for all contacts registered with the endpoint */
3094 if (ast_strlen_zero(endpoint->aors)) {
3095 astman_send_error(s, m, "No AoRs configured for endpoint\n");
3096 return 0;
3097 }
3098
3099 aors = ast_strdupa(endpoint->aors);
3100 while ((aor_name = ast_strip(strsep(&aors, ",")))) {
3101 struct sip_options_aor *aor_options;
3102
3103 aor_options = ao2_find(sip_options_aors, aor_name, OBJ_SEARCH_KEY);
3104 if (!aor_options) {
3105 continue;
3106 }
3107
3109 aor_options);
3110 ao2_ref(aor_options, -1);
3111 }
3112
3113 astman_send_ack(s, m, "Endpoint found, will qualify");
3114 return 0;
3115}
3116
3117static struct ast_cli_entry cli_options[] = {
3118 AST_CLI_DEFINE(cli_qualify, "Send an OPTIONS request to a PJSIP endpoint"),
3119 AST_CLI_DEFINE(cli_show_qualify_endpoint, "Show the current qualify options for all Aors on the PJSIP endpoint"),
3120 AST_CLI_DEFINE(cli_show_qualify_aor, "Show the PJSIP Aor current qualify options"),
3121 AST_CLI_DEFINE(cli_reload_qualify_endpoint, "Synchronize the qualify options for all Aors on the PJSIP endpoint"),
3122 AST_CLI_DEFINE(cli_reload_qualify_aor, "Synchronize the PJSIP Aor qualify options"),
3123};
3124
3125int ast_sip_format_contact_ami(void *obj, void *arg, int flags)
3126{
3127 struct ast_sip_contact_wrapper *wrapper = obj;
3128 struct ast_sip_contact *contact = wrapper->contact;
3129 struct ast_sip_ami *ami = arg;
3131 struct ast_str *buf;
3132 const struct ast_sip_endpoint *endpoint = ami->arg;
3133 char secs[AST_TIME_T_LEN];
3134
3135 buf = ast_sip_create_ami_event("ContactStatusDetail", ami);
3136 if (!buf) {
3137 return -1;
3138 }
3139
3141
3142 ast_str_append(&buf, 0, "AOR: %s\r\n", wrapper->aor_id);
3143 ast_str_append(&buf, 0, "URI: %s\r\n", contact->uri);
3144 ast_str_append(&buf, 0, "UserAgent: %s\r\n", contact->user_agent);
3145 ast_time_t_to_string(contact->expiration_time.tv_sec, secs, sizeof(secs));
3146 ast_str_append(&buf, 0, "RegExpire: %s\r\n", secs);
3147 if (!ast_strlen_zero(contact->via_addr)) {
3148 ast_str_append(&buf, 0, "ViaAddress: %s", contact->via_addr);
3149 if (contact->via_port) {
3150 ast_str_append(&buf, 0, ":%d", contact->via_port);
3151 }
3152 ast_str_append(&buf, 0, "\r\n");
3153 }
3154 if (!ast_strlen_zero(contact->call_id)) {
3155 ast_str_append(&buf, 0, "CallID: %s\r\n", contact->call_id);
3156 }
3157 ast_str_append(&buf, 0, "Status: %s\r\n",
3159 if (!status || status->status != AVAILABLE) {
3160 ast_str_append(&buf, 0, "RoundtripUsec: N/A\r\n");
3161 } else {
3162 ast_str_append(&buf, 0, "RoundtripUsec: %" PRId64 "\r\n", status->rtt);
3163 }
3164 ast_str_append(&buf, 0, "EndpointName: %s\r\n",
3165 endpoint ? ast_sorcery_object_get_id(endpoint) : S_OR(contact->endpoint_name, ""));
3166
3167 ast_str_append(&buf, 0, "ID: %s\r\n", ast_sorcery_object_get_id(contact));
3168 ast_str_append(&buf, 0, "AuthenticateQualify: %d\r\n", contact->authenticate_qualify);
3169 ast_str_append(&buf, 0, "OutboundProxy: %s\r\n", contact->outbound_proxy);
3170 ast_str_append(&buf, 0, "Path: %s\r\n", contact->path);
3171 ast_str_append(&buf, 0, "QualifyFrequency: %u\r\n", contact->qualify_frequency);
3172 ast_str_append(&buf, 0, "QualifyTimeout: %.3f\r\n", contact->qualify_timeout);
3173 ast_str_append(&buf, 0, "Qualify2xxOnly: %d\r\n", contact->qualify_2xx_only);
3174
3175 astman_append(ami->s, "%s\r\n", ast_str_buffer(buf));
3176 ami->count++;
3177
3178 ast_free(buf);
3180 return 0;
3181}
3182
3183static int format_contact_status_for_aor(void *obj, void *arg, int flags)
3184{
3185 struct ast_sip_aor *aor = obj;
3186
3188}
3189
3190static int format_ami_contact_status(const struct ast_sip_endpoint *endpoint,
3191 struct ast_sip_ami *ami)
3192{
3193 ami->arg = (void *)endpoint;
3195}
3196
3200
3201/*!
3202 * \brief Management task to clean up an AOR
3203 * \note Run by aor_options->serializer
3204 */
3205static int sip_options_cleanup_aor_task(void *obj)
3206{
3207 struct sip_options_aor *aor_options = obj;
3208
3209 ast_debug(2, "Cleaning up AOR '%s' for shutdown\n", aor_options->name);
3210
3211 aor_options->qualify_frequency = 0;
3212 if (aor_options->sched_task) {
3214 ao2_ref(aor_options->sched_task, -1);
3215 aor_options->sched_task = NULL;
3216 }
3218
3219 return 0;
3220}
3221
3222/*!
3223 * \brief Management task to clean up the environment
3224 * \note Run by management_serializer
3225 */
3226static int sip_options_cleanup_task(void *obj)
3227{
3228 struct ao2_iterator it_aor;
3229 struct sip_options_aor *aor_options;
3230
3231 if (!sip_options_aors) {
3232 /* Nothing to do */
3233 return 0;
3234 }
3235
3237 for (; (aor_options = ao2_iterator_next(&it_aor)); ao2_ref(aor_options, -1)) {
3239 sip_options_cleanup_aor_task, aor_options);
3240 }
3241 ao2_iterator_destroy(&it_aor);
3242
3243 return 0;
3244}
3245
3278
3279/*!
3280 * \brief Management task to finish setting up the environment.
3281 * \note Run by management_serializer
3282 */
3283static int sip_options_init_task(void *mgmt_serializer)
3284{
3285 management_serializer = mgmt_serializer;
3286
3289 return -1;
3290 }
3293 return -1;
3294 }
3297 return -1;
3298 }
3299
3301
3302 return 0;
3303}
3304
3310
3312{
3313 struct ast_taskprocessor *mgmt_serializer;
3314
3315 static const pj_str_t STR_OPTIONS = { "OPTIONS", 7 };
3316
3317 if (reload) {
3319 return 0;
3320 }
3321
3322 if (pjsip_endpt_register_module(ast_sip_get_pjsip_endpoint(), &options_module)
3323 != PJ_SUCCESS) {
3324 return -1;
3325 }
3326
3327 if (pjsip_endpt_add_capability(ast_sip_get_pjsip_endpoint(), NULL, PJSIP_H_ALLOW,
3328 NULL, 1, &STR_OPTIONS) != PJ_SUCCESS) {
3330 return -1;
3331 }
3332
3334 sip_options_aor_hash_fn, NULL, sip_options_aor_cmp_fn);
3335 if (!sip_options_aors) {
3337 return -1;
3338 }
3342 sip_options_endpoint_state_compositor_hash_fn, NULL,
3343 sip_options_endpoint_state_compositor_cmp_fn);
3346 return -1;
3347 }
3348
3349 mgmt_serializer = ast_sip_create_serializer("pjsip/options/manage");
3350 if (!mgmt_serializer) {
3352 return -1;
3353 }
3354
3355 /*
3356 * Set the water mark levels high because we can get a flood of
3357 * contact status updates from sip_options_synchronize() that
3358 * quickly clears on initial load or reload.
3359 */
3360 ast_taskprocessor_alert_set_levels(mgmt_serializer, -1,
3362
3363 /*
3364 * We make sure that the environment is completely setup before we allow
3365 * any other threads to post contact_status updates to the
3366 * management_serializer.
3367 */
3369 mgmt_serializer)) {
3370 /* Set management_serializer in case pushing the task actually failed. */
3371 management_serializer = mgmt_serializer;
3373 return -1;
3374 }
3375
3381
3382 return 0;
3383}
void ast_cli_unregister_multiple(void)
Definition ael_main.c:408
jack_status_t status
Definition app_jack.c:149
char * strsep(char **str, const char *delims)
Asterisk main include file. File version handling, generic pbx functions.
int ast_shutting_down(void)
Definition asterisk.c:1889
#define ast_free(a)
Definition astmm.h:180
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition astmm.h:298
#define ast_malloc(len)
A wrapper for malloc()
Definition astmm.h:191
#define ast_log
Definition astobj2.c:42
int ao2_container_dup(struct ao2_container *dest, struct ao2_container *src, enum search_flags flags)
Copy all object references in the src container into the dest container.
#define ao2_iterator_next(iter)
Definition astobj2.h:1911
#define ao2_link(container, obj)
Add an object to a container.
Definition astobj2.h:1532
@ CMP_MATCH
Definition astobj2.h:1027
@ CMP_STOP
Definition astobj2.h:1028
@ AO2_ALLOC_OPT_LOCK_NOLOCK
Definition astobj2.h:367
@ AO2_ALLOC_OPT_LOCK_RWLOCK
Definition astobj2.h:365
@ AO2_ALLOC_OPT_LOCK_MUTEX
Definition astobj2.h:363
#define ao2_callback(c, flags, cb_fn, arg)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container,...
Definition astobj2.h:1693
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
#define AO2_STRING_FIELD_CMP_FN(stype, field)
Creates a compare function for a structure string field.
Definition astobj2.h:2048
#define ao2_cleanup(obj)
Definition astobj2.h:1934
#define ao2_unlink(container, obj)
Remove an object from a container.
Definition astobj2.h:1578
@ AO2_ITERATOR_UNLINK
Definition astobj2.h:1863
#define ao2_link_flags(container, obj, flags)
Add an object to a container.
Definition astobj2.h:1554
#define ao2_find(container, arg, flags)
Definition astobj2.h:1736
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
#define AO2_STRING_FIELD_SORT_FN(stype, field)
Creates a sort function for a structure string field.
Definition astobj2.h:2064
#define ao2_unlock(a)
Definition astobj2.h:729
#define ao2_lock(a)
Definition astobj2.h:717
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition astobj2.h:459
#define ao2_alloc_options(data_size, destructor_fn, options)
Definition astobj2.h:404
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
Definition astobj2.h:480
#define AO2_STRING_FIELD_HASH_FN(stype, field)
Creates a hash function for a structure string field.
Definition astobj2.h:2032
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
@ OBJ_SEARCH_OBJECT
The arg parameter is an object of the same type.
Definition astobj2.h:1087
@ OBJ_NOLOCK
Assume that the ao2_container is already locked.
Definition astobj2.h:1063
@ OBJ_NODATA
Definition astobj2.h:1044
@ OBJ_MULTIPLE
Definition astobj2.h:1049
@ OBJ_UNLINK
Definition astobj2.h:1039
@ OBJ_SEARCH_KEY
The arg parameter is a search key, but is not an object.
Definition astobj2.h:1101
#define ao2_alloc(data_size, destructor_fn)
Definition astobj2.h:409
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Allocate and initialize a hash container with the desired number of buckets.
Definition astobj2.h:1303
#define ao2_container_clone(orig, flags)
Create a clone/copy of the given container.
Definition astobj2.h:1419
@ AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT
Reject objects with duplicate keys in container.
Definition astobj2.h:1188
@ AO2_CONTAINER_ALLOC_OPT_DUPS_REPLACE
Replace objects with duplicate keys in container.
Definition astobj2.h:1211
static struct cdr_batch * batch
static PGresult * result
Definition cel_pgsql.c:84
static int available(struct dahdi_pvt **pvt, int is_specific_channel)
General Asterisk PBX channel definitions.
#define AST_MAX_EXTENSION
Definition channel.h:134
Standard Command Line Interface.
#define CLI_SHOWUSAGE
Definition cli.h:45
#define CLI_SUCCESS
Definition cli.h:44
#define AST_CLI_DEFINE(fn, txt,...)
Definition cli.h:197
void ast_cli(int fd, const char *fmt,...)
Definition clicompat.c:6
@ CLI_INIT
Definition cli.h:152
@ CLI_GENERATE
Definition cli.h:153
#define CLI_FAILURE
Definition cli.h:46
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition cli.h:265
char buf[BUFSIZE]
Definition eagi_proxy.c:66
ast_endpoint_state
Valid states for an endpoint.
Definition endpoints.h:51
@ AST_ENDPOINT_OFFLINE
Definition endpoints.h:55
@ AST_ENDPOINT_ONLINE
Definition endpoints.h:57
static const char name[]
Definition format_mp3.c:68
void astman_send_listack(struct mansession *s, const struct message *m, char *msg, char *listflag)
Send ack in manager transaction to begin a list.
Definition manager.c:1963
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Definition manager.c:1921
void astman_send_list_complete_start(struct mansession *s, const struct message *m, const char *event_name, int count)
Start the list complete event.
Definition manager.c:1999
void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
Send ack in manager transaction.
Definition manager.c:1953
const char * astman_get_header(const struct message *m, char *var)
Get header from manager transaction.
Definition manager.c:1582
void astman_send_list_complete_end(struct mansession *s)
End the list complete event.
Definition manager.c:2007
void astman_append(struct mansession *s, const char *fmt,...)
Definition manager.c:1842
int ast_manager_unregister(const char *action)
Unregister a registered manager command.
Definition manager.c:7782
struct ast_taskprocessor * ast_sip_get_distributor_serializer_hash(int hash)
Determine the distributor serializer for a given hash.
#define ast_sip_push_task(serializer, sip_task, task_data)
Definition res_pjsip.h:2126
struct ast_taskprocessor * ast_sip_create_serializer(const char *name)
Create a new serializer for SIP tasks.
Definition res_pjsip.c:2137
struct ast_sip_sched_task * ast_sip_schedule_task(struct ast_taskprocessor *serializer, int interval, ast_sip_task sip_task, const char *name, void *task_data, enum ast_sip_scheduler_task_flags flags)
Schedule a task to run in the res_pjsip taskpool.
int ast_sip_sched_task_cancel(struct ast_sip_sched_task *schtd)
Cancels the next invocation of a task.
#define ast_sip_push_task_wait_serializer(serializer, sip_task, task_data)
Definition res_pjsip.h:2221
@ AST_SIP_SCHED_TASK_DATA_AO2
Definition res_pjsip.h:2274
@ AST_SIP_SCHED_TASK_VARIABLE
Definition res_pjsip.h:2257
static char prefix[MAX_PREFIX]
Definition http.c:145
#define ast_debug(level,...)
Log a DEBUG message.
#define LOG_ERROR
#define ast_verb(level,...)
#define LOG_WARNING
static struct ao2_container * endpoints
#define EVENT_FLAG_REPORTING
Definition manager.h:84
#define EVENT_FLAG_SYSTEM
Definition manager.h:75
#define ast_manager_register_xml(action, authority, func)
Register a manager callback using XML documentation to describe the manager.
Definition manager.h:193
Core PBX routines and definitions.
int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
Determine whether an extension exists.
Definition pbx.c:2735
static pjsip_module options_module
static void aor_observer_deleted(const void *obj)
Observer callback invoked on AOR deletion.
static pj_status_t send_options_response(pjsip_rx_data *rdata, int code)
int ast_res_pjsip_preinit_options_handling(void)
static struct ao2_container * sip_options_aors
static int sip_options_contact_status_available_count(void *obj, void *arg, int flags)
Count AVAILABLE qualified contacts.
#define ENDPOINT_STATE_COMPOSITOR_INITIAL_SIZE
The initial vector size for the endpoint state compositors on an AOR.
static int sip_options_target_result_task(void *obj)
Combine the result of one resolved target with the other targets.
static void sip_contact_status_dtor(void *obj)
Destructor for contact statuses.
static int sip_options_synchronize_aor_task(void *obj)
Task to synchronize an AOR with our local state.
static void sip_options_endpoint_unlink_aor_feeders(struct ast_sip_endpoint *endpoint, struct sip_options_endpoint_state_compositor *endpoint_state_compositor)
Unlink AORs feeding the endpoint status compositor.
static char * cli_reload_qualify_endpoint(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static void sip_options_aor_dtor(void *obj)
Destructor function for SIP OPTIONS AORs.
static char * cli_qualify(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static int sip_options_endpoint_observer_modified_task(void *obj)
Task to synchronize the endpoint.
static int sip_options_aor_observer_deleted_task(void *obj)
Task to delete an AOR from the known universe.
static struct ast_taskprocessor * management_serializer
static int sip_options_contact_update_task(void *obj)
Task which updates a dynamic contact to an AOR.
#define DEFAULT_ENCODING
static void endpoint_observer_modified(const void *obj)
Observer callback invoked on endpoint creation or modification.
static void aor_observer_modified(const void *obj)
Observer callback invoked on AOR creation or modification.
#define DEFAULT_LANGUAGE
static void sip_options_synchronize(int reload)
Synchronize our local container of AORs and endpoint state compositors with the current configuration...
static struct ao2_container * get_all_contacts(void)
static void contact_observer_created(const void *obj)
Observer callback invoked on contact creation.
static void contact_observer_deleted(const void *obj)
Observer callback invoked on contact deletion.
static void sip_options_endpoint_state_compositor_dtor(void *obj)
Destructor for endpoint state compositors.
static struct sip_options_endpoint_state_compositor * sip_options_endpoint_state_compositor_find_or_alloc(const struct ast_sip_endpoint *endpoint)
Find (or create) an endpoint state compositor.
#define AOR_STATUS_BUCKETS
These are the number of buckets (per endpoint state compositor) to use to store AOR statuses.
static void qualify_contact_cb(void *token, pjsip_event *e)
Callback for an OPTIONS response, timeout, or transport error.
static int sip_options_set_contact_status_unqualified(void *obj, void *arg, int flags)
Transition the contact status to unqualified mode.
int ast_res_pjsip_init_options_handling(int reload)
static void contact_observer_updated(const void *obj)
Observer callback invoked on contact update.
static int sip_options_endpoint_observer_deleted_task(void *obj)
Task to delete an endpoint from the known universe.
static int sip_contact_to_ami(const struct ast_sip_contact *contact, struct ast_str **buf)
static int sip_options_aor_observer_modified_task(void *obj)
Task to synchronize the AOR.
static const struct ast_sorcery_observer endpoint_observer_callbacks
Observer callbacks for endpoints.
static int sip_options_contact_add_management_task(void *obj)
Task to add a dynamic contact to an AOR in its serializer.
static const char * short_status_map[]
static int sip_options_aor_remove_task(void *obj)
Task which removes an AOR from all of the ESCs it is reporting to.
static struct ao2_container * sip_options_contact_statuses
static int sip_options_cleanup_aor_task(void *obj)
Management task to clean up an AOR.
#define CONTACT_STATUS_BUCKETS
These are the number of contact status buckets.
static int format_ami_contactlist_handler(void *obj, void *arg, int flags)
static int sip_options_unused_aor(void *obj, void *arg, int flags)
Callback which removes any unused AORs that remained after reloading.
static void sip_options_transaction_free(pjsip_transaction *tsx)
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 struct sip_options_contact_callback_data * sip_options_contact_callback_data_alloc(struct ast_sip_contact *contact, struct sip_options_aor *aor_options, struct ast_sip_endpoint *endpoint, pjsip_tx_data *resolve_tdata)
Contact callback data allocator.
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 void sip_options_queue_target_result(struct sip_options_contact_callback_data *batch, enum ast_sip_contact_status_type status)
Queue a resolved target's qualification result to be combined with the other targets.
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 void sip_options_qualify_resolve_cb(pj_status_t status, void *token, const pjsip_server_addresses *addresses)
DNS callback used to fan out a qualify to every resolved target.
static void sip_options_target_result_dtor(void *obj)
Destructor for a resolved target's qualification result.
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 void sip_options_qualify_resolve_task_dtor(void *obj)
static const struct ast_sorcery_observer aor_observer_callbacks
Observer callbacks for AORs.
static enum ast_endpoint_state sip_options_get_endpoint_state_compositor_state(const struct sip_options_endpoint_state_compositor *endpoint_state_compositor)
Return the current state of an endpoint state compositor.
static void sip_options_contact_status_update(struct ast_sip_contact_status *contact_status)
static void sip_options_set_contact_status(struct ast_sip_contact_status *contact_status, enum ast_sip_contact_status_type status)
Set the contact status for a contact.
static int sip_options_synchronize_aor(void *obj, void *arg, int flags)
Synchronize an AOR with our local state.
static int sip_options_contact_delete_task(void *obj)
Task which deletes a dynamic contact from an AOR.
static int ami_show_contacts(struct mansession *s, const struct message *m)
static void sip_options_update_endpoint_state_compositor_aor(struct sip_options_endpoint_state_compositor *endpoint_state_compositor, const char *name, enum ast_sip_contact_status_type status)
Update the AOR status on an endpoint state compositor.
static int sip_options_determine_initial_qualify_time(int qualify_frequency)
Determine an initial time for scheduling AOR qualifying.
struct ast_sip_contact_status * ast_res_pjsip_find_or_create_contact_status(const struct ast_sip_contact *contact)
static int contact_status_publish_update_task(void *obj)
Task to notify endpoints of a contact status change.
static int format_ami_contact_status(const struct ast_sip_endpoint *endpoint, struct ast_sip_ami *ami)
struct ast_sip_contact_status * ast_sip_get_contact_status(const struct ast_sip_contact *contact)
Retrieve the current status for a contact.
static int sip_options_contact_add_task(void *obj)
Task which adds a dynamic contact to an AOR.
static const struct ast_sorcery_observer contact_observer_callbacks
Observer callbacks for contacts.
const char * ast_sip_get_contact_status_label(const enum ast_sip_contact_status_type status)
translate ast_sip_contact_status_type to character string.
static struct ast_sip_endpoint_formatter contact_status_formatter
static int has_qualify_changed(const struct ast_sip_contact *contact, const struct sip_options_aor *aor_options)
Check if the contact qualify options are different than local aor qualify options.
static int sip_options_update_aor_task(void *obj)
Task to synchronize an AOR with our local state.
static void sip_options_cancel_target_transactions(struct sip_options_contact_callback_data *batch)
Terminate all in-flight target transactions for a batch.
static pj_status_t sip_options_apply_transport_to_destination(const pjsip_tx_data *tdata, pjsip_host_info *destination)
Apply a request's transport selector to its DNS destination.
#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_qualify_resolve_task(void *obj)
Process a DNS resolution result on the AOR serializer.
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:3497
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:2488
int ast_sip_is_allowed_uri(pjsip_uri *uri)
Check whether a pjsip_uri is allowed or not.
Definition res_pjsip.c:3492
int ast_sip_for_each_contact(const struct ast_sip_aor *aor, ao2_callback_fn on_contact, void *arg)
For every contact on an AOR call the given 'on_contact' handler.
Definition location.c:723
int ast_sip_for_each_aor(const char *aors, ao2_callback_fn on_aor, void *arg)
For every aor in the comma separated aors string call the given 'on_aor' handler.
Definition location.c:688
pjsip_endpoint * ast_sip_get_pjsip_endpoint(void)
Get a pointer to the PJSIP endpoint.
Definition res_pjsip.c:518
unsigned int ast_sip_get_send_contact_status_on_update_registration(void)
Retrieve the global setting 'send_contact_status_on_update_registration'.
#define AST_SIP_USER_OPTIONS_TRUNCATE_CHECK(str)
Truncate the URI user field options string if enabled.
Definition res_pjsip.h:3578
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:2221
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_persistent_endpoint_update_state(const char *endpoint_name, enum ast_endpoint_state state)
Change state of a persistent endpoint.
void ast_sip_register_endpoint_formatter(struct ast_sip_endpoint_formatter *obj)
Register an endpoint formatter.
Definition res_pjsip.c:479
int ast_sip_send_out_of_dialog_request_with_tsx(pjsip_tx_data *tdata, struct ast_sip_endpoint *endpoint, int timeout, void *token, void(*callback)(void *token, pjsip_event *e), pjsip_transaction **tsx)
Send an Out-Of-Dialog SIP request and return its transaction.
Definition res_pjsip.c:1969
void ast_sip_unregister_endpoint_formatter(struct ast_sip_endpoint_formatter *obj)
Unregister an endpoint formatter.
Definition res_pjsip.c:485
int ast_sip_sorcery_object_to_ami(const void *obj, struct ast_str **buf)
Converts a sorcery object to a string of object properties.
int ast_sip_set_outbound_proxy(pjsip_tx_data *tdata, const char *proxy)
Set the outbound proxy for an outbound SIP message.
Definition res_pjsip.c:2035
int ast_sip_create_request(const char *method, struct pjsip_dialog *dlg, struct ast_sip_endpoint *endpoint, const char *uri, struct ast_sip_contact *contact, pjsip_tx_data **tdata)
General purpose method for creating a SIP request.
Definition res_pjsip.c:1433
struct ast_str * ast_sip_create_ami_event(const char *event, struct ast_sip_ami *ami)
Creates a string to store AMI event data in.
int ast_sip_add_header(pjsip_tx_data *tdata, const char *name, const char *value)
Add a header to an outbound SIP message.
Definition res_pjsip.c:2051
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:2444
ast_sip_contact_status_type
Status type for a contact.
Definition res_pjsip.h:436
@ AVAILABLE
Definition res_pjsip.h:440
@ UNAVAILABLE
Definition res_pjsip.h:438
@ REMOVED
Definition res_pjsip.h:445
@ UNKNOWN
Definition res_pjsip.h:442
@ CREATED
Definition res_pjsip.h:444
#define NULL
Definition resample.c:96
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition sorcery.c:2381
void ast_sorcery_observer_remove(const struct ast_sorcery *sorcery, const char *type, const struct ast_sorcery_observer *callbacks)
Remove an observer from a specific object type.
Definition sorcery.c:2487
@ AST_RETRIEVE_FLAG_MULTIPLE
Return all matching objects.
Definition sorcery.h:120
@ AST_RETRIEVE_FLAG_ALL
Perform no matching, return all objects.
Definition sorcery.h:123
void * ast_sorcery_retrieve_by_id(const struct ast_sorcery *sorcery, const char *type, const char *id)
Retrieve an object using its unique identifier.
Definition sorcery.c:1917
int ast_sorcery_observer_add(const struct ast_sorcery *sorcery, const char *type, const struct ast_sorcery_observer *callbacks)
Add an observer to a specific object type.
Definition sorcery.c:2455
int ast_sorcery_object_id_compare(void *obj, void *arg, int flags)
ao2 object comparator based on sorcery id.
Definition sorcery.c:2528
int ast_sorcery_object_id_sort(const void *obj, const void *arg, int flags)
ao2 object sorter based on sorcery id.
Definition sorcery.c:2504
int ast_sorcery_object_id_hash(const void *obj, int flags)
ao2 object hasher based on sorcery id.
Definition sorcery.c:2539
void * ast_sorcery_retrieve_by_fields(const struct ast_sorcery *sorcery, const char *type, unsigned int flags, struct ast_variable *fields)
Retrieve an object or multiple objects using specific fields.
Definition sorcery.c:1961
struct ao2_container * ast_sorcery_retrieve_by_prefix(const struct ast_sorcery *sorcery, const char *type, const char *prefix, const size_t prefix_len)
Retrieve multiple objects whose id begins with the specified prefix.
Definition sorcery.c:2053
void AST_OPTIONAL_API_NAME() ast_statsd_log_string_va(const char *metric_name, const char *metric_type, const char *value, double sample_rate,...)
Send a stat to the configured statsd server.
Definition res_statsd.c:205
#define AST_STATSD_TIMER
Definition statsd.h:41
#define AST_STATSD_GAUGE
Support for publishing to a statsd server.
Definition statsd.h:32
void AST_OPTIONAL_API_NAME() ast_statsd_log_full_va(const char *metric_name, const char *metric_type, intmax_t value, double sample_rate,...)
Send a stat to the configured statsd server.
Definition res_statsd.c:228
#define ast_string_fields_copy(copy, orig)
Copy all string fields from one instance to another of the same structure.
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition strings.h:1139
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one.
Definition strings.h:80
static force_inline int attribute_pure ast_str_hash(const char *str)
Compute a hash value on a string.
Definition strings.h:1259
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition strings.h:65
char *attribute_pure ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition strings.h:761
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
Definition strings.h:223
Generic container type.
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition astobj2.h:1821
descriptor for a cli entry.
Definition cli.h:171
char * command
Definition cli.h:186
const char * usage
Definition cli.h:177
AMI variable container.
Definition res_pjsip.h:3274
struct mansession * s
Definition res_pjsip.h:3276
const struct message * m
Definition res_pjsip.h:3278
A SIP address of record.
Definition res_pjsip.h:480
double qualify_timeout
Definition res_pjsip.h:508
int qualify_2xx_only
Definition res_pjsip.h:514
struct ao2_container * permanent_contacts
Definition res_pjsip.h:504
int authenticate_qualify
Definition res_pjsip.h:498
unsigned int qualify_frequency
Definition res_pjsip.h:496
A contact's status.
Definition res_pjsip.h:453
const ast_string_field uri
Definition res_pjsip.h:459
enum ast_sip_contact_status_type status
Definition res_pjsip.h:470
enum ast_sip_contact_status_type last_status
Definition res_pjsip.h:472
const ast_string_field aor
Definition res_pjsip.h:459
struct ast_sip_security_mechanism_vector security_mechanisms
Definition res_pjsip.h:468
A wrapper for contact that adds the aor_id and a consistent contact id. Used by ast_sip_for_each_cont...
Definition res_pjsip.h:521
struct ast_sip_contact * contact
Definition res_pjsip.h:527
Contact associated with an address of record.
Definition res_pjsip.h:392
const ast_string_field uri
Definition res_pjsip.h:414
double qualify_timeout
Definition res_pjsip.h:422
const ast_string_field via_addr
Definition res_pjsip.h:414
const ast_string_field call_id
Definition res_pjsip.h:414
const ast_string_field aor
Definition res_pjsip.h:414
const ast_string_field outbound_proxy
Definition res_pjsip.h:414
struct timeval expiration_time
Definition res_pjsip.h:416
const ast_string_field path
Definition res_pjsip.h:414
const ast_string_field endpoint_name
Definition res_pjsip.h:414
int authenticate_qualify
Definition res_pjsip.h:420
const ast_string_field user_agent
Definition res_pjsip.h:414
unsigned int qualify_frequency
Definition res_pjsip.h:418
An entity responsible formatting endpoint information.
Definition res_pjsip.h:3300
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:3304
An entity with which Asterisk communicates.
Definition res_pjsip.h:1067
const ast_string_field aors
Definition res_pjsip.h:1096
Interface for a sorcery object type observer.
Definition sorcery.h:332
void(* created)(const void *object)
Callback for when an object is created.
Definition sorcery.h:334
Support for dynamic strings.
Definition strings.h:623
A ast_taskprocessor structure is a singleton by name.
In case you didn't read that giant block of text above the mansession_session struct,...
Definition manager.c:314
Structure which contains an AOR and contacts for qualifying purposes.
double qualify_timeout
Qualify timeout. 0 is diabled.
struct ao2_container * contacts
All contacts associated with this AOR.
int qualify_2xx_only
If true only authenticate if OPTIONS response is 2XX.
struct sip_options_aor::@491 compositors
The endpoint state compositors we are feeding, a reference is held to each.
struct ao2_container * dynamic_contacts
Only dynamic contacts associated with this AOR.
struct ast_taskprocessor * serializer
The serializer for this AOR.
struct ast_sip_sched_task * sched_task
The scheduler task for this AOR.
unsigned int available
The number of available contacts on this AOR.
unsigned int qualify_frequency
Frequency to send OPTIONS requests to AOR contacts. 0 is disabled.
char name[0]
The name of the AOR.
Structure used to contain information for an OPTIONS callback.
struct ast_sip_contact * contact
The contact we qualified.
pjsip_tx_data * resolve_tdata
Transaction data for the resolve request.
struct timeval rtt_start
The time at which this OPTIONS attempt was started.
struct ast_sip_endpoint * endpoint
Endpoint used to create and send each target request.
enum ast_sip_contact_status_type status
The new status of the contact.
unsigned int pending
Number of resolved targets waiting for a response.
struct sip_options_aor * aor_options
The AOR options.
struct sip_options_contact_callback_data::@492 target_transactions
Transactions for all target OPTIONS requests in this batch.
unsigned int completed
Whether the OPTIONS request(s) have been completed.
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.
char * names[PJSIP_MAX_RESOLVED_ADDRESSES]
struct sip_options_contact_callback_data * batch
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.
Result of qualifying an individual address belonging to a contact resolved from an A,...
enum ast_sip_contact_status_type status
struct sip_options_contact_callback_data * batch
userdata associated with baseline taskprocessor test
struct ast_taskprocessor * ast_taskpool_serializer_get_current(void)
Get the taskpool serializer currently associated with this thread.
Definition taskpool.c:842
An API for managing task processing threads that can be shared across modules.
void * ast_taskprocessor_unreference(struct ast_taskprocessor *tps)
Unreference the specified taskprocessor and its reference count will decrement.
const char * ast_taskprocessor_name(struct ast_taskprocessor *tps)
Return the name of the taskprocessor singleton.
#define AST_TASKPROCESSOR_HIGH_WATER_LEVEL
int ast_taskprocessor_alert_set_levels(struct ast_taskprocessor *tps, long low_water, long high_water)
Set the high and low alert water marks of the given taskprocessor queue.
Test Framework API.
#define ast_test_suite_event_notify(s, f,...)
Definition test.h:189
static struct test_val a
Time-related functions and macros.
int64_t ast_tvdiff_us(struct timeval end, struct timeval start)
Computes the difference (in microseconds) between two struct timeval instances.
Definition time.h:87
int ast_time_t_to_string(time_t time, char *buf, size_t length)
Converts to a string representation of a time_t as decimal seconds since the epoch....
Definition time.c:152
#define AST_TIME_T_LEN
Definition time.h:45
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition time.h:159
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition utils.h:981
#define ast_assert(a)
Definition utils.h:779
#define ARRAY_LEN(a)
Definition utils.h:706
#define ast_random_double()
Returns a random number between 0.0 and 1.0, inclusive.
Definition utils.h:664
#define AST_VECTOR_RESET(vec, cleanup)
Reset vector.
Definition vector.h:653
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition vector.h:637
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
Definition vector.h:185
#define AST_VECTOR_REMOVE(vec, idx, preserve_ordered)
Remove an element from a vector by index.
Definition vector.h:440
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
Definition vector.h:124
#define AST_VECTOR_APPEND(vec, elem)
Append an element to a vector, growing the vector if needed.
Definition vector.h:267
#define AST_VECTOR(name, type)
Define a vector structure.
Definition vector.h:44
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition vector.h:708