int pass_reference)
{
struct ast_bridge_channel *bridge_channel;
- int res;
+ int res = 0;
bridge_channel = bridge_channel_internal_alloc(bridge);
if (pass_reference) {
bridge_channel->tech_args = *tech_args;
}
- /* Initialize various other elements of the bridge channel structure that we can't do above */
ast_channel_lock(chan);
- ast_channel_internal_bridge_channel_set(chan, bridge_channel);
+ if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_ZOMBIE)) {
+ res = -1;
+ } else {
+ ast_channel_internal_bridge_channel_set(chan, bridge_channel);
+ }
ast_channel_unlock(chan);
bridge_channel->thread = pthread_self();
bridge_channel->chan = chan;
bridge_channel->swap = swap;
bridge_channel->features = features;
- res = bridge_channel_internal_join(bridge_channel);
+ if (!res) {
+ res = bridge_channel_internal_join(bridge_channel);
+ }
/* Cleanup all the data in the bridge channel after it leaves the bridge. */
ast_channel_lock(chan);
int ast_bridge_impart(struct ast_bridge *bridge, struct ast_channel *chan, struct ast_channel *swap, struct ast_bridge_features *features, int independent)
{
- int res;
+ int res = 0;
struct ast_bridge_channel *bridge_channel;
+ /* Imparted channels cannot have a PBX. */
+ if (ast_channel_pbx(chan)) {
+ ast_log(AST_LOG_WARNING, "Channel %s has a PBX thread and cannot be imparted into bridge %s\n",
+ ast_channel_name(chan), bridge->uniqueid);
+ return -1;
+ }
+
/* Supply an empty features structure if the caller did not. */
if (!features) {
features = ast_bridge_features_new();
return -1;
}
- /* Setup various parameters */
ast_channel_lock(chan);
- ast_channel_internal_bridge_channel_set(chan, bridge_channel);
+ if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_ZOMBIE)) {
+ ast_log(AST_LOG_NOTICE, "Channel %s is a zombie and cannot be imparted into bridge %s\n",
+ ast_channel_name(chan), bridge->uniqueid);
+ res = -1;
+ } else {
+ ast_channel_internal_bridge_channel_set(chan, bridge_channel);
+ }
ast_channel_unlock(chan);
bridge_channel->chan = chan;
bridge_channel->swap = swap;
bridge_channel->callid = ast_read_threadstorage_callid();
/* Actually create the thread that will handle the channel */
- if (independent) {
- /* Independently imparted channels cannot have a PBX. */
- ast_assert(!ast_channel_pbx(chan));
-
- res = ast_pthread_create_detached(&bridge_channel->thread, NULL,
- bridge_channel_ind_thread, bridge_channel);
- } else {
- /* Imparted channels to be departed should not have a PBX either. */
- ast_assert(!ast_channel_pbx(chan));
-
- res = ast_pthread_create(&bridge_channel->thread, NULL,
- bridge_channel_depart_thread, bridge_channel);
+ if (!res) {
+ if (independent) {
+ res = ast_pthread_create_detached(&bridge_channel->thread, NULL,
+ bridge_channel_ind_thread, bridge_channel);
+ } else {
+ res = ast_pthread_create(&bridge_channel->thread, NULL,
+ bridge_channel_depart_thread, bridge_channel);
+ }
}
if (res) {
ast_channel_unlock(chan);
if (chan_bridge) {
- RAII_VAR(struct ast_bridge_channel *, bridge_channel, NULL, ao2_cleanup);
+ struct ast_bridge_channel *bridge_channel;
ast_bridge_lock_both(bridge, chan_bridge);
bridge_channel = bridge_find_channel(chan_bridge, chan);
+
if (bridge_move_locked(bridge, chan_bridge, chan, NULL, 1)) {
ast_bridge_unlock(chan_bridge);
ast_bridge_unlock(bridge);
}
ast_channel_ref(yanked_chan);
if (ast_bridge_impart(bridge, yanked_chan, NULL, features, 1)) {
- ast_log(LOG_WARNING, "Could not add %s to the bridge\n", ast_channel_name(chan));
- ast_hangup(yanked_chan);
+ /* It is possible for us to yank a channel and have some other
+ * thread start a PBX on the channl after we yanked it. In particular,
+ * this can theoretically happen on the ;2 of a Local channel if we
+ * yank it prior to the ;1 being answered. Make sure that it isn't
+ * executing a PBX before hanging it up.
+ */
+ if (ast_channel_pbx(yanked_chan)) {
+ ast_channel_unref(yanked_chan);
+ } else {
+ ast_hangup(yanked_chan);
+ }
return -1;
}
}
bridge_channel, ast_channel_name(bridge_channel->chan));
/*
- * Get "in the bridge" before pushing the channel for any
- * masquerades on the channel to happen before bridging.
+ * Directly locking the bridge is safe here because nobody else
+ * knows about this bridge_channel yet.
+ */
+ ast_bridge_lock(bridge_channel->bridge);
+
+ /* Make sure we're still good to be put into a bridge
*/
ast_channel_lock(bridge_channel->chan);
+ if (ast_channel_internal_bridge(bridge_channel->chan)
+ || ast_test_flag(ast_channel_flags(bridge_channel->chan), AST_FLAG_ZOMBIE)) {
+ ast_channel_unlock(bridge_channel->chan);
+ ast_bridge_unlock(bridge_channel->bridge);
+ ast_debug(1, "Bridge %s: %p(%s) failed to join Bridge\n",
+ bridge_channel->bridge->uniqueid,
+ bridge_channel,
+ ast_channel_name(bridge_channel->chan));
+ return -1;
+ }
ast_channel_internal_bridge_set(bridge_channel->chan, bridge_channel->bridge);
ast_channel_unlock(bridge_channel->chan);
/* Add the jitterbuffer if the channel requires it */
ast_jb_enable_for_channel(bridge_channel->chan);
- /*
- * Directly locking the bridge is safe here because nobody else
- * knows about this bridge_channel yet.
- */
- ast_bridge_lock(bridge_channel->bridge);
-
if (!bridge_channel->bridge->callid) {
bridge_channel->bridge->callid = ast_read_threadstorage_callid();
}