diff options
author | Kevin Harwell <kharwell@digium.com> | 2015-07-08 14:56:10 -0500 |
---|---|---|
committer | Kevin Harwell <kharwell@digium.com> | 2015-07-13 12:57:56 -0500 |
commit | c8555235195ed1deb37f5e27390b0ed4da329dc5 (patch) | |
tree | 45d9a85a0858cf8e0dc9daeab658dcc3f6ef3f08 /main/bridge_channel.c | |
parent | 66b57b10f65bee8600c01a0fc03fb491edb7ad76 (diff) |
bridge.c: Fixed race condition during attended transfer
During an attended transfer a thread is started that handles imparting the
bridge channel. From the start of the thread to when the bridge channel is
ready exists a gap that can potentially cause problems (for instance, the
channel being swapped is hung up before the replacement channel enters the
bridge thus stopping the transfer). This patch adds a condition that waits
for the impart thread to get to a point of acceptable readiness before
allowing the initiating thread to continue.
ASTERISK-24782
Reported by: John Bigelow
Change-Id: I08fe33a2560da924e676df55b181e46fca604577
Diffstat (limited to 'main/bridge_channel.c')
-rw-r--r-- | main/bridge_channel.c | 25 |
1 files changed, 24 insertions, 1 deletions
diff --git a/main/bridge_channel.c b/main/bridge_channel.c index 159722697..28dfd9ccb 100644 --- a/main/bridge_channel.c +++ b/main/bridge_channel.c @@ -2560,7 +2560,27 @@ static void bridge_channel_event_join_leave(struct ast_bridge_channel *bridge_ch ao2_iterator_destroy(&iter); } -int bridge_channel_internal_join(struct ast_bridge_channel *bridge_channel) +void bridge_channel_internal_wait(struct bridge_channel_internal_cond *cond) +{ + ast_mutex_lock(&cond->lock); + while (!cond->done) { + ast_cond_wait(&cond->cond, &cond->lock); + } + ast_mutex_unlock(&cond->lock); +} + +void bridge_channel_internal_signal(struct bridge_channel_internal_cond *cond) +{ + if (cond) { + ast_mutex_lock(&cond->lock); + cond->done = 1; + ast_cond_signal(&cond->cond); + ast_mutex_unlock(&cond->lock); + } +} + +int bridge_channel_internal_join(struct ast_bridge_channel *bridge_channel, + struct bridge_channel_internal_cond *cond) { int res = 0; struct ast_bridge_features *channel_features; @@ -2590,6 +2610,7 @@ int bridge_channel_internal_join(struct ast_bridge_channel *bridge_channel) bridge_channel->bridge->uniqueid, bridge_channel, ast_channel_name(bridge_channel->chan)); + bridge_channel_internal_signal(cond); return -1; } ast_channel_internal_bridge_set(bridge_channel->chan, bridge_channel->bridge); @@ -2624,6 +2645,8 @@ int bridge_channel_internal_join(struct ast_bridge_channel *bridge_channel) } bridge_reconfigured(bridge_channel->bridge, !bridge_channel->inhibit_colp); + bridge_channel_internal_signal(cond); + if (bridge_channel->state == BRIDGE_CHANNEL_STATE_WAIT) { /* * Indicate a source change since this channel is entering the |