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
This commit is contained in:
Kevin Harwell
2015-07-08 14:56:10 -05:00
parent 66b57b10f6
commit c855523519
4 changed files with 109 additions and 9 deletions

View File

@@ -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