summaryrefslogtreecommitdiff
path: root/main
diff options
context:
space:
mode:
authorScott Griepentrog <sgriepentrog@digium.com>2013-11-01 21:51:20 +0000
committerScott Griepentrog <sgriepentrog@digium.com>2013-11-01 21:51:20 +0000
commit3b36687a560aab39d6bcb0c5b336a7be873f67be (patch)
treef4590dca6398b58e7e9ff16b5053f5a141d02942 /main
parent2d0fb7f613a99dfbfb27b570277812e21e05275d (diff)
Manager: Add equivalent AMI actions for the bridge CLI commands.
Adds the following AMI events, closely following their CLI counterparts: BridgeDestroy BridgeKick BridgeTechnologyList BridgeTechnologySuspend BridgeTechnologyUnsuspend BridgeDestroy kicks an entire bridge, where BridgeKick kicks just one channel off the bridge. When kicking a channel, specifying the bridge also (optional) insures it is not removed from the wrong bridge. The BridgeTechnology events allow viewing and changing suspension status, which affects only subsequent not active bridging. (closes ASTERISK-22356) Reported by: Richard Mudgett Review: https://reviewboard.asterisk.org/r/2973/ ........ Merged revisions 402387 from http://svn.asterisk.org/svn/asterisk/branches/12 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@402388 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'main')
-rw-r--r--main/bridge.c151
-rw-r--r--main/manager_bridges.c107
2 files changed, 252 insertions, 6 deletions
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.