/* 
 * \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;
}
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;
}
Example #3
0
struct stasis_app_control *control_create(struct ast_channel *channel, struct stasis_app *app)
{
	struct stasis_app_control *control;
	int res;

	control = ao2_alloc(sizeof(*control), control_dtor);
	if (!control) {
		return NULL;
	}

	AST_LIST_HEAD_INIT(&control->add_rules);
	AST_LIST_HEAD_INIT(&control->remove_rules);

	res = ast_cond_init(&control->wait_cond, NULL);
	if (res != 0) {
		ast_log(LOG_ERROR, "Error initializing ast_cond_t: %s\n",
			strerror(errno));
		ao2_ref(control, -1);
		return NULL;
	}

	control->app = ao2_bump(app);

	ast_channel_ref(channel);
	control->channel = channel;

	control->command_queue = ao2_container_alloc_list(
		AO2_ALLOC_OPT_LOCK_MUTEX, 0, NULL, NULL);
	if (!control->command_queue) {
		ao2_ref(control, -1);
		return NULL;
	}

	return control;
}
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;
}
/* Called with ast locked */
static int local_queryoption(struct ast_channel *ast, int option, void *data, int *datalen)
{
	struct local_pvt *p;
	struct ast_channel *bridged = NULL;
	struct ast_channel *tmp = NULL;
	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);
	if (!(tmp = IS_OUTBOUND(ast, p) ? p->owner : p->chan)) {
		ao2_unlock(p);
		return -1;
	}
	ast_channel_ref(tmp);
	ao2_unlock(p);
	ast_channel_unlock(ast); /* Held when called, unlock before locking another channel */

	ast_channel_lock(tmp);
	if (!(bridged = ast_bridged_channel(tmp))) {
		res = -1;
		ast_channel_unlock(tmp);
		goto query_cleanup;
	}
	ast_channel_ref(bridged);
	ast_channel_unlock(tmp);

query_cleanup:
	if (bridged) {
		res = ast_channel_queryoption(bridged, option, data, datalen, 0);
		bridged = ast_channel_unref(bridged);
	}
	if (tmp) {
		tmp = ast_channel_unref(tmp);
	}
	ast_channel_lock(ast); /* Lock back before we leave */

	return res;
}
/* 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;
}
Example #7
0
static int snoop_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
{
	struct stasis_app_snoop *snoop = ast_channel_tech_pvt(oldchan);

	if (snoop->chan != oldchan) {
		return -1;
	}

	ast_channel_unref(snoop->chan);
	ast_channel_ref(newchan);
	snoop->chan = newchan;

	return 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;
}
int ast_local_setup_bridge(struct ast_channel *ast, struct ast_bridge *bridge, struct ast_channel *swap, struct ast_bridge_features *features)
{
	struct local_pvt *p;
	struct local_pvt *found;
	int res = -1;

	/* Sanity checks. */
	if (!ast || !bridge) {
		ast_bridge_features_destroy(features);
		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)) {
			ao2_ref(bridge, +1);
			if (swap) {
				ast_channel_ref(swap);
			}
			found->type = LOCAL_CALL_ACTION_BRIDGE;
			found->action.bridge.join = bridge;
			found->action.bridge.swap = swap;
			found->action.bridge.features = features;
			res = 0;
		} else {
			ast_bridge_features_destroy(features);
		}
		ao2_unlock(found);
		ao2_ref(found, -1);
	}

	return res;
}
/*!
 * \brief queue a frame onto either the p->owner or p->chan
 *
 * \note the ast_unreal_pvt MUST have it's ref count bumped before entering this function and
 * decremented after this function is called.  This is a side effect of the deadlock
 * avoidance that is necessary to lock 2 channels and a tech_pvt.  Without a ref counted
 * ast_unreal_pvt, it is impossible to guarantee it will not be destroyed by another thread
 * during deadlock avoidance.
 */
static int unreal_queue_frame(struct ast_unreal_pvt *p, int isoutbound, struct ast_frame *f,
	struct ast_channel *us, int us_locked)
{
	struct ast_channel *other;

	/* Recalculate outbound channel */
	other = isoutbound ? p->owner : p->chan;
	if (!other) {
		return 0;
	}

	/* do not queue media frames if a generator is on both unreal channels */
	if (us
		&& (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO)
		&& ast_channel_generator(us)
		&& ast_channel_generator(other)) {
		return 0;
	}

	/* grab a ref on the channel before unlocking the pvt,
	 * other can not go away from us now regardless of locking */
	ast_channel_ref(other);
	if (us && us_locked) {
		ast_channel_unlock(us);
	}
	ao2_unlock(p);

	if (f->frametype == AST_FRAME_CONTROL && f->subclass.integer == AST_CONTROL_RINGING) {
		ast_setstate(other, AST_STATE_RINGING);
	}
	ast_queue_frame(other, f);

	other = ast_channel_unref(other);
	if (us && us_locked) {
		ast_channel_lock(us);
	}
	ao2_lock(p);

	return 0;
}
Example #11
0
static void bridge_stasis_queue_join_action(struct ast_bridge *self,
        struct ast_bridge_channel *bridge_channel, struct ast_bridge_channel *swap)
{
    struct defer_bridge_add_obj *defer;

    defer = ao2_alloc_options(sizeof(*defer), defer_bridge_add_dtor,
                              AO2_ALLOC_OPT_LOCK_NOLOCK);
    if (!defer) {
        return;
    }
    ao2_ref(self, +1);
    defer->bridge = self;
    if (swap) {
        ast_channel_ref(swap->chan);
        defer->swap = swap->chan;
    }

    ast_channel_lock(bridge_channel->chan);
    command_prestart_queue_command(bridge_channel->chan, defer_bridge_add,
                                   defer, __ao2_cleanup);
    ast_channel_unlock(bridge_channel->chan);
}
Example #12
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;
}
Example #13
0
/*! \brief Called when a frame should be written out to a channel */
static int bridge_write(struct ast_channel *ast, struct ast_frame *f)
{
	struct bridge_pvt *p = ast->tech_pvt;
	struct ast_channel *other = NULL;

	ao2_lock(p);
	/* only write frames to output. */
	if (p->input == ast) {
		other = p->output;
		if (other) {
			ast_channel_ref(other);
		}
	}
	ao2_unlock(p);

	if (other) {
		ast_channel_unlock(ast);
		ast_queue_frame(other, f);
		ast_channel_lock(ast);
		other = ast_channel_unref(other);
	}

	return 0;
}
Example #14
0
struct ast_channel *stasis_app_control_snoop(struct ast_channel *chan,
	enum stasis_app_snoop_direction spy, enum stasis_app_snoop_direction whisper,
	const char *app, const char *app_args, const char *snoop_id)
{
	RAII_VAR(struct stasis_app_snoop *, snoop, NULL, ao2_cleanup);
	struct ast_format_cap *caps;
	pthread_t thread;
	struct ast_assigned_ids assignedids = {
		.uniqueid = snoop_id,
	};

	if (spy == STASIS_SNOOP_DIRECTION_NONE &&
		whisper == STASIS_SNOOP_DIRECTION_NONE) {
		return NULL;
	}

	snoop = ao2_alloc_options(sizeof(*snoop), snoop_destroy, AO2_ALLOC_OPT_LOCK_NOLOCK);
	if (!snoop) {
		return NULL;
	}

	/* Allocate a buffer to store the Stasis application and arguments in */
	snoop->app = ast_str_create(64);
	if (!snoop->app) {
		return NULL;
	}

	ast_str_set(&snoop->app, 0, "%s", app);
	if (!ast_strlen_zero(app_args)) {
		ast_str_append(&snoop->app, 0, ",%s", app_args);
	}

	/* Set up a timer for the Snoop channel so it wakes up at a specific interval */
	snoop->timer = ast_timer_open();
	if (!snoop->timer) {
		return NULL;
	}
	ast_timer_set_rate(snoop->timer, 1000 / SNOOP_INTERVAL);

	/* Determine which signed linear format should be used */
	snoop_determine_format(chan, snoop);

	/* Allocate a Snoop channel and set up various parameters */
	snoop->chan = ast_channel_alloc(1, AST_STATE_UP, "", "", "", "", "", &assignedids, NULL, 0, "Snoop/%s-%08x", ast_channel_uniqueid(chan),
		(unsigned)ast_atomic_fetchadd_int((int *)&chan_idx, +1));
	if (!snoop->chan) {
		return NULL;
	}

	ast_copy_string(snoop->uniqueid, ast_channel_uniqueid(chan), sizeof(snoop->uniqueid));

	/* To keep the channel valid on the Snoop structure until it is destroyed we bump the ref up here */
	ast_channel_ref(snoop->chan);

	ast_channel_tech_set(snoop->chan, &snoop_tech);
	ao2_ref(snoop, +1);
	ast_channel_tech_pvt_set(snoop->chan, snoop);
	ast_channel_set_fd(snoop->chan, 0, ast_timer_fd(snoop->timer));

	/* The format on the Snoop channel will be this signed linear format, and it will never change */
	caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
	if (!caps) {
		ast_channel_unlock(snoop->chan);
		ast_hangup(snoop->chan);
		return NULL;
	}
	ast_format_cap_append(caps, snoop->spy_format, 0);
	ast_channel_nativeformats_set(snoop->chan, caps);
	ao2_ref(caps, -1);

	ast_channel_set_writeformat(snoop->chan, snoop->spy_format);
	ast_channel_set_rawwriteformat(snoop->chan, snoop->spy_format);
	ast_channel_set_readformat(snoop->chan, snoop->spy_format);
	ast_channel_set_rawreadformat(snoop->chan, snoop->spy_format);

	ast_channel_unlock(snoop->chan);

	if (spy != STASIS_SNOOP_DIRECTION_NONE) {
		if (snoop_setup_audiohook(chan, AST_AUDIOHOOK_TYPE_SPY, spy, &snoop->spy_direction, &snoop->spy)) {
			ast_hangup(snoop->chan);
			return NULL;
		}

		snoop->spy_samples = ast_format_get_sample_rate(snoop->spy_format) / (1000 / SNOOP_INTERVAL);
		snoop->spy_active = 1;
	}

	/* If whispering is enabled set up the audiohook */
	if (whisper != STASIS_SNOOP_DIRECTION_NONE) {
		if (snoop_setup_audiohook(chan, AST_AUDIOHOOK_TYPE_WHISPER, whisper, &snoop->whisper_direction, &snoop->whisper)) {
			ast_hangup(snoop->chan);
			return NULL;
		}

		snoop->whisper_active = 1;
	}

	/* Create the thread which services the Snoop channel */
	ao2_ref(snoop, +1);
	if (ast_pthread_create_detached_background(&thread, NULL, snoop_stasis_thread, snoop)) {
		ao2_cleanup(snoop);

		/* No other thread is servicing this channel so we can immediately hang it up */
		ast_hangup(snoop->chan);
		return NULL;
	}

	publish_chanspy_message(snoop, 1);

	/* The caller of this has a reference as well */
	return ast_channel_ref(snoop->chan);
}
Example #15
0
int ast_cel_report_event(struct ast_channel *chan, enum ast_cel_event_type event_type,
		const char *userdefevname, const char *extra, struct ast_channel *peer2)
{
	struct timeval eventtime;
	struct ast_event *ev;
	const char *peername = "";
	struct ast_channel *peer;
	char *linkedid = ast_strdupa(ast_channel_linkedid(chan));

	/* Make sure a reload is not occurring while we're checking to see if this
	 * is an event that we care about.  We could lose an important event in this
	 * process otherwise. */
	ast_mutex_lock(&reload_lock);

	/* Record the linkedid of new channels if we are tracking LINKEDID_END even if we aren't
	 * reporting on CHANNEL_START so we can track when to send LINKEDID_END */
	if (cel_enabled && ast_cel_track_event(AST_CEL_LINKEDID_END) && event_type == AST_CEL_CHANNEL_START && linkedid) {
		if (ast_cel_linkedid_ref(linkedid)) {
			ast_mutex_unlock(&reload_lock);
			return -1;
		}
	}

	if (!cel_enabled || !ast_cel_track_event(event_type)) {
		ast_mutex_unlock(&reload_lock);
		return 0;
	}

	if (event_type == AST_CEL_APP_START || event_type == AST_CEL_APP_END) {
		char *app;
		if (!(app = ao2_find(appset, (char *) ast_channel_appl(chan), OBJ_POINTER))) {
			ast_mutex_unlock(&reload_lock);
			return 0;
		}
		ao2_ref(app, -1);
	}

	ast_mutex_unlock(&reload_lock);

	ast_channel_lock(chan);
	peer = ast_bridged_channel(chan);
	if (peer) {
		ast_channel_ref(peer);
	}
	ast_channel_unlock(chan);

	if (peer) {
		ast_channel_lock(peer);
		peername = ast_strdupa(ast_channel_name(peer));
		ast_channel_unlock(peer);
	} else if (peer2) {
		ast_channel_lock(peer2);
		peername = ast_strdupa(ast_channel_name(peer2));
		ast_channel_unlock(peer2);
	}

	if (!userdefevname) {
		userdefevname = "";
	}

	if (!extra) {
		extra = "";
	}

	eventtime = ast_tvnow();

	ast_channel_lock(chan);

	ev = ast_event_new(AST_EVENT_CEL,
		AST_EVENT_IE_CEL_EVENT_TYPE, AST_EVENT_IE_PLTYPE_UINT, event_type,
		AST_EVENT_IE_CEL_EVENT_TIME, AST_EVENT_IE_PLTYPE_UINT, eventtime.tv_sec,
		AST_EVENT_IE_CEL_EVENT_TIME_USEC, AST_EVENT_IE_PLTYPE_UINT, eventtime.tv_usec,
		AST_EVENT_IE_CEL_USEREVENT_NAME, AST_EVENT_IE_PLTYPE_STR, userdefevname,
		AST_EVENT_IE_CEL_CIDNAME, AST_EVENT_IE_PLTYPE_STR,
			S_COR(ast_channel_caller(chan)->id.name.valid, ast_channel_caller(chan)->id.name.str, ""),
		AST_EVENT_IE_CEL_CIDNUM, AST_EVENT_IE_PLTYPE_STR,
			S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, ""),
		AST_EVENT_IE_CEL_CIDANI, AST_EVENT_IE_PLTYPE_STR,
			S_COR(ast_channel_caller(chan)->ani.number.valid, ast_channel_caller(chan)->ani.number.str, ""),
		AST_EVENT_IE_CEL_CIDRDNIS, AST_EVENT_IE_PLTYPE_STR,
			S_COR(ast_channel_redirecting(chan)->from.number.valid, ast_channel_redirecting(chan)->from.number.str, ""),
		AST_EVENT_IE_CEL_CIDDNID, AST_EVENT_IE_PLTYPE_STR,
			S_OR(ast_channel_dialed(chan)->number.str, ""),
		AST_EVENT_IE_CEL_EXTEN, AST_EVENT_IE_PLTYPE_STR, ast_channel_exten(chan),
		AST_EVENT_IE_CEL_CONTEXT, AST_EVENT_IE_PLTYPE_STR, ast_channel_context(chan),
		AST_EVENT_IE_CEL_CHANNAME, AST_EVENT_IE_PLTYPE_STR, ast_channel_name(chan),
		AST_EVENT_IE_CEL_APPNAME, AST_EVENT_IE_PLTYPE_STR, S_OR(ast_channel_appl(chan), ""),
		AST_EVENT_IE_CEL_APPDATA, AST_EVENT_IE_PLTYPE_STR, S_OR(ast_channel_data(chan), ""),
		AST_EVENT_IE_CEL_AMAFLAGS, AST_EVENT_IE_PLTYPE_UINT, ast_channel_amaflags(chan),
		AST_EVENT_IE_CEL_ACCTCODE, AST_EVENT_IE_PLTYPE_STR, ast_channel_accountcode(chan),
		AST_EVENT_IE_CEL_PEERACCT, AST_EVENT_IE_PLTYPE_STR, ast_channel_peeraccount(chan),
		AST_EVENT_IE_CEL_UNIQUEID, AST_EVENT_IE_PLTYPE_STR, ast_channel_uniqueid(chan),
		AST_EVENT_IE_CEL_LINKEDID, AST_EVENT_IE_PLTYPE_STR, ast_channel_linkedid(chan),
		AST_EVENT_IE_CEL_USERFIELD, AST_EVENT_IE_PLTYPE_STR, ast_channel_userfield(chan),
		AST_EVENT_IE_CEL_EXTRA, AST_EVENT_IE_PLTYPE_STR, extra,
		AST_EVENT_IE_CEL_PEER, AST_EVENT_IE_PLTYPE_STR, peername,
		AST_EVENT_IE_END);

	ast_channel_unlock(chan);

	if (peer) {
		peer = ast_channel_unref(peer);
	}

	if (ev && ast_event_queue(ev)) {
		ast_event_destroy(ev);
		return -1;
	}

	return 0;
}
Example #16
0
int ast_cel_report_event(struct ast_channel *chan, enum ast_cel_event_type event_type,
		const char *userdefevname, const char *extra, struct ast_channel *peer2)
{
	struct timeval eventtime;
	struct ast_event *ev;
	const char *peername = "";
	struct ast_channel *peer;

	ast_channel_lock(chan);
	peer = ast_bridged_channel(chan);
	if (peer) {
		ast_channel_ref(peer);
	}
	ast_channel_unlock(chan);

	/* Make sure a reload is not occurring while we're checking to see if this
	 * is an event that we care about.  We could lose an important event in this
	 * process otherwise. */
	ast_mutex_lock(&reload_lock);

	if (!cel_enabled || !ast_cel_track_event(event_type)) {
		ast_mutex_unlock(&reload_lock);
		if (peer) {
			ast_channel_unref(peer);
		}
		return 0;
	}

	if (event_type == AST_CEL_APP_START || event_type == AST_CEL_APP_END) {
		char *app;
		if (!(app = ao2_find(appset, (char *) chan->appl, OBJ_POINTER))) {
			ast_mutex_unlock(&reload_lock);
			if (peer) {
				ast_channel_unref(peer);
			}
			return 0;
		}
		ao2_ref(app, -1);
	}

	ast_mutex_unlock(&reload_lock);

	if (peer) {
		ast_channel_lock(peer);
		peername = ast_strdupa(peer->name);
		ast_channel_unlock(peer);
	} else if (peer2) {
		ast_channel_lock(peer2);
		peername = ast_strdupa(peer2->name);
		ast_channel_unlock(peer2);
	}

	if (!userdefevname) {
		userdefevname = "";
	}

	if (!extra) {
		extra = "";
	}

	eventtime = ast_tvnow();

	ast_channel_lock(chan);

	ev = ast_event_new(AST_EVENT_CEL,
		AST_EVENT_IE_CEL_EVENT_TYPE, AST_EVENT_IE_PLTYPE_UINT, event_type,
		AST_EVENT_IE_CEL_EVENT_TIME, AST_EVENT_IE_PLTYPE_UINT, eventtime.tv_sec,
		AST_EVENT_IE_CEL_EVENT_TIME_USEC, AST_EVENT_IE_PLTYPE_UINT, eventtime.tv_usec,
		AST_EVENT_IE_CEL_USEREVENT_NAME, AST_EVENT_IE_PLTYPE_STR, userdefevname,
		AST_EVENT_IE_CEL_CIDNAME, AST_EVENT_IE_PLTYPE_STR,
			S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, ""),
		AST_EVENT_IE_CEL_CIDNUM, AST_EVENT_IE_PLTYPE_STR,
			S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, ""),
		AST_EVENT_IE_CEL_CIDANI, AST_EVENT_IE_PLTYPE_STR,
			S_COR(chan->caller.ani.number.valid, chan->caller.ani.number.str, ""),
		AST_EVENT_IE_CEL_CIDRDNIS, AST_EVENT_IE_PLTYPE_STR,
			S_COR(chan->redirecting.from.number.valid, chan->redirecting.from.number.str, ""),
		AST_EVENT_IE_CEL_CIDDNID, AST_EVENT_IE_PLTYPE_STR,
			S_OR(chan->dialed.number.str, ""),
		AST_EVENT_IE_CEL_EXTEN, AST_EVENT_IE_PLTYPE_STR, chan->exten,
		AST_EVENT_IE_CEL_CONTEXT, AST_EVENT_IE_PLTYPE_STR, chan->context,
		AST_EVENT_IE_CEL_CHANNAME, AST_EVENT_IE_PLTYPE_STR, chan->name,
		AST_EVENT_IE_CEL_APPNAME, AST_EVENT_IE_PLTYPE_STR, S_OR(chan->appl, ""),
		AST_EVENT_IE_CEL_APPDATA, AST_EVENT_IE_PLTYPE_STR, S_OR(chan->data, ""),
		AST_EVENT_IE_CEL_AMAFLAGS, AST_EVENT_IE_PLTYPE_UINT, chan->amaflags,
		AST_EVENT_IE_CEL_ACCTCODE, AST_EVENT_IE_PLTYPE_STR, chan->accountcode,
		AST_EVENT_IE_CEL_PEERACCT, AST_EVENT_IE_PLTYPE_STR, chan->peeraccount,
		AST_EVENT_IE_CEL_UNIQUEID, AST_EVENT_IE_PLTYPE_STR, chan->uniqueid,
		AST_EVENT_IE_CEL_LINKEDID, AST_EVENT_IE_PLTYPE_STR, chan->linkedid,
		AST_EVENT_IE_CEL_USERFIELD, AST_EVENT_IE_PLTYPE_STR, chan->userfield,
		AST_EVENT_IE_CEL_EXTRA, AST_EVENT_IE_PLTYPE_STR, extra,
		AST_EVENT_IE_CEL_PEER, AST_EVENT_IE_PLTYPE_STR, peername,
		AST_EVENT_IE_END);

	ast_channel_unlock(chan);

	if (peer) {
		peer = ast_channel_unref(peer);
	}

	if (ev && ast_event_queue(ev)) {
		ast_event_destroy(ev);
		return -1;
	}

	return 0;
}
/*!
 * \internal
 * \note This function assumes that we're only called from the "outbound" local channel side
 *
 * \note it is assummed p is locked and reffed before entering this function
 */
static void check_bridge(struct ast_channel *ast, struct local_pvt *p)
{
	struct ast_channel *owner;
	struct ast_channel *chan;
	struct ast_channel *bridged_chan;
	struct ast_frame *f;

	/* Do a few conditional checks early on just to see if this optimization is possible */
	if (ast_test_flag(p, LOCAL_NO_OPTIMIZATION | LOCAL_ALREADY_MASQED)
		|| !p->chan || !p->owner) {
		return;
	}

	/* Safely get the channel bridged to p->chan */
	chan = ast_channel_ref(p->chan);

	ao2_unlock(p); /* don't call bridged channel with the pvt locked */
	bridged_chan = ast_bridged_channel(chan);
	ao2_lock(p);

	chan = ast_channel_unref(chan);

	/* since we had to unlock p to get the bridged chan, validate our
	 * data once again and verify the bridged channel is what we expect
	 * it to be in order to perform this optimization */
	if (ast_test_flag(p, LOCAL_NO_OPTIMIZATION | LOCAL_ALREADY_MASQED)
		|| !p->chan || !p->owner
		|| (ast_channel_internal_bridged_channel(p->chan) != bridged_chan)) {
		return;
	}

	/* only do the masquerade if we are being called on the outbound channel,
	   if it has been bridged to another channel and if there are no pending
	   frames on the owner channel (because they would be transferred to the
	   outbound channel during the masquerade)
	*/
	if (!ast_channel_internal_bridged_channel(p->chan) /* Not ast_bridged_channel!  Only go one step! */
		|| !AST_LIST_EMPTY(ast_channel_readq(p->owner))
		|| ast != p->chan /* Sanity check (should always be false) */) {
		return;
	}

	/* Masquerade bridged channel into owner */
	/* Lock everything we need, one by one, and give up if
	   we can't get everything.  Remember, we'll get another
	   chance in just a little bit */
	if (ast_channel_trylock(ast_channel_internal_bridged_channel(p->chan))) {
		return;
	}
	if (ast_check_hangup(ast_channel_internal_bridged_channel(p->chan))
		|| ast_channel_trylock(p->owner)) {
		ast_channel_unlock(ast_channel_internal_bridged_channel(p->chan));
		return;
	}

	/*
	 * At this point we have 4 locks:
	 * p, p->chan (same as ast), p->chan->_bridge, p->owner
	 *
	 * Flush a voice or video frame on the outbound channel to make
	 * the queue empty faster so we can get optimized out.
	 */
	f = AST_LIST_FIRST(ast_channel_readq(p->chan));
	if (f && (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO)) {
		AST_LIST_REMOVE_HEAD(ast_channel_readq(p->chan), frame_list);
		ast_frfree(f);
		f = AST_LIST_FIRST(ast_channel_readq(p->chan));
	}

	if (f
		|| ast_check_hangup(p->owner)
		|| ast_channel_masquerade(p->owner, ast_channel_internal_bridged_channel(p->chan))) {
		ast_channel_unlock(p->owner);
		ast_channel_unlock(ast_channel_internal_bridged_channel(p->chan));
		return;
	}

	/* Masquerade got setup. */
	ast_debug(4, "Masquerading %s <- %s\n",
		ast_channel_name(p->owner),
		ast_channel_name(ast_channel_internal_bridged_channel(p->chan)));
	if (ast_channel_monitor(p->owner)
		&& !ast_channel_monitor(ast_channel_internal_bridged_channel(p->chan))) {
		struct ast_channel_monitor *tmp;

		/* If a local channel is being monitored, we don't want a masquerade
		 * to cause the monitor to go away. Since the masquerade swaps the monitors,
		 * pre-swapping the monitors before the masquerade will ensure that the monitor
		 * ends up where it is expected.
		 */
		tmp = ast_channel_monitor(p->owner);
		ast_channel_monitor_set(p->owner, ast_channel_monitor(ast_channel_internal_bridged_channel(p->chan)));
		ast_channel_monitor_set(ast_channel_internal_bridged_channel(p->chan), tmp);
	}
	if (ast_channel_audiohooks(p->chan)) {
		struct ast_audiohook_list *audiohooks_swapper;

		audiohooks_swapper = ast_channel_audiohooks(p->chan);
		ast_channel_audiohooks_set(p->chan, ast_channel_audiohooks(p->owner));
		ast_channel_audiohooks_set(p->owner, audiohooks_swapper);
	}

	/* If any Caller ID was set, preserve it after masquerade like above. We must check
	 * to see if Caller ID was set because otherwise we'll mistakingly copy info not
	 * set from the dialplan and will overwrite the real channel Caller ID. The reason
	 * for this whole preswapping action is because the Caller ID is set on the channel
	 * thread (which is the to be masqueraded away local channel) before both local
	 * channels are optimized away.
	 */
	if (ast_channel_caller(p->owner)->id.name.valid || ast_channel_caller(p->owner)->id.number.valid
		|| ast_channel_caller(p->owner)->id.subaddress.valid || ast_channel_caller(p->owner)->ani.name.valid
		|| ast_channel_caller(p->owner)->ani.number.valid || ast_channel_caller(p->owner)->ani.subaddress.valid) {
		SWAP(*ast_channel_caller(p->owner), *ast_channel_caller(ast_channel_internal_bridged_channel(p->chan)));
	}
	if (ast_channel_redirecting(p->owner)->from.name.valid || ast_channel_redirecting(p->owner)->from.number.valid
		|| ast_channel_redirecting(p->owner)->from.subaddress.valid || ast_channel_redirecting(p->owner)->to.name.valid
		|| ast_channel_redirecting(p->owner)->to.number.valid || ast_channel_redirecting(p->owner)->to.subaddress.valid) {
		SWAP(*ast_channel_redirecting(p->owner), *ast_channel_redirecting(ast_channel_internal_bridged_channel(p->chan)));
	}
	if (ast_channel_dialed(p->owner)->number.str || ast_channel_dialed(p->owner)->subaddress.valid) {
		SWAP(*ast_channel_dialed(p->owner), *ast_channel_dialed(ast_channel_internal_bridged_channel(p->chan)));
	}
	ast_app_group_update(p->chan, p->owner);
	ast_set_flag(p, LOCAL_ALREADY_MASQED);

	ast_channel_unlock(p->owner);
	ast_channel_unlock(ast_channel_internal_bridged_channel(p->chan));

	/* Do the masquerade now. */
	owner = ast_channel_ref(p->owner);
	ao2_unlock(p);
	ast_channel_unlock(ast);
	ast_do_masquerade(owner);
	ast_channel_unref(owner);
	ast_channel_lock(ast);
	ao2_lock(p);
}
Example #18
0
int ast_unreal_channel_push_to_bridge(struct ast_channel *ast, struct ast_bridge *bridge, unsigned int flags)
{
	struct ast_bridge_features *features;
	struct ast_channel *chan;
	struct ast_channel *owner;
	RAII_VAR(struct ast_unreal_pvt *, p, NULL, ao2_cleanup);

	RAII_VAR(struct ast_callid *, bridge_callid, NULL, ast_callid_cleanup);

	ast_bridge_lock(bridge);
	bridge_callid = bridge->callid ? ast_callid_ref(bridge->callid) : NULL;
	ast_bridge_unlock(bridge);

	{
		SCOPED_CHANNELLOCK(lock, ast);
		p = ast_channel_tech_pvt(ast);
		if (!p) {
			return -1;
		}
		ao2_ref(p, +1);
	}

	{
		SCOPED_AO2LOCK(lock, p);
		chan = p->chan;
		if (!chan) {
			return -1;
		}

		owner = p->owner;
		if (!owner) {
			return -1;
		}

		ast_channel_ref(chan);
		ast_channel_ref(owner);
	}

	if (bridge_callid) {
		struct ast_callid *chan_callid;
		struct ast_callid *owner_callid;

		/* chan side call ID setting */
		ast_channel_lock(chan);

		chan_callid = ast_channel_callid(chan);
		if (!chan_callid) {
			ast_channel_callid_set(chan, bridge_callid);
		}
		ast_channel_unlock(chan);
		ast_callid_cleanup(chan_callid);

		/* owner side call ID setting */
		ast_channel_lock(owner);

		owner_callid = ast_channel_callid(owner);
		if (!owner_callid) {
			ast_channel_callid_set(owner, bridge_callid);
		}

		ast_channel_unlock(owner);
		ast_callid_cleanup(owner_callid);
	}

	/* We are done with the owner now that its call ID matches the bridge */
	ast_channel_unref(owner);
	owner = NULL;

	features = ast_bridge_features_new();
	if (!features) {
		ast_channel_unref(chan);
		return -1;
	}

	ast_set_flag(&features->feature_flags, flags);

	/* Impart the semi2 channel into the bridge */
	if (ast_bridge_impart(bridge, chan, NULL, features,
		AST_BRIDGE_IMPART_CHAN_INDEPENDENT)) {
		ast_bridge_features_destroy(features);
		ast_channel_unref(chan);
		return -1;
	}

	ao2_lock(p);
	ast_set_flag(p, AST_UNREAL_CARETAKER_THREAD);
	ao2_unlock(p);
	ast_channel_unref(chan);

	return 0;
}
/*!
 * \internal
 * \brief Determine if an extension is a parking extension
 */
static int parking_is_exten_park(const char *context, const char *exten)
{
	struct ast_exten *exten_obj;
	struct pbx_find_info info = { .stacklen = 0 }; /* the rest is reset in pbx_find_extension */
	const char *app_at_exten;

	ast_debug(4, "Checking if %s@%s is a parking exten\n", exten, context);
	exten_obj = pbx_find_extension(NULL, NULL, &info, context, exten, 1, NULL, NULL, E_MATCH);
	if (!exten_obj) {
		return 0;
	}

	app_at_exten = ast_get_extension_app(exten_obj);
	if (!app_at_exten || strcasecmp(PARK_APPLICATION, app_at_exten)) {
		return 0;
	}

	return 1;
}

/*!
 * \internal
 * \since 12.0.0
 * \brief Perform a blind transfer to a parking lot
 *
 * In general, most parking features should work to call this function. This will safely
 * park either a channel in the bridge with \ref bridge_channel or will park the entire
 * bridge if more than one channel is in the bridge. It will create the correct data to
 * pass to the \ref AstBridging Bridging API to safely park the channel.
 *
 * \param bridge_channel The bridge_channel representing the channel performing the park
 * \param context The context to blind transfer to
 * \param exten The extension to blind transfer to
 * \param parked_channel_cb Optional callback executed prior to sending the parked channel into the bridge
 * \param parked_channel_data Data for the parked_channel_cb
 *
 * \retval 0 on success
 * \retval non-zero on error
 */
static int parking_blind_transfer_park(struct ast_bridge_channel *bridge_channel,
		const char *context, const char *exten, transfer_channel_cb parked_channel_cb,
		struct transfer_channel_data *parked_channel_data)
{
	RAII_VAR(struct ast_bridge_channel *, other, NULL, ao2_cleanup);
	RAII_VAR(struct ast_channel *, other_chan, NULL, ast_channel_cleanup);

	struct ast_exten *e;
	struct pbx_find_info find_info = { .stacklen = 0 };
	int peer_count;

	if (ast_strlen_zero(context) || ast_strlen_zero(exten)) {
		return -1;
	}

	if (!bridge_channel->in_bridge) {
		return -1;
	}

	if (!parking_is_exten_park(context, exten)) {
		return -1;
	}

	ast_bridge_channel_lock_bridge(bridge_channel);
	peer_count = bridge_channel->bridge->num_channels;
	if (peer_count == 2) {
		other = ast_bridge_channel_peer(bridge_channel);
		ao2_ref(other, +1);
		other_chan = other->chan;
		ast_channel_ref(other_chan);
	}
	ast_bridge_unlock(bridge_channel->bridge);

	if (peer_count < 2) {
		/* There is nothing to do if there is no one to park. */
		return -1;
	}

	/* With a multiparty bridge, we need to do a regular blind transfer. We link the
	 * existing bridge to the parking lot with a Local channel rather than
	 * transferring others. */
	if (peer_count > 2) {
		struct ast_channel *transfer_chan = NULL;

		transfer_chan = park_local_transfer(bridge_channel->chan, context, exten, parked_channel_data);
		if (!transfer_chan) {
			return -1;
		}
		ast_channel_ref(transfer_chan);

		if (parked_channel_cb) {
			parked_channel_cb(transfer_chan, parked_channel_data, AST_BRIDGE_TRANSFER_MULTI_PARTY);
		}

		if (ast_bridge_impart(bridge_channel->bridge, transfer_chan, NULL, NULL,
			AST_BRIDGE_IMPART_CHAN_INDEPENDENT)) {
			ast_hangup(transfer_chan);
			ast_channel_unref(transfer_chan);
			return -1;
		}

		ast_channel_unref(transfer_chan);

		return 0;
	}

	/* Subscribe to park messages with the other channel entering */
	if (create_parked_subscription_full(bridge_channel->chan, ast_channel_uniqueid(other->chan), 1, parked_channel_data)) {
		return -1;
	}

	if (parked_channel_cb) {
		parked_channel_cb(other_chan, parked_channel_data, AST_BRIDGE_TRANSFER_SINGLE_PARTY);
	}

	e = pbx_find_extension(NULL, NULL, &find_info, context, exten, 1, NULL, NULL, E_MATCH);

	/* Write the park frame with the intended recipient and other data out to the bridge. */
	ast_bridge_channel_write_park(bridge_channel,
		ast_channel_uniqueid(other_chan),
		ast_channel_uniqueid(bridge_channel->chan),
		e ? ast_get_extension_app_data(e) : NULL);

	return 0;
}

/*!
 * \internal
 * \since 12.0.0
 * \brief Perform a direct park on a channel in a bridge
 *
 * \note This will be called from within the \ref AstBridging Bridging API
 *
 * \param bridge_channel The bridge_channel representing the channel to be parked
 * \param uuid_parkee The UUID of the channel being parked
 * \param uuid_parker The UUID of the channel performing the park
 * \param app_data Application parseable data to pass to the parking application
 */
static int parking_park_bridge_channel(struct ast_bridge_channel *bridge_channel, const char *uuid_parkee, const char *uuid_parker, const char *app_data)
{
	RAII_VAR(struct ast_bridge *, parking_bridge, NULL, ao2_cleanup);
	RAII_VAR(struct ast_bridge *, original_bridge, NULL, ao2_cleanup);
	RAII_VAR(struct ast_channel *, parker, NULL, ao2_cleanup);

	if (strcmp(ast_channel_uniqueid(bridge_channel->chan), uuid_parkee)) {
		/* We aren't the parkee, so ignore this action. */
		return -1;
	}

	parker = ast_channel_get_by_name(uuid_parker);

	if (!parker) {
		ast_log(LOG_NOTICE, "Channel with uuid %s left before we could start parking the call. Parking canceled.\n", uuid_parker);
		publish_parked_call_failure(bridge_channel->chan);
		return -1;
	}

	if (!(parking_bridge = park_application_setup(bridge_channel->chan, parker, app_data, NULL))) {
		publish_parked_call_failure(bridge_channel->chan);
		return -1;
	}

	ast_bridge_set_transfer_variables(bridge_channel->chan, ast_channel_name(parker), 0);

	/* bridge_channel must be locked so we can get a reference to the bridge it is currently on */
	ao2_lock(bridge_channel);

	original_bridge = bridge_channel->bridge;
	if (!original_bridge) {
		ao2_unlock(bridge_channel);
		publish_parked_call_failure(bridge_channel->chan);
		return -1;
	}

	ao2_ref(original_bridge, +1); /* Cleaned by RAII_VAR */

	ao2_unlock(bridge_channel);

	if (ast_bridge_move(parking_bridge, original_bridge, bridge_channel->chan, NULL, 1)) {
		ast_log(LOG_ERROR, "Failed to move %s into the parking bridge.\n",
			ast_channel_name(bridge_channel->chan));
		return -1;
	}

	return 0;
}