diff --git a/main/bridging.c b/main/bridging.c index 1defa19f68c7c46dcac57b0b4b20534f91ec212d..3c474f2f0c0b765757de19dcff842d6b68146cfd 100644 --- a/main/bridging.c +++ b/main/bridging.c @@ -2020,7 +2020,10 @@ static void bridge_channel_blind_transfer(struct ast_bridge_channel *bridge_chan static void after_bridge_move_channel(struct ast_channel *chan_bridged, void *data) { RAII_VAR(struct ast_channel *, chan_target, data, ao2_cleanup); - ast_channel_move(chan_target, chan_bridged); + + if (ast_channel_move(chan_target, chan_bridged)) { + ast_softhangup(chan_target, AST_SOFTHANGUP_DEV); + } } static void after_bridge_move_channel_fail(enum ast_after_bridge_cb_reason reason, void *data) @@ -2028,7 +2031,8 @@ static void after_bridge_move_channel_fail(enum ast_after_bridge_cb_reason reaso RAII_VAR(struct ast_channel *, chan_target, data, ao2_cleanup); ast_log(LOG_WARNING, "Unable to complete transfer: %s\n", - ast_after_bridge_cb_reason_string(reason)); + ast_after_bridge_cb_reason_string(reason)); + ast_softhangup(chan_target, AST_SOFTHANGUP_DEV); } static void bridge_channel_attended_transfer(struct ast_bridge_channel *bridge_channel, @@ -2040,21 +2044,22 @@ static void bridge_channel_attended_transfer(struct ast_bridge_channel *bridge_c chan_target = ast_channel_get_by_name(target_chan_name); if (!chan_target) { /* Dang, it disappeared somehow */ + bridge_handle_hangup(bridge_channel); return; } - { - SCOPED_CHANNELLOCK(lock, bridge_channel); - chan_bridged = bridge_channel->chan; - if (!chan_bridged) { - return; - } - ao2_ref(chan_bridged, +1); - } + ast_bridge_channel_lock(bridge_channel); + chan_bridged = bridge_channel->chan; + ast_assert(chan_bridged != NULL); + ao2_ref(chan_bridged, +1); + ast_bridge_channel_unlock(bridge_channel); if (ast_after_bridge_callback_set(chan_bridged, after_bridge_move_channel, - after_bridge_move_channel_fail, ast_channel_ref(chan_target))) { - return; + after_bridge_move_channel_fail, ast_channel_ref(chan_target))) { + ast_softhangup(chan_target, AST_SOFTHANGUP_DEV); + + /* Release the ref we tried to pass to ast_after_bridge_callback_set(). */ + ast_channel_unref(chan_target); } bridge_handle_hangup(bridge_channel); } @@ -5363,11 +5368,11 @@ static int bridge_channel_queue_attended_transfer(struct ast_channel *transferee } ast_copy_string(unbridged_chan_name, ast_channel_name(unbridged_chan), - sizeof(unbridged_chan_name)); + sizeof(unbridged_chan_name)); ast_bridge_channel_queue_action_data(transferee_bridge_channel, - AST_BRIDGE_ACTION_ATTENDED_TRANSFER, unbridged_chan_name, - sizeof(unbridged_chan_name)); + AST_BRIDGE_ACTION_ATTENDED_TRANSFER, unbridged_chan_name, + sizeof(unbridged_chan_name)); return 0; } @@ -5502,6 +5507,7 @@ enum ast_transfer_result ast_bridge_transfer_blind(struct ast_channel *transfere { SCOPED_LOCK(lock, bridge, ast_bridge_lock, ast_bridge_unlock); + channels = ast_bridge_peers_nolock(bridge); if (!channels) { return AST_BRIDGE_TRANSFER_FAIL; @@ -5564,11 +5570,17 @@ static enum ast_transfer_result bridge_swap_attended_transfer(struct ast_bridge struct ast_bridge_channel *bridged_to_source; bridged_to_source = ast_bridge_channel_peer(source_bridge_channel); - if (bridged_to_source && bridged_to_source->state == AST_BRIDGE_CHANNEL_STATE_WAIT - && !ast_test_flag(&bridged_to_source->features->feature_flags, AST_BRIDGE_CHANNEL_FLAG_IMMOVABLE)) { + if (bridged_to_source + && bridged_to_source->state == AST_BRIDGE_CHANNEL_STATE_WAIT + && !ast_test_flag(&bridged_to_source->features->feature_flags, + AST_BRIDGE_CHANNEL_FLAG_IMMOVABLE)) { bridged_to_source->swap = swap_channel; - return bridge_move_do(dest_bridge, bridged_to_source, 1) ? - AST_BRIDGE_TRANSFER_FAIL : AST_BRIDGE_TRANSFER_SUCCESS; + if (bridge_move_do(dest_bridge, bridged_to_source, 1)) { + return AST_BRIDGE_TRANSFER_FAIL; + } + /* Must kick the source channel out of its bridge. */ + ast_bridge_change_state(source_bridge_channel, AST_BRIDGE_CHANNEL_STATE_HANGUP); + return AST_BRIDGE_TRANSFER_SUCCESS; } else { return AST_BRIDGE_TRANSFER_INVALID; }