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

@@ -509,6 +509,8 @@ enum ast_bridge_impart_flags {
* \param features Bridge features structure.
* \param flags defined by enum ast_bridge_impart_flags.
*
* \note The given bridge must be unlocked when calling this function.
*
* \note The features parameter must be NULL or obtained by
* ast_bridge_features_new(). You must not dereference features
* after calling even if the call fails.

View File

@@ -129,11 +129,48 @@ int bridge_channel_internal_push(struct ast_bridge_channel *bridge_channel);
*/
void bridge_channel_internal_pull(struct ast_bridge_channel *bridge_channel);
/*!
* \brief Internal bridge channel wait condition and associated result.
*/
struct bridge_channel_internal_cond {
/*! Lock for the data structure */
ast_mutex_t lock;
/*! Wait condition */
ast_cond_t cond;
/*! Wait until done */
int done;
/*! The bridge channel */
struct ast_bridge_channel *bridge_channel;
};
/*!
* \internal
* \brief Wait for the expected signal.
* \since 13.5.0
*
* \param cond the wait object
*
* \return Nothing
*/
void bridge_channel_internal_wait(struct bridge_channel_internal_cond *cond);
/*!
* \internal
* \brief Signal the condition wait.
* \since 13.5.0
*
* \param cond the wait object
*
* \return Nothing
*/
void bridge_channel_internal_signal(struct bridge_channel_internal_cond *cond);
/*!
* \internal
* \brief Join the bridge_channel to the bridge (blocking)
*
* \param bridge_channel The Channel in the bridge
* \param cond data used for signaling
*
* \note The bridge_channel->swap holds a channel reference for the swap
* channel going into the bridging system. The ref ensures that the swap
@@ -148,7 +185,8 @@ void bridge_channel_internal_pull(struct ast_bridge_channel *bridge_channel);
* \retval 0 bridge channel successfully joined the bridge
* \retval -1 bridge channel failed to join the bridge
*/
int bridge_channel_internal_join(struct ast_bridge_channel *bridge_channel);
int bridge_channel_internal_join(struct ast_bridge_channel *bridge_channel,
struct bridge_channel_internal_cond *cond);
/*!
* \internal