static struct ao2_container *get_container(const char *regex, ao2_sort_fn sort_fn, ao2_callback_fn compare_fn) { struct ao2_container *child_container; regex_t regexbuf; RAII_VAR(struct ao2_container *, parent_container, stasis_cache_dump(ast_channel_cache_by_name(), ast_channel_snapshot_type()), ao2_cleanup); if (!parent_container) { return NULL; } child_container = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK, 0, sort_fn, compare_fn); if (!child_container) { return NULL; } ao2_callback(parent_container, OBJ_MULTIPLE | OBJ_NODATA, cli_message_to_snapshot, child_container); if (!ast_strlen_zero(regex)) { if (regcomp(®exbuf, regex, REG_EXTENDED | REG_NOSUB)) { ao2_ref(child_container, -1); return NULL; } ao2_callback(child_container, OBJ_UNLINK | OBJ_MULTIPLE | OBJ_NODATA, cli_filter_channels, ®exbuf); regfree(®exbuf); } return child_container; }
/*! * \brief Change the size of the threadpool * * This can either result in shrinking or growing the threadpool depending * on the new desired size and the current size. * * This function is run from the threadpool control taskprocessor thread * * \param data A set_size_data used for determining how to act * \return 0 */ static int queued_set_size(void *data) { RAII_VAR(struct set_size_data *, ssd, data, ao2_cleanup); struct ast_threadpool *pool = ssd->pool; unsigned int num_threads = ssd->size; /* We don't count zombie threads as being "live" when potentially resizing */ unsigned int current_size = ao2_container_count(pool->active_threads) + ao2_container_count(pool->idle_threads); if (current_size == num_threads) { ast_debug(3, "Not changing threadpool size since new size %u is the same as current %u\n", num_threads, current_size); return 0; } if (current_size < num_threads) { ao2_callback(pool->idle_threads, OBJ_UNLINK | OBJ_NOLOCK | OBJ_NODATA | OBJ_MULTIPLE, activate_thread, pool); /* As the above may have altered the number of current threads update it */ current_size = ao2_container_count(pool->active_threads) + ao2_container_count(pool->idle_threads); grow(pool, num_threads - current_size); ao2_callback(pool->idle_threads, OBJ_UNLINK | OBJ_NOLOCK | OBJ_NODATA | OBJ_MULTIPLE, activate_thread, pool); } else { shrink(pool, current_size - num_threads); } threadpool_send_state_changed(pool); return 0; }
static struct ao2_container *cli_contact_get_container(const char *regex) { RAII_VAR(struct ao2_container *, parent_container, NULL, ao2_cleanup); struct ao2_container *child_container; regex_t regexbuf; parent_container = cli_aor_get_container(""); if (!parent_container) { return NULL; } child_container = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK, 0, cli_contact_sort, cli_contact_compare); if (!child_container) { return NULL; } ao2_callback(parent_container, OBJ_NODATA, cli_aor_gather_contacts, child_container); if (!ast_strlen_zero(regex)) { if (regcomp(®exbuf, regex, REG_EXTENDED | REG_NOSUB)) { ao2_ref(child_container, -1); return NULL; } ao2_callback(child_container, OBJ_UNLINK | OBJ_MULTIPLE | OBJ_NODATA, cli_filter_contacts, ®exbuf); regfree(®exbuf); } return child_container; }
static void qualify_and_schedule_all(void) { struct ast_variable *var = ast_variable_new("qualify_frequency >", "0", ""); struct ao2_container *aors; struct ao2_container *contacts; if (!var) { return; } aors = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "aor", AST_RETRIEVE_FLAG_MULTIPLE, var); ao2_callback(sched_qualifies, OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK, unschedule_all_cb, NULL); if (aors) { ao2_callback(aors, OBJ_NODATA, qualify_and_schedule_all_cb, NULL); ao2_ref(aors, -1); } contacts = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "contact", AST_RETRIEVE_FLAG_MULTIPLE, var); if (contacts) { ao2_callback(contacts, OBJ_NODATA, qualify_and_schedule_cb_without_aor, NULL); ao2_ref(contacts, -1); } ast_variables_destroy(var); }
struct ao2_container *ast_sip_location_retrieve_aor_contacts_nolock_filtered(const struct ast_sip_aor *aor, unsigned int flags) { /* Give enough space for ^ at the beginning and ;@ at the end, since that is our object naming scheme */ char regex[strlen(ast_sorcery_object_get_id(aor)) + 4]; struct ao2_container *contacts; snprintf(regex, sizeof(regex), "^%s;@", ast_sorcery_object_get_id(aor)); if (!(contacts = ast_sorcery_retrieve_by_regex(ast_sip_get_sorcery(), "contact", regex))) { return NULL; } /* Prune any expired contacts and delete them, we do this first because static contacts can never expire */ ao2_callback(contacts, OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK, contact_expire, NULL); /* Add any permanent contacts from the AOR */ if (aor->permanent_contacts) { ao2_callback(aor->permanent_contacts, OBJ_NODATA, contact_link_static, contacts); } if (flags & AST_SIP_CONTACT_FILTER_REACHABLE) { ao2_callback(contacts, OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK, contact_remove_unreachable, NULL); } return contacts; }
static void send_mwi_notify(struct mwi_subscription *sub) { struct ast_sip_message_accumulator counter = { .old_msgs = 0, .new_msgs = 0, }; struct ast_sip_body_data data = { .body_type = AST_SIP_MESSAGE_ACCUMULATOR, .body_data = &counter, }; ao2_callback(sub->stasis_subs, OBJ_NODATA, get_message_count, &counter); if (sub->is_solicited) { ast_sip_subscription_notify(sub->sip_sub, &data, 0); return; } send_unsolicited_mwi_notify(sub, &counter); } static int unsubscribe_stasis(void *obj, void *arg, int flags) { struct mwi_stasis_subscription *mwi_stasis = obj; if (mwi_stasis->stasis_sub) { ast_debug(3, "Removing stasis subscription to mailbox %s\n", mwi_stasis->mailbox); mwi_stasis->stasis_sub = stasis_unsubscribe(mwi_stasis->stasis_sub); } return CMP_MATCH; } static void mwi_subscription_shutdown(struct ast_sip_subscription *sub) { struct mwi_subscription *mwi_sub; RAII_VAR(struct ast_datastore *, mwi_datastore, ast_sip_subscription_get_datastore(sub, MWI_DATASTORE), ao2_cleanup); if (!mwi_datastore) { return; } mwi_sub = mwi_datastore->data; ao2_callback(mwi_sub->stasis_subs, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, unsubscribe_stasis, NULL); } static struct ast_datastore_info mwi_ds_info = { }; static int add_mwi_datastore(struct mwi_subscription *sub) { RAII_VAR(struct ast_datastore *, mwi_datastore, NULL, ao2_cleanup); mwi_datastore = ast_sip_subscription_alloc_datastore(&mwi_ds_info, MWI_DATASTORE); if (!mwi_datastore) { return -1; } mwi_datastore->data = sub; ast_sip_subscription_add_datastore(sub->sip_sub, mwi_datastore); return 0; }
struct parked_user *parking_lot_retrieve_parked_user(struct parking_lot *lot, int target) { RAII_VAR(struct parked_user *, user, NULL, ao2_cleanup); if (target < 0) { user = ao2_callback(lot->parked_users, 0, NULL, NULL); } else { user = ao2_callback(lot->parked_users, 0, retrieve_parked_user_targeted, &target); } if (!user) { return NULL; } ao2_lock(user); if (user->resolution != PARK_UNSET) { /* Abandon. Something else has resolved the parked user before we got to it. */ ao2_unlock(user); return NULL; } ao2_unlink(lot->parked_users, user); user->resolution = PARK_ANSWERED; ao2_unlock(user); parking_lot_remove_if_unused(user->lot); /* Bump the ref count by 1 since the RAII_VAR will eat the reference otherwise */ ao2_ref(user, +1); return user; }
static void create_mwi_subscriptions(void) { struct ao2_container *mwi_subscriptions = ao2_container_alloc(MWI_BUCKETS, mwi_sub_hash, mwi_sub_cmp); RAII_VAR(struct ao2_container *, old_mwi_subscriptions, ao2_global_obj_ref(unsolicited_mwi), ao2_cleanup); RAII_VAR(struct ao2_container *, endpoints, ast_sorcery_retrieve_by_fields( ast_sip_get_sorcery(), "endpoint", AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL), ao2_cleanup); if (!mwi_subscriptions) { return; } /* We remove all the old stasis subscriptions first before applying the new configuration. This * prevents a situation where there might be multiple overlapping stasis subscriptions for an * endpoint for mailboxes. Though there may be mailbox changes during the gap between unsubscribing * and resubscribing, up-to-date mailbox state will be sent out to the endpoint when the * new stasis subscription is established */ if (old_mwi_subscriptions) { ao2_callback(old_mwi_subscriptions, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, unsubscribe, NULL); } ao2_callback(endpoints, OBJ_NODATA, create_mwi_subscriptions_for_endpoint, mwi_subscriptions); ao2_global_obj_replace_unref(unsolicited_mwi, mwi_subscriptions); ao2_ref(mwi_subscriptions, -1); }
void stasis_app_to_cli(const struct stasis_app *app, struct ast_cli_args *a) { struct ao2_iterator *channels; struct ao2_iterator *endpoints; struct ao2_iterator *bridges; struct app_forwards *forward; enum forward_type forward_type; ast_cli(a->fd, "Name: %s\n" " Debug: %s\n" " Subscription Model: %s\n", app->name, app->debug ? "Yes" : "No", app->subscription_model == STASIS_APP_SUBSCRIBE_ALL ? "Global Resource Subscription" : "Application/Explicit Resource Subscription"); ast_cli(a->fd, " Subscriptions: %d\n", ao2_container_count(app->forwards)); ast_cli(a->fd, " Channels:\n"); forward_type = FORWARD_CHANNEL; channels = ao2_callback(app->forwards, OBJ_MULTIPLE, forwards_filter_by_type, &forward_type); if (channels) { while ((forward = ao2_iterator_next(channels))) { ast_cli(a->fd, " %s (%d)\n", forward->id, forward->interested); ao2_ref(forward, -1); } ao2_iterator_destroy(channels); } ast_cli(a->fd, " Bridges:\n"); forward_type = FORWARD_BRIDGE; bridges = ao2_callback(app->forwards, OBJ_MULTIPLE, forwards_filter_by_type, &forward_type); if (bridges) { while ((forward = ao2_iterator_next(bridges))) { ast_cli(a->fd, " %s (%d)\n", forward->id, forward->interested); ao2_ref(forward, -1); } ao2_iterator_destroy(bridges); } ast_cli(a->fd, " Endpoints:\n"); forward_type = FORWARD_ENDPOINT; endpoints = ao2_callback(app->forwards, OBJ_MULTIPLE, forwards_filter_by_type, &forward_type); if (endpoints) { while ((forward = ao2_iterator_next(endpoints))) { ast_cli(a->fd, " %s (%d)\n", forward->id, forward->interested); ao2_ref(forward, -1); } ao2_iterator_destroy(endpoints); } }
static void qualify_and_schedule_all(void) { struct ao2_container *endpoints = ast_sip_get_endpoints(); ao2_callback(sched_qualifies, OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK, unschedule_all_cb, NULL); if (!endpoints) { return; } ao2_callback(endpoints, OBJ_NODATA, qualify_and_schedule_all_cb, NULL); ao2_ref(endpoints, -1); }
static int on_aor_update_endpoint_state(void *obj, void *arg, int flags) { struct ast_sip_aor *aor = obj; struct ao2_container *endpoints; RAII_VAR(struct ast_variable *, var, NULL, ast_variables_destroy); const char *aor_name = ast_sorcery_object_get_id(aor); char *aor_like; if (ast_strlen_zero(aor_name)) { return -1; } if (aor->permanent_contacts && ((int)(aor->qualify_frequency * 1000)) <= 0) { aor_like = ast_alloca(strlen(aor_name) + 3); sprintf(aor_like, "%%%s%%", aor_name); var = ast_variable_new("aors LIKE", aor_like, ""); if (!var) { return -1; } endpoints = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "endpoint", AST_RETRIEVE_FLAG_MULTIPLE, var); if (endpoints) { /* * Because aors are a string list, we have to use a pattern match but since a simple * pattern match could return an endpoint that has an aor of "aaabccc" when searching * for "abc", we still have to iterate over them to find an exact aor match. */ ao2_callback(endpoints, 0, aor_update_endpoint_state, (char *)aor_name); ao2_ref(endpoints, -1); } } return 0; }
void ast_format_cap_remove_bytype(struct ast_format_cap *cap, enum ast_format_type type) { ao2_callback(cap->formats, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE | cap->nolock, multiple_by_type_cb, &type); }
/*! * \internal * \brief Send a NOTIFY request to the endpoint. * * \detail Iterates over an endpoint's AORs sending a NOTIFY request * with the appropriate payload information to each contact. */ static int notify_endpoint(void *obj) { RAII_VAR(struct notify_data *, data, obj, ao2_cleanup); char *aor_name, *aors; if (ast_strlen_zero(data->endpoint->aors)) { ast_log(LOG_WARNING, "Unable to NOTIFY - " "endpoint has no configured AORs\n"); return -1; } aors = ast_strdupa(data->endpoint->aors); while ((aor_name = ast_strip(strsep(&aors, ",")))) { RAII_VAR(struct ast_sip_aor *, aor, ast_sip_location_retrieve_aor(aor_name), ao2_cleanup); RAII_VAR(struct ao2_container *, contacts, NULL, ao2_cleanup); if (!aor || !(contacts = ast_sip_location_retrieve_aor_contacts(aor))) { continue; } ao2_callback(contacts, OBJ_NODATA, notify_contact, data); } return 0; }
static void *do_timing(void *arg) { struct timeval next_wakeup = ast_tvnow(); while (!timing_thread.stop) { struct timespec ts = { 0, }; ao2_callback(pthread_timers, OBJ_NODATA, run_timer, NULL); next_wakeup = ast_tvadd(next_wakeup, ast_tv(0, 5000)); ts.tv_sec = next_wakeup.tv_sec; ts.tv_nsec = next_wakeup.tv_usec * 1000; ast_mutex_lock(&timing_thread.lock); if (!timing_thread.stop) { if (ao2_container_count(pthread_timers)) { ast_cond_timedwait(&timing_thread.cond, &timing_thread.lock, &ts); } else { ast_cond_wait(&timing_thread.cond, &timing_thread.lock); } } ast_mutex_unlock(&timing_thread.lock); } return NULL; }
static struct ast_sip_endpoint *anonymous_identify(pjsip_rx_data *rdata) { char domain_name[DOMAIN_NAME_LEN + 1]; struct ast_sip_endpoint *endpoint; if (get_endpoint_details(rdata, domain_name, sizeof(domain_name))) { return NULL; } if (!ast_sip_get_disable_multi_domain()) { struct ast_sip_domain_alias *alias; struct ao2_container *transport_states; struct ast_sip_transport_state *transport_state = NULL; struct ast_sip_transport *transport = NULL; char id[sizeof("anonymous@") + DOMAIN_NAME_LEN]; /* Attempt to find the endpoint given the name and domain provided */ snprintf(id, sizeof(id), "anonymous@%s", domain_name); endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", id); if (endpoint) { goto done; } /* See if an alias exists for the domain provided */ alias = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "domain_alias", domain_name); if (alias) { snprintf(id, sizeof(id), "anonymous@%s", alias->domain); ao2_ref(alias, -1); endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", id); if (endpoint) { goto done; } } /* See if the transport this came in on has a provided domain */ if ((transport_states = ast_sip_get_transport_states()) && (transport_state = ao2_callback(transport_states, 0, find_transport_state_in_use, rdata)) && (transport = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "transport", transport_state->id)) && !ast_strlen_zero(transport->domain)) { snprintf(id, sizeof(id), "anonymous@%s", transport->domain); endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", id); } ao2_cleanup(transport); ao2_cleanup(transport_state); ao2_cleanup(transport_states); if (endpoint) { goto done; } } /* Fall back to no domain */ endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", "anonymous"); done: if (endpoint) { ast_debug(3, "Retrieved anonymous endpoint '%s'\n", ast_sorcery_object_get_id(endpoint)); } return endpoint; }
/*! Continuously iterate through all the entries in the hash */ static void *hash_test_count(void *d) { const struct hash_test *data = d; int count = 0; int last_count = 0; while (count < data->max_grow) { last_count = count; count = 0; ao2_callback(data->to_be_thrashed, OBJ_MULTIPLE, increment_count, &count); if (last_count == count) { /* Allow other threads to run. */ sched_yield(); } else if (last_count > count) { /* Make sure the ao2 container never shrinks */ return "ao2 container unexpectedly shrank"; } if (is_timed_out(data)) { return "Count timed out"; } } /* Successfully iterated over all of the expected elements */ return NULL; }
struct ao2_container *ast_multi_channel_blob_get_channels(struct ast_multi_channel_blob *obj, const char *role) { RAII_VAR(struct ao2_container *, ret_container, ao2_container_alloc(NUM_MULTI_CHANNEL_BLOB_BUCKETS, channel_snapshot_hash_cb, channel_snapshot_cmp_cb), ao2_cleanup); struct ao2_iterator *it_role_snapshots; struct channel_role_snapshot *role_snapshot; char *arg; if (!obj || ast_strlen_zero(role) || !ret_container) { return NULL; } arg = ast_strdupa(role); it_role_snapshots = ao2_callback(obj->channel_snapshots, OBJ_MULTIPLE | OBJ_KEY, channel_role_multi_cmp_cb, arg); if (!it_role_snapshots) { return NULL; } while ((role_snapshot = ao2_iterator_next(it_role_snapshots))) { ao2_link(ret_container, role_snapshot->snapshot); ao2_ref(role_snapshot, -1); } ao2_iterator_destroy(it_role_snapshots); ao2_ref(ret_container, +1); return ret_container; }
int ast_format_cap_remove_byid(struct ast_format_cap *cap, enum ast_format_id id) { struct ast_format format = { .id = id, }; struct multiple_by_id_data data = { .format = &format, .match_found = 0, }; ao2_callback(cap->formats, OBJ_NODATA | cap->nolock | OBJ_MULTIPLE | OBJ_UNLINK, multiple_by_id_cb, &data); /* match_found will be set if at least one item was removed */ if (data.match_found) { return 0; } return -1; } static int multiple_by_type_cb(void *obj, void *arg, int flag) { int *type = arg; struct ast_format *format = obj; return ((AST_FORMAT_GET_TYPE(format->id)) == *type) ? CMP_MATCH : 0; }
/*! \brief Load (or reload) configuration. */ static int process_config(int reload) { RAII_VAR(struct ast_ari_conf *, conf, NULL, ao2_cleanup); switch (aco_process_config(&cfg_info, reload)) { case ACO_PROCESS_ERROR: return -1; case ACO_PROCESS_OK: case ACO_PROCESS_UNCHANGED: break; } conf = ast_ari_config_get(); if (!conf) { ast_assert(0); /* We just configured; it should be there */ return -1; } if (conf->general->enabled) { if (ao2_container_count(conf->users) == 0) { ast_log(LOG_ERROR, "No configured users for ARI\n"); } else { ao2_callback(conf->users, OBJ_NODATA, validate_user_cb, NULL); } } return 0; }
static int unsubscribe(void *obj, void *arg, int flags) { struct mwi_subscription *mwi_sub = obj; ao2_callback(mwi_sub->stasis_subs, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, unsubscribe_stasis, NULL); return CMP_MATCH; }
/*! * \internal * \brief Qualify and schedule an endpoint's contacts * * \details For the given endpoint retrieve its list of aors, qualify all * contacts, and schedule for checks if configured. */ static int qualify_and_schedule_all_cb(void *obj, void *arg, int flags) { struct ast_sip_endpoint *endpoint = obj; char *aors; char *aor_name; if (ast_strlen_zero(endpoint->aors)) { return 0; } aors = ast_strdupa(endpoint->aors); while ((aor_name = strsep(&aors, ","))) { struct ast_sip_aor *aor; struct ao2_container *contacts; aor = ast_sip_location_retrieve_aor(aor_name); if (!aor) { continue; } contacts = ast_sip_location_retrieve_aor_contacts(aor); if (contacts) { ao2_callback(contacts, OBJ_NODATA, qualify_and_schedule_cb, aor); ao2_ref(contacts, -1); } ao2_ref(aor, -1); } return 0; }
/*! \brief Function called when a contact is updated */ static void mwi_contact_updated(const void *object) { char *id = ast_strdupa(ast_sorcery_object_get_id(object)), *aor = NULL; aor = strsep(&id, ";@"); ao2_callback(unsolicited_mwi, OBJ_NODATA, send_contact_notify, aor); }
static int unload_module(void) { ao2_callback(unsolicited_mwi, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, unsubscribe, NULL); ao2_ref(unsolicited_mwi, -1); ast_sorcery_observer_remove(ast_sip_get_sorcery(), "contact", &mwi_contact_observer); ast_sip_unregister_subscription_handler(&mwi_handler); return 0; }
static void traverse_elements(void) { #ifdef DEBUG printf("Traverse hashtab\n"); #endif ao2_callback(glob_hashtab, OBJ_NODATA, do_nothing_cb, NULL); els_traversals++; /* unprotected, sometimes off, but, not really important, either */ }
static int do_reload(void) { struct ast_config *config; const char *enabled_value; const char *val; int res = 0; struct ast_flags config_flags = { 0, }; const char *s; ast_mutex_lock(&reload_lock); /* Reset all settings before reloading configuration */ cel_enabled = CEL_ENALBED_DEFAULT; eventset = CEL_DEFAULT_EVENTS; *cel_dateformat = '\0'; ao2_callback(appset, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL); config = ast_config_load2("cel.conf", "cel", config_flags); if (config == CONFIG_STATUS_FILEMISSING) { config = NULL; goto return_cleanup; } if ((enabled_value = ast_variable_retrieve(config, "general", "enable"))) { cel_enabled = ast_true(enabled_value); } if (!cel_enabled) { goto return_cleanup; } /* get the date format for logging */ if ((s = ast_variable_retrieve(config, "general", "dateformat"))) { ast_copy_string(cel_dateformat, s, sizeof(cel_dateformat)); } if ((val = ast_variable_retrieve(config, "general", "events"))) { parse_events(val); } if ((val = ast_variable_retrieve(config, "general", "apps"))) { parse_apps(val); } return_cleanup: ast_verb(3, "CEL logging %sabled.\n", cel_enabled ? "en" : "dis"); ast_mutex_unlock(&reload_lock); if (config) { ast_config_destroy(config); } return res; }
static int prune_task(const void *data) { unsigned int maxage; ast_sip_get_unidentified_request_thresholds(&unidentified_count, &unidentified_period, &unidentified_prune_interval); maxage = unidentified_period * 2; ao2_callback(unidentified_requests, OBJ_MULTIPLE | OBJ_NODATA | OBJ_UNLINK, expire_requests, &maxage); return unidentified_prune_interval * 1000; }
static int unload_module(void) { RAII_VAR(struct ao2_container *, mwi_subscriptions, ao2_global_obj_ref(unsolicited_mwi), ao2_cleanup); if (mwi_subscriptions) { ao2_callback(mwi_subscriptions, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, unsubscribe, NULL); ao2_global_obj_release(unsolicited_mwi); } ast_sip_unregister_subscription_handler(&mwi_handler); return 0; }
/*! * \internal * \brief Find an endpoint associated with the given contact. */ static struct ast_sip_endpoint *find_an_endpoint(struct ast_sip_contact *contact) { char *looking_for = (char *) ast_sorcery_object_get_id(contact); struct ao2_container *endpoints = ast_sip_get_endpoints(); struct ast_sip_endpoint *endpoint; endpoint = ao2_callback(endpoints, 0, on_endpoint, looking_for); ao2_ref(endpoints, -1); return endpoint; }
static void aor_observer_modified(const void *obj) { struct ast_sip_aor *aor = (void *)obj; struct ao2_container *contacts; contacts = ast_sip_location_retrieve_aor_contacts(aor); if (contacts) { ao2_callback(contacts, OBJ_NODATA, qualify_and_schedule_cb, aor); ao2_ref(contacts, -1); } }
static void aor_observer_deleted(const void *obj) { const struct ast_sip_aor *aor = obj; struct ao2_container *contacts; contacts = ast_sip_location_retrieve_aor_contacts(aor); if (contacts) { ao2_callback(contacts, OBJ_NODATA, unschedule_contact_cb, NULL); ao2_ref(contacts, -1); } }