]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
Bridging: Fix orphaned bridge if neither of the joining channels can join.
authorRichard Mudgett <rmudgett@digium.com>
Tue, 22 Oct 2013 17:05:14 +0000 (17:05 +0000)
committerRichard Mudgett <rmudgett@digium.com>
Tue, 22 Oct 2013 17:05:14 +0000 (17:05 +0000)
The original issue noted that the bridge is orphaned when res_parking.so
is not loaded and a call uses the dial kK flags.

A similar issue happens when only one of the park flags is used.  In this
case you have the bridge with one or the other channel left in it.  The
channel and bridge will stay around until the channel hangs up.

* Fixed the initial bridge channel push failure to act as if the channel
were kicked out of the bridge.  The bridge then decides if it needs to be
dissolved.

(closes issue ASTERISK-22629)
Reported by: Kevin Harwell

Review: https://reviewboard.asterisk.org/r/2928/

git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/12@401424 65c4cc65-6c06-0410-ace0-fbb531ad65f3

include/asterisk/bridge_channel_internal.h
main/bridge.c
main/bridge_channel.c

index 09a447d616f1614eed3130d395e1343b7d2fa238..b5a3a8de2fe48b14c79fc2cd7f23f95e35848c50 100644 (file)
@@ -107,6 +107,9 @@ void bridge_channel_settle_owed_events(struct ast_bridge *orig_bridge, struct as
  *
  * \retval 0 on success.
  * \retval -1 on failure.  The channel did not get pushed.
+ *
+ * \note On failure the caller must call
+ * ast_bridge_features_remove(bridge_channel->features, AST_BRIDGE_HOOK_REMOVE_ON_PULL);
  */
 int bridge_channel_internal_push(struct ast_bridge_channel *bridge_channel);
 
index feeb564d4cd336d76636104beba4237351d6827f..a7b61847d215a95504f679efaab8eb90cffce9f0 100644 (file)
@@ -1791,6 +1791,8 @@ void bridge_do_merge(struct ast_bridge *dst_bridge, struct ast_bridge *src_bridg
                bridge_channel_change_bridge(bridge_channel, dst_bridge);
 
                if (bridge_channel_internal_push(bridge_channel)) {
+                       ast_bridge_features_remove(bridge_channel->features,
+                               AST_BRIDGE_HOOK_REMOVE_ON_PULL);
                        ast_bridge_channel_leave_bridge(bridge_channel,
                                BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE, bridge_channel->bridge->cause);
                }
@@ -2036,11 +2038,15 @@ int bridge_do_move(struct ast_bridge *dst_bridge, struct ast_bridge_channel *bri
 
        if (bridge_channel_internal_push(bridge_channel)) {
                /* Try to put the channel back into the original bridge. */
+               ast_bridge_features_remove(bridge_channel->features,
+                       AST_BRIDGE_HOOK_REMOVE_ON_PULL);
                if (attempt_recovery && was_in_bridge) {
                        /* Point back to original bridge. */
                        bridge_channel_change_bridge(bridge_channel, orig_bridge);
 
                        if (bridge_channel_internal_push(bridge_channel)) {
+                               ast_bridge_features_remove(bridge_channel->features,
+                                       AST_BRIDGE_HOOK_REMOVE_ON_PULL);
                                ast_bridge_channel_leave_bridge(bridge_channel,
                                        BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE, bridge_channel->bridge->cause);
                                bridge_channel_settle_owed_events(orig_bridge, bridge_channel);
index f8277384fbee939cbfe214904e3185d47aea3cbd..9256a75d026ce51496a84f4fc2b35b26a92a7530 100644 (file)
@@ -1566,7 +1566,6 @@ int bridge_channel_internal_push(struct ast_bridge_channel *bridge_channel)
                || ast_bridge_channel_establish_roles(bridge_channel)) {
                ast_debug(1, "Bridge %s: pushing %p(%s) into bridge failed\n",
                        bridge->uniqueid, bridge_channel, ast_channel_name(bridge_channel->chan));
-               ast_bridge_features_remove(bridge_channel->features, AST_BRIDGE_HOOK_REMOVE_ON_PULL);
                return -1;
        }
        bridge_channel->in_bridge = 1;
@@ -1969,8 +1968,7 @@ int bridge_channel_internal_join(struct ast_bridge_channel *bridge_channel)
         */
        ast_bridge_lock(bridge_channel->bridge);
 
-       /* Make sure we're still good to be put into a bridge
-        */
+       /* Make sure we're still good to be put into a bridge */
        ast_channel_lock(bridge_channel->chan);
        if (ast_channel_internal_bridge(bridge_channel->chan)
                || ast_test_flag(ast_channel_flags(bridge_channel->chan), AST_FLAG_ZOMBIE)) {
@@ -1993,8 +1991,14 @@ int bridge_channel_internal_join(struct ast_bridge_channel *bridge_channel)
        }
 
        if (bridge_channel_internal_push(bridge_channel)) {
-               ast_bridge_channel_leave_bridge(bridge_channel,
-                       BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE, bridge_channel->bridge->cause);
+               int cause = bridge_channel->bridge->cause;
+
+               ast_bridge_unlock(bridge_channel->bridge);
+               ast_bridge_channel_kick(bridge_channel, cause);
+               ast_bridge_channel_lock_bridge(bridge_channel);
+               ast_bridge_features_remove(bridge_channel->features,
+                       AST_BRIDGE_HOOK_REMOVE_ON_PULL);
+               bridge_channel_dissolve_check(bridge_channel);
                res = -1;
        }
        bridge_reconfigured(bridge_channel->bridge, !bridge_channel->inhibit_colp);