bridge_channel.c: Fix Deadlock when using Local channels and fax gateway
authorPirmin Walthert <infos@nappsoft.ch>
Wed, 30 May 2018 06:12:30 +0000 (08:12 +0200)
committerJoshua Colp <jcolp@digium.com>
Tue, 5 Jun 2018 11:37:54 +0000 (05:37 -0600)
ast_indicate is invoked with the bridge locked. As ast_indicate locks the
other end of the bridge as well this can lead to a deadlock in some situations.
(Especially when a different thread does the same in the reverse order).
This patch calls ast_indicate after unlocking the bridge which fixes the
deadlock. Calling ast_indicate with these parameters without locking the
bridge should be safe as this is done at different places without a
bridge lock.

ASTERISK-27094 #close
Reported-by: David Brillert

Change-Id: I5f86c1e2ce75b9929a36ab589b18c450e62ea35f

main/bridge_channel.c

index eb4b9ad..7d7d26a 100644 (file)
@@ -2820,6 +2820,7 @@ static void bridge_channel_event_join_leave(struct ast_bridge_channel *bridge_ch
 int bridge_channel_internal_join(struct ast_bridge_channel *bridge_channel)
 {
        int res = 0;
+       uint8_t indicate_src_change = 0;
        struct ast_bridge_features *channel_features;
        struct ast_channel *swap;
 
@@ -2889,7 +2890,7 @@ int bridge_channel_internal_join(struct ast_bridge_channel *bridge_channel)
                 */
                if (!(bridge_channel->bridge->technology->capabilities
                        & AST_BRIDGE_CAPABILITY_MULTIMIX)) {
-                       ast_indicate(bridge_channel->chan, AST_CONTROL_SRCCHANGE);
+                       indicate_src_change = 1;
                }
 
                bridge_channel_impart_signal(bridge_channel->chan);
@@ -2899,6 +2900,10 @@ int bridge_channel_internal_join(struct ast_bridge_channel *bridge_channel)
                ao2_t_cleanup(swap, "Bridge push with swap successful");
                swap = NULL;
 
+               if (indicate_src_change) {
+                       ast_indicate(bridge_channel->chan, AST_CONTROL_SRCCHANGE);
+               }
+
                bridge_channel_event_join_leave(bridge_channel, AST_BRIDGE_HOOK_TYPE_JOIN);
 
                while (bridge_channel->state == BRIDGE_CHANNEL_STATE_WAIT) {