Ejemplo n.º 1
0
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;
}
Ejemplo n.º 2
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;
}
Ejemplo n.º 3
0
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);
}
Ejemplo n.º 4
0
/*! \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);
}
Ejemplo n.º 7
0
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);
}
Ejemplo n.º 8
0
/* 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;
}
Ejemplo n.º 9
0
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;
}
Ejemplo n.º 10
0
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);
}
Ejemplo n.º 11
0
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;
}
Ejemplo n.º 12
0
/*!
 * \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);
}
Ejemplo n.º 13
0
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;
}
Ejemplo n.º 14
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);
	}
}
Ejemplo n.º 15
0
/*!
 * \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;
}
Ejemplo n.º 16
0
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);
}
Ejemplo n.º 17
0
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;
}
Ejemplo n.º 18
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;
}
Ejemplo n.º 19
0
/*! \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;
}
Ejemplo n.º 20
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;
}
Ejemplo n.º 21
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;
}
Ejemplo n.º 22
0
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;
}
Ejemplo n.º 24
0
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;
}
Ejemplo n.º 25
0
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;
}
Ejemplo n.º 27
0
/*! \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;
}
Ejemplo n.º 28
0
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;
}
Ejemplo n.º 29
0
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);
}
Ejemplo n.º 30
0
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;
}