/*! \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"); }
/*! * \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"); }
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; }
/*! * \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; }
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); }
/*! * \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; }
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"); } }
/*! * \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"); }
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; }
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"); } }
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; }
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); }
/* * 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; }