diff options
-rwxr-xr-x | channels/chan_iax2.c | 117 | ||||
-rwxr-xr-x | channels/iax2-parser.c | 54 | ||||
-rwxr-xr-x | channels/iax2-parser.h | 6 | ||||
-rwxr-xr-x | channels/iax2.h | 8 |
4 files changed, 183 insertions, 2 deletions
diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c index b5d44aee1..029294f07 100755 --- a/channels/chan_iax2.c +++ b/channels/chan_iax2.c @@ -360,6 +360,16 @@ static int max_jitter_buffer = MAX_JITTER_BUFFER; /* If we have less than this much excess real jitter buffer, enlarge it. */ static int min_jitter_buffer = MIN_JITTER_BUFFER; +struct iax_rr { + int jitter; + int losspct; + int losscnt; + int packets; + int delay; + int dropped; + int ooo; +}; + struct chan_iax2_pvt { /* Socket to send/receive on for this call */ int sockfd; @@ -503,6 +513,14 @@ struct chan_iax2_pvt { int amaflags; struct iax2_dpcache *dpentries; struct ast_variable *vars; + /* last received remote rr */ + struct iax_rr remote_rr; + /* Current base time: (just for stats) */ + int min; + /* Dropped frame count: (just for stats) */ + int frames_dropped; + /* received frame count: (just for stats) */ + int frames_received; }; static struct ast_iax2_queue { @@ -2074,6 +2092,9 @@ static int schedule_delivery(struct iax_frame *fr, int reallydeliver, int update iaxs[fr->callno]->jitterbuffer = max /* + ((float)iaxs[fr->callno]->jitter) * 0.1 */; + /* update "min", just for RRs and stats */ + iaxs[fr->callno]->min = min; + /* If the caller just wanted us to update, return now */ if (!reallydeliver) return 0; @@ -2111,6 +2132,7 @@ static int schedule_delivery(struct iax_frame *fr, int reallydeliver, int update } else { if (option_debug) ast_log(LOG_DEBUG, "schedule_delivery: Dropping voice packet since %dms delay is too old\n", delay); + iaxs[fr->callno]->frames_dropped++; /* Free our iax frame */ iax2_frame_free(fr); } @@ -3902,6 +3924,50 @@ static int iax2_show_channels(int fd, int argc, char *argv[]) return RESULT_SUCCESS; #undef FORMAT #undef FORMAT2 +#undef FORMATB +} + +static int iax2_show_netstats(int fd, int argc, char *argv[]) +{ + int x; + int numchans = 0; + if (argc != 3) + return RESULT_SHOWUSAGE; + ast_cli(fd, " -------- LOCAL --------------------- -------- REMOTE --------------------\n"); + ast_cli(fd, "Channel RTT Jit Del Lost %% Drop OOO Kpkts Jit Del Lost %% Drop OOO Kpkts\n"); + for (x=0;x<IAX_MAX_CALLS;x++) { + ast_mutex_lock(&iaxsl[x]); + if (iaxs[x]) { +#ifdef BRIDGE_OPTIMIZATION + if (iaxs[x]->bridgecallno) + ast_cli(fd, "%-25.25s <NATIVE BRIDGED>", + iaxs[x]->owner ? iaxs[x]->owner->name : "(None)"); + else +#endif + ast_cli(fd, "%-25.25s %4d %4d %4d %5d %3d %5d %4d %6d %4d %4d %5d %3d %5d %4d %6d\n", + iaxs[x]->owner ? iaxs[x]->owner->name : "(None)", + iaxs[x]->pingtime, + iaxs[x]->jitter, + ast_test_flag(iaxs[x], IAX_USEJITTERBUF) ? jitterbufsize(iaxs[x]) : 0, + -1, + -1, + -1, + -1, + iaxs[x]->frames_received/1000, + iaxs[x]->remote_rr.jitter, + iaxs[x]->remote_rr.delay, + iaxs[x]->remote_rr.losscnt, + iaxs[x]->remote_rr.losspct, + iaxs[x]->remote_rr.dropped, + iaxs[x]->remote_rr.ooo, + iaxs[x]->remote_rr.packets/1000 + ); + numchans++; + } + ast_mutex_unlock(&iaxsl[x]); + } + ast_cli(fd, "%d active IAX channel(s)\n", numchans); + return RESULT_SUCCESS; } static int iax2_do_trunk_debug(int fd, int argc, char *argv[]) @@ -3942,6 +4008,10 @@ static char show_channels_usage[] = "Usage: iax2 show channels\n" " Lists all currently active IAX channels.\n"; +static char show_netstats_usage[] = +"Usage: iax2 show netstats\n" +" Lists network status for all currently active IAX channels.\n"; + static char show_peers_usage[] = "Usage: iax2 show peers [registered] [pattern]\n" " Lists all known IAX2 peers.\n" @@ -3974,6 +4044,8 @@ static struct ast_cli_entry cli_show_firmware = { { "iax2", "show", "firmware", NULL }, iax2_show_firmware, "Show available IAX firmwares", show_firmware_usage }; static struct ast_cli_entry cli_show_channels = { { "iax2", "show", "channels", NULL }, iax2_show_channels, "Show active IAX channels", show_channels_usage }; +static struct ast_cli_entry cli_show_netstats = + { { "iax2", "show", "netstats", NULL }, iax2_show_netstats, "Show active IAX channel netstats", show_netstats_usage }; static struct ast_cli_entry cli_show_peers = { { "iax2", "show", "peers", NULL }, iax2_show_peers, "Show defined IAX peers", show_peers_usage }; static struct ast_cli_entry cli_show_registry = @@ -5531,6 +5603,32 @@ static int check_provisioning(struct sockaddr_in *sin, char *si, unsigned int ve return 0; } +static void construct_rr(struct chan_iax2_pvt *pvt, struct iax_ie_data *iep) +{ + memset(iep, 0, sizeof(*iep)); + iax_ie_append_int(iep,IAX_IE_RR_JITTER, pvt->jitter); + iax_ie_append_int(iep,IAX_IE_RR_PKTS, pvt->frames_received); + if(!ast_test_flag(pvt, IAX_USEJITTERBUF)) + iax_ie_append_short(iep,IAX_IE_RR_DELAY, 0); + else + iax_ie_append_short(iep,IAX_IE_RR_DELAY, pvt->jitterbuffer - pvt->min); + iax_ie_append_int(iep,IAX_IE_RR_DROPPED, pvt->frames_dropped); + /* don't know, don't send! iax_ie_append_int(&ied,IAX_IE_RR_OOO, 0); */ + /* don't know, don't send! iax_ie_append_int(&ied,IAX_IE_RR_LOSS, 0); */ + +} + +static void save_rr(struct iax_frame *fr, struct iax_ies *ies) +{ + iaxs[fr->callno]->remote_rr.jitter = ies->rr_jitter; + iaxs[fr->callno]->remote_rr.losspct = ies->rr_loss >> 24; + iaxs[fr->callno]->remote_rr.losscnt = ies->rr_loss & 0xffffff; + iaxs[fr->callno]->remote_rr.packets = ies->rr_pkts; + iaxs[fr->callno]->remote_rr.delay = ies->rr_delay; + iaxs[fr->callno]->remote_rr.dropped = ies->rr_dropped; + iaxs[fr->callno]->remote_rr.ooo = ies->rr_ooo; +} + static int socket_read(int *id, int fd, short events, void *cbdata) { struct sockaddr_in sin; @@ -5733,6 +5831,10 @@ static int socket_read(int *id, int fd, short events, void *cbdata) iax_showframe(NULL, fh, 1, &sin, res - sizeof(struct ast_iax2_full_hdr)); #endif } + + /* count this frame */ + iaxs[fr.callno]->frames_received++; + if (!inaddrcmp(&sin, &iaxs[fr.callno]->addr) && !minivid && f.subclass != IAX_COMMAND_TXCNT && /* for attended transfer */ f.subclass != IAX_COMMAND_TXACC) /* for attended transfer */ @@ -6268,12 +6370,18 @@ retryowner2: /* If we're in a bridged call, just forward this */ forward_command(iaxs[fr.callno], AST_FRAME_IAX, IAX_COMMAND_PING, fr.ts, NULL, 0, -1); } else { + struct iax_ie_data pingied; + construct_rr(iaxs[fr.callno], &pingied); /* Send back a pong packet with the original timestamp */ - send_command(iaxs[fr.callno], AST_FRAME_IAX, IAX_COMMAND_PONG, fr.ts, NULL, 0, -1); + send_command(iaxs[fr.callno], AST_FRAME_IAX, IAX_COMMAND_PONG, fr.ts, pingied.buf, pingied.pos, -1); } #else + { + struct iax_ie_data pingied; + construct_rr(iaxs[fr.callno], &pingied); /* Send back a pong packet with the original timestamp */ - send_command(iaxs[fr.callno], AST_FRAME_IAX, IAX_COMMAND_PONG, fr.ts, NULL, 0, -1); + send_command(iaxs[fr.callno], AST_FRAME_IAX, IAX_COMMAND_PONG, fr.ts, pingied.buf, pingied.pos, -1); + } #endif break; case IAX_COMMAND_PONG: @@ -6289,6 +6397,9 @@ retryowner2: /* Calculate ping time */ iaxs[fr.callno]->pingtime = calc_timestamp(iaxs[fr.callno], 0, &f) - fr.ts; #endif + /* save RR info */ + save_rr(&fr, &ies); + if (iaxs[fr.callno]->peerpoke) { peer = iaxs[fr.callno]->peerpoke; if ((peer->lastms < 0) || (peer->lastms > peer->maxms)) { @@ -8228,6 +8339,7 @@ static int __unload_module(void) ast_unregister_application(papp); ast_cli_unregister(&cli_show_users); ast_cli_unregister(&cli_show_channels); + ast_cli_unregister(&cli_show_netstats); ast_cli_unregister(&cli_show_peers); ast_cli_unregister(&cli_show_firmware); ast_cli_unregister(&cli_show_registry); @@ -8308,6 +8420,7 @@ int load_module(void) ast_cli_register(&cli_show_users); ast_cli_register(&cli_show_channels); + ast_cli_register(&cli_show_netstats); ast_cli_register(&cli_show_peers); ast_cli_register(&cli_show_firmware); ast_cli_register(&cli_show_registry); diff --git a/channels/iax2-parser.c b/channels/iax2-parser.c index e9cf2db42..6adc68445 100755 --- a/channels/iax2-parser.c +++ b/channels/iax2-parser.c @@ -228,6 +228,12 @@ static struct iax2_ie { { IAX_IE_ENCRYPTION, "ENCRYPTION", dump_short }, { IAX_IE_ENCKEY, "ENCRYPTION KEY" }, { IAX_IE_CODEC_PREFS, "CODEC_PREFS", dump_prefs }, + { IAX_IE_RR_JITTER, "RR_JITTER", dump_int }, + { IAX_IE_RR_LOSS, "RR_LOSS", dump_int }, + { IAX_IE_RR_PKTS, "RR_PKTS", dump_int }, + { IAX_IE_RR_DELAY, "RR_DELAY", dump_short }, + { IAX_IE_RR_DROPPED, "RR_DROPPED", dump_int }, + { IAX_IE_RR_OOO, "RR_OUTOFORDER", dump_int }, }; static struct iax2_ie prov_ies[] = { @@ -784,6 +790,54 @@ int iax_parse_ies(struct iax_ies *ies, unsigned char *data, int datalen) } else ies->calling_tns = ntohs(get_uint16(data + 2)); break; + case IAX_IE_RR_JITTER: + if (len != (int)sizeof(unsigned int)) { + snprintf(tmp, (int)sizeof(tmp), "Expected jitter rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len); + errorf(tmp); + } else { + ies->rr_jitter = ntohl(get_uint32(data + 2)); + } + break; + case IAX_IE_RR_LOSS: + if (len != (int)sizeof(unsigned int)) { + snprintf(tmp, (int)sizeof(tmp), "Expected loss rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len); + errorf(tmp); + } else { + ies->rr_loss = ntohl(get_uint32(data + 2)); + } + break; + case IAX_IE_RR_PKTS: + if (len != (int)sizeof(unsigned int)) { + snprintf(tmp, (int)sizeof(tmp), "Expected packets rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len); + errorf(tmp); + } else { + ies->rr_pkts = ntohl(get_uint32(data + 2)); + } + break; + case IAX_IE_RR_DELAY: + if (len != (int)sizeof(unsigned short)) { + snprintf(tmp, (int)sizeof(tmp), "Expected loss rr to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len); + errorf(tmp); + } else { + ies->rr_delay = ntohs(get_uint16(data + 2)); + } + break; + case IAX_IE_RR_DROPPED: + if (len != (int)sizeof(unsigned int)) { + snprintf(tmp, (int)sizeof(tmp), "Expected packets rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len); + errorf(tmp); + } else { + ies->rr_dropped = ntohl(get_uint32(data + 2)); + } + break; + case IAX_IE_RR_OOO: + if (len != (int)sizeof(unsigned int)) { + snprintf(tmp, (int)sizeof(tmp), "Expected packets rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len); + errorf(tmp); + } else { + ies->rr_ooo = ntohl(get_uint32(data + 2)); + } + break; default: snprintf(tmp, (int)sizeof(tmp), "Ignoring unknown information element '%s' (%d) of length %d\n", iax_ie2str(ie), ie, len); outputf(tmp); diff --git a/channels/iax2-parser.h b/channels/iax2-parser.h index 691c8aa32..909360f41 100755 --- a/channels/iax2-parser.h +++ b/channels/iax2-parser.h @@ -61,6 +61,12 @@ struct iax_ies { unsigned int provver; unsigned short samprate; int provverpres; + unsigned int rr_jitter; + unsigned int rr_loss; + unsigned int rr_pkts; + unsigned short rr_delay; + unsigned int rr_dropped; + unsigned int rr_ooo; }; #define DIRECTION_INGRESS 1 diff --git a/channels/iax2.h b/channels/iax2.h index a19c671c7..4e71c7611 100755 --- a/channels/iax2.h +++ b/channels/iax2.h @@ -121,6 +121,14 @@ #define IAX_IE_ENCKEY 44 /* Encryption key (raw) */ #define IAX_IE_CODEC_PREFS 45 /* Codec Negotiation */ +#define IAX_IE_RR_JITTER 46 /* Received jitter (as in RFC1889) u32 */ +#define IAX_IE_RR_LOSS 47 /* Received loss (high byte loss pct, low 24 bits loss count, as in rfc1889 */ +#define IAX_IE_RR_PKTS 48 /* Received frames (total frames received) u32 */ +#define IAX_IE_RR_DELAY 49 /* Max playout delay for received frames (in ms) u16 */ +#define IAX_IE_RR_DROPPED 50 /* Dropped frames (presumably by jitterbuf) u32 */ +#define IAX_IE_RR_OOO 51 /* Frames received Out of Order u32 */ + + #define IAX_AUTH_PLAINTEXT (1 << 0) #define IAX_AUTH_MD5 (1 << 1) #define IAX_AUTH_RSA (1 << 2) |