diff options
author | Richard Mudgett <rmudgett@digium.com> | 2015-01-22 19:30:12 +0000 |
---|---|---|
committer | Richard Mudgett <rmudgett@digium.com> | 2015-01-22 19:30:12 +0000 |
commit | 9bff4eeca3d1fe1d10217b62d326c3907af09e00 (patch) | |
tree | e2634acc0439d25099e12990c9ee7b193c59c41a /main/bridge_channel.c | |
parent | e67ca431ee2addffd9e23c895ef170f2dc79bfb6 (diff) |
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
Diffstat (limited to 'main/bridge_channel.c')
-rw-r--r-- | main/bridge_channel.c | 13 |
1 files changed, 12 insertions, 1 deletions
diff --git a/main/bridge_channel.c b/main/bridge_channel.c index e59d28e17..ff72c57bb 100644 --- a/main/bridge_channel.c +++ b/main/bridge_channel.c @@ -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", |