[Asterisk-code-review] chan pjsip: Add 'pjsip show channelstats' (asterisk[13])

George Joseph asteriskteam at digium.com
Sun Mar 27 19:09:47 CDT 2016


George Joseph has uploaded a new change for review.

  https://gerrit.asterisk.org/2480

Change subject: chan_pjsip:  Add 'pjsip show channelstats'
......................................................................

chan_pjsip:  Add 'pjsip show channelstats'

Added the ability to show channel statistics to chan_pjsip (cli_functions.c)

Moved the existing 'pjsip show channel(s)' functionality from
pjsip_configuration to cli_functions.c.  The stats needed chan_pjsip's
private header so it made sense to move the existing channel commands as well.

Now using stasis_cache_dump to get the channel snapshots rather than retrieving
all endpoints, then getting each one's channel snapshots.  Much more efficient.

Change-Id: I03b114522126d27434030b285bf6d531ddd79869
---
M CHANGES
M channels/chan_pjsip.c
A channels/pjsip/cli_commands.c
A channels/pjsip/include/cli_functions.h
M res/res_pjsip/pjsip_cli.c
M res/res_pjsip/pjsip_configuration.c
6 files changed, 533 insertions(+), 262 deletions(-)


  git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/80/2480/1

diff --git a/CHANGES b/CHANGES
index 29b1b76..2f12ba0 100644
--- a/CHANGES
+++ b/CHANGES
@@ -9,6 +9,14 @@
 ==============================================================================
 
 ------------------------------------------------------------------------------
+--- Functionality changes from Asterisk 13.8.0 to Asterisk 13.9.0 ------------
+------------------------------------------------------------------------------
+
+chan_pjsip
+------------------
+ * Added 'pjsip show channelstats' CLI command.
+
+------------------------------------------------------------------------------
 --- Functionality changes from Asterisk 13.7.0 to Asterisk 13.8.0 ------------
 ------------------------------------------------------------------------------
 
diff --git a/channels/chan_pjsip.c b/channels/chan_pjsip.c
index 07887af..f081bd8 100644
--- a/channels/chan_pjsip.c
+++ b/channels/chan_pjsip.c
@@ -69,6 +69,7 @@
 
 #include "pjsip/include/chan_pjsip.h"
 #include "pjsip/include/dialplan_functions.h"
+#include "pjsip/include/cli_functions.h"
 
 AST_THREADSTORAGE(uniqueid_threadbuf);
 #define UNIQUEID_BUFSIZE 256
@@ -2419,6 +2420,15 @@
 		goto end;
 	}
 
+	if (pjsip_channel_cli_register()) {
+		ast_log(LOG_ERROR, "Unable to register PJSIP Channel CLI\n");
+		ast_sip_session_unregister_supplement(&chan_pjsip_ack_supplement);
+		ast_sip_session_unregister_supplement(&pbx_start_supplement);
+		ast_sip_session_unregister_supplement(&chan_pjsip_supplement);
+		ast_sip_session_unregister_supplement(&call_pickup_supplement);
+		goto end;
+	}
+
 	/* since endpoints are loaded before the channel driver their device
 	   states get set to 'invalid', so they need to be updated */
 	if ((endpoints = ast_sip_get_endpoints())) {
@@ -2445,6 +2455,8 @@
 	ao2_cleanup(pjsip_uids_onhold);
 	pjsip_uids_onhold = NULL;
 
+	pjsip_channel_cli_unregister();
+
 	ast_sip_session_unregister_supplement(&chan_pjsip_supplement);
 	ast_sip_session_unregister_supplement(&pbx_start_supplement);
 	ast_sip_session_unregister_supplement(&chan_pjsip_ack_supplement);
diff --git a/channels/pjsip/cli_commands.c b/channels/pjsip/cli_commands.c
new file mode 100644
index 0000000..8d99379
--- /dev/null
+++ b/channels/pjsip/cli_commands.c
@@ -0,0 +1,467 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2016, Fairview 5 Engineering, LLC
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*!
+ * \file
+ *
+ * \author \verbatim George Joseph <george.joseph at fairview5.com> \endverbatim
+ *
+ * \ingroup functions
+ *
+ * \brief PJSIP channel CLI functions
+ */
+
+#include "asterisk.h"
+
+ASTERISK_REGISTER_FILE()
+
+#include <pjsip.h>
+#include <pjlib.h>
+#include <pjsip_ua.h>
+
+#include "asterisk/astobj2.h"
+#include "asterisk/channel.h"
+#include "asterisk/format.h"
+#include "asterisk/res_pjsip.h"
+#include "asterisk/res_pjsip_session.h"
+#include "asterisk/res_pjsip_cli.h"
+#include "asterisk/stasis.h"
+#include "asterisk/time.h"
+#include "include/chan_pjsip.h"
+#include "include/cli_functions.h"
+
+
+static int cli_channel_iterate(void *endpoint, ao2_callback_fn callback, void *arg)
+{
+	return ast_sip_for_each_channel(endpoint, callback, arg);
+}
+
+static int cli_channelstats_iterate(void *endpoint, ao2_callback_fn callback, void *arg)
+{
+	return ast_sip_for_each_channel(endpoint, callback, arg);
+}
+
+static int cli_channel_sort(const void *obj, const void *arg, int flags)
+{
+	const struct ast_channel_snapshot *left_obj = obj;
+	const struct ast_channel_snapshot *right_obj = arg;
+	const char *right_key = arg;
+	int cmp;
+
+	switch (flags & OBJ_SEARCH_MASK) {
+	case OBJ_SEARCH_OBJECT:
+		right_key = right_obj->name;
+		/* Fall through */
+	case OBJ_SEARCH_KEY:
+		cmp = strcmp(left_obj->name, right_key);
+		break;
+	case OBJ_SEARCH_PARTIAL_KEY:
+		cmp = strncmp(left_obj->name, right_key, strlen(right_key));
+		break;
+	default:
+		cmp = 0;
+		break;
+	}
+
+	return cmp;
+}
+
+static int cli_channelstats_sort(const void *obj, const void *arg, int flags)
+{
+	const struct ast_channel_snapshot *left_obj = obj;
+	const struct ast_channel_snapshot *right_obj = arg;
+	const char *right_key = arg;
+	int cmp;
+
+	switch (flags & OBJ_SEARCH_MASK) {
+	case OBJ_SEARCH_OBJECT:
+		cmp = strcmp(left_obj->bridgeid, right_obj->bridgeid);
+		if (cmp) {
+			return cmp;
+		}
+		right_key = right_obj->name;
+		/* Fall through */
+	case OBJ_SEARCH_KEY:
+		cmp = strcmp(left_obj->name, right_key);
+		break;
+	case OBJ_SEARCH_PARTIAL_KEY:
+		cmp = strncmp(left_obj->name, right_key, strlen(right_key));
+		break;
+	default:
+		cmp = 0;
+		break;
+	}
+
+	return cmp;
+}
+
+static int cli_channel_compare(void *obj, void *arg, int flags)
+{
+	const struct ast_channel_snapshot *left_obj = obj;
+	const struct ast_channel_snapshot *right_obj = arg;
+	const char *right_key = arg;
+	int cmp = 0;
+
+	switch (flags & OBJ_SEARCH_MASK) {
+	case OBJ_SEARCH_OBJECT:
+		right_key = right_obj->name;
+		/* Fall through */
+	case OBJ_SEARCH_KEY:
+		if (strcmp(left_obj->name, right_key) == 0) {
+			cmp = CMP_MATCH | CMP_STOP;
+		}
+		break;
+	case OBJ_SEARCH_PARTIAL_KEY:
+		if (strncmp(left_obj->name, right_key, strlen(right_key)) == 0) {
+			cmp = CMP_MATCH;
+		}
+		break;
+	default:
+		cmp = 0;
+		break;
+	}
+
+	return cmp;
+}
+
+static int cli_channelstats_compare(void *obj, void *arg, int flags)
+{
+	const struct ast_channel_snapshot *left_obj = obj;
+	const struct ast_channel_snapshot *right_obj = arg;
+	const char *right_key = arg;
+	int cmp = 0;
+
+	switch (flags & OBJ_SEARCH_MASK) {
+	case OBJ_SEARCH_OBJECT:
+		if (strcmp(left_obj->bridgeid, right_obj->bridgeid) == 0
+			&& strcmp(left_obj->name, right_obj->name) == 0) {
+			return CMP_MATCH | CMP_STOP;
+		}
+		break;
+	case OBJ_SEARCH_KEY:
+		if (strcmp(left_obj->name, right_key) == 0) {
+			cmp = CMP_MATCH | CMP_STOP;
+		}
+		break;
+	case OBJ_SEARCH_PARTIAL_KEY:
+		if (strncmp(left_obj->name, right_key, strlen(right_key)) == 0) {
+			cmp = CMP_MATCH;
+		}
+		break;
+	default:
+		cmp = 0;
+		break;
+	}
+
+	return cmp;
+}
+
+static int cli_message_to_snapshot(void *obj, void *arg, int flags)
+{
+	struct stasis_message *message = obj;
+	struct ao2_container *snapshots = arg;
+	struct ast_channel_snapshot *snapshot = stasis_message_data(message);
+
+	if (!strcmp(snapshot->type, "PJSIP")) {
+		ao2_link(snapshots, snapshot);
+		return CMP_MATCH;
+	}
+
+	return 0;
+}
+
+static int cli_filter_channels(void *obj, void *arg, int flags)
+{
+	struct ast_channel_snapshot *channel = obj;
+	regex_t *regexbuf = arg;
+
+	if (!regexec(regexbuf, channel->name, 0, NULL, 0)
+		|| !regexec(regexbuf, channel->appl, 0, NULL, 0)) {
+		return 0;
+	}
+
+	return CMP_MATCH;
+}
+
+static struct ao2_container *get_container(const char *regex, ao2_sort_fn sort_fn, ao2_callback_fn compare_fn)
+{
+	struct ao2_container *child_container;
+	regex_t regexbuf;
+	RAII_VAR(struct ao2_container *, parent_container,
+		stasis_cache_dump(ast_channel_cache_by_name(), ast_channel_snapshot_type()), ao2_cleanup);
+
+	if (!parent_container) {
+		return NULL;
+	}
+
+	child_container = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK, 0, sort_fn, compare_fn);
+	if (!child_container) {
+		return NULL;
+	}
+
+	ao2_callback(parent_container, OBJ_MULTIPLE | OBJ_NODATA, cli_message_to_snapshot, child_container);
+
+	if (!ast_strlen_zero(regex)) {
+		if (regcomp(&regexbuf, regex, REG_EXTENDED | REG_NOSUB)) {
+			ao2_ref(child_container, -1);
+			return NULL;
+		}
+		ao2_callback(child_container, OBJ_UNLINK | OBJ_MULTIPLE | OBJ_NODATA, cli_filter_channels, &regexbuf);
+		regfree(&regexbuf);
+	}
+
+	return child_container;
+}
+
+static struct ao2_container *cli_channel_get_container(const char *regex)
+{
+	return get_container(regex, cli_channel_sort, cli_channel_compare);
+}
+
+static struct ao2_container *cli_channelstats_get_container(const char *regex)
+{
+	return get_container(regex, cli_channelstats_sort, cli_channelstats_compare);
+}
+
+static const char *cli_channel_get_id(const void *obj)
+{
+	const struct ast_channel_snapshot *snapshot = obj;
+
+	return snapshot->name;
+}
+
+static void *cli_channel_retrieve_by_id(const char *id)
+{
+	return ast_channel_snapshot_get_latest_by_name(id);
+}
+
+static int cli_channel_print_header(void *obj, void *arg, int flags)
+{
+	struct ast_sip_cli_context *context = arg;
+	int indent = CLI_INDENT_TO_SPACES(context->indent_level);
+	int filler = CLI_LAST_TABSTOP - indent - 13;
+
+	ast_assert(context->output_buffer != NULL);
+
+	ast_str_append(&context->output_buffer, 0,
+		"%*s:  <ChannelId%*.*s>  <State.....>  <Time.....>\n",
+		indent, "Channel", filler, filler, CLI_HEADER_FILLER);
+	if (context->recurse) {
+		context->indent_level++;
+		indent = CLI_INDENT_TO_SPACES(context->indent_level);
+		filler = CLI_LAST_TABSTOP - indent - 38;
+		ast_str_append(&context->output_buffer, 0,
+			"%*s: <DialedExten%*.*s>  CLCID: <ConnectedLineCID.......>\n",
+			indent, "Exten", filler, filler, CLI_HEADER_FILLER);
+		context->indent_level--;
+	}
+
+	return 0;
+}
+
+static int cli_channel_print_body(void *obj, void *arg, int flags)
+{
+	const struct ast_channel_snapshot *snapshot = obj;
+	struct ast_sip_cli_context *context = arg;
+	char *print_name = NULL;
+	int print_name_len;
+	int indent;
+	int flexwidth;
+	char *print_time = alloca(32);
+
+	ast_assert(context->output_buffer != NULL);
+
+	print_name_len = strlen(snapshot->name) + strlen(snapshot->appl) + 2;
+	print_name = alloca(print_name_len);
+
+	/* Append the application */
+	snprintf(print_name, print_name_len, "%s/%s", snapshot->name, snapshot->appl);
+
+	indent = CLI_INDENT_TO_SPACES(context->indent_level);
+	flexwidth = CLI_LAST_TABSTOP - indent;
+
+	ast_format_duration_hh_mm_ss(ast_tvnow().tv_sec - snapshot->creationtime.tv_sec, print_time, 32);
+
+	ast_str_append(&context->output_buffer, 0, "%*s: %-*.*s %-12.12s  %-11.11s\n",
+		CLI_INDENT_TO_SPACES(context->indent_level), "Channel",
+		flexwidth, flexwidth,
+		print_name,
+		ast_state2str(snapshot->state),
+		print_time);
+
+	if (context->recurse) {
+		context->indent_level++;
+		indent = CLI_INDENT_TO_SPACES(context->indent_level);
+		flexwidth = CLI_LAST_TABSTOP - indent - 25;
+
+		ast_str_append(&context->output_buffer, 0,
+			"%*s: %-*.*s  CLCID: \"%s\" <%s>\n",
+			indent, "Exten",
+			flexwidth, flexwidth,
+			snapshot->exten,
+			snapshot->connected_name,
+			snapshot->connected_number
+			);
+		context->indent_level--;
+		if (context->indent_level == 0) {
+			ast_str_append(&context->output_buffer, 0, "\n");
+		}
+	}
+
+	return 0;
+}
+
+static int cli_channelstats_print_header(void *obj, void *arg, int flags)
+{
+	struct ast_sip_cli_context *context = arg;
+
+	ast_assert(context->output_buffer != NULL);
+
+	ast_str_append(&context->output_buffer, 0,
+		"                                             ...........Receive......... .........Transmit..........\n"
+		" BridgeId ChannelId ........ UpTime.. Codec.   Count    Lost Pct  Jitter   Count    Lost Pct  Jitter RTT....\n"
+		" =================");
+
+	return 0;
+}
+
+static int cli_channelstats_print_body(void *obj, void *arg, int flags)
+{
+	struct ast_sip_cli_context *context = arg;
+	const struct ast_channel_snapshot *snapshot = obj;
+	struct ast_channel *channel = ast_channel_get_by_name(snapshot->name);
+	struct ast_sip_channel_pvt *cpvt = channel ? ast_channel_tech_pvt(channel) : NULL;
+	struct chan_pjsip_pvt *pvt = cpvt ? cpvt->pvt : NULL;
+	struct ast_sip_session_media *media = pvt ? pvt->media[SIP_MEDIA_AUDIO] : NULL;
+	struct ast_rtp_codecs *codecs = media && media->rtp ? ast_rtp_instance_get_codecs(media->rtp) : NULL;
+	struct ast_format *format = codecs ? ast_rtp_codecs_get_payload_format(codecs, 0) : NULL;
+	struct ast_rtp_instance_stats stats;
+	char *print_name = NULL;
+	char *print_time = alloca(32);
+
+	ast_assert(context->output_buffer != NULL);
+
+	if (!media || !media->rtp) {
+		ast_str_append(&context->output_buffer, 0, " %s not valid\n", snapshot->name);
+		ao2_cleanup(channel);
+		return -1;
+	}
+
+	print_name = ast_strdupa(snapshot->name);
+	/* Skip the PJSIP/.  We know what channel type it is and we need the space. */
+	print_name += 6;
+
+	ast_format_duration_hh_mm_ss(ast_tvnow().tv_sec - snapshot->creationtime.tv_sec, print_time, 32);
+
+	if (ast_rtp_instance_get_stats(media->rtp, &stats, AST_RTP_INSTANCE_STAT_ALL)) {
+		ast_str_append(&context->output_buffer, 0, "%s direct media\n", snapshot->name);
+	} else {
+		ast_str_append(&context->output_buffer, 0,
+			" %8.8s %-18.18s %-8.8s %-6.6s %6u%s %6u%s %3u %7.3f %6u%s %6u%s %3u %7.3f %7.3f\n",
+			snapshot->bridgeid,
+			print_name,
+			print_time,
+			format ? ast_format_get_name(format) : "",
+			stats.rxcount > 100000 ? stats.rxcount / 1000 : stats.rxcount,
+			stats.rxcount > 100000 ? "K": " ",
+			stats.rxploss > 100000 ? stats.rxploss / 1000 : stats.rxploss,
+			stats.rxploss > 100000 ? "K": " ",
+			stats.rxcount ? (stats.rxploss * 100) / stats.rxcount : 0,
+			MIN(stats.rxjitter, 999.999),
+			stats.txcount > 100000 ? stats.txcount / 1000 : stats.txcount,
+			stats.txcount > 100000 ? "K": " ",
+			stats.txploss > 100000 ? stats.txploss / 1000 : stats.txploss,
+			stats.txploss > 100000 ? "K": " ",
+			stats.txcount ? (stats.txploss * 100) / stats.txcount : 0,
+			MIN(stats.txjitter, 999.999),
+			MIN(stats.normdevrtt, 999.999)
+		);
+	}
+
+	ao2_cleanup(format);
+	ao2_cleanup(channel);
+
+	return 0;
+}
+
+static struct ast_cli_entry cli_commands[] = {
+	AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "List PJSIP Channels",
+		.command = "pjsip list channels",
+		.usage = "Usage: pjsip list channels [ like <pattern> ]\n"
+				"       List the active PJSIP channels\n"
+				"       Optional regular expression pattern is used to filter the list.\n"),
+	AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "Show PJSIP Channels",
+		.command = "pjsip show channels",
+		.usage = "Usage: pjsip show channels [ like <pattern> ]\n"
+				"       List(detailed) the active PJSIP channels\n"
+				"       Optional regular expression pattern is used to filter the list.\n"),
+	AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "Show PJSIP Channel",
+		.command = "pjsip show channel",
+		.usage = "Usage: pjsip show channel\n"
+				 "       List(detailed) the active PJSIP channel\n"),
+
+	AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "Show PJSIP Channel Stats",
+		.command = "pjsip show channelstats",
+		.usage = "Usage: pjsip show channelstats [ like <pattern> ]\n"
+				"       List(detailed) the active PJSIP channel stats\n"
+				"       Optional regular expression pattern is used to filter the list.\n"),
+};
+
+struct ast_sip_cli_formatter_entry *channelstats_formatter;
+struct ast_sip_cli_formatter_entry *channel_formatter;
+
+int pjsip_channel_cli_register(void)
+{
+	channel_formatter = ao2_alloc(sizeof(struct ast_sip_cli_formatter_entry), NULL);
+	if (!channel_formatter) {
+		ast_log(LOG_ERROR, "Unable to allocate memory for channel_formatter\n");
+		return -1;
+	}
+	channel_formatter->name = "channel";
+	channel_formatter->print_header = cli_channel_print_header;
+	channel_formatter->print_body = cli_channel_print_body;
+	channel_formatter->get_container = cli_channel_get_container;
+	channel_formatter->iterate = cli_channel_iterate;
+	channel_formatter->retrieve_by_id = cli_channel_retrieve_by_id;
+	channel_formatter->get_id = cli_channel_get_id;
+
+	channelstats_formatter = ao2_alloc(sizeof(struct ast_sip_cli_formatter_entry), NULL);
+	if (!channelstats_formatter) {
+		ao2_ref(channel_formatter, -1);
+		ast_log(LOG_ERROR, "Unable to allocate memory for channelstats_formatter\n");
+		return -1;
+	}
+	channelstats_formatter->name = "channelstat";
+	channelstats_formatter->print_header = cli_channelstats_print_header;
+	channelstats_formatter->print_body = cli_channelstats_print_body;
+	channelstats_formatter->get_container = cli_channelstats_get_container;
+	channelstats_formatter->iterate = cli_channelstats_iterate;
+	channelstats_formatter->retrieve_by_id = cli_channel_retrieve_by_id;
+	channelstats_formatter->get_id = cli_channel_get_id;
+
+	ast_sip_register_cli_formatter(channel_formatter);
+	ast_sip_register_cli_formatter(channelstats_formatter);
+	ast_cli_register_multiple(cli_commands, ARRAY_LEN(cli_commands));
+
+	return 0;
+}
+
+void pjsip_channel_cli_unregister(void)
+{
+	ast_cli_unregister_multiple(cli_commands, ARRAY_LEN(cli_commands));
+	ast_sip_unregister_cli_formatter(channel_formatter);
+	ast_sip_unregister_cli_formatter(channelstats_formatter);
+}
diff --git a/channels/pjsip/include/cli_functions.h b/channels/pjsip/include/cli_functions.h
new file mode 100644
index 0000000..8720077
--- /dev/null
+++ b/channels/pjsip/include/cli_functions.h
@@ -0,0 +1,45 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2016, Fairview 5 Engineering, LLC.
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*!
+ * \file
+ *
+ * \author \verbatim George Joseph <george.joseph at fairview5.com> \endverbatim
+ *
+ * \brief PJSIP CLI functions header file
+ */
+
+#ifndef _PJSIP_CLI_FUNCTIONS
+#define _PJSIP_CLI_FUNCTIONS
+
+
+/*!
+ * \brief Registers the channel cli commands
+ * \since 13.9.0
+ *
+ * \retval 0 on success
+ * \retval -1 on failure
+ */
+int pjsip_channel_cli_register(void);
+
+/*!
+ * \brief Unregisters the channel cli commands
+ * \since 13.9.0
+ */
+void pjsip_channel_cli_unregister(void);
+
+
+#endif /* _PJSIP_CLI_FUNCTIONS */
diff --git a/res/res_pjsip/pjsip_cli.c b/res/res_pjsip/pjsip_cli.c
index bbd0ac4..e6433f4 100644
--- a/res/res_pjsip/pjsip_cli.c
+++ b/res/res_pjsip/pjsip_cli.c
@@ -197,7 +197,7 @@
 	ast_str_append(&context.output_buffer, 0, "\n");
 	formatter_entry->print_header(NULL, &context, 0);
 	ast_str_append(&context.output_buffer, 0,
-		" =========================================================================================\n\n");
+		"==========================================================================================\n\n");
 
 	if (is_container || cmd == CLI_GENERATE) {
 		container = formatter_entry->get_container(regex);
diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c
index ebd6212..ea808ce 100644
--- a/res/res_pjsip/pjsip_configuration.c
+++ b/res/res_pjsip/pjsip_configuration.c
@@ -1435,235 +1435,6 @@
 	return s_container;
 }
 
-static int cli_channel_populate_container(void *obj, void *arg, int flags)
-{
-	struct ast_channel_snapshot *snapshot = obj;
-
-	ao2_link(arg, snapshot);
-
-	return 0;
-}
-
-static int cli_channel_iterate(void *container, ao2_callback_fn callback, void *args)
-{
-	const struct ast_sip_endpoint *endpoint = container;
-
-	ast_sip_for_each_channel(endpoint, callback, args);
-
-	return 0;
-}
-
-static int cli_channel_sort(const void *obj, const void *arg, int flags)
-{
-	const struct ast_channel_snapshot *left_obj = obj;
-	const struct ast_channel_snapshot *right_obj = arg;
-	const char *right_key = arg;
-	int cmp;
-
-	switch (flags & OBJ_SEARCH_MASK) {
-	case OBJ_SEARCH_OBJECT:
-		right_key = right_obj->name;
-		/* Fall through */
-	case OBJ_SEARCH_KEY:
-		cmp = strcmp(left_obj->name, right_key);
-		break;
-	case OBJ_SEARCH_PARTIAL_KEY:
-		cmp = strncmp(left_obj->name, right_key, strlen(right_key));
-		break;
-	default:
-		cmp = 0;
-		break;
-	}
-
-	return cmp;
-}
-
-static int cli_channel_compare(void *obj, void *arg, int flags)
-{
-	const struct ast_channel_snapshot *left_obj = obj;
-	const struct ast_channel_snapshot *right_obj = arg;
-	const char *right_key = arg;
-	int cmp = 0;
-
-	switch (flags & OBJ_SEARCH_MASK) {
-	case OBJ_SEARCH_OBJECT:
-		right_key = right_obj->name;
-		/* Fall through */
-	case OBJ_SEARCH_KEY:
-		if (strcmp(left_obj->name, right_key) == 0) {
-			cmp = CMP_MATCH | CMP_STOP;
-		}
-		break;
-	case OBJ_SEARCH_PARTIAL_KEY:
-		if (strncmp(left_obj->name, right_key, strlen(right_key)) == 0) {
-			cmp = CMP_MATCH;
-		}
-		break;
-	default:
-		cmp = 0;
-		break;
-	}
-
-	return cmp;
-}
-
-static int cli_channel_hash(const void *obj, int flags)
-{
-	const struct ast_channel_snapshot *snapshot = obj;
-
-	if (flags & OBJ_SEARCH_OBJECT) {
-		return ast_str_hash(snapshot->name);
-	} else if (flags & OBJ_SEARCH_KEY) {
-		return ast_str_hash(obj);
-	}
-
-	return -1;
-}
-
-static int cli_endpoint_gather_channels(void *obj, void *arg, int flags)
-{
-	struct ast_sip_endpoint *endpoint = obj;
-	struct ao2_container *channels = arg;
-
-	ast_sip_for_each_channel(endpoint, cli_channel_populate_container, channels);
-
-	return 0;
-}
-
-static int cli_filter_channels(void *obj, void *arg, int flags)
-{
-	struct ast_channel_snapshot *channel = obj;
-	regex_t *regexbuf = arg;
-
-	if (!regexec(regexbuf, channel->name, 0, NULL, 0)
-		|| !regexec(regexbuf, channel->appl, 0, NULL, 0)) {
-		return 0;
-	}
-
-	return CMP_MATCH;
-}
-
-static struct ao2_container *cli_channel_get_container(const char *regex)
-{
-	RAII_VAR(struct ao2_container *, parent_container, NULL, ao2_cleanup);
-	struct ao2_container *child_container;
-	regex_t regexbuf;
-
-	parent_container = cli_endpoint_get_container("");
-	if (!parent_container) {
-		return NULL;
-	}
-	child_container = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_NOLOCK, 0, 17,
-		cli_channel_hash, cli_channel_sort, cli_channel_compare);
-	if (!child_container) {
-		return NULL;
-	}
-
-	ao2_callback(parent_container, OBJ_NODATA, cli_endpoint_gather_channels, child_container);
-
-	if (!ast_strlen_zero(regex)) {
-		if (regcomp(&regexbuf, regex, REG_EXTENDED | REG_NOSUB)) {
-			ao2_ref(child_container, -1);
-			return NULL;
-		}
-		ao2_callback(child_container, OBJ_UNLINK | OBJ_MULTIPLE | OBJ_NODATA, cli_filter_channels, &regexbuf);
-		regfree(&regexbuf);
-	}
-
-	return child_container;
-}
-
-static const char *cli_channel_get_id(const void *obj)
-{
-	const struct ast_channel_snapshot *snapshot = obj;
-
-	return snapshot->name;
-}
-
-static void *cli_channel_retrieve_by_id(const char *id)
-{
-	RAII_VAR(struct ao2_container *, container, cli_channel_get_container(""), ao2_cleanup);
-
-	return ao2_find(container, id, OBJ_KEY | OBJ_NOLOCK);
-}
-
-static int cli_channel_print_header(void *obj, void *arg, int flags)
-{
-	struct ast_sip_cli_context *context = arg;
-	int indent = CLI_INDENT_TO_SPACES(context->indent_level);
-	int filler = CLI_LAST_TABSTOP - indent - 13;
-
-	ast_assert(context->output_buffer != NULL);
-
-	ast_str_append(&context->output_buffer, 0,
-		"%*s:  <ChannelId%*.*s>  <State.....>  <Time(sec)>\n",
-		indent, "Channel", filler, filler, CLI_HEADER_FILLER);
-	if (context->recurse) {
-		context->indent_level++;
-		indent = CLI_INDENT_TO_SPACES(context->indent_level);
-		filler = CLI_LAST_TABSTOP - indent - 38;
-		ast_str_append(&context->output_buffer, 0,
-			"%*s: <DialedExten%*.*s>  CLCID: <ConnectedLineCID.......>\n",
-			indent, "Exten", filler, filler, CLI_HEADER_FILLER);
-		context->indent_level--;
-	}
-
-	return 0;
-}
-
-static int cli_channel_print_body(void *obj, void *arg, int flags)
-{
-	const struct ast_channel_snapshot *snapshot = obj;
-	struct ast_sip_cli_context *context = arg;
-	struct timeval current_time;
-	char *print_name = NULL;
-	int print_name_len;
-	int indent;
-	int flexwidth;
-
-	ast_assert(context->output_buffer != NULL);
-
-	gettimeofday(&current_time, NULL);
-
-	print_name_len = strlen(snapshot->name) + strlen(snapshot->appl) + 2;
-	if (!(print_name = alloca(print_name_len))) {
-		return -1;
-	}
-
-	snprintf(print_name, print_name_len, "%s/%s", snapshot->name, snapshot->appl);
-
-	indent = CLI_INDENT_TO_SPACES(context->indent_level);
-	flexwidth = CLI_LAST_TABSTOP - indent;
-
-	ast_str_append(&context->output_buffer, 0, "%*s: %-*.*s %-12.12s  %11ld\n",
-		CLI_INDENT_TO_SPACES(context->indent_level), "Channel",
-		flexwidth, flexwidth,
-		print_name,
-		ast_state2str(snapshot->state),
-		current_time.tv_sec - snapshot->creationtime.tv_sec);
-
-	if (context->recurse) {
-		context->indent_level++;
-		indent = CLI_INDENT_TO_SPACES(context->indent_level);
-		flexwidth = CLI_LAST_TABSTOP - indent - 25;
-
-		ast_str_append(&context->output_buffer, 0,
-			"%*s: %-*.*s  CLCID: \"%s\" <%s>\n",
-			indent, "Exten",
-			flexwidth, flexwidth,
-			snapshot->exten,
-			snapshot->connected_name,
-			snapshot->connected_number
-			);
-		context->indent_level--;
-		if (context->indent_level == 0) {
-			ast_str_append(&context->output_buffer, 0, "\n");
-		}
-	}
-
-	return 0;
-}
-
 static int cli_endpoint_iterate(void *obj, ao2_callback_fn callback, void *args)
 {
 	ao2_callback(obj, OBJ_NODATA, callback, args);
@@ -1782,21 +1553,6 @@
 }
 
 static struct ast_cli_entry cli_commands[] = {
-	AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "List PJSIP Channels",
-		.command = "pjsip list channels",
-		.usage = "Usage: pjsip list channels [ like <pattern> ]\n"
-				"       List the active PJSIP channels\n"
-				"       Optional regular expression pattern is used to filter the list.\n"),
-	AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "Show PJSIP Channels",
-		.command = "pjsip show channels",
-		.usage = "Usage: pjsip show channels [ like <pattern> ]\n"
-				"       List(detailed) the active PJSIP channels\n"
-				"       Optional regular expression pattern is used to filter the list.\n"),
-	AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "Show PJSIP Channel",
-		.command = "pjsip show channel",
-		.usage = "Usage: pjsip show channel\n"
-				 "       List(detailed) the active PJSIP channel\n"),
-
 	AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "List PJSIP Endpoints",
 		.command = "pjsip list endpoints",
 		.usage = "Usage: pjsip list endpoints [ like <pattern> ]\n"
@@ -1989,21 +1745,6 @@
 		return -1;
 	}
 
-	channel_formatter = ao2_alloc(sizeof(struct ast_sip_cli_formatter_entry), NULL);
-	if (!channel_formatter) {
-		ast_log(LOG_ERROR, "Unable to allocate memory for channel_formatter\n");
-		ast_sorcery_unref(sip_sorcery);
-		sip_sorcery = NULL;
-		return -1;
-	}
-	channel_formatter->name = "channel";
-	channel_formatter->print_header = cli_channel_print_header;
-	channel_formatter->print_body = cli_channel_print_body;
-	channel_formatter->get_container = cli_channel_get_container;
-	channel_formatter->iterate = cli_channel_iterate;
-	channel_formatter->retrieve_by_id = cli_channel_retrieve_by_id;
-	channel_formatter->get_id = cli_channel_get_id;
-
 	endpoint_formatter = ao2_alloc(sizeof(struct ast_sip_cli_formatter_entry), NULL);
 	if (!endpoint_formatter) {
 		ast_log(LOG_ERROR, "Unable to allocate memory for endpoint_formatter\n");
@@ -2019,7 +1760,6 @@
 	endpoint_formatter->retrieve_by_id = cli_endpoint_retrieve_by_id;
 	endpoint_formatter->get_id = ast_sorcery_object_get_id;
 
-	ast_sip_register_cli_formatter(channel_formatter);
 	ast_sip_register_cli_formatter(endpoint_formatter);
 	ast_cli_register_multiple(cli_commands, ARRAY_LEN(cli_commands));
 
@@ -2046,7 +1786,6 @@
 	ast_manager_unregister(AMI_SHOW_ENDPOINTS);
 	ast_cli_unregister_multiple(cli_commands, ARRAY_LEN(cli_commands));
 	ast_sip_unregister_cli_formatter(endpoint_formatter);
-	ast_sip_unregister_cli_formatter(channel_formatter);
 	ast_sip_destroy_cli();
 	ao2_cleanup(persistent_endpoints);
 }

-- 
To view, visit https://gerrit.asterisk.org/2480
To unsubscribe, visit https://gerrit.asterisk.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I03b114522126d27434030b285bf6d531ddd79869
Gerrit-PatchSet: 1
Gerrit-Project: asterisk
Gerrit-Branch: 13
Gerrit-Owner: George Joseph <george.joseph at fairview5.com>



More information about the asterisk-code-review mailing list