/*! \brief Observer callback for when a contact is created */ static void contact_expiration_observer_created(const void *object) { const struct ast_sip_contact *contact = object; struct contact_expiration *expiration; int expires = MAX(0, ast_tvdiff_ms(contact->expiration_time, ast_tvnow())); if (ast_tvzero(contact->expiration_time)) { return; } expiration = ao2_alloc_options(sizeof(*expiration), contact_expiration_destroy, AO2_ALLOC_OPT_LOCK_NOLOCK); if (!expiration) { return; } expiration->contact = (struct ast_sip_contact*)contact; ao2_ref(expiration->contact, +1); ao2_ref(expiration, +1); if ((expiration->sched = ast_sched_add(sched, expires, contact_expiration_expire, expiration)) < 0) { ao2_ref(expiration, -1); ast_log(LOG_ERROR, "Scheduled expiration for contact '%s' could not be performed, contact may persist past life\n", ast_sorcery_object_get_id(contact)); } else { ao2_link(contact_autoexpire, expiration); } ao2_ref(expiration, -1); }
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; }
/*! \brief Internal callback function which links static contacts into another container */ static int contact_link_static(void *obj, void *arg, int flags) { struct ao2_container *dest = arg; ao2_link(dest, obj); return 0; }
static void sorcery_astdb_retrieve_prefix(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *prefix, const size_t prefix_len) { const char *family_prefix = data; size_t family_len = strlen(family_prefix) + strlen(type) + 1; /* +1 for slash delimiter */ char family[family_len + 1]; char tree[prefix_len + 1]; RAII_VAR(struct ast_db_entry *, entries, NULL, ast_db_freetree); struct ast_db_entry *entry; snprintf(tree, sizeof(tree), "%.*s", (int) prefix_len, prefix); snprintf(family, sizeof(family), "%s/%s", family_prefix, type); if (!(entries = ast_db_gettree_by_prefix(family, tree))) { return; } for (entry = entries; entry; entry = entry->next) { /* The key in the entry includes the family, so we need to strip it out */ const char *key = entry->key + family_len + 2; RAII_VAR(struct ast_json *, json, NULL, ast_json_unref); struct ast_json_error error; RAII_VAR(void *, object, NULL, ao2_cleanup); RAII_VAR(struct ast_variable *, objset, NULL, ast_variables_destroy); if (!(json = ast_json_load_string(entry->data, &error)) || (ast_json_to_ast_variables(json, &objset) != AST_JSON_TO_AST_VARS_CODE_SUCCESS) || !(objset = sorcery_astdb_filter_objectset(objset, sorcery, type)) || !(object = ast_sorcery_alloc(sorcery, type, key)) || ast_sorcery_objectset_apply(sorcery, object, objset)) { return; } ao2_link(objects, object); } }
static int pthread_timer_open(void) { struct pthread_timer *timer; int fd; if (!(timer = ao2_alloc(sizeof(*timer), pthread_timer_destructor))) { errno = ENOMEM; return -1; } timer->pipe[PIPE_READ] = timer->pipe[PIPE_WRITE] = -1; timer->state = TIMER_STATE_IDLE; if (pipe(timer->pipe)) { ao2_ref(timer, -1); return -1; } ao2_lock(pthread_timers); if (!ao2_container_count(pthread_timers)) { ast_mutex_lock(&timing_thread.lock); ast_cond_signal(&timing_thread.cond); ast_mutex_unlock(&timing_thread.lock); } ao2_link(pthread_timers, timer); ao2_unlock(pthread_timers); fd = timer->pipe[PIPE_READ]; ao2_ref(timer, -1); return fd; }
static void *pthread_timer_open(void) { struct pthread_timer *timer; int i; if (!(timer = ao2_alloc(sizeof(*timer), pthread_timer_destructor))) { errno = ENOMEM; return NULL; } timer->pipe[PIPE_READ] = timer->pipe[PIPE_WRITE] = -1; timer->state = TIMER_STATE_IDLE; if (pipe(timer->pipe)) { ao2_ref(timer, -1); return NULL; } for (i = 0; i < ARRAY_LEN(timer->pipe); ++i) { int flags = fcntl(timer->pipe[i], F_GETFL); flags |= O_NONBLOCK; fcntl(timer->pipe[i], F_SETFL, flags); } ao2_lock(pthread_timers); if (!ao2_container_count(pthread_timers)) { ast_mutex_lock(&timing_thread.lock); ast_cond_signal(&timing_thread.cond); ast_mutex_unlock(&timing_thread.lock); } ao2_link(pthread_timers, timer); ao2_unlock(pthread_timers); return timer; }
/*! * \brief Add threads to the threadpool * * This function is called from the threadpool's control taskprocessor thread. * \param pool The pool that is expanding * \delta The number of threads to add to the pool */ static void grow(struct ast_threadpool *pool, int delta) { int i; int current_size = ao2_container_count(pool->active_threads) + ao2_container_count(pool->idle_threads); if (pool->options.max_size && current_size + delta > pool->options.max_size) { delta = pool->options.max_size - current_size; } ast_debug(3, "Increasing threadpool %s's size by %d\n", ast_taskprocessor_name(pool->tps), delta); for (i = 0; i < delta; ++i) { struct worker_thread *worker = worker_thread_alloc(pool); if (!worker) { return; } if (ao2_link(pool->idle_threads, worker)) { if (worker_thread_start(worker)) { ast_log(LOG_ERROR, "Unable to start worker thread %d. Destroying.\n", worker->id); ao2_unlink(pool->active_threads, worker); } } else { ast_log(LOG_WARNING, "Failed to activate worker thread %d. Destroying.\n", worker->id); } ao2_ref(worker, -1); } }
/*! * \brief Activate idle threads * * This function always returns CMP_MATCH because all workers that this * function acts on need to be seen as matches so they are unlinked from the * list of idle threads. * * Called as an ao2_callback in the threadpool's control taskprocessor thread. * \param obj The worker to activate * \param arg The pool where the worker belongs * \retval CMP_MATCH */ static int activate_thread(void *obj, void *arg, int flags) { struct worker_thread *worker = obj; struct ast_threadpool *pool = arg; if (!ao2_link(pool->active_threads, worker)) { /* If we can't link the idle thread into the active container, then * we'll just leave the thread idle and not wake it up. */ ast_log(LOG_WARNING, "Failed to activate thread %d. Remaining idle\n", worker->id); return 0; } if (worker_set_state(worker, ALIVE)) { ast_debug(1, "Failed to activate thread %d. It is dead\n", worker->id); /* The worker thread will no longer exist in the active threads or * idle threads container after this. */ ao2_unlink(pool->active_threads, worker); } return CMP_MATCH; }
static void parse_apps(const char *val) { char *apps = ast_strdupa(val); char *cur_app; if (!ast_cel_track_event(AST_CEL_APP_START) && !ast_cel_track_event(AST_CEL_APP_END)) { ast_log(LOG_WARNING, "An apps= config line, but not tracking APP events\n"); return; } while ((cur_app = strsep(&apps, ","))) { char *app; cur_app = ast_strip(cur_app); if (ast_strlen_zero(cur_app)) { continue; } if (!(app = ao2_alloc(strlen(cur_app) + 1, NULL))) { continue; } strcpy(app, cur_app); ao2_link(appset, app); ao2_ref(app, -1); app = NULL; } }
/*! \brief Custom handler for permanent URIs */ static int permanent_uri_handler(const struct aco_option *opt, struct ast_variable *var, void *obj) { struct ast_sip_aor *aor = obj; const char *aor_id = ast_sorcery_object_get_id(aor); char *contacts; char *contact_uri; if (ast_strlen_zero(var->value)) { return 0; } contacts = ast_strdupa(var->value); while ((contact_uri = ast_strip(strsep(&contacts, ",")))) { struct ast_sip_contact *contact; struct ast_sip_contact_status *status; char hash[33]; char contact_id[strlen(aor_id) + sizeof(hash) + 2]; if (ast_strlen_zero(contact_uri)) { continue; } if (ast_sip_validate_uri_length(contact_uri)) { ast_log(LOG_ERROR, "Contact uri or hostname length exceeds pjproject limit: %s\n", contact_uri); return -1; } if (!aor->permanent_contacts) { aor->permanent_contacts = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK, AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT, permanent_uri_sort_fn, NULL); if (!aor->permanent_contacts) { return -1; } } ast_md5_hash(hash, contact_uri); snprintf(contact_id, sizeof(contact_id), "%s@@%s", aor_id, hash); contact = ast_sorcery_alloc(ast_sip_get_sorcery(), "contact", contact_id); if (!contact) { return -1; } ast_string_field_set(contact, uri, contact_uri); status = ast_res_pjsip_find_or_create_contact_status(contact); if (!status) { ao2_ref(contact, -1); return -1; } ao2_ref(status, -1); ao2_link(aor->permanent_contacts, contact); ao2_ref(contact, -1); } return 0; }
static int cache_dump_cb(void *obj, void *arg, int flags) { struct cache_dump_data *cache_dump = arg; struct cache_entry *entry = obj; if (!cache_dump->type || entry->type == cache_dump->type) { ao2_link(cache_dump->cached, entry->snapshot); } return 0; }
int ast_datastores_add(struct ao2_container *datastores, struct ast_datastore *datastore) { ast_assert(datastore != NULL); ast_assert(datastore->info != NULL); ast_assert(!ast_strlen_zero(datastore->uid)); if (!ao2_link(datastores, datastore)) { return -1; } return 0; }
static void sorcery_astdb_retrieve_regex(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *regex) { const char *prefix = data; char family[strlen(prefix) + strlen(type) + 2]; char tree[strlen(regex) + 1]; RAII_VAR(struct ast_db_entry *, entries, NULL, ast_db_freetree); regex_t expression; struct ast_db_entry *entry; snprintf(family, sizeof(family), "%s/%s", prefix, type); if (regex[0] == '^') { /* * For performance reasons, try to create an astDB prefix * pattern from the regex to reduce the number of entries * retrieved from astDB for regex to then match. */ if (make_astdb_prefix_pattern(tree, regex)) { return; } } else { tree[0] = '\0'; } if (!(entries = ast_db_gettree(family, tree)) || regcomp(&expression, regex, REG_EXTENDED | REG_NOSUB)) { return; } for (entry = entries; entry; entry = entry->next) { /* The key in the entry includes the family, so we need to strip it out for regex purposes */ const char *key = entry->key + strlen(family) + 2; RAII_VAR(struct ast_json *, json, NULL, ast_json_unref); struct ast_json_error error; RAII_VAR(void *, object, NULL, ao2_cleanup); RAII_VAR(struct ast_variable *, objset, NULL, ast_variables_destroy); if (regexec(&expression, key, 0, NULL, 0)) { continue; } else if (!(json = ast_json_load_string(entry->data, &error)) || (ast_json_to_ast_variables(json, &objset) != AST_JSON_TO_AST_VARS_CODE_SUCCESS) || !(objset = sorcery_astdb_filter_objectset(objset, sorcery, type)) || !(object = ast_sorcery_alloc(sorcery, type, key)) || ast_sorcery_objectset_apply(sorcery, object, objset)) { regfree(&expression); return; } ao2_link(objects, object); } regfree(&expression); }
/*! * \brief Move a worker thread from the active container to the idle container. * * This function is called from the threadpool's control taskprocessor thread. * \param data A thread_worker_pair containing the threadpool and the worker to move. * \return 0 */ static int queued_active_thread_idle(void *data) { struct thread_worker_pair *pair = data; ao2_link(pair->pool->idle_threads, pair->worker); ao2_unlink(pair->pool->active_threads, pair->worker); threadpool_send_state_changed(pair->pool); ao2_ref(pair, -1); return 0; }
static int cli_message_to_snapshot(void *obj, void *arg, int flags) { struct stasis_message *message = obj; struct ao2_container *snapshots = arg; struct ast_channel_snapshot *snapshot = stasis_message_data(message); if (!strcmp(snapshot->type, "PJSIP")) { ao2_link(snapshots, snapshot); return CMP_MATCH; } return 0; }
/*! \brief Callback function which adds non-permanent contacts to a container */ static int registrar_add_non_permanent(void *obj, void *arg, int flags) { struct ast_sip_contact *contact = obj; struct ao2_container *container = arg; if (ast_tvzero(contact->expiration_time)) { return 0; } ao2_link(container, contact); return 0; }
static int create_mwi_subscriptions_for_endpoint(void *obj, void *arg, int flags) { RAII_VAR(struct mwi_subscription *, aggregate_sub, NULL, ao2_cleanup); struct ast_sip_endpoint *endpoint = obj; struct ao2_container *mwi_subscriptions = arg; char *mailboxes; char *mailbox; if (ast_strlen_zero(endpoint->subscription.mwi.mailboxes)) { return 0; } if (endpoint->subscription.mwi.aggregate) { aggregate_sub = mwi_subscription_alloc(endpoint, 0, NULL); if (!aggregate_sub) { return 0; } } mailboxes = ast_strdupa(endpoint->subscription.mwi.mailboxes); while ((mailbox = strsep(&mailboxes, ","))) { struct mwi_subscription *sub = aggregate_sub ?: mwi_subscription_alloc(endpoint, 0, NULL); RAII_VAR(struct mwi_stasis_subscription *, mwi_stasis_sub, mwi_stasis_subscription_alloc(mailbox, sub), ao2_cleanup); if (mwi_stasis_sub) { ao2_link(sub->stasis_subs, mwi_stasis_sub); } if (!aggregate_sub) { ao2_link(mwi_subscriptions, sub); ao2_cleanup(sub); } } if (aggregate_sub) { ao2_link(mwi_subscriptions, aggregate_sub); } return 0; }
/*! \brief Internal helper function which retrieves an object, or multiple objects, using fields for criteria */ static void *sorcery_astdb_retrieve_fields_common(const struct ast_sorcery *sorcery, void *data, const char *type, const struct ast_variable *fields, struct ao2_container *objects) { const char *prefix = data; char family[strlen(prefix) + strlen(type) + 2]; RAII_VAR(struct ast_db_entry *, entries, NULL, ast_db_freetree); struct ast_db_entry *entry; snprintf(family, sizeof(family), "%s/%s", prefix, type); if (!(entries = ast_db_gettree(family, NULL))) { return NULL; } for (entry = entries; entry; entry = entry->next) { const char *key = entry->key + strlen(family) + 2; RAII_VAR(struct ast_json *, json, NULL, ast_json_unref); struct ast_json_error error; RAII_VAR(struct ast_variable *, existing, NULL, ast_variables_destroy); void *object = NULL; if (!(json = ast_json_load_string(entry->data, &error))) { return NULL; } if (ast_json_to_ast_variables(json, &existing) != AST_JSON_TO_AST_VARS_CODE_SUCCESS) { return NULL; } existing = sorcery_astdb_filter_objectset(existing, sorcery, type); if (fields && !ast_variable_lists_match(existing, fields, 0)) { continue; } if (!(object = ast_sorcery_alloc(sorcery, type, key)) || ast_sorcery_objectset_apply(sorcery, object, existing)) { ao2_cleanup(object); return NULL; } if (!objects) { return object; } ao2_link(objects, object); ao2_cleanup(object); } return NULL; }
static void add_element(void) { char keybuf[100]; struct ht_element *x = ao2_alloc(sizeof(struct ht_element), ht_destroy); sprintf(keybuf,"key%08d", glob_highwater++); x->key = strdup(keybuf); x->val = strdup("interesting data"); #ifdef DEBUG printf("+ %s\n", keybuf); #endif ao2_link(glob_hashtab, x); els_added++; /* unprotected, sometimes off, but, not really important, either */ }
int ast_str_container_add(struct ao2_container *str_container, const char *add) { char *ao2_add; /* The ao2_add object is immutable so it doesn't need a lock of its own. */ ao2_add = ao2_alloc_options(strlen(add) + 1, NULL, AO2_ALLOC_OPT_LOCK_NOLOCK); if (!ao2_add) { return -1; } strcpy(ao2_add, add);/* Safe */ ao2_link(str_container, ao2_add); ao2_ref(ao2_add, -1); return 0; }
static struct serializer *serializer_find_or_create(const char *aor_name) { struct serializer *ser = ao2_find(serializers, aor_name, OBJ_SEARCH_KEY); if (ser) { return ser; } if (!(ser = serializer_create(aor_name))) { return NULL; } ao2_link(serializers, ser); return ser; }
int ast_channel_dialed_causes_add(const struct ast_channel *chan, const struct ast_control_pvt_cause_code *cause_code, int datalen) { struct ast_control_pvt_cause_code *ao2_cause_code; ao2_find(chan->dialed_causes, cause_code->chan_name, OBJ_KEY | OBJ_UNLINK | OBJ_NODATA); ao2_cause_code = ao2_alloc(datalen, NULL); if (ao2_cause_code) { memcpy(ao2_cause_code, cause_code, datalen); ao2_link(chan->dialed_causes, ao2_cause_code); ao2_ref(ao2_cause_code, -1); return 0; } else { return -1; } }
/*! * \brief Activate idle threads * * This function always returns CMP_MATCH because all workers that this * function acts on need to be seen as matches so they are unlinked from the * list of idle threads. * * Called as an ao2_callback in the threadpool's control taskprocessor thread. * \param obj The worker to activate * \param arg The pool where the worker belongs * \retval CMP_MATCH */ static int activate_thread(void *obj, void *arg, int flags) { struct worker_thread *worker = obj; struct ast_threadpool *pool = arg; if (!ao2_link(pool->active_threads, worker)) { /* If we can't link the idle thread into the active container, then * we'll just leave the thread idle and not wake it up. */ ast_log(LOG_WARNING, "Failed to activate thread %d. Remaining idle\n", worker->id); return 0; } worker_set_state(worker, ALIVE); return CMP_MATCH; }
/*! * \brief ao2 callback to zombify a set number of threads. * * Threads will be zombified as long as as the counter has not reached * zero. The counter is decremented with each thread that is zombified. * * Zombifying a thread involves removing it from its current container, * adding it to the zombie container, and changing the state of the * worker to a zombie * * This callback is called from the threadpool control taskprocessor thread. * * \param obj The worker thread that may be zombified * \param arg The pool to which the worker belongs * \param data The counter * \param flags Unused * \retval CMP_MATCH The zombified thread should be removed from its current container * \retval CMP_STOP Stop attempting to zombify threads */ static int zombify_threads(void *obj, void *arg, void *data, int flags) { struct worker_thread *worker = obj; struct ast_threadpool *pool = arg; int *num_to_zombify = data; if ((*num_to_zombify)-- > 0) { if (!ao2_link(pool->zombie_threads, worker)) { ast_log(LOG_WARNING, "Failed to zombify active thread %d. Thread will remain active\n", worker->id); return 0; } worker_set_state(worker, ZOMBIE); return CMP_MATCH; } else { return CMP_STOP; } }
void ast_multi_channel_blob_add_channel(struct ast_multi_channel_blob *obj, const char *role, struct ast_channel_snapshot *snapshot) { RAII_VAR(struct channel_role_snapshot *, role_snapshot, NULL, ao2_cleanup); int role_len = strlen(role) + 1; if (!obj || ast_strlen_zero(role) || !snapshot) { return; } role_snapshot = ao2_alloc(sizeof(*role_snapshot) + role_len, channel_role_snapshot_dtor); if (!role_snapshot) { return; } ast_copy_string(role_snapshot->role, role, role_len); role_snapshot->snapshot = snapshot; ao2_ref(role_snapshot->snapshot, +1); ao2_link(obj->channel_snapshots, role_snapshot); }
void ast_format_cap_add(struct ast_format_cap *cap, const struct ast_format *format) { struct ast_format *fnew; if (!format || !format->id) { return; } if (!(fnew = ao2_alloc(sizeof(struct ast_format), NULL))) { return; } ast_format_copy(fnew, format); if (cap->nolock) { ao2_link_nolock(cap->formats, fnew); } else { ao2_link(cap->formats, fnew); } ao2_ref(fnew, -1); }
struct ast_sip_sched_task *ast_sip_schedule_task(struct ast_taskprocessor *serializer, int interval, ast_sip_task sip_task, char *name, void *task_data, enum ast_sip_scheduler_task_flags flags) { #define ID_LEN 13 /* task_deadbeef */ struct ast_sip_sched_task *schtd; int res; if (interval < 0) { return NULL; } schtd = ao2_alloc((sizeof(*schtd) + (!ast_strlen_zero(name) ? strlen(name) : ID_LEN) + 1), schtd_destructor); if (!schtd) { return NULL; } schtd->task_id = ast_atomic_fetchadd_int(&task_count, 1); schtd->serializer = serializer; schtd->task = sip_task; if (!ast_strlen_zero(name)) { strcpy(schtd->name, name); /* Safe */ } else { sprintf(schtd->name, "task_%08x", schtd->task_id); } schtd->task_data = task_data; schtd->flags = flags; schtd->interval = interval; schtd->when_queued = ast_tvnow(); if (flags & AST_SIP_SCHED_TASK_DATA_AO2) { ao2_ref(task_data, +1); } res = ast_sched_add(scheduler_context, interval, push_to_serializer, (const void *)schtd); if (res < 0) { ao2_ref(schtd, -1); return NULL; } else { schtd->current_scheduler_id = res; ao2_link(tasks, schtd); } return schtd; #undef ID_LEN }
/*! \brief Custom handler for permanent URIs */ static int permanent_uri_handler(const struct aco_option *opt, struct ast_variable *var, void *obj) { struct ast_sip_aor *aor = obj; const char *aor_id = ast_sorcery_object_get_id(aor); char *contacts; char *contact_uri; if (ast_strlen_zero(var->value)) { return 0; } contacts = ast_strdupa(var->value); while ((contact_uri = strsep(&contacts, ","))) { struct ast_sip_contact *contact; char contact_id[strlen(aor_id) + strlen(contact_uri) + 2 + 1]; if (ast_sip_push_task_synchronous(NULL, permanent_contact_validate, contact_uri)) { ast_log(LOG_ERROR, "Permanent URI on aor '%s' with contact '%s' failed to parse\n", ast_sorcery_object_get_id(aor), contact_uri); return -1; } if (!aor->permanent_contacts) { aor->permanent_contacts = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK, AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT, permanent_uri_sort_fn, NULL); if (!aor->permanent_contacts) { return -1; } } snprintf(contact_id, sizeof(contact_id), "%s@@%s", aor_id, contact_uri); contact = ast_sorcery_alloc(ast_sip_get_sorcery(), "contact", contact_id); if (!contact) { return -1; } ast_string_field_set(contact, uri, contact_uri); ao2_link(aor->permanent_contacts, contact); ao2_ref(contact, -1); } return 0; }
/*! \brief Internal helper function which retrieves an object, or multiple objects, using fields for criteria */ static void *sorcery_astdb_retrieve_fields_common(const struct ast_sorcery *sorcery, void *data, const char *type, const struct ast_variable *fields, struct ao2_container *objects) { const char *prefix = data; char family[strlen(prefix) + strlen(type) + 2]; RAII_VAR(struct ast_db_entry *, entries, NULL, ast_db_freetree); RAII_VAR(struct ast_json *, criteria, NULL, ast_json_unref); struct ast_db_entry *entry; snprintf(family, sizeof(family), "%s/%s", prefix, type); if (!(entries = ast_db_gettree(family, NULL)) || (fields && !(criteria = sorcery_objectset_to_json(fields)))) { return NULL; } for (entry = entries; entry; entry = entry->next) { const char *key = entry->key + strlen(family) + 2; RAII_VAR(struct ast_json *, json, NULL, ast_json_unref); struct ast_json_error error; RAII_VAR(struct ast_variable *, objset, NULL, ast_variables_destroy); void *object = NULL; if (!(json = ast_json_load_string(entry->data, &error))) { return NULL; } else if (criteria && !sorcery_json_equal(json, criteria)) { continue; } else if (!(objset = sorcery_json_to_objectset(json)) || !(object = ast_sorcery_alloc(sorcery, type, key)) || ast_sorcery_objectset_apply(sorcery, object, objset)) { ao2_cleanup(object); return NULL; } if (!objects) { return object; } ao2_link(objects, object); ao2_cleanup(object); } return NULL; }
static int kqueue_timer_open(void) { struct kqueue_timer *timer; int handle; if (!(timer = ao2_alloc(sizeof(*timer), timer_destroy))) { ast_log(LOG_ERROR, "Could not allocate memory for kqueue_timer structure\n"); return -1; } if ((handle = kqueue()) < 0) { ast_log(LOG_ERROR, "Failed to create kqueue timer: %s\n", strerror(errno)); ao2_ref(timer, -1); return -1; } timer->handle = handle; ao2_link(kqueue_timers, timer); /* Get rid of the reference from the allocation */ ao2_ref(timer, -1); return handle; }