int AST_OPTIONAL_API_NAME(ast_websocket_server_add_protocol)(struct ast_websocket_server *server, const char *name, ast_websocket_callback callback) { struct websocket_protocol *protocol; if (!server->protocols) { return -1; } ao2_lock(server->protocols); /* Ensure a second protocol handler is not registered for the same protocol */ if ((protocol = ao2_find(server->protocols, name, OBJ_KEY | OBJ_NOLOCK))) { ao2_ref(protocol, -1); ao2_unlock(server->protocols); return -1; } if (!(protocol = ao2_alloc(sizeof(*protocol), protocol_destroy_fn))) { ao2_unlock(server->protocols); return -1; } if (!(protocol->name = ast_strdup(name))) { ao2_ref(protocol, -1); ao2_unlock(server->protocols); return -1; } protocol->callback = callback; ao2_link_flags(server->protocols, protocol, OBJ_NOLOCK); ao2_unlock(server->protocols); ao2_ref(protocol, -1); ast_verb(2, "WebSocket registered sub-protocol '%s'\n", name); return 0; }
/*! * \brief Performs common setup for a bridge playback operation * with both new controls and when existing controls are found. * * \param args_media medias to play * \param args_media_count number of media items in \c media * \param args_lang language string split from arguments * \param args_offset_ms milliseconds offset split from arguments * \param args_playback_id string to use for playback split from * arguments (null valid) * \param response ARI response being built * \param bridge Bridge the playback is being peformed on * \param found_channel The channel that was found controlling playback * * \retval PLAY_FOUND_SUCCESS The operation was successful * \retval PLAY_FOUND_FAILURE The operation failed (terminal failure) * \retval PLAY_FOUND_CHANNEL_UNAVAILABLE The operation failed because * the channel requested to playback with is breaking down. */ static enum play_found_result ari_bridges_play_found(const char **args_media, size_t args_media_count, const char *args_lang, int args_offset_ms, int args_skipms, const char *args_playback_id, struct ast_ari_response *response, struct ast_bridge *bridge, struct ast_channel *found_channel) { RAII_VAR(struct ast_channel *, play_channel, found_channel, ao2_cleanup); RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup); RAII_VAR(char *, playback_url, NULL, ast_free); RAII_VAR(struct ast_json *, json, NULL, ast_json_unref); control = stasis_app_control_find_by_channel(play_channel); if (!control) { return PLAY_FOUND_CHANNEL_UNAVAILABLE; } ao2_lock(control); if (stasis_app_control_is_done(control)) { /* We failed to queue the action. Bailout and return that we aren't terminal. */ ao2_unlock(control); return PLAY_FOUND_CHANNEL_UNAVAILABLE; } if (ari_bridges_play_helper(args_media, args_media_count, args_lang, args_offset_ms, args_skipms, args_playback_id, response, bridge, control, &json, &playback_url)) { ao2_unlock(control); return PLAY_FOUND_FAILURE; } ao2_unlock(control); ast_ari_response_created(response, playback_url, ast_json_ref(json)); return PLAY_FOUND_SUCCESS; }
void ast_threadpool_shutdown(struct ast_threadpool *pool) { if (!pool) { return; } /* Shut down the taskprocessors and everything else just * takes care of itself via the taskprocessor callbacks */ ao2_lock(pool); pool->shutting_down = 1; ao2_unlock(pool); ast_taskprocessor_unreference(pool->control_tps); ast_taskprocessor_unreference(pool->tps); }
/*! \internal * \brief cmp format attributes using an interface */ static enum ast_format_cmp_res format_cmp_helper(const struct ast_format *format1, const struct ast_format *format2) { enum ast_format_cmp_res res = AST_FORMAT_CMP_EQUAL; struct interface_ao2_wrapper *wrapper; if (!(wrapper = find_interface(format1))) { return res; } ao2_rdlock(wrapper); if (!wrapper->interface || !wrapper->interface->format_attr_cmp) { ao2_unlock(wrapper); ao2_ref(wrapper, -1); return res; } res = wrapper->interface->format_attr_cmp(&format1->fattr, &format2->fattr); ao2_unlock(wrapper); ao2_ref(wrapper, -1); return res; }
int stasis_message_router_set_default(struct stasis_message_router *router, stasis_subscription_cb callback, void *data) { ast_assert(router != NULL); ast_assert(callback != NULL); ao2_lock(router); router->default_route.callback = callback; router->default_route.data = data; ao2_unlock(router); /* While this implementation can never fail, it used to be able to */ return 0; }
void stasis_message_router_remove_cache_update( struct stasis_message_router *router, struct stasis_message_type *message_type) { ast_assert(router != NULL); if (!message_type) { /* Cannot remove a NULL type. */ return; } ao2_lock(router); route_table_remove(&router->cache_routes, message_type); ao2_unlock(router); }
static void check_endpoint(pjsip_rx_data *rdata, struct unidentified_request *unid, const char *name) { int64_t ms = ast_tvdiff_ms(ast_tvnow(), unid->first_seen); ao2_wrlock(unid); unid->count++; if (ms < (unidentified_period * 1000) && unid->count >= unidentified_count) { log_failed_request(rdata, "No matching endpoint found", unid->count, ms); ast_sip_report_invalid_endpoint(name, rdata); } ao2_unlock(unid); }
/* Called with ast locked */ int ast_unreal_queryoption(struct ast_channel *ast, int option, void *data, int *datalen) { struct ast_unreal_pvt *p; struct ast_channel *peer; struct ast_channel *other; int res = 0; if (option != AST_OPTION_T38_STATE) { /* AST_OPTION_T38_STATE is the only supported option at this time */ return -1; } /* for some reason the channel is not locked in channel.c when this function is called */ if (!(p = ast_channel_tech_pvt(ast))) { return -1; } ao2_lock(p); other = AST_UNREAL_IS_OUTBOUND(ast, p) ? p->owner : p->chan; if (!other) { ao2_unlock(p); return -1; } ast_channel_ref(other); ao2_unlock(p); ast_channel_unlock(ast); /* Held when called, unlock before locking another channel */ peer = ast_channel_bridge_peer(other); if (peer) { res = ast_channel_queryoption(peer, option, data, datalen, 0); ast_channel_unref(peer); } ast_channel_unref(other); ast_channel_lock(ast); /* Lock back before we leave */ return res; }
int ast_format_get_value(const struct ast_format *format, int key, void *value) { int res = 0; struct interface_ao2_wrapper *wrapper; if (!(wrapper = find_interface(format))) { return -1; } ao2_rdlock(wrapper); if (!wrapper->interface || !wrapper->interface->format_attr_get_val) { ao2_unlock(wrapper); ao2_ref(wrapper, -1); return -1; } res = wrapper->interface->format_attr_get_val(&format->fattr, key, value); ao2_unlock(wrapper); ao2_ref(wrapper, -1); return res; }
void app_shutdown(struct stasis_app *app) { ao2_lock(app); ast_assert(app_is_finished(app)); stasis_message_router_unsubscribe(app->router); app->router = NULL; stasis_message_router_unsubscribe(app->bridge_router); app->bridge_router = NULL; stasis_message_router_unsubscribe(app->endpoint_router); app->endpoint_router = NULL; ao2_unlock(app); }
int ast_sip_location_add_contact(struct ast_sip_aor *aor, const char *uri, struct timeval expiration_time, const char *path_info, const char *user_agent, const char *via_addr, int via_port, const char *call_id, struct ast_sip_endpoint *endpoint) { int res; ao2_lock(aor); res = ast_sip_location_add_contact_nolock(aor, uri, expiration_time, path_info, user_agent, via_addr, via_port, call_id, endpoint); ao2_unlock(aor); return res; }
/*! * \internal * \since 12.0.0 * \brief If we are down to the last reference of a wrapper and it's still contained within the list, remove it from the list. * * \param wrapper reference to wait bridge wrapper being checked for list culling - will be cleared on exit */ static void wait_wrapper_removal(struct wait_bridge_wrapper *wrapper) { if (!wrapper) { return; } ao2_lock(wait_bridge_wrappers); if (ao2_ref(wrapper, 0) == 2) { /* Either we have the only real reference or else wrapper isn't in the container anyway. */ ao2_unlink(wait_bridge_wrappers, wrapper); } ao2_unlock(wait_bridge_wrappers); ao2_cleanup(wrapper); }
int __ast_named_lock_put(const char *filename, int lineno, const char *func, struct ast_named_lock *lock) { if (!lock) { return -1; } ao2_lock(named_locks); if (ao2_ref(lock, -1) == 2) { ao2_unlink_flags(named_locks, lock, OBJ_NOLOCK); } ao2_unlock(named_locks); return 0; }
void sccpconf_announce_channel_depart(struct ast_channel *chan) { struct announce_pvt *p = ast_channel_tech_pvt(chan); if (!p) { return; } ao2_ref(p, +1); ao2_lock(p); if (!ast_test_flag(&p->base, AST_UNREAL_CARETAKER_THREAD)) { ao2_unlock(p); ao2_ref(p, -1); return; } ast_clear_flag(&p->base, AST_UNREAL_CARETAKER_THREAD); chan = p->base.chan; ao2_unlock(p); ao2_ref(p, -1); if (chan) { ast_bridge_depart(chan); ast_channel_unref(chan); } }
/*! * \brief Send a pvt in with no locks held and get all locks * * \note NO locks should be held prior to calling this function * \note The pvt must have a ref held before calling this function * \note if outchan or outowner is set != NULL after calling this function * those channels are locked and reffed. * \note Batman. */ static void awesome_locking(struct local_pvt *p, struct ast_channel **outchan, struct ast_channel **outowner) { struct ast_channel *chan = NULL; struct ast_channel *owner = NULL; ao2_lock(p); for (;;) { if (p->chan) { chan = p->chan; ast_channel_ref(chan); } if (p->owner) { owner = p->owner; ast_channel_ref(owner); } ao2_unlock(p); /* if we don't have both channels, then this is very easy */ if (!owner || !chan) { if (owner) { ast_channel_lock(owner); } else if(chan) { ast_channel_lock(chan); } } else { /* lock both channels first, then get the pvt lock */ ast_channel_lock_both(chan, owner); } ao2_lock(p); /* Now that we have all the locks, validate that nothing changed */ if (p->owner != owner || p->chan != chan) { if (owner) { ast_channel_unlock(owner); owner = ast_channel_unref(owner); } if (chan) { ast_channel_unlock(chan); chan = ast_channel_unref(chan); } continue; } break; } *outowner = p->owner; *outchan = p->chan; }
static void pthread_timer_ack(int handle, unsigned int quantity) { struct pthread_timer *timer; ast_assert(quantity > 0); if (!(timer = find_timer(handle, 0))) { return; } ao2_lock(timer); read_pipe(timer, quantity); ao2_unlock(timer); ao2_ref(timer, -1); }
static int run_timer(void *obj, void *arg, int flags) { struct pthread_timer *timer = obj; if (timer->state == TIMER_STATE_IDLE) { return 0; } ao2_lock(timer); if (check_timer(timer)) { write_byte(timer); } ao2_unlock(timer); return 0; }
struct ast_sip_endpoint *ast_sip_dialog_get_endpoint(pjsip_dialog *dlg) { struct distributor_dialog_data *dist; struct ast_sip_endpoint *endpoint; dist = ao2_find(dialog_associations, dlg, OBJ_SEARCH_KEY); if (dist) { ao2_lock(dist); endpoint = ao2_bump(dist->endpoint); ao2_unlock(dist); ao2_ref(dist, -1); } else { endpoint = NULL; } return endpoint; }
/*! \brief Scheduled recurring query callback */ static int dns_query_recurring_scheduled_callback(const void *data) { struct ast_dns_query_recurring *recurring = (struct ast_dns_query_recurring *)data; ao2_lock(recurring); recurring->timer = -1; if (!recurring->cancelled) { recurring->active = ast_dns_resolve_async(recurring->name, recurring->rr_type, recurring->rr_class, dns_query_recurring_resolution_callback, recurring); } ao2_unlock(recurring); ao2_ref(recurring, -1); return 0; }
static int app_event_filter_set(struct stasis_app *app, struct ast_json **member, struct ast_json *filter, const char *filter_type) { if (filter && ast_json_typeof(filter) == AST_JSON_OBJECT) { if (!ast_json_object_size(filter)) { /* If no filters are specified then reset this filter type */ filter = NULL; } else { /* Otherwise try to get the filter array for this type */ filter = ast_json_object_get(filter, filter_type); if (!filter) { /* A filter type exists, but not this one, so don't update */ return 0; } } } /* At this point the filter object should be an array */ if (filter && ast_json_typeof(filter) != AST_JSON_ARRAY) { ast_log(LOG_ERROR, "Invalid json type event filter - app: %s, filter: %s\n", app->name, filter_type); return -1; } if (filter) { /* Confirm that at least the type names are specified */ struct ast_json *obj; int i; for (i = 0; i < ast_json_array_size(filter) && (obj = ast_json_array_get(filter, i)); ++i) { if (ast_strlen_zero(ast_json_object_string_get(obj, "type"))) { ast_log(LOG_ERROR, "Filter event must have a type - app: %s, " "filter: %s\n", app->name, filter_type); return -1; } } } ao2_lock(app); ast_json_unref(*member); *member = filter ? ast_json_ref(filter) : NULL; ao2_unlock(app); return 0; }
struct ao2_container *ast_sip_location_retrieve_aor_contacts(const struct ast_sip_aor *aor) { struct ao2_container *contacts; struct ast_named_lock *lock; lock = ast_named_lock_get(AST_NAMED_LOCK_TYPE_RWLOCK, "aor", ast_sorcery_object_get_id(aor)); if (!lock) { return NULL; } ao2_wrlock(lock); contacts = ast_sip_location_retrieve_aor_contacts_nolock(aor); ao2_unlock(lock); ast_named_lock_put(lock); return contacts; }
static int run_timer(void *obj, void *arg, int flags) { struct pthread_timer *timer = obj; if (timer->state == TIMER_STATE_IDLE) { return 0; } ao2_lock(timer); if (check_timer(timer)) { timer->pending_ticks++; signal_pipe(timer); } ao2_unlock(timer); return 0; }
int stasis_message_router_add_cache_update(struct stasis_message_router *router, struct stasis_message_type *message_type, stasis_subscription_cb callback, void *data) { int res; ast_assert(router != NULL); if (!message_type) { /* Cannot cache a route to NULL type. */ return -1; } ao2_lock(router); res = route_table_add(&router->cache_routes, message_type, callback, data); ao2_unlock(router); return res; }
int stasis_app_event_allowed(const char *app_name, struct ast_json *event) { struct stasis_app *app = stasis_app_get_by_name(app_name); int res; if (!app) { return 0; } ao2_lock(app); res = !app_event_filter_matched(app->events_disallowed, event, 0) && app_event_filter_matched(app->events_allowed, event, 1); ao2_unlock(app); ao2_ref(app, -1); return res; }
int sccpconf_announce_channel_push(struct ast_channel *ast, struct ast_bridge *bridge) { struct ast_bridge_features *features; struct ast_channel *chan; struct announce_pvt *p = NULL; { ast_channel_lock(ast); p = ast_channel_tech_pvt(ast); if (!p) { ast_channel_unlock(ast); return -1; } ao2_ref(p, +1); chan = p->base.chan; if (!chan) { ast_channel_unlock(ast); ao2_cleanup(p); return -1; } ast_channel_ref(chan); ast_channel_unlock(ast); } features = ast_bridge_features_new(); if (!features) { ast_channel_unref(chan); ao2_cleanup(p); return -1; } ast_set_flag(&features->feature_flags, AST_BRIDGE_CHANNEL_FLAG_IMMOVABLE); // Impart the output channel into the bridge if (ast_bridge_impart(bridge, chan, NULL, features, AST_BRIDGE_IMPART_CHAN_DEPARTABLE)) { ast_bridge_features_destroy(features); ast_channel_unref(chan); ao2_cleanup(p); return -1; } ao2_lock(p); ast_set_flag(&p->base, AST_UNREAL_CARETAKER_THREAD); ao2_unlock(p); ao2_cleanup(p); return 0; }
static int timerfd_timer_ack(void *data, unsigned int quantity) { struct timerfd_timer *timer = data; uint64_t expirations; int read_result = 0; int res = 0; ao2_lock(timer); do { struct itimerspec timer_status; if (timerfd_gettime(timer->fd, &timer_status)) { ast_log(LOG_ERROR, "Call to timerfd_gettime() using handle %d error: %s\n", timer->fd, strerror(errno)); expirations = 0; res = -1; break; } if (timer_status.it_value.tv_sec == 0 && timer_status.it_value.tv_nsec == 0) { ast_debug(1, "Avoiding read on disarmed timerfd %d\n", timer->fd); expirations = 0; break; } read_result = read(timer->fd, &expirations, sizeof(expirations)); if (read_result == -1) { if (errno == EINTR || errno == EAGAIN) { continue; } else { ast_log(LOG_ERROR, "Read error: %s\n", strerror(errno)); res = -1; break; } } } while (read_result != sizeof(expirations)); ao2_unlock(timer); if (expirations != quantity) { ast_debug(2, "Expected to acknowledge %u ticks but got %llu instead\n", quantity, (unsigned long long) expirations); } return res; }
/*! \brief Helper function which adds or removes a channel and nudges the thread */ static void multiplexed_add_or_remove(struct multiplexed_thread *multiplexed_thread, struct ast_channel *chan, int add) { int i, removed = 0; pthread_t thread = AST_PTHREADT_NULL; ao2_lock(multiplexed_thread); multiplexed_nudge(multiplexed_thread); for (i = 0; i < MULTIPLEXED_MAX_CHANNELS; i++) { if (multiplexed_thread->chans[i] == chan) { if (!add) { multiplexed_thread->chans[i] = NULL; multiplexed_thread->service_count--; removed = 1; } break; } else if (!multiplexed_thread->chans[i] && add) { multiplexed_thread->chans[i] = chan; multiplexed_thread->service_count++; break; } } if (multiplexed_thread->service_count && multiplexed_thread->thread == AST_PTHREADT_NULL) { ao2_ref(multiplexed_thread, +1); if (ast_pthread_create(&multiplexed_thread->thread, NULL, multiplexed_thread_function, multiplexed_thread)) { ao2_ref(multiplexed_thread, -1); ast_debug(1, "Failed to create an actual thread for multiplexed thread '%p', trying next time\n", multiplexed_thread); } } else if (!multiplexed_thread->service_count && multiplexed_thread->thread != AST_PTHREADT_NULL) { thread = multiplexed_thread->thread; multiplexed_thread->thread = AST_PTHREADT_STOP; } else if (!add && removed) { memmove(multiplexed_thread->chans + i, multiplexed_thread->chans + i + 1, sizeof(struct ast_channel *) * (MULTIPLEXED_MAX_CHANNELS - (i + 1))); } ao2_unlock(multiplexed_thread); if (thread != AST_PTHREADT_NULL) { pthread_join(thread, NULL); } return; }
int ast_dns_resolve_recurring_cancel(struct ast_dns_query_recurring *recurring) { int res = 0; ao2_lock(recurring); recurring->cancelled = 1; AST_SCHED_DEL_UNREF(ast_dns_get_sched(), recurring->timer, ao2_ref(recurring, -1)); if (recurring->active) { res = ast_dns_resolve_cancel(recurring->active); ao2_replace(recurring->active, NULL); } ao2_unlock(recurring); return res; }
void control_wait(struct stasis_app_control *control) { if (!control) { return; } ast_assert(control->command_queue != NULL); ao2_lock(control->command_queue); while (ao2_container_count(control->command_queue) == 0) { int res = ast_cond_wait(&control->wait_cond, ao2_object_get_lockaddr(control->command_queue)); if (res < 0) { ast_log(LOG_ERROR, "Error waiting on command queue\n"); break; } } ao2_unlock(control->command_queue); }
static enum ast_timer_event pthread_timer_get_event(int handle) { struct pthread_timer *timer; enum ast_timer_event res = AST_TIMING_EVENT_EXPIRED; if (!(timer = find_timer(handle, 0))) { return res; } ao2_lock(timer); if (timer->continuous && timer->pending_ticks == 1) { res = AST_TIMING_EVENT_CONTINUOUS; } ao2_unlock(timer); ao2_ref(timer, -1); return res; }