aboutsummaryrefslogtreecommitdiffstats
path: root/channels/chan_sip.c
diff options
context:
space:
mode:
authoroej <oej@f38db490-d61c-443f-a65b-d21fe96a405b>2008-07-05 19:27:42 +0000
committeroej <oej@f38db490-d61c-443f-a65b-d21fe96a405b>2008-07-05 19:27:42 +0000
commit1b3aa4be885923c2fe20ced67566fa662c3afa55 (patch)
tree66d5eda276da7f3e74e3e261874de6bef7f35b91 /channels/chan_sip.c
parent304d288b7ec52e9c89f741666a24056f4e6f6534 (diff)
Add new SIP cli command "sip show channelstats" that displays some QoS data (if we have RTCP reports
and not use the p2p rtp bridge). I could not find a way to detect us using the p2p bridge, which would be nice. git-svn-id: http://svn.digium.com/svn/asterisk/trunk@128197 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'channels/chan_sip.c')
-rw-r--r--channels/chan_sip.c124
1 files changed, 113 insertions, 11 deletions
diff --git a/channels/chan_sip.c b/channels/chan_sip.c
index 280e128e3..7ff5eed29 100644
--- a/channels/chan_sip.c
+++ b/channels/chan_sip.c
@@ -311,6 +311,22 @@ enum invitestates {
INV_CANCELLED = 7, /*!< Transaction cancelled by client or server in non-terminated state */
};
+/*! \brief Readable descriptions of device states.
+ \note Should be aligned to above table as index */
+static const struct invstate2stringtable {
+ const enum invitestates state;
+ const char const *desc;
+} invitestate2string[] = {
+ {INV_NONE, "None" },
+ {INV_CALLING, "Calling (Trying)"},
+ {INV_PROCEEDING, "Proceeding "},
+ {INV_EARLY_MEDIA, "Early media"},
+ {INV_COMPLETED, "Completed (done)"},
+ {INV_CONFIRMED, "Confirmed (up)"},
+ {INV_TERMINATED, "Done"},
+ {INV_CANCELLED, "Cancelled"}
+};
+
enum xmittype {
XMIT_CRITICAL = 2, /*!< Transmit critical SIP message reliably, with re-transmits.
If it fails, it's critical and will cause a teardown of the session */
@@ -453,6 +469,14 @@ struct sip_proxy {
/* Room for a SRV record chain based on the name */
};
+/*! \brief argument for the 'show channels|subscriptions' callback. */
+struct __show_chan_arg {
+ int fd;
+ int subscriptions;
+ int numchans; /* return value */
+};
+
+
/*! \brief States whether a SIP message can create a dialog in Asterisk. */
enum can_create_dialog {
CAN_NOT_CREATE_DIALOG,
@@ -2018,6 +2042,7 @@ static char *complete_sip_user(const char *word, int state, int flags2);
static char *complete_sip_show_user(const char *line, const char *word, int pos, int state);
static char *complete_sipnotify(const char *line, const char *word, int pos, int state);
static char *sip_show_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
+static char *sip_show_channelstats(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
static char *sip_show_history(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
static char *sip_do_debug_ip(int fd, char *arg);
static char *sip_do_debug_peer(int fd, char *arg);
@@ -14117,6 +14142,91 @@ static char *sip_unregister(struct ast_cli_entry *e, int cmd, struct ast_cli_arg
return CLI_SUCCESS;
}
+/*! \brief Callback for show_chanstats */
+static int show_chanstats_cb(void *__cur, void *__arg, int flags)
+{
+#define FORMAT2 "%-15.15s %-11.11s %-8.8s %-10.10s %-10.10s (%-2.2s) %-6.6s %-10.10s %-10.10s ( %%) %-6.6s\n"
+#define FORMAT "%-15.15s %-11.11s %-8.8s %-10.10u%-1.1s %-10.10u (%-2.2u%%) %-6.6u %-10.10u%-1.1s %-10.10u (%-2.2u%%) %-6.6u\n"
+ struct sip_pvt *cur = __cur;
+ unsigned int rxcount;
+ unsigned int txcount;
+ char durbuf[10];
+ int duration;
+ int durh, durm, durs;
+ struct ast_channel *c = cur->owner;
+ struct __show_chan_arg *arg = __arg;
+ int fd = arg->fd;
+
+
+ if (cur->subscribed != NONE) /* Subscriptions */
+ return 0; /* don't care, we scan all channels */
+
+ if (!cur->rtp) {
+ if (sipdebug)
+ ast_cli(fd, "%-15.15s %-11.11s (inv state: %s) -- %s\n", ast_inet_ntoa(cur->sa.sin_addr), cur->callid, invitestate2string[cur->invitestate].desc, "-- No RTP active");
+ return 0; /* don't care, we scan all channels */
+ }
+ rxcount = ast_rtp_get_qosvalue(cur->rtp, AST_RTP_RXCOUNT);
+ txcount = ast_rtp_get_qosvalue(cur->rtp, AST_RTP_TXCOUNT);
+
+ /* Find the duration of this channel */
+ if (c && c->cdr && !ast_tvzero(c->cdr->start)) {
+ duration = (int)(ast_tvdiff_ms(ast_tvnow(), c->cdr->start) / 1000);
+ durh = duration / 3600;
+ durm = (duration % 3600) / 60;
+ durs = duration % 60;
+ snprintf(durbuf, sizeof(durbuf), "%02d:%02d:%02d", durh, durm, durs);
+ } else {
+ durbuf[0] = '\0';
+ }
+ /* Print stats for every call with RTP */
+ ast_cli(fd, FORMAT,
+ ast_inet_ntoa(cur->sa.sin_addr),
+ cur->callid,
+ durbuf,
+ rxcount > (unsigned int) 100000 ? (unsigned int) (rxcount)/(unsigned int) 1000 : rxcount,
+ rxcount > (unsigned int) 100000 ? "K":" ",
+ ast_rtp_get_qosvalue(cur->rtp, AST_RTP_RXPLOSS),
+ rxcount > ast_rtp_get_qosvalue(cur->rtp, AST_RTP_RXPLOSS) ? (unsigned int) (ast_rtp_get_qosvalue(cur->rtp, AST_RTP_RXPLOSS) / rxcount * 100) : 0,
+ ast_rtp_get_qosvalue(cur->rtp, AST_RTP_RXJITTER),
+ txcount > (unsigned int) 100000 ? (unsigned int) (txcount)/(unsigned int) 1000 : txcount,
+ txcount > (unsigned int) 100000 ? "K":" ",
+ ast_rtp_get_qosvalue(cur->rtp, AST_RTP_TXPLOSS),
+ txcount > ast_rtp_get_qosvalue(cur->rtp, AST_RTP_TXPLOSS) ? (unsigned int) (ast_rtp_get_qosvalue(cur->rtp, AST_RTP_TXPLOSS)/ txcount * 100) : 0,
+ ast_rtp_get_qosvalue(cur->rtp, AST_RTP_TXJITTER)
+ );
+ arg->numchans++;
+
+ return 0; /* don't care, we scan all channels */
+}
+
+/*! \brief SIP show channelstats CLI (main function) */
+static char *sip_show_channelstats(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+ struct __show_chan_arg arg = { .fd = a->fd, .numchans = 0 };
+
+ switch (cmd) {
+ case CLI_INIT:
+ e->command = "sip show channelstats";
+ e->usage =
+ "Usage: sip show channelstats\n"
+ " Lists all currently active SIP channel's RTCP statistics.\n"
+ " Note that calls in the much optimized RTP P2P bridge mode will not show any packets here.";
+ return NULL;
+ }
+
+ if (a->argc != 3)
+ return CLI_SHOWUSAGE;
+
+ ast_cli(a->fd, FORMAT2, "Peer", "Call ID", "Duration", "Recv: Pack", "Lost", "%", "Jitter", "Send: Pack", "Lost", "Jitter");
+ /* iterate on the container and invoke the callback on each item */
+ ao2_t_callback(dialogs, OBJ_NODATA, show_chanstats_cb, &arg, "callback to sip show chanstats");
+ ast_cli(a->fd, "%d active SIP channel%s\n", arg.numchans, (arg.numchans != 1) ? "s" : "");
+ return CLI_SUCCESS;
+}
+#undef FORMAT
+#undef FORMAT2
+
/*! \brief List global settings for the SIP channel */
static char *sip_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
{
@@ -14334,13 +14444,6 @@ static const struct cfsubscription_types *find_subscription_type(enum subscripti
* that support iteration through callbacks will be a lot easier.
*/
-/*! \brief argument for the 'show channels|subscriptions' callback. */
-struct __show_chan_arg {
- int fd;
- int subscriptions;
- int numchans; /* return value */
-};
-
#define FORMAT4 "%-15.15s %-10.10s %-15.15s %-15.15s %-13.13s %-15.15s %-10.10s %-6.6d\n"
#define FORMAT3 "%-15.15s %-10.10s %-15.15s %-15.15s %-13.13s %-15.15s %-10.10s %-6.6s\n"
#define FORMAT2 "%-15.15s %-10.10s %-15.15s %-15.15s %-7.7s %-15.15s %-6.6s\n"
@@ -14436,8 +14539,6 @@ static char *sip_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_
* given position. As many functions of this kind, each invokation has
* O(state) time complexity so be careful in using it.
*/
-
-
static char *complete_sipch(const char *line, const char *word, int pos, int state)
{
int which=0;
@@ -23001,12 +23102,13 @@ static int reload(void)
static struct ast_cli_entry cli_sip_do_history_deprecated = AST_CLI_DEFINE(sip_do_history_deprecated, "Enable/Disable SIP history");
/*! \brief SIP Cli commands definition */
static struct ast_cli_entry cli_sip[] = {
- AST_CLI_DEFINE(sip_show_channels, "List active SIP channels/subscriptions"),
+ AST_CLI_DEFINE(sip_show_channels, "List active SIP channels or subscriptions"),
+ AST_CLI_DEFINE(sip_show_channelstats, "List statistics for active SIP channels"),
AST_CLI_DEFINE(sip_show_domains, "List our local SIP domains."),
AST_CLI_DEFINE(sip_show_inuse, "List all inuse/limits"),
AST_CLI_DEFINE(sip_show_objects, "List all SIP object allocations"),
AST_CLI_DEFINE(sip_show_peers, "List defined SIP peers"),
- AST_CLI_DEFINE(sip_dbdump, "dump peer info into realtime db sql format"),
+ AST_CLI_DEFINE(sip_dbdump, "Dump peer info into realtime database SQL format"),
AST_CLI_DEFINE(sip_show_registry, "List SIP registration status"),
AST_CLI_DEFINE(sip_unregister, "Unregister (force expiration) a SIP peer from the registery\n"),
AST_CLI_DEFINE(sip_show_settings, "Show SIP global settings"),