diff options
author | Scott Griepentrog <sgriepentrog@digium.com> | 2015-01-29 23:03:14 +0000 |
---|---|---|
committer | Scott Griepentrog <sgriepentrog@digium.com> | 2015-01-29 23:03:14 +0000 |
commit | 388d691f34d7cfcb77130965bf8709eee4b692c1 (patch) | |
tree | 1b9064d7cc66b65ea4918d2765845ebbdeb5ba8e /main/bridge.c | |
parent | f61c80a8f7b30af0551167e6fe59d9e9c005f60d (diff) |
stasis transfer: fix stasis bridge push race part two
When swapping a Local channel in place of one already
in a bridge (to complete a bridge attended transfer),
the channel that was swapped out can actually be hung
up before the stasis bridge push callback executes on
the independant transfer thread. This results in the
stasis app loop dropping out and removing the control
that has the the app name which the local replacement
channel needs so it can re-enter stasis.
To avoid this race condition a new push_peek callback
has been added, and called from the ast_bridge_impart
thread before it launches the independant thread that
will complete the transfer. Now the stasis push_peek
callback can copy the stasis app name before the swap
channel can hang up.
ASTERISK-24649
Review: https://reviewboard.asterisk.org/r/4382/
........
Merged revisions 431450 from http://svn.asterisk.org/svn/asterisk/branches/13
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@431451 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'main/bridge.c')
-rw-r--r-- | main/bridge.c | 45 |
1 files changed, 45 insertions, 0 deletions
diff --git a/main/bridge.c b/main/bridge.c index 9fb6e3223..c1fc145c6 100644 --- a/main/bridge.c +++ b/main/bridge.c @@ -904,6 +904,26 @@ static int bridge_base_get_merge_priority(struct ast_bridge *self) return 0; } +/*! + * \internal + * \brief ast_bridge base push_peek method. + * \since 13.2.0 + * + * \param self Bridge to operate upon. + * \param bridge_channel Bridge channel to push. + * \param swap Bridge channel to swap places with if not NULL. + * + * \note On entry, self is already locked. + * \note Stub because of nothing to do. + * + * \retval 0 on success + * \retval -1 on failure + */ +static int bridge_base_push_peek(struct ast_bridge *self, struct ast_bridge_channel *bridge_channel, struct ast_bridge_channel *swap) +{ + return 0; +} + struct ast_bridge_methods ast_bridge_base_v_table = { .name = "base", .destroy = bridge_base_destroy, @@ -912,6 +932,7 @@ struct ast_bridge_methods ast_bridge_base_v_table = { .pull = bridge_base_pull, .notify_masquerade = bridge_base_notify_masquerade, .get_merge_priority = bridge_base_get_merge_priority, + .push_peek = bridge_base_push_peek, }; struct ast_bridge *ast_bridge_base_new(uint32_t capabilities, unsigned int flags, const char *creator, const char *name, const char *id) @@ -1589,6 +1610,18 @@ int ast_bridge_join(struct ast_bridge *bridge, bridge_channel->features = features; bridge_channel->inhibit_colp = !!(flags & AST_BRIDGE_JOIN_INHIBIT_JOIN_COLP); + /* allow subclass to peek at upcoming push operation */ + if (bridge->v_table->push_peek && !res) { + struct ast_bridge_channel *bcswap = NULL; + + ast_bridge_lock(bridge); + if (bridge_channel->swap) { + bcswap = bridge_find_channel(bridge, bridge_channel->swap); + } + res = bridge->v_table->push_peek(bridge, bridge_channel, bcswap); + ast_bridge_unlock(bridge); + } + if (!res) { res = bridge_channel_internal_join(bridge_channel); } @@ -1724,6 +1757,18 @@ int ast_bridge_impart(struct ast_bridge *bridge, (flags & AST_BRIDGE_IMPART_CHAN_MASK) == AST_BRIDGE_IMPART_CHAN_DEPARTABLE; bridge_channel->callid = ast_read_threadstorage_callid(); + /* allow subclass to peek at swap channel before it can hangup */ + if (bridge->v_table->push_peek && !res) { + struct ast_bridge_channel *bcswap = NULL; + + ast_bridge_lock(bridge); + if (bridge_channel->swap) { + bcswap = bridge_find_channel(bridge, bridge_channel->swap); + } + res = bridge->v_table->push_peek(bridge, bridge_channel, bcswap); + ast_bridge_unlock(bridge); + } + /* Actually create the thread that will handle the channel */ if (!res) { if ((flags & AST_BRIDGE_IMPART_CHAN_MASK) == AST_BRIDGE_IMPART_CHAN_INDEPENDENT) { |