26 #include "asterisk/res_pjsip.h"
33 #include "asterisk/statsd.h"
34 #include "include/res_pjsip_private.h"
36 #include "asterisk/threadpool.h"
96 #define DEFAULT_LANGUAGE "en"
97 #define DEFAULT_ENCODING "identity"
101 #define AOR_BUCKETS 61
103 #define AOR_BUCKETS 1567
108 #define CONTACT_STATUS_BUCKETS 61
110 #define CONTACT_STATUS_BUCKETS 1567
114 #define CONTACT_BUCKETS 13
117 #define ENDPOINT_STATE_COMPOSITOR_BUCKETS 13
120 #define ENDPOINT_STATE_COMPOSITOR_INITIAL_SIZE 1
123 #define AOR_STATUS_BUCKETS 3
126 #define MAX_UNLOAD_TIMEOUT_TIME 10
207 static struct
ao2_container *sip_options_endpoint_state_compositors;
215 static pj_status_t send_options_response(pjsip_rx_data *rdata,
int code)
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;
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);
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));
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));
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));
247 ast_sip_add_header(tdata,
"Accept-Encoding", DEFAULT_ENCODING);
248 ast_sip_add_header(tdata,
"Accept-Language", DEFAULT_LANGUAGE);
251 status = pjsip_dlg_send_response(dlg, trans, tdata);
255 endpoint = ast_pjsip_rdata_get_endpoint(rdata);
256 status = ast_sip_send_stateful_response(rdata, tdata, endpoint);
257 ao2_cleanup(endpoint);
260 if (status != PJ_SUCCESS) {
261 ast_log(LOG_ERROR,
"Unable to send response (%d)\n", status);
267 static pj_bool_t options_on_rx_request(pjsip_rx_data *rdata)
273 if (pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_options_method)) {
277 if (!(endpoint = ast_pjsip_rdata_get_endpoint(rdata))) {
281 ruri = rdata->msg_info.msg->line.req.uri;
282 if (!ast_sip_is_allowed_uri(ruri)) {
283 send_options_response(rdata, 416);
287 ast_copy_pj_str(exten, ast_sip_pjsip_uri_get_username(ruri),
sizeof(exten));
293 AST_SIP_USER_OPTIONS_TRUNCATE_CHECK(exten);
300 send_options_response(rdata, 503);
301 }
else if (!ast_strlen_zero(exten)
303 send_options_response(rdata, 404);
305 send_options_response(rdata, 200);
310 static pjsip_module options_module = {
311 .name = {
"Options Module", 14},
313 .priority = PJSIP_MOD_PRIORITY_APPLICATION,
314 .on_rx_request = options_on_rx_request,
317 static const char *status_map[] = {
318 [UNAVAILABLE] =
"Unreachable",
319 [AVAILABLE] =
"Reachable",
320 [UNKNOWN] =
"Unknown",
321 [CREATED] =
"NonQualified",
322 [REMOVED] =
"Removed",
325 static const char *short_status_map[] = {
326 [UNAVAILABLE] =
"Unavail",
327 [AVAILABLE] =
"Avail",
328 [UNKNOWN] =
"Unknown",
329 [CREATED] =
"NonQual",
330 [REMOVED] =
"Removed",
333 const char *ast_sip_get_contact_status_label(
const enum ast_sip_contact_status_type status)
335 ast_assert(0 <= status && status < ARRAY_LEN(status_map));
336 return status_map[status];
339 const char *ast_sip_get_contact_short_status_label(
const enum ast_sip_contact_status_type status)
341 ast_assert(0 <= status && status < ARRAY_LEN(short_status_map));
342 return short_status_map[status];
346 static void sip_contact_status_dtor(
void *obj)
358 size_t size =
sizeof(*contact_status) + strlen(name) + 1;
360 contact_status = ao2_alloc_options(size, sip_contact_status_dtor,
362 if (!contact_status) {
370 strcpy(contact_status->
name, name);
371 return contact_status;
378 dst = sip_contact_status_alloc(src->
name);
405 static struct ao2_container *sip_options_contact_statuses_alloc(
void)
413 ast_sip_contact_status_hash_fn, ast_sip_contact_status_sort_fn,
414 ast_sip_contact_status_cmp_fn);
418 static void sip_options_publish_contact_state(
const struct sip_options_aor *aor_options,
427 ast_sip_persistent_endpoint_publish_contact_state(endpoint_state_compositor->
name,
436 static int contact_status_publish_update_task(
void *obj)
443 sip_options_publish_contact_state(aor_options, contact_status);
455 if (mgmt_serializer) {
477 if (!sip_options_contact_statuses) {
486 ao2_lock(sip_options_contact_statuses);
489 contact_status = ao2_find(sip_options_contact_statuses,
491 if (contact_status) {
492 ao2_unlock(sip_options_contact_statuses);
493 return contact_status;
498 if (!contact_status) {
499 ao2_unlock(sip_options_contact_statuses);
503 contact_status->
rtt = 0;
504 contact_status->
status = CREATED;
509 ao2_unlock(sip_options_contact_statuses);
515 ao2_unlock(sip_options_contact_statuses);
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));
520 sip_options_contact_status_update(contact_status);
522 return contact_status;
550 struct timeval rtt_start;
552 enum ast_sip_contact_status_type status;
567 for (; (aor_status = ao2_iterator_next(&it_aor_statuses));
ao2_ref(aor_status, -1)) {
584 const char *name,
enum ast_sip_contact_status_type status)
589 aor_status = ao2_find(endpoint_state_compositor->
aor_statuses, name,
593 if (status == REMOVED) {
597 aor_status = ao2_alloc_options(
sizeof(*aor_status) + strlen(name) + 1, NULL,
603 strcpy(aor_status->
name, name);
607 if (status == REMOVED) {
614 aor_status->
available = (status == AVAILABLE ? 1 : 0);
618 if (!endpoint_state_compositor->
active) {
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);
629 sip_options_get_endpoint_state_compositor_state(endpoint_state_compositor);
632 ast_sip_persistent_endpoint_update_state(endpoint_state_compositor->
name,
637 static void sip_options_notify_endpoint_state_compositors(
struct sip_options_aor *aor_options,
638 enum ast_sip_contact_status_type status)
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);
654 if (status == REMOVED) {
663 static int sip_options_contact_status_notify_task(
void *obj)
679 ao2_ref(contact_callback_data, -1);
687 ao2_ref(contact_callback_data, -1);
692 cs_old = ao2_find(sip_options_contact_statuses,
696 ao2_ref(contact_callback_data, -1);
701 cs_new = sip_contact_status_copy(cs_old);
704 ao2_ref(contact_callback_data, -1);
710 cs_new->
status == AVAILABLE
713 ao2_link(sip_options_contact_statuses, cs_new);
720 if (cs_new->
status == AVAILABLE) {
724 sip_options_notify_endpoint_state_compositors(
728 ast_assert(cs_new->
status == UNAVAILABLE);
733 sip_options_notify_endpoint_state_compositors(
738 ast_verb(3,
"Contact %s/%s is now %s. RTT: %.3f msec\n",
741 ast_sip_get_contact_status_label(cs_new->
status),
742 cs_new->
rtt / 1000.0);
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));
749 sip_options_contact_status_update(cs_new);
755 ast_sip_get_contact_status_label(cs_new->
status));
757 ast_debug(3,
"Contact %s/%s status didn't change: %s, RTT: %.3f msec\n",
760 ast_sip_get_contact_status_label(cs_new->
status),
761 cs_new->
rtt / 1000.0);
764 ast_statsd_log_full_va(
"PJSIP.contacts.%s.rtt", AST_STATSD_TIMER,
765 cs_new->
status != AVAILABLE ? -1 : cs_new->
rtt / 1000,
774 ast_sip_get_contact_status_label(cs_new->
status),
777 ast_debug(3,
"AOR '%s' now has %d available contacts\n",
782 ao2_ref(contact_callback_data, -1);
788 static void qualify_contact_cb(
void *token, pjsip_event *e)
791 enum ast_sip_contact_status_type
status;
793 switch(e->body.tsx_state.type) {
795 ast_log(LOG_ERROR,
"Unexpected PJSIP event %u\n", e->body.tsx_state.type);
797 case PJSIP_EVENT_TRANSPORT_ERROR:
798 case PJSIP_EVENT_TIMER:
799 status = UNAVAILABLE;
801 case PJSIP_EVENT_RX_MSG:
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",
814 ao2_ref(contact_callback_data, -1);
821 static void sip_options_contact_callback_data_dtor(
void *obj)
825 ao2_cleanup(contact_callback_data->
contact);
835 contact_callback_data = ao2_alloc_options(
sizeof(*contact_callback_data),
837 if (!contact_callback_data) {
845 return contact_callback_data;
849 static int sip_options_qualify_contact(
void *obj,
void *arg,
int flags)
854 pjsip_tx_data *tdata;
858 ast_debug(3,
"Qualifying contact '%s' on AOR '%s'\n",
870 endpoint_state_compositor->
name);
873 ast_debug(3,
"Could not find an endpoint to qualify contact '%s' on AOR '%s'\n",
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);
887 ast_log(LOG_ERROR,
"Unable to apply outbound proxy on request to qualify contact %s\n",
889 pjsip_tx_data_dec_ref(tdata);
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);
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);
910 if (ast_sip_send_out_of_dialog_request(tdata, endpoint,
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);
925 static int sip_options_qualify_aor(
void *obj)
929 ast_debug(3,
"Qualifying all contacts on AOR '%s'\n", aor_options->
name);
940 static int sip_options_remove_contact(
void *obj,
void *arg,
int flags);
943 static void sip_options_aor_dtor(
void *obj)
953 sip_options_remove_contact, aor_options);
1012 static void sip_options_remove_contact_status(
struct sip_options_aor *aor_options,
1021 ast_debug(3,
"Attempted to remove contact status for '%s' but it does not exist\n",
1026 ast_verb(2,
"Contact %s/%s has been deleted\n", contact->
aor, contact->
uri);
1029 cs_new = sip_contact_status_copy(cs_old);
1041 cs_new->
status = REMOVED;
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));
1049 sip_options_contact_status_update(cs_new);
1063 sip_options_notify_endpoint_state_compositors(aor_options, UNAVAILABLE);
1066 ast_debug(3,
"AOR '%s' now has %d available contacts\n", aor_options->
name,
1085 static int sip_options_remove_contact(
void *obj,
void *arg,
int flags)
1090 sip_options_remove_contact_status(aor_options, contact);
1098 int initial_interval;
1099 int max_time = ast_sip_get_max_initial_qualify_time();
1101 if (max_time && max_time < qualify_frequency) {
1102 initial_interval = max_time;
1108 return 0 < initial_interval ? initial_interval : 1;
1113 enum ast_sip_contact_status_type status)
1118 cs_new = sip_contact_status_copy(contact_status);
1132 ao2_link(sip_options_contact_statuses, cs_new);
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));
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));
1144 sip_options_contact_status_update(cs_new);
1150 ast_sip_get_contact_status_label(cs_new->
status));
1156 static int sip_options_set_contact_status_unqualified(
void *obj,
void *arg,
int flags)
1161 contact_status = ast_res_pjsip_find_or_create_contact_status(contact);
1162 if (!contact_status) {
1166 switch (contact_status->
status) {
1170 sip_options_set_contact_status(contact_status, CREATED);
1183 static int sip_options_set_contact_status_qualified(
void *obj,
void *arg,
int flags)
1188 contact_status = ast_res_pjsip_find_or_create_contact_status(contact);
1189 if (!contact_status) {
1193 switch (contact_status->
status) {
1195 sip_options_set_contact_status(contact_status, UNAVAILABLE);
1210 static int sip_options_contact_status_available_count(
void *obj,
void *arg,
int flags)
1216 contact_status = ast_res_pjsip_find_or_create_contact_status(contact);
1217 if (!contact_status) {
1222 switch (contact_status->
status) {
1242 static void sip_options_apply_aor_configuration(
struct sip_options_aor *aor_options,
1249 ast_debug(3,
"Configuring AOR '%s' with current state of configuration and world\n",
1260 if (!existing_contacts) {
1261 ast_log(LOG_WARNING,
"Synchronization of AOR '%s' failed for qualify, retaining existing state\n",
1272 for (; (contact = ao2_iterator_next(&iter));
ao2_ref(contact, -1)) {
1288 char prefix[prefix_len + 1];
1293 prefix, prefix_len);
1302 for (; (contact = ao2_iterator_next(&iter));
ao2_ref(contact, -1)) {
1311 sip_options_remove_contact, aor_options);
1312 ao2_ref(existing_contacts, -1);
1323 sip_options_set_contact_status_unqualified, NULL);
1325 ast_debug(3,
"AOR '%s' is unqualified, number of available contacts is therefore '%d'\n",
1329 sip_options_set_contact_status_qualified, NULL);
1331 ast_debug(3,
"AOR '%s' has transitioned from unqualified to qualified, reset available contacts to 0\n",
1340 sip_options_contact_status_available_count, &aor_options->
available);
1371 ast_log(LOG_ERROR,
"Unable to schedule qualify for contacts of AOR '%s'\n",
1377 ast_debug(3,
"AOR '%s' now has %d available contacts\n", aor_options->
name,
1385 static int sip_options_synchronize_aor_task(
void *obj)
1390 ast_debug(3,
"Synchronizing AOR '%s' with current state of configuration and world\n",
1393 sip_options_apply_aor_configuration(task_data->
aor_options, task_data->
aor,
1408 ao2_lock(endpoint_state_compositor);
1409 endpoint_state_compositor->
active = 0;
1410 sip_options_update_endpoint_state_compositor_aor(endpoint_state_compositor,
1412 ao2_unlock(endpoint_state_compositor);
1423 static int sip_options_synchronize_aor(
void *obj,
void *arg,
int flags)
1430 task_data.
aor_options = ao2_find(sip_options_aors,
1438 task_data.
added = 1;
1441 sip_options_synchronize_aor_task(&task_data);
1446 sip_options_synchronize_aor_task, &task_data);
1460 static void sip_options_endpoint_state_compositor_dtor(
void *obj)
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;
1486 endpoint_state_compositor = ao2_alloc(
sizeof(*endpoint_state_compositor)
1488 sip_options_endpoint_state_compositor_dtor);
1489 if (!endpoint_state_compositor) {
1490 ao2_unlock(sip_options_endpoint_state_compositors);
1500 sip_options_endpoint_aor_status_hash_fn, NULL,
1501 sip_options_endpoint_aor_status_cmp_fn);
1503 ao2_unlock(sip_options_endpoint_state_compositors);
1504 ao2_ref(endpoint_state_compositor, -1);
1510 ao2_link_flags(sip_options_endpoint_state_compositors, endpoint_state_compositor,
1512 ao2_unlock(sip_options_endpoint_state_compositors);
1514 return endpoint_state_compositor;
1529 static int sip_options_endpoint_compositor_add_task(
void *obj)
1533 ast_debug(3,
"Adding endpoint compositor '%s' to AOR '%s'\n",
1557 static int sip_options_endpoint_compositor_remove_task(
void *obj)
1562 ast_debug(3,
"Removing endpoint compositor '%s' from AOR '%s'\n",
1575 ao2_ref(endpoint_state_compositor, -1);
1586 static int sip_options_synchronize_endpoint(
void *obj,
void *arg,
int flags)
1594 if (ast_strlen_zero(endpoint->
aors)) {
1596 ast_debug(3,
"Endpoint '%s' is not interested in any AORs so not creating endpoint state compositor\n",
1601 ast_debug(3,
"Synchronizing endpoint '%s' with AORs '%s'\n",
1605 while ((aor_name =
ast_strip(strsep(&aors,
",")))) {
1606 if (ast_strlen_zero(aor_name)) {
1610 ast_debug(3,
"Filtered AOR '%s' on endpoint '%s' as we are looking for '%s'\n",
1622 ast_debug(3,
"Endpoint '%s' referenced invalid AOR '%s'\n",
1633 sip_options_endpoint_state_compositor_find_or_alloc(endpoint);
1635 ast_log(LOG_WARNING,
1636 "Could not create endpoint state compositor for '%s', endpoint state will be incorrect\n",
1647 sip_options_endpoint_compositor_add_task, &task_data);
1677 ast_debug(3,
"Endpoint '%s' has no AORs feeding it, setting it to offline state as default\n",
1690 static int sip_options_aor_remove_task(
void *obj)
1694 sip_options_notify_endpoint_state_compositors(aor_options, REMOVED);
1709 static int sip_options_unused_aor(
void *obj,
void *arg,
int flags)
1713 ast_debug(3,
"AOR '%s' is no longer configured, removing it\n", aor_options->
name);
1726 static int sip_options_unused_endpoint_state_compositor(
void *obj,
void *arg,
int flags)
1735 ast_sip_persistent_endpoint_update_state(endpoint_state_compositor->
name,
1751 static int sip_options_synchronize_task(
void *obj)
1782 sip_options_unused_aor, NULL);
1801 sip_options_unused_endpoint_state_compositor, NULL);
1807 static void sip_options_synchronize(
int reload)
1821 static void sip_options_endpoint_unlink_aor_feeders(
struct ast_sip_endpoint *endpoint,
1830 ao2_lock(endpoint_state_compositor);
1831 endpoint_state_compositor->
active = 0;
1835 for (; (aor_status = ao2_iterator_next(&it_aor_statuses));
ao2_ref(aor_status, -1)) {
1842 ast_debug(3,
"Removing endpoint state compositor '%s' from AOR '%s'\n",
1844 ao2_unlock(endpoint_state_compositor);
1846 sip_options_endpoint_compositor_remove_task, &task_data);
1847 ao2_lock(endpoint_state_compositor);
1858 ao2_unlock(endpoint_state_compositor);
1865 static int sip_options_endpoint_observer_deleted_task(
void *obj)
1870 endpoint_state_compositor = ao2_find(sip_options_endpoint_state_compositors,
1872 if (!endpoint_state_compositor) {
1876 ast_debug(3,
"Endpoint '%s' has been deleted, removing endpoint state compositor from AORs\n",
1878 sip_options_endpoint_unlink_aor_feeders(endpoint, endpoint_state_compositor);
1879 ao2_ref(endpoint_state_compositor, -1);
1885 static void endpoint_observer_deleted(
const void *obj)
1888 sip_options_endpoint_observer_deleted_task, (
void *) obj);
1895 static int sip_options_endpoint_observer_modified_task(
void *obj)
1900 ast_debug(3,
"Endpoint '%s' has been created or modified, updating state\n",
1903 endpoint_state_compositor = ao2_find(sip_options_endpoint_state_compositors,
1905 if (endpoint_state_compositor) {
1907 sip_options_endpoint_unlink_aor_feeders(endpoint, endpoint_state_compositor);
1908 ao2_ref(endpoint_state_compositor, -1);
1912 sip_options_synchronize_endpoint(endpoint, NULL, 0);
1917 static void endpoint_observer_modified(
const void *obj)
1920 sip_options_endpoint_observer_modified_task, (
void *)obj);
1925 .
created = endpoint_observer_modified,
1926 .updated = endpoint_observer_modified,
1927 .deleted = endpoint_observer_deleted,
1934 static int sip_options_update_aor_task(
void *obj)
1939 ast_debug(3,
"Individually updating AOR '%s' with current state of configuration and world\n",
1942 sip_options_apply_aor_configuration(task_data->
aor_options, task_data->
aor,
1946 ast_debug(3,
"After modifying AOR '%s' it has now become available\n",
1948 sip_options_notify_endpoint_state_compositors(task_data->
aor_options, AVAILABLE);
1950 ast_debug(3,
"After modifying AOR '%s' it has become unavailable\n",
1952 sip_options_notify_endpoint_state_compositors(task_data->
aor_options, UNAVAILABLE);
1962 static int sip_options_aor_observer_modified_task(
void *obj)
1972 aor_options = sip_options_aor_alloc(aor);
1983 sip_options_apply_aor_configuration(aor_options, aor, 1);
1984 ao2_link(sip_options_aors, aor_options);
2008 sip_options_update_aor_task, &task_data);
2017 static void aor_observer_modified(
const void *obj)
2020 sip_options_aor_observer_modified_task, (
void *) obj);
2027 static int sip_options_aor_observer_deleted_task(
void *obj)
2038 ast_debug(3,
"AOR '%s' has been deleted, removing it\n", aor_options->
name);
2048 static void aor_observer_deleted(
const void *obj)
2051 sip_options_aor_observer_deleted_task, (
void *) obj);
2056 .
created = aor_observer_modified,
2057 .updated = aor_observer_modified,
2058 .deleted = aor_observer_deleted,
2096 static int sip_options_contact_add_task(
void *obj)
2104 contact_status = ast_res_pjsip_find_or_create_contact_status(task_data->
contact);
2105 ao2_cleanup(contact_status);
2112 ast_debug(3,
"Starting scheduled callback on AOR '%s' for qualifying as there is now a contact on it\n",
2131 ast_log(LOG_ERROR,
"Unable to schedule qualify for contacts of AOR '%s'\n",
2142 ast_debug(3,
"An unqualified contact has been added to AOR '%s' so it is now available\n",
2144 sip_options_notify_endpoint_state_compositors(task_data->
aor_options,
2156 static int sip_options_contact_add_management_task(
void *obj)
2170 ast_debug(3,
"AOR '%s' qualify options have been modified. Synchronize an AOR local state\n",
2172 sip_options_aor_observer_modified_task(aor);
2182 sip_options_contact_add_task, &task_data);
2189 static void contact_observer_created(
const void *obj)
2192 sip_options_contact_add_management_task, (
void *) obj);
2199 static int sip_options_contact_update_task(
void *obj)
2204 contact_status = ast_sip_get_contact_status(task_data->
contact);
2205 if (contact_status) {
2206 switch (contact_status->
status) {
2212 sip_options_contact_status_update(contact_status);
2222 ast_free(task_data);
2227 static void contact_observer_updated(
const void *obj)
2232 if (has_qualify_changed(contact, aor_options)) {
2238 ast_debug(3,
"AOR '%s' qualify options have been modified. Synchronize an AOR local state\n",
2241 sip_options_aor_observer_modified_task, aor);
2246 if (aor_options && ast_sip_get_send_contact_status_on_update_registration()) {
2261 sip_options_contact_update_task, task_data)) {
2264 ast_free(task_data);
2267 ao2_cleanup(aor_options);
2275 static int sip_options_contact_delete_task(
void *obj)
2289 ast_debug(3,
"Terminating scheduled callback on AOR '%s' as there are no contacts to qualify\n",
2301 ast_debug(3,
"An unqualified contact has been removed from AOR '%s' leaving no remaining contacts\n",
2303 sip_options_notify_endpoint_state_compositors(task_data->
aor_options,
2315 static int sip_options_contact_delete_management_task(
void *obj)
2328 sip_options_contact_delete_task, &task_data);
2335 static void contact_observer_deleted(
const void *obj)
2338 sip_options_contact_delete_management_task, (
void *) obj);
2343 .
created = contact_observer_created,
2344 .updated = contact_observer_updated,
2345 .deleted = contact_observer_deleted,
2351 const char *endpoint_name;
2359 "Usage: pjsip qualify <endpoint>\n"
2360 " Send a SIP OPTIONS request to all contacts on the endpoint.\n";
2367 return CLI_SHOWUSAGE;
2370 endpoint_name = a->argv[2];
2375 ast_cli(a->fd,
"Unable to retrieve endpoint %s\n", endpoint_name);
2379 if (ast_strlen_zero(endpoint->
aors)) {
2380 ast_cli(a->fd,
"No AORs configured for endpoint '%s'\n", endpoint_name);
2385 while ((aor_name =
ast_strip(strsep(&aors,
",")))) {
2388 aor_options = ao2_find(sip_options_aors, aor_name,
OBJ_SEARCH_KEY);
2393 ast_cli(a->fd,
"Qualifying AOR '%s' on endpoint '%s'\n", aor_name, endpoint_name);
2415 return ast_sip_sorcery_object_to_ami(contact, buf);
2418 static int format_ami_contactlist_handler(
void *obj,
void *arg,
int flags)
2425 buf = ast_sip_create_ami_event(
"ContactList", ami);
2430 if (sip_contact_to_ami(contact, &buf)) {
2436 status = ast_sip_get_contact_status(contact);
2438 ast_sip_get_contact_status_label(status ? status->
status : UNKNOWN));
2439 if (!status || status->
status != AVAILABLE) {
2444 ao2_cleanup(status);
2460 contacts = get_all_contacts();
2472 astman_send_listack(s, m,
"A listing of Contacts follows, presented as ContactList events",
2488 const char *endpoint_name;
2494 e->
command =
"pjsip show qualify endpoint";
2496 "Usage: pjsip show qualify endpoint <id>\n"
2497 " Show the current qualify options for all Aors on the PJSIP endpoint.\n";
2504 return CLI_SHOWUSAGE;
2507 endpoint_name = a->argv[4];
2512 ast_cli(a->fd,
"Unable to retrieve endpoint %s\n", endpoint_name);
2516 if (ast_strlen_zero(endpoint->
aors)) {
2517 ast_cli(a->fd,
"No AORs configured for endpoint '%s'\n", endpoint_name);
2522 while ((aor_name =
ast_strip(strsep(&aors,
",")))) {
2525 aor_options = ao2_find(sip_options_aors, aor_name,
OBJ_SEARCH_KEY);
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));
2534 ast_cli(a->fd,
"\n");
2544 const char *aor_name;
2548 e->
command =
"pjsip show qualify aor";
2550 "Usage: pjsip show qualify aor <id>\n"
2551 " Show the PJSIP Aor current qualify options.\n";
2558 return CLI_SHOWUSAGE;
2561 aor_name = a->argv[4];
2563 aor_options = ao2_find(sip_options_aors, aor_name,
OBJ_SEARCH_KEY);
2565 ast_cli(a->fd,
"Unable to retrieve aor '%s' qualify options\n", aor_name);
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));
2581 const char *endpoint_name;
2587 e->
command =
"pjsip reload qualify endpoint";
2589 "Usage: pjsip reload qualify endpoint <id>\n"
2590 " Synchronize the qualify options for all Aors on the PJSIP endpoint.\n";
2597 return CLI_SHOWUSAGE;
2600 endpoint_name = a->argv[4];
2605 ast_cli(a->fd,
"Unable to retrieve endpoint %s\n", endpoint_name);
2609 if (ast_strlen_zero(endpoint->
aors)) {
2610 ast_cli(a->fd,
"No AORs configured for endpoint '%s'\n", endpoint_name);
2615 while ((aor_name =
ast_strip(strsep(&aors,
",")))) {
2623 ast_cli(a->fd,
"Synchronizing AOR '%s' on endpoint '%s'\n", aor_name, endpoint_name);
2625 sip_options_aor_observer_modified_task, aor);
2635 const char *aor_name;
2639 e->
command =
"pjsip reload qualify aor";
2641 "Usage: pjsip reload qualify aor <id>\n"
2642 " Synchronize the PJSIP Aor qualify options.\n";
2649 return CLI_SHOWUSAGE;
2652 aor_name = a->argv[4];
2656 ast_cli(a->fd,
"Unable to retrieve aor '%s'\n", aor_name);
2660 ast_cli(a->fd,
"Synchronizing AOR '%s'\n", aor_name);
2662 sip_options_aor_observer_modified_task, aor);
2675 if (ast_strlen_zero(endpoint_name)) {
2688 if (ast_strlen_zero(endpoint->
aors)) {
2694 while ((aor_name =
ast_strip(strsep(&aors,
",")))) {
2697 aor_options = ao2_find(sip_options_aors, aor_name,
OBJ_SEARCH_KEY);
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"),
2719 int ast_sip_format_contact_ami(
void *obj,
void *arg,
int flags)
2727 char secs[AST_TIME_T_LEN];
2729 buf = ast_sip_create_ami_event(
"ContactStatusDetail", ami);
2734 status = ast_sip_get_contact_status(contact);
2741 if (!ast_strlen_zero(contact->
via_addr)) {
2748 if (!ast_strlen_zero(contact->
call_id)) {
2752 ast_sip_get_contact_status_label(status ? status->
status : UNKNOWN));
2753 if (!status || status->
status != AVAILABLE) {
2772 ao2_cleanup(status);
2776 static int format_contact_status_for_aor(
void *obj,
void *arg,
int flags)
2780 return ast_sip_for_each_contact(aor, ast_sip_format_contact_ami, arg);
2783 static int format_ami_contact_status(
const struct ast_sip_endpoint *endpoint,
2786 ami->
arg = (
void *)endpoint;
2787 return ast_sip_for_each_aor(endpoint->
aors, format_contact_status_for_aor, ami);
2798 static int sip_options_cleanup_aor_task(
void *obj)
2802 ast_debug(2,
"Cleaning up AOR '%s' for shutdown\n", aor_options->
name);
2819 static int sip_options_cleanup_task(
void *obj)
2824 if (!sip_options_aors) {
2830 for (; (aor_options = ao2_iterator_next(&it_aor));
ao2_ref(aor_options, -1)) {
2832 sip_options_cleanup_aor_task, aor_options);
2839 void ast_res_pjsip_cleanup_options_handling(
void)
2847 ast_sip_unregister_endpoint_formatter(&contact_status_formatter);
2850 &contact_observer_callbacks);
2852 &aor_observer_callbacks);
2854 &endpoint_observer_callbacks);
2856 mgmt_serializer = management_serializer;
2857 management_serializer = NULL;
2858 if (mgmt_serializer) {
2862 remaining = ast_serializer_shutdown_group_join(shutdown_group,
2863 MAX_UNLOAD_TIMEOUT_TIME);
2865 ast_log(LOG_WARNING,
"Cleanup incomplete. Could not stop %d AORs.\n",
2868 ao2_cleanup(shutdown_group);
2869 shutdown_group = NULL;
2871 if (mgmt_serializer) {
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;
2882 pjsip_endpt_unregister_module(ast_sip_get_pjsip_endpoint(), &options_module);
2889 static int sip_options_init_task(
void *mgmt_serializer)
2891 management_serializer = mgmt_serializer;
2893 shutdown_group = ast_serializer_shutdown_group_alloc();
2894 if (!shutdown_group) {
2899 &endpoint_observer_callbacks)) {
2903 &aor_observer_callbacks)) {
2907 &contact_observer_callbacks)) {
2911 sip_options_synchronize(0);
2916 int ast_res_pjsip_preinit_options_handling(
void)
2918 sip_options_contact_statuses = sip_options_contact_statuses_alloc();
2919 return sip_options_contact_statuses ? 0 : -1;
2922 int ast_res_pjsip_init_options_handling(
int reload)
2926 static const pj_str_t STR_OPTIONS = {
"OPTIONS", 7 };
2929 sip_options_synchronize(1);
2933 if (pjsip_endpt_register_module(ast_sip_get_pjsip_endpoint(), &options_module)
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();
2945 sip_options_aor_hash_fn, NULL, sip_options_aor_cmp_fn);
2946 if (!sip_options_aors) {
2947 ast_res_pjsip_cleanup_options_handling();
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();
2961 if (!mgmt_serializer) {
2962 ast_res_pjsip_cleanup_options_handling();
2982 management_serializer = mgmt_serializer;
2983 ast_res_pjsip_cleanup_options_handling();
2987 ast_sip_register_endpoint_formatter(&contact_status_formatter);
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
void ast_taskprocessor_build_name(char *buf, unsigned int size, const char *format,...)
Build a taskprocessor name with a sequence number on the end.
void astman_append(struct mansession *s, const char *fmt,...)
Asterisk main include file. File version handling, generic pbx functions.
int ast_shutting_down(void)
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.
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.
The arg parameter is a search key, but is not an object.
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.
Time-related functions and macros.
#define ao2_container_clone(orig, flags)
Create a clone/copy of the given container.
int ast_sip_sched_task_cancel(struct ast_sip_sched_task *schtd)
Cancels the next invocation of a task.
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.
descriptor for a cli entry.
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
#define AST_TASKPROCESSOR_HIGH_WATER_LEVEL
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.
unsigned int available
The number of available contacts on this AOR.
#define AST_VECTOR_APPEND(vec, elem)
Append an element to a vector, growing the vector if needed.
void(* created)(const void *object)
Callback for when an object is created.
Perform no matching, return all objects.
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.
char name[0]
The name of the endpoint.
Assume that the ao2_container is already locked.
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.
#define ast_cli_register_multiple(e, len)
Register multiple commands.
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().
Return all matching objects.
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.
void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
Send ack in manager transaction.
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.
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).
struct ao2_container * aor_statuses
The last contributed available status of the AORs feeding this compositor.
ast_endpoint_state
Valid states for an endpoint.
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.
void * ast_sorcery_retrieve_by_id(const struct ast_sorcery *sorcery, const char *type, const char *id)
Retrieve an object using its unique identifier.
Structure which contains information required to synchronize.
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
unsigned int qualify_frequency
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.
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
General Asterisk PBX channel definitions.
void astman_send_list_complete_end(struct mansession *s)
End the list complete event.
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
#define ast_strdupa(s)
duplicate a string in memory from the stack
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.
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
#define AST_MAX_EXTENSION
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
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.
int ast_sorcery_object_id_sort(const void *obj, const void *arg, int flags)
ao2 object sorter based on sorcery id.
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
#define ast_malloc(len)
A wrapper for malloc()
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.
#define ast_debug(level,...)
Log a DEBUG message.
#define AST_VECTOR(name, type)
Define a vector structure.
An entity with which Asterisk communicates.
int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
Determine whether an extension exists.
struct sip_options_endpoint_state_compositor * endpoint_state_compositor
The 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.
Structure which contains an AOR and contacts for qualifying purposes.
#define ast_test_suite_event_notify(s, f,...)
int ast_manager_unregister(const char *action)
Unregister a registered manager command.
#define ast_string_fields_copy(copy, orig)
Copy all string fields from one instance to another of the same structure.
#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.
Support for dynamic strings.
struct ast_taskprocessor * serializer
The serializer for this AOR.
#define ao2_unlink(container, obj)
Remove an object from a container.
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.
Interface for a sorcery object type observer.
int added
Whether this AOR is being added.
struct ast_taskprocessor * ast_sip_create_serializer(const char *name)
Create a new serializer for SIP tasks.
userdata associated with baseline taskprocessor test
static struct stasis_rest_handlers endpoints
REST handler for /api-docs/endpoints.json.
#define AST_VECTOR_RESET(vec, cleanup)
Reset vector.
struct ao2_container * permanent_contacts
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.
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.
The arg parameter is an object of the same type.
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
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.
Replace objects with duplicate keys in container.
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.
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...
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...
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.
struct ao2_container * contacts
All contacts associated with this AOR.
int64_t ast_tvdiff_us(struct timeval end, struct timeval start)
Computes the difference (in microseconds) between two struct timeval instances.
#define ast_random_double()
Returns a random number between 0.0 and 1.0, inclusive.
Reject objects with duplicate keys in container.
AO2_STRING_FIELD_SORT_FN(transport_monitor, key)
Sort function for struct transport_monitor.
const ast_string_field aors
#define ast_manager_register_xml(action, authority, func)
Register a manager callback using XML documentation to describe the manager.
void ast_sip_security_mechanisms_vector_destroy(struct ast_sip_security_mechanism_vector *security_mechanisms)
Free contents of a security mechanism vector.
#define AST_VECTOR_REMOVE(vec, idx, preserve_ordered)
Remove an element from a vector by index.
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
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
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.
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
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.
void astman_send_listack(struct mansession *s, const struct message *m, char *msg, char *listflag)
Send ack in manager transaction to begin a list.
#define ao2_link(container, obj)
Add an object to a container.
struct ao2_container * dynamic_contacts
Only dynamic contacts associated with this AOR.