Example #1
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");
}
Example #2
0
/*!
 * \internal
 * \brief Remove the contact from the scheduler.
 */
static void unschedule_qualify(struct ast_sip_contact *contact)
{
	struct sched_data *data;

	data = ao2_find(sched_qualifies, contact, OBJ_UNLINK | OBJ_SEARCH_KEY);
	if (!data) {
		return;
	}

	AST_SCHED_DEL_UNREF(sched, data->id,
		ao2_t_ref(data, -1, "Delete scheduler entry ref"));
	ao2_t_ref(data, -1, "Done with ao2_find ref");
}
Example #3
0
static char *complete_show_sorcery_object(struct ao2_container *container,
	struct ast_sip_cli_formatter_entry *formatter_entry,
	const char *word, int state)
{
	char *result = NULL;
	int wordlen = strlen(word);
	int which = 0;

	struct ao2_iterator i = ao2_iterator_init(container, 0);
	void *object;

	while ((object = ao2_t_iterator_next(&i, "iterate thru endpoints table"))) {
		const char *id = formatter_entry->get_id(object);
		if (!strncasecmp(word, id, wordlen)
			&& ++which > state) {
			result = ast_strdup(id);
		}
		ao2_t_ref(object, -1, "toss iterator endpoint ptr before break");
		if (result) {
			break;
		}
	}
	ao2_iterator_destroy(&i);

	return result;
}
Example #4
0
/*!
 * \internal
 * \brief fopencookie()/funopen() stream close function.
 *
 * \param cookie Stream control data.
 *
 * \retval 0 on success.
 * \retval -1 on error.
 */
static int tcptls_stream_close(void *cookie)
{
	struct ast_tcptls_stream *stream = cookie;

	if (!stream) {
		errno = EBADF;
		return -1;
	}

	if (stream->fd != -1) {
#if defined(DO_SSL)
		if (stream->ssl) {
			int res;

			/*
			 * According to the TLS standard, it is acceptable for an
			 * application to only send its shutdown alert and then
			 * close the underlying connection without waiting for
			 * the peer's response (this way resources can be saved,
			 * as the process can already terminate or serve another
			 * connection).
			 */
			res = SSL_shutdown(stream->ssl);
			if (res < 0) {
				ast_log(LOG_ERROR, "SSL_shutdown() failed: %d\n",
					SSL_get_error(stream->ssl, res));
			}

			if (!stream->ssl->server) {
				/* For client threads, ensure that the error stack is cleared */
#if OPENSSL_VERSION_NUMBER >= 0x10000000L
				ERR_remove_thread_state(NULL);
#else
				ERR_remove_state(0);
#endif	/* OPENSSL_VERSION_NUMBER >= 0x10000000L */
			}

			SSL_free(stream->ssl);
			stream->ssl = NULL;
		}
#endif	/* defined(DO_SSL) */

		/*
		 * Issuing shutdown() is necessary here to avoid a race
		 * condition where the last data written may not appear
		 * in the TCP stream.  See ASTERISK-23548
		 */
		shutdown(stream->fd, SHUT_RDWR);
		if (close(stream->fd)) {
			ast_log(LOG_ERROR, "close() failed: %s\n", strerror(errno));
		}
		stream->fd = -1;
	}
	ao2_t_ref(stream, -1, "Closed tcptls stream cookie");

	return 0;
}
Example #5
0
static void session_instance_destructor(void *obj)
{
	struct ast_tcptls_session_instance *i = obj;

	if (i->stream_cookie) {
		ao2_t_ref(i->stream_cookie, -1, "Destroying tcptls session instance");
		i->stream_cookie = NULL;
	}
	ast_free(i->overflow_buf);
	ao2_cleanup(i->private_data);
}
Example #6
0
/*!
 * \internal
 * \brief Open a custom FILE stream for tcptls.
 *
 * \param stream Stream cookie control data.
 * \param ssl SSL state if not NULL.
 * \param fd Socket file descriptor.
 * \param timeout ms to wait for an event on fd. -1 if timeout disabled.
 *
 * \retval fp on success.
 * \retval NULL on error.
 */
static FILE *tcptls_stream_fopen(struct ast_tcptls_stream *stream, SSL *ssl, int fd, int timeout)
{
	FILE *fp;

#if defined(HAVE_FOPENCOOKIE)	/* the glibc/linux interface */
	static const cookie_io_functions_t cookie_funcs = {
		tcptls_stream_read,
		tcptls_stream_write,
		NULL,
		tcptls_stream_close
	};
#endif	/* defined(HAVE_FOPENCOOKIE) */

	if (fd == -1) {
		/* Socket not open. */
		return NULL;
	}

	stream->ssl = ssl;
	stream->fd = fd;
	stream->timeout = timeout;
	ao2_t_ref(stream, +1, "Opening tcptls stream cookie");

#if defined(HAVE_FUNOPEN)	/* the BSD interface */
	fp = funopen(stream, tcptls_stream_read, tcptls_stream_write, NULL,
		tcptls_stream_close);
#elif defined(HAVE_FOPENCOOKIE)	/* the glibc/linux interface */
	fp = fopencookie(stream, "w+", cookie_funcs);
#else
	/* could add other methods here */
	ast_debug(2, "No stream FILE methods attempted!\n");
	fp = NULL;
#endif

	if (!fp) {
		stream->fd = -1;
		ao2_t_ref(stream, -1, "Failed to open tcptls stream cookie");
	}
	return fp;
}
Example #7
0
static void cpg_confchg_cb(cpg_handle_t handle, const struct cpg_name *group_name,
		const struct cpg_address *member_list, size_t member_list_entries,
		const struct cpg_address *left_list, size_t left_list_entries,
		const struct cpg_address *joined_list, size_t joined_list_entries)
{
	unsigned int i;


	for (i = 0; i < left_list_entries; i++) {
		const struct cpg_address *cpg_node = &left_list[i];
		struct corosync_node* node;

		node = ao2_find(nodes, &cpg_node->nodeid, OBJ_UNLINK | OBJ_SEARCH_KEY);
		if (!node) {
			continue;
		}

		publish_cluster_discovery_to_stasis_full(node, 0);
		ao2_ref(node, -1);
	}

	/* If any new nodes have joined, dump our cache of events we are publishing
	 * that originated from this server. */
	if (!joined_list_entries) {
		return;
	}

	for (i = 0; i < ARRAY_LEN(event_types); i++) {
		struct ao2_container *messages;

		ast_rwlock_rdlock(&event_types_lock);
		if (!event_types[i].publish) {
			ast_rwlock_unlock(&event_types_lock);
			continue;
		}

		if (!event_types[i].cache_fn || !event_types[i].message_type_fn) {
			ast_rwlock_unlock(&event_types_lock);
			continue;
		}

		messages = stasis_cache_dump_by_eid(event_types[i].cache_fn(),
			event_types[i].message_type_fn(),
			&ast_eid_default);
		ast_rwlock_unlock(&event_types_lock);

		ao2_callback(messages, OBJ_NODATA, dump_cache_cb, NULL);

		ao2_t_ref(messages, -1, "Dispose of dumped cache");
	}
}
Example #8
0
/*!
 * \internal
 * \brief Set up a scheduled qualify contact check.
 */
static void schedule_qualify(struct ast_sip_contact *contact, int initial_interval)
{
	struct sched_data *data;

	data = sched_data_create(contact);
	if (!data) {
		return;
	}

	ast_assert(contact->qualify_frequency != 0);

	ao2_t_ref(data, +1, "Ref for qualify_contact_sched() scheduler entry");
	data->id = ast_sched_add_variable(sched, initial_interval,
		qualify_contact_sched, data, 1);
	if (data->id < 0) {
		ao2_t_ref(data, -1, "Cleanup failed scheduler add");
		ast_log(LOG_ERROR, "Unable to schedule qualify for contact %s\n",
			contact->uri);
	} else if (!ao2_link(sched_qualifies, data)) {
		AST_SCHED_DEL_UNREF(sched, data->id,
			ao2_t_ref(data, -1, "Cleanup scheduler for failed ao2_link"));
	}
	ao2_t_ref(data, -1, "Done setting up scheduler entry");
}
Example #9
0
void ast_channel_internal_cleanup(struct ast_channel *chan)
{
	if (chan->dialed_causes) {
		ao2_t_ref(chan->dialed_causes, -1,
			"done with dialed causes since the channel is going away");
		chan->dialed_causes = NULL;
	}

	ast_string_field_free_memory(chan);

	chan->endpoint_forward = stasis_forward_cancel(chan->endpoint_forward);

	stasis_cp_single_unsubscribe(chan->topics);
	chan->topics = NULL;
}
Example #10
0
static void cpg_confchg_cb(cpg_handle_t handle, const struct cpg_name *group_name,
		const struct cpg_address *member_list, size_t member_list_entries,
		const struct cpg_address *left_list, size_t left_list_entries,
		const struct cpg_address *joined_list, size_t joined_list_entries)
{
	unsigned int i;

	/* If any new nodes have joined, dump our cache of events we are publishing
	 * that originated from this server. */

	if (!joined_list_entries) {
		return;
	}

	for (i = 0; i < ARRAY_LEN(event_types); i++) {
		struct ao2_container *messages;

		ast_rwlock_rdlock(&event_types_lock);
		if (!event_types[i].publish) {
			ast_rwlock_unlock(&event_types_lock);
			continue;
		}

		if (!event_types[i].cache_fn || !event_types[i].message_type_fn) {
			ast_rwlock_unlock(&event_types_lock);
			continue;
		}

		messages = stasis_cache_dump_by_eid(event_types[i].cache_fn(),
			event_types[i].message_type_fn(),
			&ast_eid_default);
		ast_rwlock_unlock(&event_types_lock);

		ao2_callback(messages, OBJ_NODATA, dump_cache_cb, NULL);

		ao2_t_ref(messages, -1, "Dispose of dumped cache");
	}
}
Example #11
0
static int sched_qualifies_empty(void *obj, void *arg, int flags)
{
	ao2_t_ref(obj, -1, "Release ref held by destroyed scheduler context.");
	return CMP_MATCH;
}
Example #12
0
static int unload_module(void)
{
	ao2_t_ref(native_rtp_bridge.format_capabilities, -1, "Dispose of capabilities in module unload");
	return ast_bridge_technology_unregister(&native_rtp_bridge);
}
Example #13
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;
}