[Home]

Summary:ASTERISK-23987: BridgeWait: channel entering into holding bridge that is being destroyed fails to successfully join the newly created holding bridge
Reporter:Matt Jordan (mjordan)Labels:
Date Opened:2014-07-02 17:21:28Date Closed:2014-07-25 05:55:31
Priority:MajorRegression?
Status:Closed/CompleteComponents:Applications/app_bridgewait Core/Bridging
Versions:12.3.2 Frequency of
Occurrence
Related
Issues:
Environment:Attachments:
Description:Holding bridges created by {{BridgeWait}} are a bit interesting: each named holding bridge can be shared by multiple participants. This creates an interesting race condition.

When the last channel leaves a bridge created by {{BridgeWait}}, we have to destroy the bridge. However, in some cases, a channel may be trying to enter the named holding bridge at the same time. Because {{BridgeWait}} cannot hold onto a reference to the bridge (as otherwise the bridge would never get disposed of), there is a case where a channel will attempt to join a holding bridge that just got destroyed.

The code handles this case: when this occurs, {{ast_bridge_join}} will fail. If {{ast_bridge_join}} fails, we attempt again - the attempt in and of itself will cause a new named holding bridge to be created, and from the perspective of the user, the join succeeds.

{code}
for (;;) {
RAII_VAR(struct wait_bridge_wrapper *, bridge_wrapper, get_wait_bridge_wrapper(bridge_name), wait_wrapper_removal);

if (!bridge_wrapper) {
ast_log(LOG_WARNING, "Failed to find or create waiting bridge '%s' for '%s'.\n", bridge_name, ast_channel_name(chan));
bridge_join_failed = 1;
break;
}

ast_verb(3, "%s is entering waiting bridge %s:%s\n", ast_channel_name(chan), bridge_name, bridge_wrapper->bridge->uniqueid);

if (ast_bridge_join(bridge_wrapper->bridge, chan, NULL, &chan_features, NULL, 0)) {
/* It's possible for a holding bridge to vanish out from under us since we can't lock it.
* Unlink the wrapper and then loop if the bridge we try to enter is dissolved. */
ast_verb(3, "Waiting bridge '%s:%s' is no longer joinable. Creating new bridge and trying again.\n",
bridge_name, bridge_wrapper->bridge->uniqueid);
ao2_unlink(wait_bridge_wrappers, bridge_wrapper);
continue;
}

break;
}
{code}

Unfortunately, this doesn't quite work. When the {{ast_bridge_join}} fails, we do create a new holding bridge, and we do attempt to put the channel into it. Unfortunately, the channel immediately bounces out of it:

{noformat}
   -- Executing [s@hold:1] BridgeWait("PJSIP/103-00000017", "holding_lot") in new stack
   -- PJSIP/103-00000017 is entering waiting bridge holding_lot:7b69b650-22d7-4ed0-83bf-d7b00acd23ba
   -- Waiting bridge 'holding_lot:7b69b650-22d7-4ed0-83bf-d7b00acd23ba' is no longer joinable. Creating new bridge and trying again.
   -- PJSIP/103-00000017 is entering waiting bridge holding_lot:24828e7f-ff78-4aa4-93d4-cee8cd4eced9
   -- Channel PJSIP/103-00000017 joined 'holding_bridge' base-bridge <24828e7f-ff78-4aa4-93d4-cee8cd4eced9>
   -- Started music on hold, class 'default', on channel 'PJSIP/103-00000017'
   -- Stopped music on hold on PJSIP/103-00000017
   -- Channel PJSIP/103-00000017 left 'holding_bridge' base-bridge <24828e7f-ff78-4aa4-93d4-cee8cd4eced9>
{noformat}

For some reason, we're immediately entering and bouncing right back out of the newly created holding bridge. When the race condition isn't hit, the channel joins just fine.
Comments: