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