Esempio n. 1
0
/*! \brief Internal built in feature for blind transfers */
static int feature_blind_transfer(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt)
{
	char exten[AST_MAX_EXTENSION] = "";
	struct ast_channel *chan = NULL;
	struct ast_bridge_features_blind_transfer *blind_transfer = hook_pvt;
	const char *context = (blind_transfer && !ast_strlen_zero(blind_transfer->context) ? blind_transfer->context : bridge_channel->chan->context);

	/* Grab the extension to transfer to */
	if (!grab_transfer(bridge_channel->chan, exten, sizeof(exten), context)) {
		ast_stream_and_wait(bridge_channel->chan, "pbx-invalid", AST_DIGIT_ANY);
		ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_WAIT);
		return 0;
	}

	/* Get a channel that is the destination we wish to call */
	if (!(chan = dial_transfer(bridge_channel->chan, exten, context))) {
		ast_stream_and_wait(bridge_channel->chan, "beeperr", AST_DIGIT_ANY);
		ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_WAIT);
		return 0;
	}

	/* This is sort of the fun part. We impart the above channel onto the bridge, and have it take our place. */
	ast_bridge_impart(bridge, chan, bridge_channel->chan, NULL);

	return 0;
}
Esempio n. 2
0
/*! \brief Called when the channel should actually be dialed */
static int bridge_call(struct ast_channel *ast, char *dest, int timeout)
{
	struct bridge_pvt *p = ast->tech_pvt;

	/* If no bridge has been provided on the input channel, bail out */
	if (!ast->bridge) {
		return -1;
	}

	/* Impart the output channel upon the given bridge of the input channel */
	ast_bridge_impart(p->input->bridge, p->output, NULL, NULL, 0);

	return 0;
}
Esempio n. 3
0
static void *app_control_dial(struct stasis_app_control *control,
	struct ast_channel *chan, void *data)
{
	RAII_VAR(struct ast_dial *, dial, ast_dial_create(), ast_dial_destroy);
	RAII_VAR(struct stasis_app_control_dial_data *, dial_data, data, ast_free);
	enum ast_dial_result res;
	char *tech, *resource;

	struct ast_channel *new_chan;
	struct ast_bridge *bridge;

	tech = dial_data->endpoint;
	if (!(resource = strchr(tech, '/'))) {
		return NULL;
	}
	*resource++ = '\0';

	if (!dial) {
		ast_log(LOG_ERROR, "Failed to create dialing structure.\n");
		return NULL;
	}

	if (ast_dial_append(dial, tech, resource) < 0) {
		ast_log(LOG_ERROR, "Failed to add %s/%s to dialing structure.\n", tech, resource);
		return NULL;
	}

	ast_dial_set_global_timeout(dial, dial_data->timeout);

	res = ast_dial_run(dial, NULL, 0);
	if (res != AST_DIAL_RESULT_ANSWERED || !(new_chan = ast_dial_answered_steal(dial))) {
		return NULL;
	}

	if (!(bridge = ast_bridge_basic_new())) {
		ast_log(LOG_ERROR, "Failed to create basic bridge.\n");
		return NULL;
	}

	if (ast_bridge_impart(bridge, new_chan, NULL, NULL,
		AST_BRIDGE_IMPART_CHAN_INDEPENDENT)) {
		ast_hangup(new_chan);
	} else {
		stasis_app_control_add_channel_to_bridge(control, bridge);
	}

	return NULL;
}
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;
}
Esempio n. 5
0
/*!
 * \brief Add a channel to the singleton dial bridge.
 *
 * \param control The Stasis control structure
 * \param chan The channel to add to the bridge
 * \retval -1 Failed
 * \retval 0 Success
 */
static int add_to_dial_bridge(struct stasis_app_control *control, struct ast_channel *chan)
{
	struct ast_bridge *bridge;

	bridge = get_dial_bridge();
	if (!bridge) {
		return -1;
	}

	control->bridge = bridge;
	ast_bridge_set_after_callback(chan, dial_bridge_after_cb, dial_bridge_after_cb_failed, control);
	if (ast_bridge_impart(bridge, chan, NULL, NULL, AST_BRIDGE_IMPART_CHAN_DEPARTABLE)) {
		control->bridge = NULL;
		ao2_ref(bridge, -1);
		return -1;
	}

	ao2_ref(bridge, -1);

	return 0;
}
Esempio n. 6
0
int conf_announce_channel_push(struct ast_channel *ast)
{
	struct ast_bridge_features *features;
	struct ast_channel *chan;
	RAII_VAR(struct announce_pvt *, p, NULL, ao2_cleanup);

	{
		SCOPED_CHANNELLOCK(lock, ast);

		p = ast_channel_tech_pvt(ast);
		if (!p) {
			return -1;
		}
		ao2_ref(p, +1);
		chan = p->base.chan;
		if (!chan) {
			return -1;
		}
	}

	features = ast_bridge_features_new();
	if (!features) {
		return -1;
	}
	ast_set_flag(&features->feature_flags, AST_BRIDGE_CHANNEL_FLAG_IMMOVABLE);

	/* Impart the output channel into the bridge */
	if (ast_bridge_impart(p->bridge, chan, NULL, features,
		AST_BRIDGE_IMPART_CHAN_INDEPENDENT)) {
		return -1;
	}
	ao2_lock(p);
	ast_set_flag(&p->base, AST_UNREAL_CARETAKER_THREAD);
	ao2_unlock(p);
	return 0;
}
Esempio n. 7
0
/*! \brief Initiate new call, part of PBX interface
 *         dest is the dial string */
static int local_call(struct ast_channel *ast, const char *dest, int timeout)
{
	struct local_pvt *p = ast_channel_tech_pvt(ast);
	int pvt_locked = 0;

	struct ast_channel *owner = NULL;
	struct ast_channel *chan = NULL;
	int res;
	char *reduced_dest = ast_strdupa(dest);
	char *slash;
	const char *chan_cid;

	if (!p) {
		return -1;
	}

	/* since we are letting go of channel locks that were locked coming into
	 * this function, then we need to give the tech pvt a ref */
	ao2_ref(p, 1);
	ast_channel_unlock(ast);

	ast_unreal_lock_all(&p->base, &chan, &owner);
	pvt_locked = 1;

	if (owner != ast) {
		res = -1;
		goto return_cleanup;
	}

	if (!owner || !chan) {
		res = -1;
		goto return_cleanup;
	}

	ast_unreal_call_setup(owner, chan);

	/*
	 * If the local channel has /n on the end of it, we need to lop
	 * that off for our argument to setting up the CC_INTERFACES
	 * variable.
	 */
	if ((slash = strrchr(reduced_dest, '/'))) {
		*slash = '\0';
	}
	ast_set_cc_interfaces_chanvar(chan, reduced_dest);

	ao2_unlock(p);
	pvt_locked = 0;

	ast_channel_unlock(owner);

	chan_cid = S_COR(ast_channel_caller(chan)->id.number.valid,
		ast_channel_caller(chan)->id.number.str, NULL);
	if (chan_cid) {
		chan_cid = ast_strdupa(chan_cid);
	}
	ast_channel_unlock(chan);

	res = -1;
	switch (p->type) {
	case LOCAL_CALL_ACTION_DIALPLAN:
		if (!ast_exists_extension(NULL, p->context, p->exten, 1, chan_cid)) {
			ast_log(LOG_NOTICE, "No such extension/context %s@%s while calling Local channel\n",
				p->exten, p->context);
		} else {
			publish_local_bridge_message(p);

			/* Start switch on sub channel */
			res = ast_pbx_start(chan);
		}
		break;
	case LOCAL_CALL_ACTION_BRIDGE:
		publish_local_bridge_message(p);
		ast_answer(chan);
		res = ast_bridge_impart(p->action.bridge.join, chan, p->action.bridge.swap,
			p->action.bridge.features, AST_BRIDGE_IMPART_CHAN_INDEPENDENT);
		ao2_ref(p->action.bridge.join, -1);
		p->action.bridge.join = NULL;
		ao2_cleanup(p->action.bridge.swap);
		p->action.bridge.swap = NULL;
		p->action.bridge.features = NULL;
		break;
	case LOCAL_CALL_ACTION_MASQUERADE:
		publish_local_bridge_message(p);
		ast_answer(chan);
		res = ast_channel_move(p->action.masq, chan);
		if (!res) {
			/* Chan is now an orphaned zombie.  Destroy it. */
			ast_hangup(chan);
		}
		p->action.masq = ast_channel_unref(p->action.masq);
		break;
	}
	if (!res) {
		ao2_lock(p);
		ast_set_flag(&p->base, AST_UNREAL_CARETAKER_THREAD);
		ao2_unlock(p);
	}

	/* we already unlocked them, clear them here so the cleanup label won't touch them. */
	owner = ast_channel_unref(owner);
	chan = ast_channel_unref(chan);

return_cleanup:
	if (p) {
		if (pvt_locked) {
			ao2_unlock(p);
		}
		ao2_ref(p, -1);
	}
	if (chan) {
		ast_channel_unlock(chan);
		ast_channel_unref(chan);
	}

	/*
	 * owner is supposed to be == to ast, if it is, don't unlock it
	 * because ast must exit locked
	 */
	if (owner) {
		if (owner != ast) {
			ast_channel_unlock(owner);
			ast_channel_lock(ast);
		}
		ast_channel_unref(owner);
	} else {
		/* we have to exit with ast locked */
		ast_channel_lock(ast);
	}

	return res;
}
Esempio n. 8
0
/*! \brief Internal built in feature for attended transfers */
static int feature_attended_transfer(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt)
{
	char exten[AST_MAX_EXTENSION] = "";
	struct ast_channel *chan = NULL;
	struct ast_bridge *attended_bridge = NULL;
	struct ast_bridge_features caller_features, called_features;
	enum ast_bridge_channel_state attended_bridge_result;
	struct ast_bridge_features_attended_transfer *attended_transfer = hook_pvt;
	const char *context = (attended_transfer && !ast_strlen_zero(attended_transfer->context) ? attended_transfer->context : bridge_channel->chan->context);

	/* Grab the extension to transfer to */
	if (!grab_transfer(bridge_channel->chan, exten, sizeof(exten), context)) {
		ast_stream_and_wait(bridge_channel->chan, "pbx-invalid", AST_DIGIT_ANY);
		ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_WAIT);
		return 0;
	}

	/* Get a channel that is the destination we wish to call */
	if (!(chan = dial_transfer(bridge_channel->chan, exten, context))) {
		ast_stream_and_wait(bridge_channel->chan, "beeperr", AST_DIGIT_ANY);
		ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_WAIT);
		return 0;
	}

	/* Create a bridge to use to talk to the person we are calling */
	if (!(attended_bridge = ast_bridge_new(AST_BRIDGE_CAPABILITY_1TO1MIX, 0))) {
		ast_hangup(chan);
		ast_stream_and_wait(bridge_channel->chan, "beeperr", AST_DIGIT_ANY);
		ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_WAIT);
		return 0;
	}

	/* Setup our called features structure so that if they hang up we immediately get thrown out of the bridge */
	ast_bridge_features_init(&called_features);
	ast_bridge_features_set_flag(&called_features, AST_BRIDGE_FLAG_DISSOLVE);

	/* This is how this is going down, we are imparting the channel we called above into this bridge first */
	ast_bridge_impart(attended_bridge, chan, NULL, &called_features);

	/* Before we join setup a features structure with the hangup option, just in case they want to use DTMF */
	ast_bridge_features_init(&caller_features);
	ast_bridge_features_enable(&caller_features, AST_BRIDGE_BUILTIN_HANGUP,
				   (attended_transfer && !ast_strlen_zero(attended_transfer->complete) ? attended_transfer->complete : "*1"), NULL);
	ast_bridge_features_hook(&caller_features, (attended_transfer && !ast_strlen_zero(attended_transfer->threeway) ? attended_transfer->threeway : "*2"),
				 attended_threeway_transfer, NULL);
	ast_bridge_features_hook(&caller_features, (attended_transfer && !ast_strlen_zero(attended_transfer->abort) ? attended_transfer->abort : "*3"),
				 attended_abort_transfer, NULL);

	/* But for the caller we want to join the bridge in a blocking fashion so we don't spin around in this function doing nothing while waiting */
	attended_bridge_result = ast_bridge_join(attended_bridge, bridge_channel->chan, NULL, &caller_features);

	/* Since the above returned the caller features structure is of no more use */
	ast_bridge_features_cleanup(&caller_features);

	/* Drop the channel we are transferring to out of the above bridge since it has ended */
	if ((attended_bridge_result != AST_BRIDGE_CHANNEL_STATE_HANGUP) && !ast_bridge_depart(attended_bridge, chan)) {
		/* If the user wants to turn this into a threeway transfer then do so, otherwise they take our place */
		if (attended_bridge_result == AST_BRIDGE_CHANNEL_STATE_DEPART) {
			/* We want to impart them upon the bridge and just have us return to it as normal */
			ast_bridge_impart(bridge, chan, NULL, NULL);
		} else {
			ast_bridge_impart(bridge, chan, bridge_channel->chan, NULL);
		}
	} else {
		ast_stream_and_wait(bridge_channel->chan, "beeperr", AST_DIGIT_ANY);
		ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_WAIT);
	}

	/* Now that all channels are out of it we can destroy the bridge and the called features structure */
	ast_bridge_features_cleanup(&called_features);
	ast_bridge_destroy(attended_bridge);

	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;
}
Esempio n. 10
0
int ast_bridge_call_with_flags(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, unsigned int flags)
{
	int res;
	struct ast_bridge *bridge;
	struct ast_bridge_features chan_features;
	struct ast_bridge_features *peer_features;

	/* Setup features. */
	res = ast_bridge_features_init(&chan_features);
	peer_features = ast_bridge_features_new();
	if (res || !peer_features) {
		ast_bridge_features_destroy(peer_features);
		ast_bridge_features_cleanup(&chan_features);
		bridge_failed_peer_goto(chan, peer);
		return -1;
	}

	if (pre_bridge_setup(chan, peer, config, &chan_features, peer_features)) {
		ast_bridge_features_destroy(peer_features);
		ast_bridge_features_cleanup(&chan_features);
		bridge_failed_peer_goto(chan, peer);
		return -1;
	}

	/* Create bridge */
	bridge = ast_bridge_basic_new();
	if (!bridge) {
		ast_bridge_features_destroy(peer_features);
		ast_bridge_features_cleanup(&chan_features);
		bridge_failed_peer_goto(chan, peer);
		return -1;
	}

	ast_bridge_basic_set_flags(bridge, flags);

	/* Put peer into the bridge */
	if (ast_bridge_impart(bridge, peer, NULL, peer_features,
		AST_BRIDGE_IMPART_CHAN_INDEPENDENT | AST_BRIDGE_IMPART_INHIBIT_JOIN_COLP)) {
		ast_bridge_destroy(bridge, 0);
		ast_bridge_features_cleanup(&chan_features);
		bridge_failed_peer_goto(chan, peer);
		return -1;
	}

	/* Join bridge */
	ast_bridge_join(bridge, chan, NULL, &chan_features, NULL,
		AST_BRIDGE_JOIN_PASS_REFERENCE | AST_BRIDGE_JOIN_INHIBIT_JOIN_COLP);

	/*
	 * If the bridge was broken for a hangup that isn't real, then
	 * don't run the h extension, because the channel isn't really
	 * hung up.  This should really only happen with
	 * AST_SOFTHANGUP_ASYNCGOTO.
	 */
	res = -1;
	ast_channel_lock(chan);
	if (ast_channel_softhangup_internal_flag(chan) & AST_SOFTHANGUP_ASYNCGOTO) {
		res = 0;
	}
	ast_channel_unlock(chan);

	ast_bridge_features_cleanup(&chan_features);

	if (res && config->end_bridge_callback) {
		config->end_bridge_callback(config->end_bridge_callback_data);
	}

	return res;
}
Esempio n. 11
0
static int app_control_add_channel_to_bridge(
    struct stasis_app_control *control,
    struct ast_channel *chan, void *data)
{
    struct ast_bridge *bridge = data;
    int res;

    if (!control || !bridge) {
        return -1;
    }

    ast_debug(3, "%s: Adding to bridge %s\n",
              stasis_app_control_get_channel_id(control),
              bridge->uniqueid);

    ast_assert(chan != NULL);

    /* Depart whatever Stasis bridge we're currently in. */
    if (stasis_app_get_bridge(control)) {
        /* Note that it looks like there's a race condition here, since
         * we don't have control locked. But this happens from the
         * control callback thread, so there won't be any other
         * concurrent attempts to bridge.
         */
        ast_bridge_depart(chan);
    }


    res = ast_bridge_set_after_callback(chan, bridge_after_cb,
                                        bridge_after_cb_failed, control);
    if (res != 0) {
        ast_log(LOG_ERROR, "Error setting after-bridge callback\n");
        return -1;
    }

    {
        /* pbx and bridge are modified by the bridging impart thread.
         * It shouldn't happen concurrently, but we still need to lock
         * for the memory fence.
         */
        SCOPED_AO2LOCK(lock, control);

        /* Save off the channel's PBX */
        ast_assert(control->pbx == NULL);
        if (!control->pbx) {
            control->pbx = ast_channel_pbx(chan);
            ast_channel_pbx_set(chan, NULL);
        }

        res = ast_bridge_impart(bridge,
                                chan,
                                NULL, /* swap channel */
                                NULL, /* features */
                                AST_BRIDGE_IMPART_CHAN_DEPARTABLE);
        if (res != 0) {
            ast_log(LOG_ERROR, "Error adding channel to bridge\n");
            ast_channel_pbx_set(chan, control->pbx);
            control->pbx = NULL;
            return -1;
        }

        ast_assert(stasis_app_get_bridge(control) == NULL);
        control->bridge = bridge;
    }
    return 0;
}
Esempio n. 12
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;
}
Esempio n. 13
0
int control_swap_channel_in_bridge(struct stasis_app_control *control, struct ast_bridge *bridge, struct ast_channel *chan, struct ast_channel *swap)
{
	int res;

	if (!control || !bridge) {
		return -1;
	}

	ast_debug(3, "%s: Adding to bridge %s\n",
		stasis_app_control_get_channel_id(control),
		bridge->uniqueid);

	ast_assert(chan != NULL);

	/* Depart whatever Stasis bridge we're currently in. */
	if (stasis_app_get_bridge(control)) {
		/* Note that it looks like there's a race condition here, since
		 * we don't have control locked. But this happens from the
		 * control callback thread, so there won't be any other
		 * concurrent attempts to bridge.
		 */
		ast_bridge_depart(chan);
	}


	res = ast_bridge_set_after_callback(chan, bridge_after_cb,
		bridge_after_cb_failed, control);
	if (res != 0) {
		ast_log(LOG_ERROR, "Error setting after-bridge callback\n");
		return -1;
	}

	{
		/* pbx and bridge are modified by the bridging impart thread.
		 * It shouldn't happen concurrently, but we still need to lock
		 * for the memory fence.
		 */
		SCOPED_AO2LOCK(lock, control);

		/* Ensure the controlling application is subscribed early enough
		 * to receive the ChannelEnteredBridge message. This works in concert
		 * with the subscription handled in the Stasis application execution
		 * loop */
		app_subscribe_bridge(control->app, bridge);

		/* Save off the channel's PBX */
		ast_assert(control->pbx == NULL);
		if (!control->pbx) {
			control->pbx = ast_channel_pbx(chan);
			ast_channel_pbx_set(chan, NULL);
		}

		res = ast_bridge_impart(bridge,
			chan,
			swap,
			NULL, /* features */
			AST_BRIDGE_IMPART_CHAN_DEPARTABLE);
		if (res != 0) {
			ast_log(LOG_ERROR, "Error adding channel to bridge\n");
			ast_channel_pbx_set(chan, control->pbx);
			control->pbx = NULL;
			return -1;
		}

		ast_assert(stasis_app_get_bridge(control) == NULL);
		control->bridge = bridge;

		ast_channel_lock(chan);
		set_interval_hook(chan);
		ast_channel_unlock(chan);
	}
	return 0;
}
Esempio n. 14
0
int control_swap_channel_in_bridge(struct stasis_app_control *control, struct ast_bridge *bridge, struct ast_channel *chan, struct ast_channel *swap)
{
	int res;
	struct ast_bridge_features *features;

	if (!control || !bridge) {
		return -1;
	}

	ast_debug(3, "%s: Adding to bridge %s\n",
		stasis_app_control_get_channel_id(control),
		bridge->uniqueid);

	ast_assert(chan != NULL);

	/* Depart whatever Stasis bridge we're currently in. */
	if (stasis_app_get_bridge(control)) {
		/* Note that it looks like there's a race condition here, since
		 * we don't have control locked. But this happens from the
		 * control callback thread, so there won't be any other
		 * concurrent attempts to bridge.
		 */
		ast_bridge_depart(chan);
	}


	res = ast_bridge_set_after_callback(chan, bridge_after_cb,
		bridge_after_cb_failed, control);
	if (res != 0) {
		ast_log(LOG_ERROR, "Error setting after-bridge callback\n");
		return -1;
	}

	ao2_lock(control);

	/* Ensure the controlling application is subscribed early enough
	 * to receive the ChannelEnteredBridge message. This works in concert
	 * with the subscription handled in the Stasis application execution
	 * loop */
	app_subscribe_bridge(control->app, bridge);

	/* Save off the channel's PBX */
	ast_assert(control->pbx == NULL);
	if (!control->pbx) {
		control->pbx = ast_channel_pbx(chan);
		ast_channel_pbx_set(chan, NULL);
	}

	/* Pull bridge features from the control */
	features = control->bridge_features;
	control->bridge_features = NULL;

	ast_assert(stasis_app_get_bridge(control) == NULL);
	/* We need to set control->bridge here since bridge_after_cb may be run
	 * before ast_bridge_impart returns.  bridge_after_cb gets a reason
	 * code so it can tell if the bridge is actually valid or not.
	 */
	control->bridge = bridge;

	/* We can't be holding the control lock while impart is running
	 * or we could create a deadlock with bridge_after_cb which also
	 * tries to lock control.
	 */
	ao2_unlock(control);
	res = ast_bridge_impart(bridge,
		chan,
		swap,
		features, /* features */
		AST_BRIDGE_IMPART_CHAN_DEPARTABLE);
	if (res != 0) {
		/* ast_bridge_impart failed before it could spawn the depart
		 * thread.  The callbacks aren't called in this case.
		 * The impart could still fail even if ast_bridge_impart returned
		 * ok but that's handled by bridge_after_cb.
		 */
		ast_log(LOG_ERROR, "Error adding channel to bridge\n");
		ao2_lock(control);
		ast_channel_pbx_set(chan, control->pbx);
		control->pbx = NULL;
		control->bridge = NULL;
		ao2_unlock(control);
	} else {
		ast_channel_lock(chan);
		set_interval_hook(chan);
		ast_channel_unlock(chan);
	}

	return res;
}