/*! \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);
}
Пример #2
0
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;
}
Пример #3
0
/*! \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;
}
Пример #4
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);
	}
}
Пример #5
0
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;
}
Пример #6
0
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;
}
Пример #7
0
/*!
 * \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);
	}
}
Пример #8
0
/*!
 * \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;
}
Пример #9
0
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;
	}
}
Пример #10
0
/*! \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;
}
Пример #11
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;
}
Пример #12
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;
}
Пример #13
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);
}
Пример #14
0
/*!
 * \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;
}
Пример #15
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;
}
Пример #16
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;
}
Пример #17
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;
}
Пример #18
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;
}
Пример #19
0
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 */
}
Пример #20
0
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;
}
Пример #21
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;
}
Пример #22
0
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;
	}
}
Пример #23
0
/*!
 * \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;
}
Пример #24
0
/*!
 * \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;
	}
}
Пример #25
0
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);
}
Пример #26
0
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);
}
Пример #27
0
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
}
Пример #28
0
/*! \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;
}
Пример #29
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;
}
Пример #30
0
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;
}