diff options
-rw-r--r-- | channels/chan_iax2.c | 101 | ||||
-rw-r--r-- | channels/iax2-parser.c | 173 | ||||
-rw-r--r-- | channels/iax2-parser.h | 1 | ||||
-rw-r--r-- | channels/iax2.h | 8 |
4 files changed, 200 insertions, 83 deletions
diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c index d2b5180f3..fd0c89f0c 100644 --- a/channels/chan_iax2.c +++ b/channels/chan_iax2.c @@ -455,6 +455,9 @@ static AST_LIST_HEAD_STATIC(registrations, iax2_registry); /* If consecutive voice frame timestamps jump by more than this many milliseconds, then jitter buffer will resync */ #define TS_GAP_FOR_JB_RESYNC 5000 +/* used for first_iax_message and last_iax_message. If this bit is set it was TX, else RX */ +#define MARK_IAX_SUBCLASS_TX 0x8000 + static int iaxthreadcount = DEFAULT_THREAD_COUNT; static int iaxmaxthreadcount = DEFAULT_MAX_THREAD_COUNT; static int iaxdynamicthreadcount = 0; @@ -494,6 +497,10 @@ struct chan_iax2_pvt { unsigned int lastvsent; /*! Next outgoing timestamp if everything is good */ unsigned int nextpred; + /*! iax frame subclass that began iax2_pvt entry. 0x8000 bit is set on TX */ + int first_iax_message; + /*! Last iax frame subclass sent or received for a iax2_pvt. 0x8000 bit is set on TX */ + int last_iax_message; /*! True if the last voice we transmitted was not silence/CNG */ unsigned int notsilenttx:1; /*! Ping time */ @@ -4917,6 +4924,13 @@ static int iax2_send(struct chan_iax2_pvt *pvt, struct ast_frame *f, unsigned in } pvt->lastvsent = fts; } + if (f->frametype == AST_FRAME_IAX) { + /* 0x8000 marks this message as TX:, this bit will be stripped later */ + pvt->last_iax_message = f->subclass | MARK_IAX_SUBCLASS_TX; + if (!pvt->first_iax_message) { + pvt->first_iax_message = pvt->last_iax_message; + } + } /* Allocate an iax_frame */ if (now) { fr = &frb.fr2; @@ -4994,7 +5008,7 @@ static int iax2_send(struct chan_iax2_pvt *pvt, struct ast_frame *f, unsigned in } else ast_log(LOG_WARNING, "Supposed to send packet encrypted, but no key?\n"); } - + if (now) { res = send_packet(fr); } else @@ -5560,11 +5574,13 @@ static char *handle_cli_iax2_show_registry(struct ast_cli_entry *e, int cmd, str static char *handle_cli_iax2_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { -#define FORMAT2 "%-20.20s %-15.15s %-10.10s %-11.11s %-11.11s %-7.7s %-6.6s %-6.6s %s\n" -#define FORMAT "%-20.20s %-15.15s %-10.10s %5.5d/%5.5d %5.5d/%5.5d %-5.5dms %-4.4dms %-4.4dms %-6.6s\n" +#define FORMAT2 "%-20.20s %-15.15s %-10.10s %-11.11s %-11.11s %-7.7s %-6.6s %-6.6s %s %s %9s\n" +#define FORMAT "%-20.20s %-15.15s %-10.10s %5.5d/%5.5d %5.5d/%5.5d %-5.5dms %-4.4dms %-4.4dms %-6.6s %s%s %3s%s\n" #define FORMATB "%-20.20s %-15.15s %-10.10s %5.5d/%5.5d %5.5d/%5.5d [Native Bridged to ID=%5.5d]\n" int x; int numchans = 0; + char first_message[10] = { 0, }; + char last_message[10] = { 0, }; switch (cmd) { case CLI_INIT: @@ -5579,13 +5595,12 @@ static char *handle_cli_iax2_show_channels(struct ast_cli_entry *e, int cmd, str if (a->argc != 3) return CLI_SHOWUSAGE; - ast_cli(a->fd, FORMAT2, "Channel", "Peer", "Username", "ID (Lo/Rem)", "Seq (Tx/Rx)", "Lag", "Jitter", "JitBuf", "Format"); + ast_cli(a->fd, FORMAT2, "Channel", "Peer", "Username", "ID (Lo/Rem)", "Seq (Tx/Rx)", "Lag", "Jitter", "JitBuf", "Format", "FirstMsg", "LastMsg"); for (x = 0; x < ARRAY_LEN(iaxs); x++) { ast_mutex_lock(&iaxsl[x]); if (iaxs[x]) { int lag, jitter, localdelay; jb_info jbinfo; - if (ast_test_flag(iaxs[x], IAX_USEJITTERBUF)) { jb_getinfo(iaxs[x]->jb, &jbinfo); jitter = jbinfo.jitter; @@ -5594,17 +5609,24 @@ static char *handle_cli_iax2_show_channels(struct ast_cli_entry *e, int cmd, str jitter = -1; localdelay = 0; } + + iax_frame_subclass2str(iaxs[x]->first_iax_message & ~MARK_IAX_SUBCLASS_TX, first_message, sizeof(first_message)); + iax_frame_subclass2str(iaxs[x]->last_iax_message & ~MARK_IAX_SUBCLASS_TX, last_message, sizeof(last_message)); lag = iaxs[x]->remote_rr.delay; ast_cli(a->fd, FORMAT, iaxs[x]->owner ? iaxs[x]->owner->name : "(None)", - ast_inet_ntoa(iaxs[x]->addr.sin_addr), + ast_inet_ntoa(iaxs[x]->addr.sin_addr), S_OR(iaxs[x]->username, "(None)"), iaxs[x]->callno, iaxs[x]->peercallno, iaxs[x]->oseqno, iaxs[x]->iseqno, lag, jitter, localdelay, - ast_getformatname(iaxs[x]->voiceformat) ); + ast_getformatname(iaxs[x]->voiceformat), + (iaxs[x]->first_iax_message & MARK_IAX_SUBCLASS_TX) ? "Tx:" : "Rx:", + first_message, + (iaxs[x]->last_iax_message & MARK_IAX_SUBCLASS_TX) ? "Tx:" : "Rx:", + last_message); numchans++; } ast_mutex_unlock(&iaxsl[x]); @@ -5620,14 +5642,18 @@ static int ast_cli_netstats(struct mansession *s, int fd, int limit_fmt) { int x; int numchans = 0; -#define ACN_FORMAT1 "%-25.25s %4d %4d %4d %5d %3d %5d %4d %6d %4d %4d %5d %3d %5d %4d %6d\n" -#define ACN_FORMAT2 "%s %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d\n" + char first_message[10] = { 0, }; + char last_message[10] = { 0, }; +#define ACN_FORMAT1 "%-20.25s %4d %4d %4d %5d %3d %5d %4d %6d %4d %4d %5d %3d %5d %4d %6d %s%s %4s%s\n" +#define ACN_FORMAT2 "%s %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %s%s %s%s\n" for (x = 0; x < ARRAY_LEN(iaxs); x++) { ast_mutex_lock(&iaxsl[x]); if (iaxs[x]) { int localjitter, localdelay, locallost, locallosspct, localdropped, localooo; jb_info jbinfo; - + iax_frame_subclass2str(iaxs[x]->first_iax_message & ~MARK_IAX_SUBCLASS_TX, first_message, sizeof(first_message)); + iax_frame_subclass2str(iaxs[x]->last_iax_message & ~MARK_IAX_SUBCLASS_TX, last_message, sizeof(last_message)); + if(ast_test_flag(iaxs[x], IAX_USEJITTERBUF)) { jb_getinfo(iaxs[x]->jb, &jbinfo); localjitter = jbinfo.jitter; @@ -5645,29 +5671,32 @@ static int ast_cli_netstats(struct mansession *s, int fd, int limit_fmt) localooo = -1; } if (s) - astman_append(s, limit_fmt ? ACN_FORMAT1 : ACN_FORMAT2, - iaxs[x]->owner ? iaxs[x]->owner->name : "(None)", - iaxs[x]->pingtime, - localjitter, - localdelay, - locallost, - locallosspct, - localdropped, - localooo, - 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); + iaxs[x]->owner ? iaxs[x]->owner->name : "(None)", + iaxs[x]->pingtime, + localjitter, + localdelay, + locallost, + locallosspct, + localdropped, + localooo, + 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, + (iaxs[x]->first_iax_message & MARK_IAX_SUBCLASS_TX) ? "Tx:" : "Rx:", + first_message, + (iaxs[x]->last_iax_message & MARK_IAX_SUBCLASS_TX) ? "Tx:" : "Rx:", + last_message); else ast_cli(fd, limit_fmt ? ACN_FORMAT1 : ACN_FORMAT2, iaxs[x]->owner ? iaxs[x]->owner->name : "(None)", iaxs[x]->pingtime, - localjitter, + localjitter, localdelay, locallost, locallosspct, @@ -5680,8 +5709,11 @@ static int ast_cli_netstats(struct mansession *s, int fd, int limit_fmt) iaxs[x]->remote_rr.losspct, iaxs[x]->remote_rr.dropped, iaxs[x]->remote_rr.ooo, - iaxs[x]->remote_rr.packets/1000 - ); + iaxs[x]->remote_rr.packets/1000, + (iaxs[x]->first_iax_message & MARK_IAX_SUBCLASS_TX) ? "Tx:" : "Rx:", + first_message, + (iaxs[x]->last_iax_message & MARK_IAX_SUBCLASS_TX) ? "Tx:" : "Rx:", + last_message); numchans++; } ast_mutex_unlock(&iaxsl[x]); @@ -5706,8 +5738,8 @@ static char *handle_cli_iax2_show_netstats(struct ast_cli_entry *e, int cmd, str } if (a->argc != 3) return CLI_SHOWUSAGE; - ast_cli(a->fd, " -------- LOCAL --------------------- -------- REMOTE --------------------\n"); - ast_cli(a->fd, "Channel RTT Jit Del Lost %% Drop OOO Kpkts Jit Del Lost %% Drop OOO Kpkts\n"); + ast_cli(a->fd, " -------- LOCAL --------------------- -------- REMOTE --------------------\n"); + ast_cli(a->fd, "Channel RTT Jit Del Lost %% Drop OOO Kpkts Jit Del Lost %% Drop OOO Kpkts FirstMsg LastMsg\n"); numchans = ast_cli_netstats(NULL, a->fd, 1); ast_cli(a->fd, "%d active IAX channel%s\n", numchans, (numchans != 1) ? "s" : ""); return CLI_SUCCESS; @@ -8642,7 +8674,10 @@ retryowner: if (iaxdebug) ast_debug(1, "For call=%d, set last=%d\n", fr->callno, fr->ts); } - + iaxs[fr->callno]->last_iax_message = f.subclass; + if (!iaxs[fr->callno]->first_iax_message) { + iaxs[fr->callno]->first_iax_message = f.subclass; + } switch(f.subclass) { case IAX_COMMAND_ACK: /* Do nothing */ diff --git a/channels/iax2-parser.c b/channels/iax2-parser.c index 127e205d4..dec3c2d35 100644 --- a/channels/iax2-parser.c +++ b/channels/iax2-parser.c @@ -398,6 +398,132 @@ static void dump_ies(unsigned char *iedata, int len) outputf("\n"); } +void iax_frame_subclass2str(enum iax_frame_subclass subclass, char *str, size_t len) +{ + const char *cmd = "Unknown"; + + /* if an error occurs here during compile, that means a new iax frame subclass + * has been added to the iax_frame_subclass enum. Add the new subclass to the + * switch case and make sure to update it with a new string representation. */ + switch (subclass) { + case IAX_COMMAND_NEW: + cmd = "NEW "; + break; + case IAX_COMMAND_PING: + cmd = "PING "; + break; + case IAX_COMMAND_PONG: + cmd = "PONG "; + break; + case IAX_COMMAND_ACK: + cmd = "ACK "; + break; + case IAX_COMMAND_HANGUP: + cmd = "HANGUP "; + break; + case IAX_COMMAND_REJECT: + cmd = "REJECT "; + break; + case IAX_COMMAND_ACCEPT: + cmd = "ACCEPT "; + break; + case IAX_COMMAND_AUTHREQ: + cmd = "AUTHREQ"; + break; + case IAX_COMMAND_AUTHREP: + cmd = "AUTHREP"; + break; + case IAX_COMMAND_INVAL: + cmd = "INVAL "; + break; + case IAX_COMMAND_LAGRQ: + cmd = "LAGRQ "; + break; + case IAX_COMMAND_LAGRP: + cmd = "LAGRP "; + break; + case IAX_COMMAND_REGREQ: + cmd = "REGREQ "; + break; + case IAX_COMMAND_REGAUTH: + cmd = "REGAUTH"; + break; + case IAX_COMMAND_REGACK: + cmd = "REGACK "; + break; + case IAX_COMMAND_REGREJ: + cmd = "REGREJ "; + break; + case IAX_COMMAND_REGREL: + cmd = "REGREL "; + break; + case IAX_COMMAND_VNAK: + cmd = "VNAK "; + break; + case IAX_COMMAND_DPREQ: + cmd = "DPREQ "; + break; + case IAX_COMMAND_DPREP: + cmd = "DPREP "; + break; + case IAX_COMMAND_DIAL: + cmd = "DIAL "; + break; + case IAX_COMMAND_TXREQ: + cmd = "TXREQ "; + break; + case IAX_COMMAND_TXCNT: + cmd = "TXCNT "; + break; + case IAX_COMMAND_TXACC: + cmd = "TXACC "; + break; + case IAX_COMMAND_TXREADY: + cmd = "TXREADY"; + break; + case IAX_COMMAND_TXREL: + cmd = "TXREL "; + break; + case IAX_COMMAND_TXREJ: + cmd = "TXREJ "; + break; + case IAX_COMMAND_QUELCH: + cmd = "QUELCH "; + break; + case IAX_COMMAND_UNQUELCH: + cmd = "UNQULCH"; + break; + case IAX_COMMAND_POKE: + cmd = "POKE "; + break; + case IAX_COMMAND_PAGE: + cmd = "PAGE "; + break; + case IAX_COMMAND_MWI: + cmd = "MWI "; + break; + case IAX_COMMAND_UNSUPPORT: + cmd = "UNSPRTD"; + break; + case IAX_COMMAND_TRANSFER: + cmd = "TRANSFR"; + break; + case IAX_COMMAND_PROVISION: + cmd = "PROVISN"; + break; + case IAX_COMMAND_FWDOWNL: + cmd = "FWDWNLD"; + break; + case IAX_COMMAND_FWDATA: + cmd = "FWDATA "; + break; + case IAX_COMMAND_TXMEDIA: + cmd = "TXMEDIA"; + break; + } + ast_copy_string(str, cmd, len); +} + void iax_showframe(struct iax_frame *f, struct ast_iax2_full_hdr *fhi, int rx, struct sockaddr_in *sin, int datalen) { const char *frames[] = { @@ -415,47 +541,6 @@ void iax_showframe(struct iax_frame *f, struct ast_iax2_full_hdr *fhi, int rx, s "MODEM ", "DTMF_B ", }; - const char *iaxs[] = { - "(0?)", - "NEW ", - "PING ", - "PONG ", - "ACK ", - "HANGUP ", - "REJECT ", - "ACCEPT ", - "AUTHREQ", - "AUTHREP", - "INVAL ", - "LAGRQ ", - "LAGRP ", - "REGREQ ", - "REGAUTH", - "REGACK ", - "REGREJ ", - "REGREL ", - "VNAK ", - "DPREQ ", - "DPREP ", - "DIAL ", - "TXREQ ", - "TXCNT ", - "TXACC ", - "TXREADY", - "TXREL ", - "TXREJ ", - "QUELCH ", - "UNQULCH", - "POKE ", - "PAGE ", - "MWI ", - "UNSPRTD", - "TRANSFR", - "PROVISN", - "FWDWNLD", - "FWDATA ", - "TXMEDIA" - }; const char *cmds[] = { "(0?)", "HANGUP ", @@ -523,12 +608,8 @@ void iax_showframe(struct iax_frame *f, struct ast_iax2_full_hdr *fhi, int rx, s sprintf(subclass2, "%c", fh->csub); subclass = subclass2; } else if (fh->type == AST_FRAME_IAX) { - if (fh->csub >= (int)sizeof(iaxs)/(int)sizeof(iaxs[0])) { - snprintf(subclass2, sizeof(subclass2), "(%d?)", fh->csub); + iax_frame_subclass2str((int)fh->csub, subclass2, sizeof(subclass2)); subclass = subclass2; - } else { - subclass = iaxs[(int)fh->csub]; - } } else if (fh->type == AST_FRAME_CONTROL) { if (fh->csub >= (int)sizeof(cmds)/(int)sizeof(cmds[0])) { snprintf(subclass2, sizeof(subclass2), "(%d?)", fh->csub); diff --git a/channels/iax2-parser.h b/channels/iax2-parser.h index e75cd4209..9de873b35 100644 --- a/channels/iax2-parser.h +++ b/channels/iax2-parser.h @@ -150,6 +150,7 @@ void iax_set_output(void (*output)(const char *data)); /* Choose a different function for errors */ void iax_set_error(void (*output)(const char *data)); void iax_showframe(struct iax_frame *f, struct ast_iax2_full_hdr *fhi, int rx, struct sockaddr_in *sin, int datalen); +void iax_frame_subclass2str(enum iax_frame_subclass subclass, char *str, size_t len); const char *iax_ie2str(int ie); diff --git a/channels/iax2.h b/channels/iax2.h index a945afee4..85cead903 100644 --- a/channels/iax2.h +++ b/channels/iax2.h @@ -44,7 +44,7 @@ #define IAX_WINDOW 64 /*! Subclass for AST_FRAME_IAX */ -enum { +enum iax_frame_subclass { IAX_COMMAND_NEW = 1, IAX_COMMAND_PING = 2, IAX_COMMAND_PONG = 3, @@ -104,7 +104,7 @@ enum { /*! Provision device */ IAX_COMMAND_PROVISION = 35, /*! Download firmware */ - IAX_COMMAND_FWDOWNL = 36, + IAX_COMMAND_FWDOWNL = 36, /*! Firmware Data */ IAX_COMMAND_FWDATA = 37, /*! Transfer media only */ @@ -112,10 +112,10 @@ enum { }; /*! By default require re-registration once per minute */ -#define IAX_DEFAULT_REG_EXPIRE 60 +#define IAX_DEFAULT_REG_EXPIRE 60 /*! How long to wait before closing bridged call */ -#define IAX_LINGER_TIMEOUT 10 +#define IAX_LINGER_TIMEOUT 10 #define IAX_DEFAULT_PORTNO 4569 |