mirror of
https://github.com/asterisk/asterisk.git
synced 2025-10-12 15:45:18 +00:00
Bridge core: Pass a ref with the swap channel when joining a bridge.
When code imparts a channel into a bridge to swap with another channel, a ref needs to be held on the swap channel to ensure that it cannot dissapear before finding it in the bridge. * The ast_bridge_join() swap channel parameter now always steals a ref for the swap channel. This is the only change to the bridge framework's public API semantics. * bridge_channel_internal_join() now requires the bridge_channel->swap channel to pass in a ref. ASTERISK-24649 Reported by: John Bigelow Review: https://reviewboard.asterisk.org/r/4354/ ........ Merged revisions 430975 from http://svn.asterisk.org/svn/asterisk/branches/13 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@430976 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
@@ -1560,6 +1560,7 @@ int ast_bridge_join(struct ast_bridge *bridge,
|
||||
ao2_ref(bridge, -1);
|
||||
}
|
||||
if (!bridge_channel) {
|
||||
ao2_t_cleanup(swap, "Error exit: bridge_channel alloc failed");
|
||||
res = -1;
|
||||
goto join_exit;
|
||||
}
|
||||
@@ -1567,6 +1568,7 @@ int ast_bridge_join(struct ast_bridge *bridge,
|
||||
ast_assert(features != NULL);
|
||||
if (!features) {
|
||||
ao2_ref(bridge_channel, -1);
|
||||
ao2_t_cleanup(swap, "Error exit: features is NULL");
|
||||
res = -1;
|
||||
goto join_exit;
|
||||
}
|
||||
@@ -1596,6 +1598,8 @@ int ast_bridge_join(struct ast_bridge *bridge,
|
||||
ast_channel_internal_bridge_channel_set(chan, NULL);
|
||||
ast_channel_unlock(chan);
|
||||
bridge_channel->chan = NULL;
|
||||
/* If bridge_channel->swap is not NULL then the join failed. */
|
||||
ao2_t_cleanup(bridge_channel->swap, "Bridge complete: join failed");
|
||||
bridge_channel->swap = NULL;
|
||||
bridge_channel->features = NULL;
|
||||
|
||||
@@ -1624,7 +1628,12 @@ static void *bridge_channel_depart_thread(void *data)
|
||||
|
||||
bridge_channel_internal_join(bridge_channel);
|
||||
|
||||
/* cleanup */
|
||||
/*
|
||||
* cleanup
|
||||
*
|
||||
* If bridge_channel->swap is not NULL then the join failed.
|
||||
*/
|
||||
ao2_t_cleanup(bridge_channel->swap, "Bridge complete: Departable impart join failed");
|
||||
bridge_channel->swap = NULL;
|
||||
ast_bridge_features_destroy(bridge_channel->features);
|
||||
bridge_channel->features = NULL;
|
||||
@@ -1653,6 +1662,8 @@ static void *bridge_channel_ind_thread(void *data)
|
||||
ast_channel_internal_bridge_channel_set(chan, NULL);
|
||||
ast_channel_unlock(chan);
|
||||
bridge_channel->chan = NULL;
|
||||
/* If bridge_channel->swap is not NULL then the join failed. */
|
||||
ao2_t_cleanup(bridge_channel->swap, "Bridge complete: Independent impart join failed");
|
||||
bridge_channel->swap = NULL;
|
||||
ast_bridge_features_destroy(bridge_channel->features);
|
||||
bridge_channel->features = NULL;
|
||||
@@ -1706,7 +1717,7 @@ int ast_bridge_impart(struct ast_bridge *bridge,
|
||||
}
|
||||
ast_channel_unlock(chan);
|
||||
bridge_channel->chan = chan;
|
||||
bridge_channel->swap = swap;
|
||||
bridge_channel->swap = ao2_t_bump(swap, "Setting up bridge impart");
|
||||
bridge_channel->features = features;
|
||||
bridge_channel->inhibit_colp = !!(flags & AST_BRIDGE_IMPART_INHIBIT_JOIN_COLP);
|
||||
bridge_channel->depart_wait =
|
||||
@@ -1730,6 +1741,7 @@ int ast_bridge_impart(struct ast_bridge *bridge,
|
||||
ast_channel_internal_bridge_channel_set(chan, NULL);
|
||||
ast_channel_unlock(chan);
|
||||
bridge_channel->chan = NULL;
|
||||
ao2_t_cleanup(bridge_channel->swap, "Bridge complete: Impart failed");
|
||||
bridge_channel->swap = NULL;
|
||||
ast_bridge_features_destroy(bridge_channel->features);
|
||||
bridge_channel->features = NULL;
|
||||
@@ -2171,7 +2183,11 @@ int bridge_do_move(struct ast_bridge *dst_bridge, struct ast_bridge_channel *bri
|
||||
/*
|
||||
* The channel died as a result of being pulled. Leave it
|
||||
* pointing to the original bridge.
|
||||
*
|
||||
* Clear out the swap channel pointer. A ref is not held
|
||||
* by bridge_channel->swap at this point.
|
||||
*/
|
||||
bridge_channel->swap = NULL;
|
||||
bridge_reconfigured(orig_bridge, 0);
|
||||
return -1;
|
||||
}
|
||||
|
@@ -2490,11 +2490,11 @@ static void bridge_channel_event_join_leave(struct ast_bridge_channel *bridge_ch
|
||||
ao2_iterator_destroy(&iter);
|
||||
}
|
||||
|
||||
/*! \brief Join a channel to a bridge and handle anything the bridge may want us to do */
|
||||
int bridge_channel_internal_join(struct ast_bridge_channel *bridge_channel)
|
||||
{
|
||||
int res = 0;
|
||||
struct ast_bridge_features *channel_features;
|
||||
struct ast_channel *swap;
|
||||
|
||||
ast_debug(1, "Bridge %s: %p(%s) is joining\n",
|
||||
bridge_channel->bridge->uniqueid,
|
||||
@@ -2538,6 +2538,9 @@ int bridge_channel_internal_join(struct ast_bridge_channel *bridge_channel)
|
||||
bridge_channel->bridge->callid = ast_read_threadstorage_callid();
|
||||
}
|
||||
|
||||
/* Take the swap channel ref from the bridge_channel struct. */
|
||||
swap = bridge_channel->swap;
|
||||
|
||||
if (bridge_channel_internal_push(bridge_channel)) {
|
||||
int cause = bridge_channel->bridge->cause;
|
||||
|
||||
@@ -2563,6 +2566,11 @@ int bridge_channel_internal_join(struct ast_bridge_channel *bridge_channel)
|
||||
}
|
||||
|
||||
ast_bridge_unlock(bridge_channel->bridge);
|
||||
|
||||
/* Must release any swap ref after unlocking the bridge. */
|
||||
ao2_t_cleanup(swap, "Bridge push with swap successful");
|
||||
swap = NULL;
|
||||
|
||||
bridge_channel_event_join_leave(bridge_channel, AST_BRIDGE_HOOK_TYPE_JOIN);
|
||||
|
||||
while (bridge_channel->state == BRIDGE_CHANNEL_STATE_WAIT) {
|
||||
@@ -2583,6 +2591,9 @@ int bridge_channel_internal_join(struct ast_bridge_channel *bridge_channel)
|
||||
|
||||
ast_bridge_unlock(bridge_channel->bridge);
|
||||
|
||||
/* Must release any swap ref after unlocking the bridge. */
|
||||
ao2_t_cleanup(swap, "Bridge push with swap failed or exited immediately");
|
||||
|
||||
/* Complete any active hold before exiting the bridge. */
|
||||
if (ast_channel_hold_state(bridge_channel->chan) == AST_CONTROL_HOLD) {
|
||||
ast_debug(1, "Channel %s simulating UNHOLD for bridge end.\n",
|
||||
|
Reference in New Issue
Block a user