From f6c33771f660c3ad15bc554b355cb21e83c85e36 Mon Sep 17 00:00:00 2001
From: Mark Michelson <mmichelson@digium.com>
Date: Mon, 9 May 2016 14:27:53 -0500
Subject: [PATCH] Bridging: introduce "invisible" bridges.

Invisible bridges function the same as normal bridges, but they have the
following restrictions:

* They never show up in CLI, AMI, or ARI queries.
* They do not have Stasis messages published about them.

Invisible bridges' main use is for when use of the bridging system is
desired, but the bridge should not be known to users of the Asterisk
system.

ASTERISK-25925

Change-Id: I804a209d3181d7c54e3d61a60eb462e7ce0e3670
---
 include/asterisk/bridge_features.h |  2 ++
 main/bridge.c                      | 24 ++++++++++++++----------
 main/manager_bridges.c             |  2 +-
 main/stasis_bridges.c              | 13 +++++++++++++
 main/stasis_channels.c             |  4 +++-
 5 files changed, 33 insertions(+), 12 deletions(-)

diff --git a/include/asterisk/bridge_features.h b/include/asterisk/bridge_features.h
index df01a0dca8..7fcb85bd20 100644
--- a/include/asterisk/bridge_features.h
+++ b/include/asterisk/bridge_features.h
@@ -53,6 +53,8 @@ enum ast_bridge_feature_flags {
 	AST_BRIDGE_FLAG_TRANSFER_PROHIBITED = (1 << 8),
 	/*! Bridge transfers require transfer of entire bridge rather than individual channels */
 	AST_BRIDGE_FLAG_TRANSFER_BRIDGE_ONLY = (1 << 9),
+	/*! Bridge is invisible to AMI/CLI/ARI/etc. */
+	AST_BRIDGE_FLAG_INVISIBLE = (1 << 10),
 };
 
 /*! \brief Flags used for per bridge channel features */
diff --git a/main/bridge.c b/main/bridge.c
index ce6b9601be..68ac24bba5 100644
--- a/main/bridge.c
+++ b/main/bridge.c
@@ -759,11 +759,13 @@ struct ast_bridge *bridge_base_init(struct ast_bridge *self, uint32_t capabiliti
 	ast_set_flag(&self->feature_flags, flags);
 	self->allowed_capabilities = capabilities;
 
-	if (bridge_topics_init(self) != 0) {
-		ast_log(LOG_WARNING, "Bridge %s: Could not initialize topics\n",
-			self->uniqueid);
-		ao2_ref(self, -1);
-		return NULL;
+	if (!(flags & AST_BRIDGE_FLAG_INVISIBLE)) {
+		if (bridge_topics_init(self) != 0) {
+			ast_log(LOG_WARNING, "Bridge %s: Could not initialize topics\n",
+				self->uniqueid);
+			ao2_ref(self, -1);
+			return NULL;
+		}
 	}
 
 	/* Use our helper function to find the "best" bridge technology. */
@@ -793,9 +795,11 @@ struct ast_bridge *bridge_base_init(struct ast_bridge *self, uint32_t capabiliti
 		return NULL;
 	}
 
-	if (!ast_bridge_topic(self)) {
-		ao2_ref(self, -1);
-		return NULL;
+	if (!(flags & AST_BRIDGE_FLAG_INVISIBLE)) {
+		if (!ast_bridge_topic(self)) {
+			ao2_ref(self, -1);
+			return NULL;
+		}
 	}
 
 	return self;
@@ -4321,8 +4325,8 @@ static struct ast_bridge *acquire_bridge(struct ast_channel *chan)
 	bridge = ast_channel_get_bridge(chan);
 	ast_channel_unlock(chan);
 
-	if (bridge
-		&& ast_test_flag(&bridge->feature_flags, AST_BRIDGE_FLAG_MASQUERADE_ONLY)) {
+	if (bridge && ast_test_flag(&bridge->feature_flags,
+			(AST_BRIDGE_FLAG_MASQUERADE_ONLY | AST_BRIDGE_FLAG_INVISIBLE))) {
 		ao2_ref(bridge, -1);
 		bridge = NULL;
 	}
diff --git a/main/manager_bridges.c b/main/manager_bridges.c
index dd3e98b8d5..2069d507cd 100644
--- a/main/manager_bridges.c
+++ b/main/manager_bridges.c
@@ -572,7 +572,7 @@ static int manager_bridge_kick(struct mansession *s, const struct message *m)
 		}
 	} else {
 		bridge = ast_bridge_find_by_id(bridge_uniqueid);
-		if (!bridge) {
+		if (!bridge || ast_test_flag(&bridge->feature_flags, AST_BRIDGE_FLAG_INVISIBLE)) {
 			astman_send_error(s, m, "Bridge not found");
 			return 0;
 		}
diff --git a/main/stasis_bridges.c b/main/stasis_bridges.c
index d06ee14a7a..0e46edbea3 100644
--- a/main/stasis_bridges.c
+++ b/main/stasis_bridges.c
@@ -232,6 +232,10 @@ struct ast_bridge_snapshot *ast_bridge_snapshot_create(struct ast_bridge *bridge
 	RAII_VAR(struct ast_bridge_snapshot *, snapshot, NULL, ao2_cleanup);
 	struct ast_bridge_channel *bridge_channel;
 
+	if (ast_test_flag(&bridge->feature_flags, AST_BRIDGE_FLAG_INVISIBLE)) {
+		return NULL;
+	}
+
 	snapshot = ao2_alloc_options(sizeof(*snapshot), bridge_snapshot_dtor,
 		AO2_ALLOC_OPT_LOCK_NOLOCK);
 	if (!snapshot || ast_string_field_init(snapshot, 128)) {
@@ -371,6 +375,8 @@ void ast_bridge_publish_merge(struct ast_bridge *to, struct ast_bridge *from)
 
 	ast_assert(to != NULL);
 	ast_assert(from != NULL);
+	ast_assert(ast_test_flag(&to->feature_flags, AST_BRIDGE_FLAG_INVISIBLE) == 0);
+	ast_assert(ast_test_flag(&from->feature_flags, AST_BRIDGE_FLAG_INVISIBLE) == 0);
 
 	merge_msg = bridge_merge_message_create(to, from);
 	if (!merge_msg) {
@@ -447,6 +453,10 @@ void ast_bridge_publish_enter(struct ast_bridge *bridge, struct ast_channel *cha
 	RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
 	RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
 
+	if (ast_test_flag(&bridge->feature_flags, AST_BRIDGE_FLAG_INVISIBLE)) {
+		return;
+	}
+
 	if (swap) {
 		blob = ast_json_pack("{s: s}", "swap", ast_channel_uniqueid(swap));
 		if (!blob) {
@@ -468,6 +478,9 @@ void ast_bridge_publish_leave(struct ast_bridge *bridge, struct ast_channel *cha
 {
 	RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
 
+	if (ast_test_flag(&bridge->feature_flags, AST_BRIDGE_FLAG_INVISIBLE)) {
+		return;
+	}
 	msg = ast_bridge_blob_create(ast_channel_left_bridge_type(), bridge, chan, NULL);
 	if (!msg) {
 		return;
diff --git a/main/stasis_channels.c b/main/stasis_channels.c
index eb1f1bc622..e56d1b928b 100644
--- a/main/stasis_channels.c
+++ b/main/stasis_channels.c
@@ -256,7 +256,9 @@ struct ast_channel_snapshot *ast_channel_snapshot_create(struct ast_channel *cha
 	ast_string_field_set(snapshot, language, ast_channel_language(chan));
 
 	if ((bridge = ast_channel_get_bridge(chan))) {
-		ast_string_field_set(snapshot, bridgeid, bridge->uniqueid);
+		if (!ast_test_flag(&bridge->feature_flags, AST_BRIDGE_FLAG_INVISIBLE)) {
+			ast_string_field_set(snapshot, bridgeid, bridge->uniqueid);
+		}
 		ao2_cleanup(bridge);
 	}
 
-- 
GitLab