AMI: Add CoreShowChannelMap action.
Adds a new AMI action (CoreShowChannelMap) that takes in a channel name and provides a list of all channels that are connected to that channel, following local channel connections as well. Resolves: #104 UserNote: New AMI action CoreShowChannelMap has been added.
This commit is contained in:
parent
f56477a604
commit
d6d77dc1fb
204
main/manager.c
204
main/manager.c
|
@ -68,6 +68,7 @@
|
|||
#include "asterisk/module.h"
|
||||
#include "asterisk/config.h"
|
||||
#include "asterisk/callerid.h"
|
||||
#include "asterisk/core_local.h"
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/cli.h"
|
||||
#include "asterisk/app.h"
|
||||
|
@ -1041,6 +1042,33 @@
|
|||
<xi:include xpointer="xpointer(/docs/managerEvent[@name='CoreShowChannelsComplete'])" />
|
||||
</responses>
|
||||
</manager>
|
||||
<managerEvent language="en_US" name="CoreShowChannelMapComplete">
|
||||
<managerEventInstance class="EVENT_FLAG_CALL">
|
||||
<synopsis>Raised at the end of the CoreShowChannelMap list produced by the CoreShowChannelMap command.</synopsis>
|
||||
<syntax>
|
||||
<parameter name="EventList">
|
||||
<para>Conveys the status of the command response list</para>
|
||||
</parameter>
|
||||
<parameter name="ListItems">
|
||||
<para>The total number of list items produced</para>
|
||||
</parameter>
|
||||
</syntax>
|
||||
</managerEventInstance>
|
||||
</managerEvent>
|
||||
<manager name="CoreShowChannelMap" language="en_US">
|
||||
<synopsis>
|
||||
List all channels connected to the specified channel.
|
||||
</synopsis>
|
||||
<syntax>
|
||||
<parameter name="Channel">
|
||||
<para>The channel to get the mapping for. Requires a channel name.</para>
|
||||
</parameter>
|
||||
</syntax>
|
||||
<description>
|
||||
<para>List all channels currently connected to the specified channel. This can be any channel, including
|
||||
Local channels, and Local channels will be followed through to their other half.</para>
|
||||
</description>
|
||||
</manager>
|
||||
<manager name="LoggerRotate" language="en_US">
|
||||
<synopsis>
|
||||
Reload and rotate the Asterisk logger.
|
||||
|
@ -6873,6 +6901,180 @@ static int action_coreshowchannels(struct mansession *s, const struct message *m
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*! \brief Helper function to add a channel name to the vector */
|
||||
static int coreshowchannelmap_add_to_map(struct ao2_container *c, const char *s)
|
||||
{
|
||||
char *str;
|
||||
|
||||
str = ast_strdup(s);
|
||||
if (!str) {
|
||||
ast_log(LOG_ERROR, "Unable to append channel to channel map\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* If this is a duplicate, it will be ignored */
|
||||
ast_str_container_add(c, str);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! \brief Recursive function to get all channels in a bridge. Follow local channels as well */
|
||||
static int coreshowchannelmap_add_connected_channels(struct ao2_container *channel_map,
|
||||
struct ast_channel_snapshot *channel_snapshot, struct ast_bridge_snapshot *bridge_snapshot)
|
||||
{
|
||||
int res = 0;
|
||||
struct ao2_iterator iter;
|
||||
char *current_channel_uid;
|
||||
|
||||
iter = ao2_iterator_init(bridge_snapshot->channels, 0);
|
||||
while ((current_channel_uid = ao2_iterator_next(&iter))) {
|
||||
struct ast_channel_snapshot *current_channel_snapshot;
|
||||
int add_channel_res;
|
||||
|
||||
/* Don't add the original channel to the list - it's either already in there,
|
||||
* or it's the channel we want the map for */
|
||||
if (!strcmp(current_channel_uid, channel_snapshot->base->uniqueid)) {
|
||||
ao2_ref(current_channel_uid, -1);
|
||||
continue;
|
||||
}
|
||||
|
||||
current_channel_snapshot = ast_channel_snapshot_get_latest(current_channel_uid);
|
||||
if (!current_channel_snapshot) {
|
||||
ast_debug(5, "Unable to get channel snapshot\n");
|
||||
ao2_ref(current_channel_uid, -1);
|
||||
continue;
|
||||
}
|
||||
|
||||
add_channel_res = coreshowchannelmap_add_to_map(channel_map, current_channel_snapshot->base->name);
|
||||
if (add_channel_res) {
|
||||
res = 1;
|
||||
ao2_ref(current_channel_snapshot, -1);
|
||||
ao2_ref(current_channel_uid, -1);
|
||||
break;
|
||||
}
|
||||
|
||||
/* If this is a local channel that we haven't seen yet, let's go ahead and find out what else is connected to it */
|
||||
if (ast_begins_with(current_channel_snapshot->base->name, "Local")) {
|
||||
struct ast_channel_snapshot *other_local_snapshot;
|
||||
struct ast_bridge_snapshot *other_bridge_snapshot;
|
||||
int size = strlen(current_channel_snapshot->base->name);
|
||||
char other_local[size + 1];
|
||||
|
||||
/* Don't copy the trailing number - set it to 1 or 2, whichever one it currently is not */
|
||||
ast_copy_string(other_local, current_channel_snapshot->base->name, size);
|
||||
other_local[size - 1] = ast_ends_with(current_channel_snapshot->base->name, "1") ? '2' : '1';
|
||||
other_local[size] = '\0';
|
||||
|
||||
other_local_snapshot = ast_channel_snapshot_get_latest_by_name(other_local);
|
||||
if (!other_local_snapshot) {
|
||||
ast_debug(5, "Unable to get other local channel snapshot\n");
|
||||
ao2_ref(current_channel_snapshot, -1);
|
||||
ao2_ref(current_channel_uid, -1);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (coreshowchannelmap_add_to_map(channel_map, other_local_snapshot->base->name)) {
|
||||
res = 1;
|
||||
ao2_ref(current_channel_snapshot, -1);
|
||||
ao2_ref(current_channel_uid, -1);
|
||||
ao2_ref(other_local_snapshot, -1);
|
||||
break;
|
||||
}
|
||||
|
||||
other_bridge_snapshot = ast_bridge_get_snapshot_by_uniqueid(other_local_snapshot->bridge->id);
|
||||
if (other_bridge_snapshot) {
|
||||
res = coreshowchannelmap_add_connected_channels(channel_map, other_local_snapshot, other_bridge_snapshot);
|
||||
}
|
||||
|
||||
ao2_ref(current_channel_snapshot, -1);
|
||||
ao2_ref(current_channel_uid, -1);
|
||||
ao2_ref(other_local_snapshot, -1);
|
||||
ao2_ref(other_bridge_snapshot, -1);
|
||||
|
||||
if (res) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
ao2_iterator_destroy(&iter);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/*! \brief Manager command "CoreShowChannelMap" - Lists all channels connected to
|
||||
* the specified channel. */
|
||||
static int action_coreshowchannelmap(struct mansession *s, const struct message *m)
|
||||
{
|
||||
const char *actionid = astman_get_header(m, "ActionID");
|
||||
const char *channel_name = astman_get_header(m, "Channel");
|
||||
char *current_channel_name;
|
||||
char id_text[256];
|
||||
int total = 0;
|
||||
struct ao2_container *channel_map;
|
||||
struct ao2_iterator i;
|
||||
RAII_VAR(struct ast_bridge_snapshot *, bridge_snapshot, NULL, ao2_cleanup);
|
||||
RAII_VAR(struct ast_channel_snapshot *, channel_snapshot, NULL, ao2_cleanup);
|
||||
|
||||
if (!ast_strlen_zero(actionid)) {
|
||||
snprintf(id_text, sizeof(id_text), "ActionID: %s\r\n", actionid);
|
||||
} else {
|
||||
id_text[0] = '\0';
|
||||
}
|
||||
|
||||
if (ast_strlen_zero(channel_name)) {
|
||||
astman_send_error(s, m, "CoreShowChannelMap requires a channel.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
channel_snapshot = ast_channel_snapshot_get_latest_by_name(channel_name);
|
||||
if (!channel_snapshot) {
|
||||
astman_send_error(s, m, "Could not get channel snapshot\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
bridge_snapshot = ast_bridge_get_snapshot_by_uniqueid(channel_snapshot->bridge->id);
|
||||
if (!bridge_snapshot) {
|
||||
astman_send_listack(s, m, "Channel map will follow", "start");
|
||||
astman_send_list_complete_start(s, m, "CoreShowChannelMapComplete", 0);
|
||||
astman_send_list_complete_end(s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
channel_map = ast_str_container_alloc_options(AO2_ALLOC_OPT_LOCK_NOLOCK | AO2_CONTAINER_ALLOC_OPT_DUPS_OBJ_REJECT, 1);
|
||||
if (!channel_map) {
|
||||
astman_send_error(s, m, "Could not create channel map\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
astman_send_listack(s, m, "Channel map will follow", "start");
|
||||
|
||||
if (coreshowchannelmap_add_connected_channels(channel_map, channel_snapshot, bridge_snapshot)) {
|
||||
astman_send_error(s, m, "Could not complete channel map\n");
|
||||
ao2_ref(channel_map, -1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
i = ao2_iterator_init(channel_map, 0);
|
||||
while ((current_channel_name = ao2_iterator_next(&i))) {
|
||||
astman_append(s,
|
||||
"Event: CoreShowChannelMap\r\n"
|
||||
"%s"
|
||||
"Channel: %s\r\n"
|
||||
"ConnectedChannel: %s\r\n\n",
|
||||
id_text,
|
||||
channel_name,
|
||||
current_channel_name);
|
||||
total++;
|
||||
}
|
||||
ao2_iterator_destroy(&i);
|
||||
|
||||
ao2_ref(channel_map, -1);
|
||||
astman_send_list_complete_start(s, m, "CoreShowChannelMapComplete", total);
|
||||
astman_send_list_complete_end(s);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! \brief Manager command "LoggerRotate" - reloads and rotates the logger in
|
||||
* the same manner as the CLI command 'logger rotate'. */
|
||||
static int action_loggerrotate(struct mansession *s, const struct message *m)
|
||||
|
@ -9450,6 +9652,7 @@ static void manager_shutdown(void)
|
|||
ast_manager_unregister("Reload");
|
||||
ast_manager_unregister("LoggerRotate");
|
||||
ast_manager_unregister("CoreShowChannels");
|
||||
ast_manager_unregister("CoreShowChannelMap");
|
||||
ast_manager_unregister("ModuleLoad");
|
||||
ast_manager_unregister("ModuleCheck");
|
||||
ast_manager_unregister("AOCMessage");
|
||||
|
@ -9665,6 +9868,7 @@ static int __init_manager(int reload, int by_external_config)
|
|||
ast_manager_register_xml_core("Reload", EVENT_FLAG_CONFIG | EVENT_FLAG_SYSTEM, action_reload);
|
||||
ast_manager_register_xml_core("LoggerRotate", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, action_loggerrotate);
|
||||
ast_manager_register_xml_core("CoreShowChannels", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, action_coreshowchannels);
|
||||
ast_manager_register_xml_core("CoreShowChannelMap", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, action_coreshowchannelmap);
|
||||
ast_manager_register_xml_core("ModuleLoad", EVENT_FLAG_SYSTEM, manager_moduleload);
|
||||
ast_manager_register_xml_core("ModuleCheck", EVENT_FLAG_SYSTEM, manager_modulecheck);
|
||||
ast_manager_register_xml_core("AOCMessage", EVENT_FLAG_AOC, action_aocmessage);
|
||||
|
|
Loading…
Reference in New Issue