예제 #1
0
/*
 * This function is run in the context of the serializer.
 * It runs the task with a simple call and reschedules based on the result.
 */
static int run_task(void *data)
{
	RAII_VAR(struct ast_sip_sched_task *, schtd, ao2_bump(data), ao2_cleanup);
	int res;
	int delay;

	ao2_lock(schtd);
	schtd->last_start = ast_tvnow();
	schtd->is_running = 1;
	schtd->run_count++;
	ao2_unlock(schtd);

	res = schtd->task(schtd->task_data);

	ao2_lock(schtd);
	schtd->is_running = 0;
	schtd->last_end = ast_tvnow();

	/*
	 * Don't restart if the task returned 0 or if the interval
	 * was set to 0 while the task was running
	 */
	if (!res || !schtd->interval) {
		schtd->interval = 0;
		ao2_unlock(schtd);
		ao2_unlink(tasks, schtd);
		return -1;
	}

	if (schtd->flags & AST_SIP_SCHED_TASK_VARIABLE) {
		schtd->interval = res;
	}

	if (schtd->flags & AST_SIP_SCHED_TASK_DELAY) {
		delay = schtd->interval;
	} else {
		delay = schtd->interval - (ast_tvdiff_ms(schtd->last_end, schtd->last_start) % schtd->interval);
	}

	schtd->current_scheduler_id = ast_sched_add(scheduler_context, delay, push_to_serializer, (const void *)schtd);
	if (schtd->current_scheduler_id < 0) {
		schtd->interval = 0;
		ao2_unlock(schtd);
		ao2_unlink(tasks, schtd);
		return -1;
	}

	ao2_unlock(schtd);

	return 0;
}
예제 #2
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;

	for (;;) {
		ao2_lock(p);
		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);
			}
			ao2_lock(p);
		} 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);
			}
			ao2_unlock(p);
			continue;
		}

		break;
	}
	*outowner = p->owner;
	*outchan = p->chan;
}
예제 #3
0
/*! \brief Return the bridged channel of a Local channel */
static struct ast_channel *local_bridgedchannel(struct ast_channel *chan, struct ast_channel *bridge)
{
	struct local_pvt *p = ast_channel_tech_pvt(bridge);
	struct ast_channel *bridged = bridge;

	if (!p) {
		ast_debug(1, "Asked for bridged channel on '%s'/'%s', returning <none>\n",
			ast_channel_name(chan), ast_channel_name(bridge));
		return NULL;
	}

	ao2_lock(p);

	if (ast_test_flag(p, LOCAL_BRIDGE)) {
		/* Find the opposite channel */
		bridged = (bridge == p->owner ? p->chan : p->owner);

		/* Now see if the opposite channel is bridged to anything */
		if (!bridged) {
			bridged = bridge;
		} else if (ast_channel_internal_bridged_channel(bridged)) {
			bridged = ast_channel_internal_bridged_channel(bridged);
		}
	}

	ao2_unlock(p);

	return bridged;
}
예제 #4
0
static enum ast_timer_event timerfd_timer_get_event(int handle)
{
	enum ast_timer_event res;
	struct timerfd_timer *our_timer, find_helper = {
		.handle = handle,
	};

	if (handle == -1) {
		ast_log(LOG_ERROR, "Attempting to get event from timerfd handle -1");
		return -1;
	}

	if (!(our_timer = ao2_find(timerfd_timers, &find_helper, OBJ_POINTER))) {
		ast_log(LOG_ERROR, "Couldn't find timer with handle %d\n", handle);
		return -1;
	}
	ao2_lock(our_timer);

	if (our_timer->is_continuous) {
		res = AST_TIMING_EVENT_CONTINUOUS;
	} else {
		res = AST_TIMING_EVENT_EXPIRED;
	}

	ao2_unlock(our_timer);
	ao2_ref(our_timer, -1);
	return res;
}
예제 #5
0
파일: control.c 프로젝트: vzar/asterisk
static struct stasis_app_command *exec_command_on_condition(
    struct stasis_app_control *control, stasis_app_command_cb command_fn,
    void *data, app_command_can_exec_cb can_exec_fn)
{
    int retval;
    struct stasis_app_command *command;

    command_fn = command_fn ? : noop_cb;

    command = command_create(command_fn, data);
    if (!command) {
        return NULL;
    }

    ao2_lock(control->command_queue);
    if (can_exec_fn && (retval = can_exec_fn(control))) {
        ao2_unlock(control->command_queue);
        command_complete(command, retval);
        return command;
    }

    ao2_link_flags(control->command_queue, command, OBJ_NOLOCK);
    ast_cond_signal(&control->wait_cond);
    ao2_unlock(control->command_queue);

    return command;
}
예제 #6
0
static int timerfd_timer_set_rate(int handle, unsigned int rate)
{
	struct timerfd_timer *our_timer, find_helper = {
		.handle = handle,
	};
	int res = 0;

	if (handle == -1) {
		ast_log(LOG_ERROR, "Attempting to set rate on timerfd handle -1");
		return -1;
	}

	if (!(our_timer = ao2_find(timerfd_timers, &find_helper, OBJ_POINTER))) {
		ast_log(LOG_ERROR, "Couldn't find timer with handle %d\n", handle);
		return -1;
	}
	ao2_lock(our_timer);

	our_timer->saved_timer.it_value.tv_sec = 0;
	our_timer->saved_timer.it_value.tv_nsec = rate ? (long) (1000000000 / rate) : 0L;
	our_timer->saved_timer.it_interval.tv_sec = our_timer->saved_timer.it_value.tv_sec;
	our_timer->saved_timer.it_interval.tv_nsec = our_timer->saved_timer.it_value.tv_nsec;

	if (!our_timer->is_continuous) {
		res = timerfd_settime(handle, 0, &our_timer->saved_timer, NULL);
	}

	ao2_unlock(our_timer);
	ao2_ref(our_timer, -1);

	return res;
}
예제 #7
0
void ast_sip_dialog_set_endpoint(pjsip_dialog *dlg, struct ast_sip_endpoint *endpoint)
{
	struct distributor_dialog_data *dist;

	ao2_wrlock(dialog_associations);
	dist = ao2_find(dialog_associations, dlg, OBJ_SEARCH_KEY | OBJ_NOLOCK);
	if (!dist) {
		if (endpoint) {
			dist = ao2_alloc(sizeof(*dist), NULL);
			if (dist) {
				dist->dlg = dlg;
				dist->endpoint = endpoint;
				ao2_link_flags(dialog_associations, dist, OBJ_NOLOCK);
				ao2_ref(dist, -1);
			}
		}
	} else {
		ao2_lock(dist);
		dist->endpoint = endpoint;
		if (!dist->serializer && !dist->endpoint) {
			ao2_unlink_flags(dialog_associations, dist, OBJ_NOLOCK);
		}
		ao2_unlock(dist);
		ao2_ref(dist, -1);
	}
	ao2_unlock(dialog_associations);
}
예제 #8
0
struct parked_user *parking_lot_retrieve_parked_user(struct parking_lot *lot, int target)
{
	RAII_VAR(struct parked_user *, user, NULL, ao2_cleanup);

	if (target < 0) {
		user = ao2_callback(lot->parked_users, 0, NULL, NULL);
	} else {
		user = ao2_callback(lot->parked_users, 0, retrieve_parked_user_targeted, &target);
	}

	if (!user) {
		return NULL;
	}

	ao2_lock(user);
	if (user->resolution != PARK_UNSET) {
		/* Abandon. Something else has resolved the parked user before we got to it. */
		ao2_unlock(user);
		return NULL;
	}

	ao2_unlink(lot->parked_users, user);
	user->resolution = PARK_ANSWERED;
	ao2_unlock(user);

	parking_lot_remove_if_unused(user->lot);

	/* Bump the ref count by 1 since the RAII_VAR will eat the reference otherwise */
	ao2_ref(user, +1);
	return user;
}
예제 #9
0
int ast_unreal_answer(struct ast_channel *ast)
{
	struct ast_unreal_pvt *p = ast_channel_tech_pvt(ast);
	int isoutbound;
	int res = -1;

	if (!p) {
		return -1;
	}

	ao2_ref(p, 1);
	ao2_lock(p);
	isoutbound = AST_UNREAL_IS_OUTBOUND(ast, p);
	if (isoutbound) {
		/* Pass along answer since somebody answered us */
		struct ast_frame answer = { AST_FRAME_CONTROL, { AST_CONTROL_ANSWER } };

		res = unreal_queue_frame(p, isoutbound, &answer, ast, 1);
	} else {
		ast_log(LOG_WARNING, "Huh?  %s is being asked to answer?\n",
			ast_channel_name(ast));
	}
	ao2_unlock(p);
	ao2_ref(p, -1);
	return res;
}
예제 #10
0
int ast_unreal_write(struct ast_channel *ast, struct ast_frame *f)
{
	struct ast_unreal_pvt *p = ast_channel_tech_pvt(ast);
	int res = -1;

	if (!p) {
		return -1;
	}

	/* Just queue for delivery to the other side */
	ao2_ref(p, 1);
	ao2_lock(p);
	switch (f->frametype) {
	case AST_FRAME_VOICE:
	case AST_FRAME_VIDEO:
		if (got_optimized_out(ast, p)) {
			break;
		}
		/* fall through */
	default:
		res = unreal_queue_frame(p, AST_UNREAL_IS_OUTBOUND(ast, p), f, ast, 1);
		break;
	}
	ao2_unlock(p);
	ao2_ref(p, -1);

	return res;
}
예제 #11
0
void control_mark_done(struct stasis_app_control *control)
{
	/* Locking necessary to sync with other threads adding commands to the queue. */
	ao2_lock(control->command_queue);
	control->is_done = 1;
	ao2_unlock(control->command_queue);
}
예제 #12
0
static void *pthread_timer_open(void)
{
	struct pthread_timer *timer;

	if (!(timer = ao2_alloc(sizeof(*timer), pthread_timer_destructor))) {
		errno = ENOMEM;
		return NULL;
	}

	timer->pipe[PIPE_READ] = timer->pipe[PIPE_WRITE] = -1;
	timer->state = TIMER_STATE_IDLE;

	if (ast_pipe_nonblock(timer->pipe)) {
		ao2_ref(timer, -1);
		return NULL;
	}

	ao2_lock(pthread_timers);
	if (!ao2_container_count(pthread_timers)) {
		ast_mutex_lock(&timing_thread.lock);
		ast_cond_signal(&timing_thread.cond);
		ast_mutex_unlock(&timing_thread.lock);
	}
	ao2_link_flags(pthread_timers, timer, OBJ_NOLOCK);
	ao2_unlock(pthread_timers);

	return timer;
}
예제 #13
0
static int pthread_timer_disable_continuous(int handle)
{
	struct pthread_timer *timer;

	if (!(timer = find_timer(handle, 0))) {
		errno = EINVAL;
		return -1;
	}

	ao2_lock(timer);
	if (timer->continuous) {
		timer->continuous = 0;
		if (read_pipe(timer, 1) != 0) {
			/* Let the errno from read_pipe propagate up */
			ao2_unlock(timer);
			ao2_ref(timer, -1);
			return -1;
		}
	}
	ao2_unlock(timer);

	ao2_ref(timer, -1);

	return 0;
}
예제 #14
0
파일: named_locks.c 프로젝트: GGGO/asterisk
struct ast_named_lock *__ast_named_lock_get(const char *filename, int lineno, const char *func,
	enum ast_named_lock_type lock_type, const char *keyspace, const char *key)
{
	struct ast_named_lock *lock = NULL;
	int concat_key_buff_len = strlen(keyspace) + strlen(key) + 2;
	char *concat_key = ast_alloca(concat_key_buff_len);

	sprintf(concat_key, "%s-%s", keyspace, key); /* Safe */

	ao2_lock(named_locks);
	lock = ao2_find(named_locks, concat_key, OBJ_SEARCH_KEY | OBJ_NOLOCK);
	if (lock) {
		ao2_unlock(named_locks);
		ast_assert((ao2_options_get(lock) & AO2_ALLOC_OPT_LOCK_MASK) == lock_type);
		return lock;
	}

	lock = ao2_alloc_options(sizeof(*lock) + concat_key_buff_len, NULL, lock_type);
	if (lock) {
		strcpy(lock->key, concat_key); /* Safe */
		ao2_link_flags(named_locks, lock, OBJ_NOLOCK);
	}
	ao2_unlock(named_locks);

	return lock;
}
예제 #15
0
/*! \brief Function called when a contact is added */
static void mwi_contact_added(const void *object)
{
	const struct ast_sip_contact *contact = object;
	struct ao2_iterator *mwi_subs;
	struct mwi_subscription *mwi_sub;
	const char *endpoint_id = ast_sorcery_object_get_id(contact->endpoint);

	if (ast_strlen_zero(contact->endpoint->subscription.mwi.mailboxes)) {
		return;
	}

	ao2_lock(unsolicited_mwi);

	mwi_subs = ao2_find(unsolicited_mwi, endpoint_id, OBJ_SEARCH_KEY | OBJ_MULTIPLE | OBJ_NOLOCK | OBJ_UNLINK);
	if (mwi_subs) {
		for (; (mwi_sub = ao2_iterator_next(mwi_subs)); ao2_cleanup(mwi_sub)) {
			unsubscribe(mwi_sub, NULL, 0);
		}
		ao2_iterator_destroy(mwi_subs);
	}

	create_mwi_subscriptions_for_endpoint(contact->endpoint, NULL, 0);

	ao2_unlock(unsolicited_mwi);

	mwi_contact_updated(object);
}
예제 #16
0
static int local_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
{
	struct local_pvt *p = ast_channel_tech_pvt(newchan);

	if (!p) {
		return -1;
	}

	ao2_lock(p);

	if ((p->owner != oldchan) && (p->chan != oldchan)) {
		ast_log(LOG_WARNING, "Old channel wasn't %p but was %p/%p\n", oldchan, p->owner, p->chan);
		ao2_unlock(p);
		return -1;
	}
	if (p->owner == oldchan) {
		p->owner = newchan;
	} else {
		p->chan = newchan;
	}

	/* Do not let a masquerade cause a Local channel to be bridged to itself! */
	if (!ast_check_hangup(newchan) && ((p->owner && ast_channel_internal_bridged_channel(p->owner) == p->chan) || (p->chan && ast_channel_internal_bridged_channel(p->chan) == p->owner))) {
		ast_log(LOG_WARNING, "You can not bridge a Local channel to itself!\n");
		ao2_unlock(p);
		ast_queue_hangup(newchan);
		return -1;
	}

	ao2_unlock(p);
	return 0;
}
예제 #17
0
static int local_write(struct ast_channel *ast, struct ast_frame *f)
{
	struct local_pvt *p = ast_channel_tech_pvt(ast);
	int res = -1;
	int isoutbound;

	if (!p) {
		return -1;
	}

	/* Just queue for delivery to the other side */
	ao2_ref(p, 1); /* ref for local_queue_frame */
	ao2_lock(p);
	isoutbound = IS_OUTBOUND(ast, p);

	if (isoutbound
		&& (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO)) {
		check_bridge(ast, p);
	}

	if (!ast_test_flag(p, LOCAL_ALREADY_MASQED)) {
		res = local_queue_frame(p, isoutbound, f, ast, 1);
	} else {
		ast_debug(1, "Not posting to '%s' queue since already masqueraded out\n",
			ast_channel_name(ast));
		res = 0;
	}
	ao2_unlock(p);
	ao2_ref(p, -1);

	return res;
}
예제 #18
0
static int pthread_timer_set_rate(void *data, unsigned int rate)
{
	struct pthread_timer *timer = data;

	if (rate > MAX_RATE) {
		ast_log(LOG_ERROR, "res_timing_pthread only supports timers at a "
				"max rate of %d / sec\n", MAX_RATE);
		errno = EINVAL;
		return -1;
	}

	ao2_lock(timer);

	if ((timer->rate = rate)) {
		timer->interval = roundf(1000.0 / ((float) rate));
		timer->start = ast_tvnow();
		timer->state = TIMER_STATE_TICKING;
	} else {
		timer->interval = 0;
		timer->start = ast_tv(0, 0);
		timer->state = TIMER_STATE_IDLE;
	}
	timer->tick_count = 0;

	ao2_unlock(timer);

	return 0;
}
예제 #19
0
static int register_contact_transport_remove_cb(void *data)
{
	struct contact_transport_monitor *monitor = data;
	struct ast_sip_contact *contact;
	struct ast_sip_aor *aor;

	aor = ast_sip_location_retrieve_aor(monitor->aor_name);
	if (!aor) {
		ao2_ref(monitor, -1);
		return 0;
	}

	ao2_lock(aor);
	contact = ast_sip_location_retrieve_contact(monitor->contact_name);
	if (contact) {
		ast_sip_location_delete_contact(contact);
		ast_verb(3, "Removed contact '%s' from AOR '%s' due to transport shutdown\n",
			contact->uri, monitor->aor_name);
		ast_test_suite_event_notify("AOR_CONTACT_REMOVED",
			"Contact: %s\r\n"
			"AOR: %s\r\n"
			"UserAgent: %s",
			contact->uri,
			monitor->aor_name,
			contact->user_agent);
		ao2_ref(contact, -1);
	}
	ao2_unlock(aor);
	ao2_ref(aor, -1);

	ao2_ref(monitor, -1);
	return 0;
}
예제 #20
0
int AST_OPTIONAL_API_NAME(ast_websocket_add_protocol)(const char *name, ast_websocket_callback callback)
{
	struct websocket_protocol *protocol;

	ao2_lock(protocols);

	/* Ensure a second protocol handler is not registered for the same protocol */
	if ((protocol = ao2_find(protocols, name, OBJ_KEY | OBJ_NOLOCK))) {
		ao2_ref(protocol, -1);
		ao2_unlock(protocols);
		return -1;
	}

	if (!(protocol = ao2_alloc(sizeof(*protocol), protocol_destroy_fn))) {
		ao2_unlock(protocols);
		return -1;
	}

	if (!(protocol->name = ast_strdup(name))) {
		ao2_ref(protocol, -1);
		ao2_unlock(protocols);
		return -1;
	}

	protocol->callback = callback;

	ao2_link_flags(protocols, protocol, OBJ_NOLOCK);
	ao2_unlock(protocols);
	ao2_ref(protocol, -1);

	ast_verb(2, "WebSocket registered sub-protocol '%s'\n", name);

	return 0;
}
예제 #21
0
static void *pthread_timer_open(void)
{
	struct pthread_timer *timer;
	int i;

	if (!(timer = ao2_alloc(sizeof(*timer), pthread_timer_destructor))) {
		errno = ENOMEM;
		return NULL;
	}

	timer->pipe[PIPE_READ] = timer->pipe[PIPE_WRITE] = -1;
	timer->state = TIMER_STATE_IDLE;

	if (pipe(timer->pipe)) {
		ao2_ref(timer, -1);
		return NULL;
	}

	for (i = 0; i < ARRAY_LEN(timer->pipe); ++i) {
		int flags = fcntl(timer->pipe[i], F_GETFL);
		flags |= O_NONBLOCK;
		fcntl(timer->pipe[i], F_SETFL, flags);
	}
	
	ao2_lock(pthread_timers);
	if (!ao2_container_count(pthread_timers)) {
		ast_mutex_lock(&timing_thread.lock);
		ast_cond_signal(&timing_thread.cond);
		ast_mutex_unlock(&timing_thread.lock);
	}
	ao2_link(pthread_timers, timer);
	ao2_unlock(pthread_timers);

	return timer;
}
예제 #22
0
static int pthread_timer_open(void)
{
	struct pthread_timer *timer;
	int fd;

	if (!(timer = ao2_alloc(sizeof(*timer), pthread_timer_destructor))) {
		errno = ENOMEM;
		return -1;
	}

	timer->pipe[PIPE_READ] = timer->pipe[PIPE_WRITE] = -1;
	timer->state = TIMER_STATE_IDLE;

	if (pipe(timer->pipe)) {
		ao2_ref(timer, -1);
		return -1;
	}

	ao2_lock(pthread_timers);
	if (!ao2_container_count(pthread_timers)) {
		ast_mutex_lock(&timing_thread.lock);
		ast_cond_signal(&timing_thread.cond);
		ast_mutex_unlock(&timing_thread.lock);
	}
	ao2_link(pthread_timers, timer);
	ao2_unlock(pthread_timers);

	fd = timer->pipe[PIPE_READ];

	ao2_ref(timer, -1);

	return fd;
}
예제 #23
0
파일: app.c 프로젝트: roramirez/asterisk
/*!
 * \brief Send a message to the given application.
 * \param app App to send the message to.
 * \param message Message to send.
 */
void app_send(struct stasis_app *app, struct ast_json *message)
{
	stasis_app_cb handler;
	char eid[20];
	void *data;

	if (ast_json_object_set(message, "asterisk_id", ast_json_string_create(
			ast_eid_to_str(eid, sizeof(eid), &ast_eid_default)))) {
		ast_log(AST_LOG_WARNING, "Failed to append EID to outgoing event %s\n",
			ast_json_string_get(ast_json_object_get(message, "type")));
	}

	/* Copy off mutable state with lock held */
	ao2_lock(app);
	handler = app->handler;
	data = ao2_bump(app->data);
	ao2_unlock(app);
	/* Name is immutable; no need to copy */

	if (handler) {
		handler(data, app->name, message);
	} else {
		ast_verb(3,
			"Inactive Stasis app '%s' missed message\n", app->name);
	}
	ao2_cleanup(data);
}
예제 #24
0
/*! \brief Hangup a call through the local proxy channel */
static int local_hangup(struct ast_channel *ast)
{
	struct local_pvt *p = ast_channel_tech_pvt(ast);
	int res;

	if (!p) {
		return -1;
	}

	/* give the pvt a ref to fulfill calling requirements. */
	ao2_ref(p, +1);
	res = ast_unreal_hangup(&p->base, ast);
	if (!res) {
		int unlink;

		ao2_lock(p);
		unlink = !p->base.owner && !p->base.chan;
		ao2_unlock(p);
		if (unlink) {
			ao2_unlink(locals, p);
		}
	}
	ao2_ref(p, -1);

	return res;
}
예제 #25
0
static int manager_optimize_away(struct mansession *s, const struct message *m)
{
	const char *channel;
	struct local_pvt *p;
	struct local_pvt *found;
	struct ast_channel *chan;

	channel = astman_get_header(m, "Channel");
	if (ast_strlen_zero(channel)) {
		astman_send_error(s, m, "'Channel' not specified.");
		return 0;
	}

	chan = ast_channel_get_by_name(channel);
	if (!chan) {
		astman_send_error(s, m, "Channel does not exist.");
		return 0;
	}

	p = ast_channel_tech_pvt(chan);
	ast_channel_unref(chan);

	found = p ? ao2_find(locals, p, 0) : NULL;
	if (found) {
		ao2_lock(found);
		ast_clear_flag(&found->base, AST_UNREAL_NO_OPTIMIZATION);
		ao2_unlock(found);
		ao2_ref(found, -1);
		astman_send_ack(s, m, "Queued channel to be optimized away");
	} else {
		astman_send_error(s, m, "Unable to find channel");
	}

	return 0;
}
예제 #26
0
int ast_local_setup_masquerade(struct ast_channel *ast, struct ast_channel *masq)
{
	struct local_pvt *p;
	struct local_pvt *found;
	int res = -1;

	/* Sanity checks. */
	if (!ast || !masq) {
		return -1;
	}

	ast_channel_lock(ast);
	p = ast_channel_tech_pvt(ast);
	ast_channel_unlock(ast);

	found = p ? ao2_find(locals, p, 0) : NULL;
	if (found) {
		ao2_lock(found);
		if (found->type == LOCAL_CALL_ACTION_DIALPLAN
			&& found->base.owner
			&& found->base.chan
			&& !ast_test_flag(&found->base, AST_UNREAL_CARETAKER_THREAD)) {
			ast_channel_ref(masq);
			found->type = LOCAL_CALL_ACTION_MASQUERADE;
			found->action.masq = masq;
			res = 0;
		}
		ao2_unlock(found);
		ao2_ref(found, -1);
	}

	return res;
}
예제 #27
0
struct ast_channel *ast_local_get_peer(struct ast_channel *ast)
{
	struct local_pvt *p = ast_channel_tech_pvt(ast);
	struct local_pvt *found;
	struct ast_channel *peer;

	if (!p) {
		return NULL;
	}

	found = p ? ao2_find(locals, p, 0) : NULL;
	if (!found) {
		/* ast is either not a local channel or it has alredy been hungup */
		return NULL;
	}
	ao2_lock(found);
	if (ast == p->base.owner) {
		peer = p->base.chan;
	} else if (ast == p->base.chan) {
		peer = p->base.owner;
	} else {
		peer = NULL;
	}
	if (peer) {
		ast_channel_ref(peer);
	}
	ao2_unlock(found);
	ao2_ref(found, -1);
	return peer;
}
예제 #28
0
/*!
 * \brief Callback handler for Stasis application messages.
 */
static void app_handler(void *data, const char *app_name,
			struct ast_json *message)
{
	struct event_session *session = data;
	int res;
	const char *msg_type = S_OR(
		ast_json_string_get(ast_json_object_get(message, "type")),
		"");
	const char *msg_application = S_OR(
		ast_json_string_get(ast_json_object_get(message, "application")),
		"");
 
	/* Determine if we've been replaced */
	if (strcmp(msg_type, "ApplicationReplaced") == 0 &&
		strcmp(msg_application, app_name) == 0) {
		ao2_find(session->websocket_apps, msg_application,
			OBJ_UNLINK | OBJ_NODATA);
	}

	res = ast_json_object_set(message, "application",
				  ast_json_string_create(app_name));
	if(res != 0) {
		return;
	}

	ao2_lock(session);
	if (session->ws_session) {
		ast_ari_websocket_session_write(session->ws_session, message);
	}
	ao2_unlock(session);
}
예제 #29
0
/* Called with ast locked */
static int local_setoption(struct ast_channel *ast, int option, void * data, int datalen)
{
	int res = 0;
	struct local_pvt *p = NULL;
	struct ast_channel *otherchan = NULL;
	ast_chan_write_info_t *write_info;

	if (option != AST_OPTION_CHANNEL_WRITE) {
		return -1;
	}

	write_info = data;

	if (write_info->version != AST_CHAN_WRITE_INFO_T_VERSION) {
		ast_log(LOG_ERROR, "The chan_write_info_t type has changed, and this channel hasn't been updated!\n");
		return -1;
	}

	if (!strcmp(write_info->function, "CHANNEL")
		&& !strncasecmp(write_info->data, "hangup_handler_", 15)) {
		/* Block CHANNEL(hangup_handler_xxx) writes to the other local channel. */
		return 0;
	}

	/* get the tech pvt */
	if (!(p = ast_channel_tech_pvt(ast))) {
		return -1;
	}
	ao2_ref(p, 1);
	ast_channel_unlock(ast); /* Held when called, unlock before locking another channel */

	/* get the channel we are supposed to write to */
	ao2_lock(p);
	otherchan = (write_info->chan == p->owner) ? p->chan : p->owner;
	if (!otherchan || otherchan == write_info->chan) {
		res = -1;
		otherchan = NULL;
		ao2_unlock(p);
		goto setoption_cleanup;
	}
	ast_channel_ref(otherchan);

	/* clear the pvt lock before grabbing the channel */
	ao2_unlock(p);

	ast_channel_lock(otherchan);
	res = write_info->write_fn(otherchan, write_info->function, write_info->data, write_info->value);
	ast_channel_unlock(otherchan);

setoption_cleanup:
	if (p) {
		ao2_ref(p, -1);
	}
	if (otherchan) {
		ast_channel_unref(otherchan);
	}
	ast_channel_lock(ast); /* Lock back before we leave */
	return res;
}
예제 #30
0
/*! \brief Thread function that executes for multiplexed threads */
static void *multiplexed_thread_function(void *data)
{
	struct multiplexed_thread *multiplexed_thread = data;
	int fds = multiplexed_thread->pipe[0];

	ao2_lock(multiplexed_thread);

	ast_debug(1, "Starting actual thread for multiplexed thread '%p'\n", multiplexed_thread);

	while (multiplexed_thread->thread != AST_PTHREADT_STOP) {
		struct ast_channel *winner = NULL, *first = multiplexed_thread->chans[0];
		int to = -1, outfd = -1;

		/* Move channels around so not just the first one gets priority */
		memmove(multiplexed_thread->chans, multiplexed_thread->chans + 1, sizeof(struct ast_channel *) * (multiplexed_thread->service_count - 1));
		multiplexed_thread->chans[multiplexed_thread->service_count - 1] = first;

		multiplexed_thread->waiting = 1;
		ao2_unlock(multiplexed_thread);
		winner = ast_waitfor_nandfds(multiplexed_thread->chans, multiplexed_thread->service_count, &fds, 1, NULL, &outfd, &to);
		multiplexed_thread->waiting = 0;
		ao2_lock(multiplexed_thread);

		if (outfd > -1) {
			int nudge;

			if (read(multiplexed_thread->pipe[0], &nudge, sizeof(nudge)) < 0) {
				if (errno != EINTR && errno != EAGAIN) {
					ast_log(LOG_WARNING, "read() failed for pipe on multiplexed thread '%p': %s\n", multiplexed_thread, strerror(errno));
				}
			}
		}
		if (winner && winner->bridge) {
			ast_bridge_handle_trip(winner->bridge, NULL, winner, -1);
		}
	}

	multiplexed_thread->thread = AST_PTHREADT_NULL;

	ast_debug(1, "Stopping actual thread for multiplexed thread '%p'\n", multiplexed_thread);

	ao2_unlock(multiplexed_thread);
	ao2_ref(multiplexed_thread, -1);

	return NULL;
}