int ast_unreal_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
{
	struct ast_unreal_pvt *p = ast_channel_tech_pvt(newchan);
	struct ast_bridge *bridge_owner;
	struct ast_bridge *bridge_chan;

	if (!p) {
		return -1;
	}

	ao2_lock(p);

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

	if (ast_check_hangup(newchan) || !p->owner || !p->chan) {
		ao2_unlock(p);
		return 0;
	}

	/* Do not let a masquerade cause an unreal channel to be bridged to itself! */
	bridge_owner = ast_channel_internal_bridge(p->owner);
	bridge_chan = ast_channel_internal_bridge(p->chan);
	if (bridge_owner && bridge_owner == bridge_chan) {
		ast_log(LOG_WARNING, "You can not bridge an unreal channel (%s) to itself!\n",
			ast_channel_name(newchan));
		ao2_unlock(p);
		ast_queue_hangup(newchan);
		return -1;
	}

	ao2_unlock(p);
	return 0;
}
Beispiel #2
0
/*! \brief Helper function to not deadlock when queueing the hangup frame */
static void bridge_queue_hangup(struct bridge_pvt *p, struct ast_channel *us)
{
	struct ast_channel *other = (p->input == us ? p->output : p->input);

	while (other && ast_channel_trylock(other)) {
		ast_mutex_unlock(&p->lock);
		do {
			CHANNEL_DEADLOCK_AVOIDANCE(us);
		} while (ast_mutex_trylock(&p->lock));
		other = (p->input == us ? p->output : p->input);
	}

	/* We basically queue the frame up on the other channel if present */
	if (other) {
		ast_queue_hangup(other);
		ast_channel_unlock(other);
	}

	return;
}