summaryrefslogtreecommitdiff
path: root/main/bridge_channel.c
diff options
context:
space:
mode:
authorRichard Mudgett <rmudgett@digium.com>2017-08-16 15:22:04 -0500
committerRichard Mudgett <rmudgett@digium.com>2017-08-22 11:59:49 -0500
commit6ad8249233080aab4f2ea0e72f3e0b7ef384f243 (patch)
tree923b8dfbbb3e6acb5db30ba351e2b8a3c77c0158 /main/bridge_channel.c
parent9c70c883697d63e6f16b0b06b688a6131423c7e1 (diff)
bridge: Fix softmix bridge deadlock.
* Fix deadlock in bridge_softmix.c:softmix_bridge_stream_topology_changed() between bridge_channel and channel locks. * The new bridge technology topology change callbacks must be called with the bridge locked. The callback references the bridge channel list, the bridge technology could change, and the bridge stream mapping is updated. ASTERISK-27212 Change-Id: Ide4360ab853607e738ad471721af3f561ddd83be
Diffstat (limited to 'main/bridge_channel.c')
-rw-r--r--main/bridge_channel.c19
1 files changed, 15 insertions, 4 deletions
diff --git a/main/bridge_channel.c b/main/bridge_channel.c
index 1427fd014..c465ec16e 100644
--- a/main/bridge_channel.c
+++ b/main/bridge_channel.c
@@ -2434,6 +2434,7 @@ static const char *controls[] = {
static void bridge_handle_trip(struct ast_bridge_channel *bridge_channel)
{
struct ast_frame *frame;
+ int blocked;
if (!ast_strlen_zero(ast_channel_call_forward(bridge_channel->chan))) {
/* TODO If early bridging is ever used by anything other than ARI,
@@ -2485,10 +2486,16 @@ static void bridge_handle_trip(struct ast_bridge_channel *bridge_channel)
ast_channel_publish_dial(NULL, bridge_channel->chan, NULL, controls[frame->subclass.integer]);
break;
case AST_CONTROL_STREAM_TOPOLOGY_REQUEST_CHANGE:
- if (bridge_channel->bridge->technology->stream_topology_request_change &&
- bridge_channel->bridge->technology->stream_topology_request_change(
- bridge_channel->bridge, bridge_channel)) {
- /* Topology change was denied so drop frame */
+ ast_bridge_channel_lock_bridge(bridge_channel);
+ blocked = bridge_channel->bridge->technology->stream_topology_request_change
+ && bridge_channel->bridge->technology->stream_topology_request_change(
+ bridge_channel->bridge, bridge_channel);
+ ast_bridge_unlock(bridge_channel->bridge);
+ if (blocked) {
+ /*
+ * Topology change was intercepted by the bridge technology
+ * so drop frame.
+ */
bridge_frame_free(frame);
return;
}
@@ -2498,12 +2505,14 @@ static void bridge_handle_trip(struct ast_bridge_channel *bridge_channel)
* If a stream topology has changed then the bridge_channel's
* media mapping needs to be updated.
*/
+ ast_bridge_channel_lock_bridge(bridge_channel);
if (bridge_channel->bridge->technology->stream_topology_changed) {
bridge_channel->bridge->technology->stream_topology_changed(
bridge_channel->bridge, bridge_channel);
} else {
ast_bridge_channel_stream_map(bridge_channel);
}
+ ast_bridge_unlock(bridge_channel->bridge);
break;
default:
break;
@@ -2990,9 +2999,11 @@ struct ast_bridge_channel *bridge_channel_internal_alloc(struct ast_bridge *brid
void ast_bridge_channel_stream_map(struct ast_bridge_channel *bridge_channel)
{
+ ast_bridge_channel_lock(bridge_channel);
ast_channel_lock(bridge_channel->chan);
ast_stream_topology_map(ast_channel_get_stream_topology(bridge_channel->chan),
&bridge_channel->bridge->media_types, &bridge_channel->stream_map.to_bridge,
&bridge_channel->stream_map.to_channel);
ast_channel_unlock(bridge_channel->chan);
+ ast_bridge_channel_unlock(bridge_channel);
}