summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/asterisk/bridge.h11
-rw-r--r--main/bridge.c151
-rw-r--r--main/manager_bridges.c107
3 files changed, 263 insertions, 6 deletions
diff --git a/include/asterisk/bridge.h b/include/asterisk/bridge.h
index a28481c90..53673c7f7 100644
--- a/include/asterisk/bridge.h
+++ b/include/asterisk/bridge.h
@@ -1020,6 +1020,17 @@ struct ast_channel *ast_bridge_peer(struct ast_bridge *bridge, struct ast_channe
*/
void ast_bridge_features_remove(struct ast_bridge_features *features, enum ast_bridge_hook_remove_flags flags);
+/*!
+ * \brief Find bridge by id
+ * \since 12.0.0
+ *
+ * \param bridge_id Bridge identifier
+ *
+ * \return NULL bridge not found
+ * \return non-NULL reference to bridge
+ */
+struct ast_bridge *ast_bridge_find_by_id(const char *bridge_id);
+
#if defined(__cplusplus) || defined(c_plusplus)
}
#endif
diff --git a/main/bridge.c b/main/bridge.c
index a7b61847d..1c3bf16e3 100644
--- a/main/bridge.c
+++ b/main/bridge.c
@@ -27,6 +27,48 @@
<support_level>core</support_level>
***/
+/*** DOCUMENTATION
+ <manager name="BridgeTechnologyList" language="en_US">
+ <synopsis>
+ List available bridging technologies and their statuses.
+ </synopsis>
+ <syntax>
+ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
+ </syntax>
+ <description>
+ <para>Returns detailed information about the available bridging technologies.</para>
+ </description>
+ </manager>
+ <manager name="BridgeTechnologySuspend" language="en_US">
+ <synopsis>
+ Suspend a bridging technology.
+ </synopsis>
+ <syntax>
+ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
+ <parameter name="BridgeTechnology" required="true">
+ <para>The name of the bridging technology to suspend.</para>
+ </parameter>
+ </syntax>
+ <description>
+ <para>Marks a bridging technology as suspended, which prevents subsequently created bridges from using it.</para>
+ </description>
+ </manager>
+ <manager name="BridgeTechnologyUnsuspend" language="en_US">
+ <synopsis>
+ Unsuspend a bridging technology.
+ </synopsis>
+ <syntax>
+ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
+ <parameter name="BridgeTechnology" required="true">
+ <para>The name of the bridging technology to unsuspend.</para>
+ </parameter>
+ </syntax>
+ <description>
+ <para>Clears a previously suspended bridging technology, which allows subsequently created bridges to use it.</para>
+ </description>
+ </manager>
+***/
+
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
@@ -4485,6 +4527,11 @@ static int bridge_sort_cmp(const void *obj_left, const void *obj_right, int flag
return cmp;
}
+struct ast_bridge *ast_bridge_find_by_id(const char *bridge_id)
+{
+ return ao2_find(bridges, bridge_id, OBJ_SEARCH_KEY);
+}
+
struct bridge_complete {
/*! Nth match to return. */
int state;
@@ -4673,7 +4720,7 @@ static char *handle_bridge_destroy_specific(struct ast_cli_entry *e, int cmd, st
return CLI_SHOWUSAGE;
}
- bridge = ao2_find(bridges, a->argv[2], OBJ_KEY);
+ bridge = ast_bridge_find_by_id(a->argv[2]);
if (!bridge) {
ast_cli(a->fd, "Bridge '%s' not found\n", a->argv[2]);
return CLI_SUCCESS;
@@ -4692,7 +4739,7 @@ static char *complete_bridge_participant(const char *bridge_name, const char *li
int which;
int wordlen;
- bridge = ao2_find(bridges, bridge_name, OBJ_KEY);
+ bridge = ast_bridge_find_by_id(bridge_name);
if (!bridge) {
return NULL;
}
@@ -4739,7 +4786,7 @@ static char *handle_bridge_kick_channel(struct ast_cli_entry *e, int cmd, struct
return CLI_SHOWUSAGE;
}
- bridge = ao2_find(bridges, a->argv[2], OBJ_KEY);
+ bridge = ast_bridge_find_by_id(a->argv[2]);
if (!bridge) {
ast_cli(a->fd, "Bridge '%s' not found\n", a->argv[2]);
return CLI_SUCCESS;
@@ -4891,13 +4938,102 @@ static char *handle_bridge_technology_suspend(struct ast_cli_entry *e, int cmd,
static struct ast_cli_entry bridge_cli[] = {
AST_CLI_DEFINE(handle_bridge_show_all, "List all bridges"),
AST_CLI_DEFINE(handle_bridge_show_specific, "Show information about a bridge"),
-/* XXX ASTERISK-22356 need AMI action equivalents to the following CLI commands. */
AST_CLI_DEFINE(handle_bridge_destroy_specific, "Destroy a bridge"),
AST_CLI_DEFINE(handle_bridge_kick_channel, "Kick a channel from a bridge"),
AST_CLI_DEFINE(handle_bridge_technology_show, "List registered bridge technologies"),
AST_CLI_DEFINE(handle_bridge_technology_suspend, "Suspend/unsuspend a bridge technology"),
};
+
+static int handle_manager_bridge_tech_suspend(struct mansession *s, const struct message *m, int suspend)
+{
+ const char *name = astman_get_header(m, "BridgeTechnology");
+ struct ast_bridge_technology *cur;
+ int successful = 0;
+
+ if (ast_strlen_zero(name)) {
+ astman_send_error(s, m, "BridgeTechnology must be provided");
+ return 0;
+ }
+
+ AST_RWLIST_RDLOCK(&bridge_technologies);
+ AST_RWLIST_TRAVERSE(&bridge_technologies, cur, entry) {
+
+ if (!strcasecmp(cur->name, name)) {
+ successful = 1;
+ if (suspend) {
+ ast_bridge_technology_suspend(cur);
+ } else {
+ ast_bridge_technology_unsuspend(cur);
+ }
+ break;
+ }
+ }
+ AST_RWLIST_UNLOCK(&bridge_technologies);
+ if (!successful) {
+ astman_send_error(s, m, "BridgeTechnology not found");
+ return 0;
+ }
+
+ astman_send_ack(s, m, (suspend ? "Suspended bridge technology" : "Unsuspended bridge technology"));
+ return 0;
+}
+
+static int manager_bridge_tech_suspend(struct mansession *s, const struct message *m)
+{
+ return handle_manager_bridge_tech_suspend(s, m, 1);
+}
+
+static int manager_bridge_tech_unsuspend(struct mansession *s, const struct message *m)
+{
+ return handle_manager_bridge_tech_suspend(s, m, 0);
+}
+
+static int manager_bridge_tech_list(struct mansession *s, const struct message *m)
+{
+ const char *id = astman_get_header(m, "ActionID");
+ RAII_VAR(struct ast_str *, id_text, ast_str_create(128), ast_free);
+ struct ast_bridge_technology *cur;
+
+ if (!id_text) {
+ astman_send_error(s, m, "Internal error");
+ return -1;
+ }
+
+ if (!ast_strlen_zero(id)) {
+ ast_str_set(&id_text, 0, "ActionID: %s\r\n", id);
+ }
+
+ astman_send_ack(s, m, "Bridge technology listing will follow");
+
+ AST_RWLIST_RDLOCK(&bridge_technologies);
+ AST_RWLIST_TRAVERSE(&bridge_technologies, cur, entry) {
+ const char *type;
+
+ type = tech_capability2str(cur->capabilities);
+
+ astman_append(s,
+ "Event: BridgeTechnologyListItem\r\n"
+ "BridgeTechnology: %s\r\n"
+ "BridgeType: %s\r\n"
+ "BridgePriority: %d\r\n"
+ "BridgeSuspended: %s\r\n"
+ "%s"
+ "\r\n",
+ cur->name, type, cur->preference, AST_YESNO(cur->suspended),
+ ast_str_buffer(id_text));
+ }
+ AST_RWLIST_UNLOCK(&bridge_technologies);
+
+ astman_append(s,
+ "Event: BridgeTechnologyListComplete\r\n"
+ "%s"
+ "\r\n",
+ ast_str_buffer(id_text));
+
+ return 0;
+}
+
/*!
* \internal
* \brief Print bridge object key (name).
@@ -4929,6 +5065,9 @@ static void bridge_prnt_obj(void *v_obj, void *where, ao2_prnt_fn *prnt)
*/
static void bridge_shutdown(void)
{
+ ast_manager_unregister("BridgeTechnologyList");
+ ast_manager_unregister("BridgeTechnologySuspend");
+ ast_manager_unregister("BridgeTechnologyUnsuspend");
ast_cli_unregister_multiple(bridge_cli, ARRAY_LEN(bridge_cli));
ao2_container_unregister("bridges");
ao2_cleanup(bridges);
@@ -4961,5 +5100,9 @@ int ast_bridging_init(void)
ast_cli_register_multiple(bridge_cli, ARRAY_LEN(bridge_cli));
+ ast_manager_register_xml_core("BridgeTechnologyList", 0, manager_bridge_tech_list);
+ ast_manager_register_xml_core("BridgeTechnologySuspend", 0, manager_bridge_tech_suspend);
+ ast_manager_register_xml_core("BridgeTechnologyUnsuspend", 0, manager_bridge_tech_unsuspend);
+
return 0;
}
diff --git a/main/manager_bridges.c b/main/manager_bridges.c
index fad676b56..e012ebb6d 100644
--- a/main/manager_bridges.c
+++ b/main/manager_bridges.c
@@ -101,6 +101,39 @@ static struct stasis_message_router *bridge_state_router;
<para>Returns detailed information about a bridge and the channels in it.</para>
</description>
</manager>
+ <manager name="BridgeDestroy" language="en_US">
+ <synopsis>
+ Destroy a bridge.
+ </synopsis>
+ <syntax>
+ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
+ <parameter name="BridgeUniqueid" required="true">
+ <para>The unique ID of the bridge to destroy.</para>
+ </parameter>
+ </syntax>
+ <description>
+ <para>Deletes the bridge, causing channels to continue or hang up.</para>
+ </description>
+ </manager>
+ <manager name="BridgeKick" language="en_US">
+ <synopsis>
+ Kick a channel from a bridge.
+ </synopsis>
+ <syntax>
+ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
+ <parameter name="BridgeUniqueid" required="false">
+ <para>The unique ID of the bridge containing the channel to
+ destroy. This parameter can be omitted, or supplied to insure
+ that the channel is not removed from the wrong bridge.</para>
+ </parameter>
+ <parameter name="Channel" required="true">
+ <para>The channel to kick out of a bridge.</para>
+ </parameter>
+ </syntax>
+ <description>
+ <para>The channel is removed from the bridge.</para>
+ </description>
+ </manager>
***/
/*! \brief The \ref stasis subscription returned by the forwarding of the channel topic
@@ -419,7 +452,7 @@ static int manager_bridge_info(struct mansession *s, const struct message *m)
if (ast_strlen_zero(bridge_uniqueid)) {
astman_send_error(s, m, "BridgeUniqueid must be provided");
- return -1;
+ return 0;
}
if (!ast_strlen_zero(id)) {
@@ -429,7 +462,7 @@ static int manager_bridge_info(struct mansession *s, const struct message *m)
msg = stasis_cache_get(ast_bridge_cache(), ast_bridge_snapshot_type(), bridge_uniqueid);
if (!msg) {
astman_send_error(s, m, "Specified BridgeUniqueid not found");
- return -1;
+ return 0;
}
astman_send_ack(s, m, "Bridge channel listing will follow");
@@ -450,6 +483,72 @@ static int manager_bridge_info(struct mansession *s, const struct message *m)
return 0;
}
+static int manager_bridge_destroy(struct mansession *s, const struct message *m)
+{
+ const char *bridge_uniqueid = astman_get_header(m, "BridgeUniqueid");
+ struct ast_bridge *bridge;
+
+ if (ast_strlen_zero(bridge_uniqueid)) {
+ astman_send_error(s, m, "BridgeUniqueid must be provided");
+ return 0;
+ }
+
+ bridge = ast_bridge_find_by_id(bridge_uniqueid);
+ if (!bridge) {
+ astman_send_error(s, m, "Specified BridgeUniqueid not found");
+ return 0;
+ }
+ ast_bridge_destroy(bridge, 0);
+
+ astman_send_ack(s, m, "Bridge has been destroyed");
+
+ return 0;
+}
+
+static int manager_bridge_kick(struct mansession *s, const struct message *m)
+{
+ const char *bridge_uniqueid = astman_get_header(m, "BridgeUniqueid");
+ const char *channel_name = astman_get_header(m, "Channel");
+ RAII_VAR(struct ast_bridge *, bridge, NULL, ao2_cleanup);
+ RAII_VAR(struct ast_channel *, channel, NULL, ao2_cleanup);
+
+ if (ast_strlen_zero(channel_name)) {
+ astman_send_error(s, m, "Channel must be provided");
+ return 0;
+ }
+
+ channel = ast_channel_get_by_name(channel_name);
+ if (!channel) {
+ astman_send_error(s, m, "Channel does not exist");
+ return 0;
+ }
+
+ if (ast_strlen_zero(bridge_uniqueid)) {
+ /* get the bridge from the channel */
+ ast_channel_lock(channel);
+ bridge = ast_channel_get_bridge(channel);
+ ast_channel_unlock(channel);
+ if (!bridge) {
+ astman_send_error(s, m, "Channel is not in a bridge");
+ return 0;
+ }
+ } else {
+ bridge = ast_bridge_find_by_id(bridge_uniqueid);
+ if (!bridge) {
+ astman_send_error(s, m, "Bridge not found");
+ return 0;
+ }
+ }
+
+ if (ast_bridge_kick(bridge, channel)) {
+ astman_send_error(s, m, "Channel kick from bridge failed");
+ return 0;
+ }
+
+ astman_send_ack(s, m, "Channel has been kicked");
+ return 0;
+}
+
static void manager_bridging_cleanup(void)
{
stasis_forward_cancel(topic_forwarder);
@@ -460,6 +559,8 @@ static void manager_bridging_shutdown(void)
{
ast_manager_unregister("BridgeList");
ast_manager_unregister("BridgeInfo");
+ ast_manager_unregister("BridgeDestroy");
+ ast_manager_unregister("BridgeKick");
}
int manager_bridging_init(void)
@@ -510,6 +611,8 @@ int manager_bridging_init(void)
ret |= ast_manager_register_xml_core("BridgeList", 0, manager_bridges_list);
ret |= ast_manager_register_xml_core("BridgeInfo", 0, manager_bridge_info);
+ ret |= ast_manager_register_xml_core("BridgeDestroy", 0, manager_bridge_destroy);
+ ret |= ast_manager_register_xml_core("BridgeKick", 0, manager_bridge_kick);
/* If somehow we failed to add any routes, just shut down the whole
* thing and fail it.