static struct stasis_message_router *stasis_message_router_create_internal(
	struct stasis_topic *topic, int use_thread_pool)
{
	int res;
	RAII_VAR(struct stasis_message_router *, router, NULL, ao2_cleanup);

	router = ao2_t_alloc(sizeof(*router), router_dtor, stasis_topic_name(topic));
	if (!router) {
		return NULL;
	}

	res = 0;
	res |= AST_VECTOR_INIT(&router->routes, 0);
	res |= AST_VECTOR_INIT(&router->cache_routes, 0);
	if (res) {
		return NULL;
	}

	if (use_thread_pool) {
		router->subscription = stasis_subscribe_pool(topic, router_dispatch, router);
	} else {
		router->subscription = stasis_subscribe(topic, router_dispatch, router);
	}
	if (!router->subscription) {
		return NULL;
	}

	ao2_ref(router, +1);
	return router;
}
예제 #2
0
파일: stasis.c 프로젝트: GGGO/asterisk
struct stasis_subscription *internal_stasis_subscribe(
	struct stasis_topic *topic,
	stasis_subscription_cb callback,
	void *data,
	int needs_mailbox,
	int use_thread_pool)
{
	RAII_VAR(struct stasis_subscription *, sub, NULL, ao2_cleanup);

	if (!topic) {
		return NULL;
	}

	/* The ao2 lock is used for join_cond. */
	sub = ao2_t_alloc(sizeof(*sub), subscription_dtor, stasis_topic_name(topic));
	if (!sub) {
		return NULL;
	}
	ast_uuid_generate_str(sub->uniqueid, sizeof(sub->uniqueid));

	if (needs_mailbox) {
		char tps_name[AST_TASKPROCESSOR_MAX_NAME + 1];

		/* Create name with seq number appended. */
		ast_taskprocessor_build_name(tps_name, sizeof(tps_name), "sub%c:%s",
			use_thread_pool ? 'p' : 'm',
			stasis_topic_name(topic));

		/*
		 * With a small number of subscribers, a thread-per-sub is
		 * acceptable. For a large number of subscribers, a thread
		 * pool should be used.
		 */
		if (use_thread_pool) {
			sub->mailbox = ast_threadpool_serializer(tps_name, pool);
		} else {
			sub->mailbox = ast_taskprocessor_get(tps_name, TPS_REF_DEFAULT);
		}
		if (!sub->mailbox) {
			return NULL;
		}
		ast_taskprocessor_set_local(sub->mailbox, sub);
		/* Taskprocessor has a reference */
		ao2_ref(sub, +1);
	}

	ao2_ref(topic, +1);
	sub->topic = topic;
	sub->callback = callback;
	sub->data = data;
	ast_cond_init(&sub->join_cond, NULL);

	if (topic_add_subscription(topic, sub) != 0) {
		return NULL;
	}
	send_subscription_subscribe(topic, sub);

	ao2_ref(sub, +1);
	return sub;
}
예제 #3
0
/*! \brief Publish a Corosync ping to \ref stasis */
static void publish_corosync_ping_to_stasis(struct ast_event *event)
{
	struct corosync_ping_payload *payload;
	struct stasis_message *message;

	ast_assert(ast_event_get_type(event) == AST_EVENT_PING);
	ast_assert(event != NULL);

	if (!corosync_ping_message_type()) {
		return;
	}

	payload = ao2_t_alloc(sizeof(*payload), corosync_ping_payload_dtor, "Create ping payload");
	if (!payload) {
		return;
	}
	payload->event = event;

	message = stasis_message_create(corosync_ping_message_type(), payload);
	if (!message) {
		ao2_t_ref(payload, -1, "Destroy payload on off nominal");
		return;
	}

	stasis_publish(corosync_topic(), message);

	ao2_t_ref(payload, -1, "Hand ref to stasis");
	ao2_t_ref(message, -1, "Hand ref to stasis");
}
예제 #4
0
struct stasis_cp_all *stasis_cp_all_create(const char *name,
	snapshot_get_id id_fn)
{
	char *cached_name = NULL;
	struct stasis_cp_all *all;
	static int cache_id;

	all = ao2_t_alloc(sizeof(*all), all_dtor, name);
	if (!all) {
		return NULL;
	}

	ast_asprintf(&cached_name, "cache_pattern:%d/%s", ast_atomic_fetchadd_int(&cache_id, +1), name);
	if (!cached_name) {
		ao2_ref(all, -1);

		return NULL;
	}

	all->topic = stasis_topic_create(name);
	all->topic_cached = stasis_topic_create(cached_name);
	ast_free(cached_name);
	all->cache = stasis_cache_create(id_fn);
	all->forward_all_to_cached =
		stasis_forward_all(all->topic, all->topic_cached);

	if (!all->topic || !all->topic_cached || !all->cache ||
		!all->forward_all_to_cached) {
		ao2_ref(all, -1);

		return NULL;
	}

	return all;
}
예제 #5
0
struct stasis_cp_single *stasis_cp_sink_create(struct stasis_cp_all *all,
	const char *name)
{
	struct stasis_cp_single *one;

	one = ao2_t_alloc(sizeof(*one), one_dtor, name);
	if (!one) {
		return NULL;
	}

	one->topic = stasis_topic_create(name);
	if (!one->topic) {
		ao2_ref(one, -1);

		return NULL;
	}

	one->topic_cached = stasis_caching_topic_create(one->topic, all->cache);
	if (!one->topic_cached) {
		ao2_ref(one, -1);

		return NULL;
	}

	return one;
}
struct stasis_cp_all *stasis_cp_all_create(const char *name,
	snapshot_get_id id_fn)
{
	RAII_VAR(char *, cached_name, NULL, ast_free);
	RAII_VAR(struct stasis_cp_all *, all, NULL, ao2_cleanup);

	all = ao2_t_alloc(sizeof(*all), all_dtor, name);
	if (!all) {
		return NULL;
	}

	ast_asprintf(&cached_name, "%s-cached", name);
	if (!cached_name) {
		return NULL;
	}

	all->topic = stasis_topic_create(name);
	all->topic_cached = stasis_topic_create(cached_name);
	all->cache = stasis_cache_create(id_fn);
	all->forward_all_to_cached =
		stasis_forward_all(all->topic, all->topic_cached);

	if (!all->topic || !all->topic_cached || !all->cache ||
		!all->forward_all_to_cached) {
		return NULL;
	}

	ao2_ref(all, +1);
	return all;
}
struct stasis_cp_single *stasis_cp_single_create(struct stasis_cp_all *all,
	const char *name)
{
	RAII_VAR(struct stasis_cp_single *, one, NULL, ao2_cleanup);

	one = ao2_t_alloc(sizeof(*one), one_dtor, name);
	if (!one) {
		return NULL;
	}

	one->topic = stasis_topic_create(name);
	if (!one->topic) {
		return NULL;
	}
	one->topic_cached = stasis_caching_topic_create(one->topic, all->cache);
	if (!one->topic_cached) {
		return NULL;
	}

	one->forward_topic_to_all = stasis_forward_all(one->topic, all->topic);
	if (!one->forward_topic_to_all) {
		return NULL;
	}
	one->forward_cached_to_all = stasis_forward_all(
		stasis_caching_get_topic(one->topic_cached), all->topic_cached);
	if (!one->forward_cached_to_all) {
		return NULL;
	}

	ao2_ref(one, +1);
	return one;
}
예제 #8
0
파일: stasis.c 프로젝트: cfhb/vlink-cti
struct stasis_subscription *internal_stasis_subscribe(
	struct stasis_topic *topic,
	stasis_subscription_cb callback,
	void *data,
	int needs_mailbox,
	int use_thread_pool)
{
	RAII_VAR(struct stasis_subscription *, sub, NULL, ao2_cleanup);

	if (!topic) {
		return NULL;
	}

	/* The ao2 lock is used for join_cond. */
	sub = ao2_t_alloc(sizeof(*sub), subscription_dtor, topic->name);
	if (!sub) {
		return NULL;
	}
	ast_uuid_generate_str(sub->uniqueid, sizeof(sub->uniqueid));

	if (needs_mailbox) {
		/* With a small number of subscribers, a thread-per-sub is
		 * acceptable. For larger number of subscribers, a thread
		 * pool should be used.
		 */
		if (use_thread_pool) {
			sub->mailbox = ast_threadpool_serializer(sub->uniqueid, pool);
		} else {
			sub->mailbox = ast_taskprocessor_get(sub->uniqueid,
				TPS_REF_DEFAULT);
		}
		if (!sub->mailbox) {
			return NULL;
		}
		ast_taskprocessor_set_local(sub->mailbox, sub);
		/* Taskprocessor has a reference */
		ao2_ref(sub, +1);
	}

	ao2_ref(topic, +1);
	sub->topic = topic;
	sub->callback = callback;
	sub->data = data;
	ast_cond_init(&sub->join_cond, NULL);

	if (topic_add_subscription(topic, sub) != 0) {
		return NULL;
	}
	send_subscription_subscribe(topic, sub);

	ao2_ref(sub, +1);
	return sub;
}
예제 #9
0
/*!
 * \internal
 * \brief Create the scheduling data object.
 */
static struct sched_data *sched_data_create(struct ast_sip_contact *contact)
{
	struct sched_data *data;

	data = ao2_t_alloc(sizeof(*data), sched_data_destructor, contact->uri);
	if (!data) {
		ast_log(LOG_ERROR, "Unable to create schedule qualify data for contact %s\n",
			contact->uri);
		return NULL;
	}

	data->contact = contact;
	ao2_ref(data->contact, +1);

	return data;
}
예제 #10
0
파일: app.c 프로젝트: roramirez/asterisk
static struct app_forwards *forwards_create(struct stasis_app *app,
	const char *id)
{
	struct app_forwards *forwards;

	if (!app || ast_strlen_zero(id)) {
		return NULL;
	}

	forwards = ao2_t_alloc(sizeof(*forwards) + strlen(id) + 1, forwards_dtor, id);
	if (!forwards) {
		return NULL;
	}

	strcpy(forwards->id, id); /* SAFE */

	return forwards;
}
예제 #11
0
파일: stasis.c 프로젝트: GGGO/asterisk
struct stasis_topic *stasis_topic_create(const char *name)
{
	struct stasis_topic *topic;
	int res = 0;

	topic = ao2_t_alloc(sizeof(*topic), topic_dtor, name);
	if (!topic) {
		return NULL;
	}

	topic->name = ast_strdup(name);
	res |= AST_VECTOR_INIT(&topic->subscribers, INITIAL_SUBSCRIBERS_MAX);
	res |= AST_VECTOR_INIT(&topic->upstream_topics, 0);
	if (!topic->name || res) {
		ao2_cleanup(topic);
		return NULL;
	}

	return topic;
}
예제 #12
0
/*
 * This is testing code for astobj
 */
static char *handle_astobj2_test(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
{
	struct ao2_container *c1;
	struct ao2_container *c2;
	int i, lim;
	char *obj;
	static int prof_id = -1;
	struct ast_cli_args fake_args = { a->fd, 0, NULL };

	switch (cmd) {
	case CLI_INIT:
		e->command = "astobj2 test";
		e->usage = "Usage: astobj2 test <num>\n"
			   "       Runs astobj2 test. Creates 'num' objects,\n"
			   "       and test iterators, callbacks and maybe other stuff\n";
		return NULL;
	case CLI_GENERATE:
		return NULL;
	}

	if (a->argc != 3) {
		return CLI_SHOWUSAGE;
	}

	if (prof_id == -1) {
		prof_id = ast_add_profile("ao2_alloc", 0);
	}

	ast_cli(a->fd, "argc %d argv %s %s %s\n", a->argc, a->argv[0], a->argv[1], a->argv[2]);
	lim = atoi(a->argv[2]);
	ast_cli(a->fd, "called astobj_test\n");

	handle_astobj2_stats(e, CLI_HANDLER, &fake_args);
	/*
	 * Allocate a list container.
	 */
	c1 = ao2_t_container_alloc_list(AO2_ALLOC_OPT_LOCK_MUTEX, 0, NULL /* no sort */,
		NULL /* no callback */, "test");
	ast_cli(a->fd, "container allocated as %p\n", c1);

	/*
	 * fill the container with objects.
	 * ao2_alloc() gives us a reference which we pass to the
	 * container when we do the insert.
	 */
	for (i = 0; i < lim; i++) {
		ast_mark(prof_id, 1 /* start */);
		obj = ao2_t_alloc(80, NULL,"test");
		ast_mark(prof_id, 0 /* stop */);
		ast_cli(a->fd, "object %d allocated as %p\n", i, obj);
		sprintf(obj, "-- this is obj %d --", i);
		ao2_link(c1, obj);
		/* At this point, the refcount on obj is 2 due to the allocation
		 * and linking. We can go ahead and reduce the refcount by 1
		 * right here so that when the container is unreffed later, the
		 * objects will be freed
		 */
		ao2_t_ref(obj, -1, "test");
	}

	ast_cli(a->fd, "testing callbacks\n");
	ao2_t_callback(c1, 0, print_cb, a, "test callback");

	ast_cli(a->fd, "testing container cloning\n");
	c2 = ao2_container_clone(c1, 0);
	if (ao2_container_count(c1) != ao2_container_count(c2)) {
		ast_cli(a->fd, "Cloned container does not have the same number of objects!\n");
	}
	ao2_t_callback(c2, 0, print_cb, a, "test callback");

	ast_cli(a->fd, "testing iterators, remove every second object\n");
	{
		struct ao2_iterator ai;
		int x = 0;

		ai = ao2_iterator_init(c1, 0);
		while ( (obj = ao2_t_iterator_next(&ai,"test")) ) {
			ast_cli(a->fd, "iterator on <%s>\n", obj);
			if (x++ & 1)
				ao2_t_unlink(c1, obj,"test");
			ao2_t_ref(obj, -1,"test");
		}
		ao2_iterator_destroy(&ai);
		ast_cli(a->fd, "testing iterators again\n");
		ai = ao2_iterator_init(c1, 0);
		while ( (obj = ao2_t_iterator_next(&ai,"test")) ) {
			ast_cli(a->fd, "iterator on <%s>\n", obj);
			ao2_t_ref(obj, -1,"test");
		}
		ao2_iterator_destroy(&ai);
	}

	ast_cli(a->fd, "testing callbacks again\n");
	ao2_t_callback(c1, 0, print_cb, a, "test callback");

	ast_verbose("now you should see an error and possible assertion failure messages:\n");
	ao2_t_ref(&i, -1, "");	/* i is not a valid object so we print an error here */

	ast_cli(a->fd, "destroy container\n");
	ao2_t_ref(c1, -1, "");	/* destroy container */
	ao2_t_ref(c2, -1, "");	/* destroy container */
	handle_astobj2_stats(e, CLI_HANDLER, &fake_args);
	return CLI_SUCCESS;
}