summaryrefslogtreecommitdiff
path: root/main/bridge_channel.c
diff options
context:
space:
mode:
authorKevin Harwell <kharwell@digium.com>2015-07-08 14:56:10 -0500
committerKevin Harwell <kharwell@digium.com>2015-07-13 12:57:56 -0500
commitc8555235195ed1deb37f5e27390b0ed4da329dc5 (patch)
tree45d9a85a0858cf8e0dc9daeab658dcc3f6ef3f08 /main/bridge_channel.c
parent66b57b10f65bee8600c01a0fc03fb491edb7ad76 (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.c25
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