Commit 59855b0c authored by Victor Seva's avatar Victor Seva

New upstream version 1.4.1

parent 0793f4da
2016-10-28 Ivan Alonso <kaian@irontec.com>
* sngrep 1.4.1 released
* Capture
* Reworked how IP fragments are assembled
* Increased default capture snapshot length
* SIP
* Added support for any kind of uri schemes
* Added support for Warning header code
* Added support for Reason header text
* Added callstates BUSY and DIVERTED
* Call List
* Fixed a bug displaying sort by column ('<','>' keybinding)
* Call Flow
* Fixed a bug where arrows with same timestamp were not displayed
* Settings
* Added a setting for filter.payload
* Other
* Fixed text typos
2016-08-08 Ivan Alonso <kaian@irontec.com>
* sngrep 1.4.0 released
......
AC_PREREQ([2.59])
AC_INIT([sngrep], [1.4.0], [kaian@irontec.com], [sngrep], [http://www.irontec.com/])
AC_INIT([sngrep], [1.4.1], [kaian@irontec.com], [sngrep], [http://www.irontec.com/])
AM_INIT_AUTOMAKE([1.9])
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
AC_CONFIG_HEADERS([src/config.h])
......
......@@ -3,7 +3,7 @@
.\" Copyright (c) 2013-2016 Ivan Alonso <kaian@irontec.com>
.\" Copyright (c) 2013-2016 Irontec S.L.
.TH SNGREP 8 "January 2016" "sngrep 1.4.0"
.TH SNGREP 8 "January 2016" "sngrep 1.4.1"
.SH NAME
......
sngrep (1.4.1) experimental; urgency=low
* sngrep 1.4.1 released
-- Ivan Alonso <kaian@irontec.com> Fri, 28 Oct 2016 11:24:14 +0200
sngrep (1.4.0) experimental; urgency=low
* sngrep 1.4.0 released
......
......@@ -128,7 +128,7 @@ capture_online(const char *dev, const char *outfile)
}
// Open capture device
capinfo->handle = pcap_open_live(dev, BUFSIZ, 1, 1000, errbuf);
capinfo->handle = pcap_open_live(dev, MAXIMUM_SNAPLEN, 1, 1000, errbuf);
if (capinfo->handle == NULL) {
fprintf(stderr, "Couldn't open device %s: %s\n", dev, errbuf);
return 2;
......@@ -472,17 +472,27 @@ capture_packet_reasm_ip(capture_info_t *capinfo, const struct pcap_pkthdr *heade
pkt = packet_create(ip_ver, ip_proto, src, dst, ip_id);
packet_add_frame(pkt, header, packet);
vector_append(capture_cfg.ip_reasm, pkt);
return NULL;
}
// If no more fragments
// Add this IP content length to the total captured of the packet
pkt->ip_cap_len += ip_len;
// Calculate how much data we need to complete this packet
// The total packet size can only be known using the last fragment of the packet
// where 'No more fragments is enabled' and it's calculated based on the
// last fragment offset
if ((ip_off & IP_MF) == 0) {
pkt->ip_exp_len = ip_frag_off + ip_len + ip_hl;
}
// If we have the whole packet (captured length is expected length)
if (pkt->ip_cap_len == pkt->ip_exp_len) {
// TODO Dont check the flag, check the holes
// Calculate assembled IP payload data
it = vector_iterator(pkt->frames);
while ((frame = vector_iterator_next(&it))) {
struct ip *frame_ip = (struct ip *) (frame->data + link_hl);
len_data += frame->header->caplen - link_hl - frame_ip->ip_hl * 4;
len_data += ntohs(frame_ip->ip_len) - frame_ip->ip_hl * 4;
}
// Check packet content length
......@@ -498,7 +508,7 @@ capture_packet_reasm_ip(capture_info_t *capinfo, const struct pcap_pkthdr *heade
struct ip *frame_ip = (struct ip *) (frame->data + link_hl);
memcpy(packet + link_hl + ip_hl + (ntohs(frame_ip->ip_off) & IP_OFFMASK) * 8,
frame->data + link_hl + frame_ip->ip_hl * 4,
frame->header->caplen - link_hl - frame_ip->ip_hl * 4);
ntohs(frame_ip->ip_len) - frame_ip->ip_hl * 4);
}
*caplen = link_hl + ip_hl + len_data;
......
......@@ -74,6 +74,8 @@
//! Max allowed packet assembled size
#define MAX_CAPTURE_LEN 20480
//! Max allowed packet length
#define MAXIMUM_SNAPLEN 262144
//! Define VLAN 802.1Q Ethernet type
#ifndef ETHERTYPE_8021Q
......
......@@ -116,8 +116,9 @@ call_list_create(ui_t *ui)
// Set autoscroll default status
info->autoscroll = setting_enabled(SETTING_CL_AUTOSCROLL);
// Apply initial configured method filters
// Apply initial configured filters
filter_method_from_setting(setting_get_value(SETTING_FILTER_METHODS));
filter_payload_from_setting(setting_get_value(SETTING_FILTER_PAYLOAD));
}
void
......@@ -865,9 +866,9 @@ call_list_handle_menu_key(ui_t *ui, int key)
}
// Restore list position
mvderwin(info->list_win, 4, 0);
mvderwin(info->list_win, 5, 0);
// Restore list window size
wresize(info->list_win, ui->height - 5, ui->width);
wresize(info->list_win, ui->height - 6, ui->width);
break;
default:
// Parse next action
......@@ -1041,8 +1042,8 @@ call_list_select_sort_attribute(ui_t *ui)
// Activete sorting menu
info->menu_active = 1;
wresize(info->list_win, ui->height - 5, ui->width - 12);
mvderwin(info->list_win, 4, 12);
wresize(info->list_win, ui->height - 6, ui->width - 12);
mvderwin(info->list_win, 5, 12);
// Create menu entries
for (i = 0; i < info->columncnt; i++) {
......@@ -1054,7 +1055,7 @@ call_list_select_sort_attribute(ui_t *ui)
// Set main window and sub window
set_menu_win(info->menu, ui->win);
set_menu_sub(info->menu, derwin(ui->win, 20, 15, 4, 0));
set_menu_sub(info->menu, derwin(ui->win, 20, 15, 5, 0));
werase(menu_win(info->menu));
set_menu_format(info->menu, ui->height, 1);
set_menu_mark(info->menu, "");
......
......@@ -52,7 +52,7 @@ void
filter_create(ui_t *ui)
{
filter_info_t *info;
const char *method;
const char *method, *payload;
// Cerate a new indow for the panel and form
ui_panel_create(ui, 16, 50);
......@@ -85,7 +85,7 @@ filter_create(ui_t *ui)
field_opts_off(info->fields[FLD_FILTER_SIPTO], O_AUTOSKIP);
field_opts_off(info->fields[FLD_FILTER_SRC], O_AUTOSKIP);
field_opts_off(info->fields[FLD_FILTER_DST], O_AUTOSKIP);
field_opts_off(info->fields[FLD_FILTER_PAYLOAD], O_AUTOSKIP);
field_opts_off(info->fields[FLD_FILTER_PAYLOAD], O_AUTOSKIP | O_STATIC);
field_opts_off(info->fields[FLD_FILTER_REGISTER], O_AUTOSKIP);
field_opts_off(info->fields[FLD_FILTER_INVITE], O_AUTOSKIP);
field_opts_off(info->fields[FLD_FILTER_SUBSCRIBE], O_AUTOSKIP);
......@@ -126,6 +126,10 @@ filter_create(ui_t *ui)
if (!(method = filter_get(FILTER_METHOD)))
method = setting_get_value(SETTING_FILTER_METHODS);
// Get Payload filter
if (!(payload = filter_get(FILTER_PAYLOAD)))
payload = setting_get_value(SETTING_FILTER_PAYLOAD);
// Set Default field values
set_field_buffer(info->fields[FLD_FILTER_SIPFROM], 0, filter_get(FILTER_SIPFROM));
set_field_buffer(info->fields[FLD_FILTER_SIPTO], 0, filter_get(FILTER_SIPTO));
......@@ -182,7 +186,7 @@ int
filter_handle_key(ui_t *ui, int key)
{
int field_idx;
char field_value[30];
char field_value[MAX_SETTING_LEN];
int action = -1;
// Get panel information
......@@ -304,7 +308,7 @@ filter_handle_key(ui_t *ui, int key)
void
filter_save_options(ui_t *ui)
{
char field_value[30];
char field_value[MAX_SETTING_LEN];
char *expr;
int field_id;
char method_expr[256];
......@@ -429,3 +433,9 @@ filter_method_from_setting(const char *value)
}
}
void
filter_payload_from_setting(const char *value)
{
if (value) filter_set(FILTER_PAYLOAD, value);
}
......@@ -150,4 +150,10 @@ filter_field_method(int field_id);
void
filter_method_from_setting(const char *value);
/**
* @brief Set Payload filter from filter.payload setting
*/
void
filter_payload_from_setting(const char *value);
#endif
......@@ -346,7 +346,7 @@ int
draw_message_pos(WINDOW *win, sip_msg_t *msg, int starting)
{
int height, width, line, column, i;
const char *cur_line, *payload;
const char *cur_line, *payload, *method = NULL;
int syntax = setting_enabled(SETTING_SYNTAX);
// Default text format
......@@ -357,6 +357,11 @@ draw_message_pos(WINDOW *win, sip_msg_t *msg, int starting)
// Get window of main panel
getmaxyx(win, height, width);
// Get message method (if request)
if (msg_is_request(msg)) {
method = sip_method_str(msg->reqresp);
}
// Get packet payload
cur_line = payload = (const char *) msg_get_payload(msg);
......@@ -377,7 +382,7 @@ draw_message_pos(WINDOW *win, sip_msg_t *msg, int starting)
attrs = A_BOLD | COLOR_PAIR(CP_RED_ON_DEF);
// SIP URI syntax
if (!strncasecmp(payload + i, "sip:", 4)) {
if (method && i == strlen(method) + 1) {
attrs = A_BOLD | COLOR_PAIR(CP_CYAN_ON_DEF);
}
} else {
......
......@@ -68,7 +68,7 @@ settings_entry_t entries[] = {
{ CAT_SETTINGS_CAPTURE, FLD_SETTINGS_SIP_NOINCOMPLETE, SETTING_SIP_NOINCOMPLETE, "Capture full transactions ................." },
{ CAT_SETTINGS_CAPTURE, FLD_SETTINGS_SAVEPATH, SETTING_SAVEPATH, "Default Save path ........................." },
{ CAT_SETTINGS_CALL_FLOW, FLD_SETTINGS_CF_FORCERAW, SETTING_CF_FORCERAW, "Show message preview panel ................" },
{ CAT_SETTINGS_CALL_FLOW, FLD_SETTINGS_CF_HIGHTLIGHT, SETTING_CF_HIGHTLIGHT, "Selected message hightlight ..............." },
{ CAT_SETTINGS_CALL_FLOW, FLD_SETTINGS_CF_HIGHTLIGHT, SETTING_CF_HIGHTLIGHT, "Selected message highlight ................" },
{ CAT_SETTINGS_CALL_FLOW, FLD_SETTINGS_CF_LOCALHIGHLIGHT, SETTING_CF_LOCALHIGHLIGHT, "Highlight local addresses ................." },
{ CAT_SETTINGS_CALL_FLOW, FLD_SETTINGS_CF_SPLITCACALLID, SETTING_CF_SPLITCALLID, "Merge columns with same address ..........." },
{ CAT_SETTINGS_CALL_FLOW, FLD_SETTINGS_CF_SDPONLY, SETTING_CF_SDP_INFO, "Show SDP information in messages .........." },
......@@ -191,7 +191,7 @@ settings_create(ui_t *ui)
mvwaddch(ui->win, 6, ui->width - 1, ACS_RTEE);
wattroff(ui->win, COLOR_PAIR(CP_BLUE_ON_DEF));
wattron(ui->win, COLOR_PAIR(CP_CYAN_ON_DEF));
mvwprintw(ui->win, 3, 1, " Use arrow keys, PgUp, PgDown and Tab to move arround settings.");
mvwprintw(ui->win, 3, 1, " Use arrow keys, PgUp, PgDown and Tab to move around settings.");
mvwprintw(ui->win, 4, 1, " Settings with (*) requires restart.");
wattroff(ui->win, COLOR_PAIR(CP_CYAN_ON_DEF));
......
......@@ -33,6 +33,8 @@
* | Calls: 10 CANCELLED: 2 (12.2%) |
* | Messages: 200 IN CALL: 10 (60.5%) |
* | REJECTED: 0 (0.0%) |
* | BUSY: 0 (0.0%) |
* | DIVERTED: 0 (0.0%) |
* | CALL SETUP: 0 (0.0%) |
* +---------------------------------------------------------+
* | INVITE: 10 (0.5%) 1XX: 123 (1.5%) |
......@@ -44,7 +46,6 @@
* | PUBLISH: 0 (0.0%) 7XX: 0 (0.0%) |
* | MESSAGE: 0 (0.0%) 8XX: 0 (0.0%) |
* | INFO: 0 (0.0%) |
* | ACK: 300 (7.2%) |
* | BYE: 10 (0.5%) |
* | CANCEL: 0 (0.0%) |
* +---------------------------------------------------------+
......@@ -79,7 +80,7 @@ stats_create(ui_t *ui)
// Counters!
struct {
int dtotal, dcalls, completed, cancelled, incall, rejected, setup;
int dtotal, dcalls, completed, cancelled, incall, rejected, setup, busy, diverted;
int mtotal, invite, regist, subscribe, update, notify, options;
int publish, message, info, ack, bye, cancel;
int r100, r200, r300, r400, r500, r600, r700, r800;
......@@ -87,15 +88,15 @@ stats_create(ui_t *ui)
memset(&stats, 0, sizeof(stats));
// Calculate window dimensions
ui_panel_create(ui, 23, 60);
ui_panel_create(ui, 25, 60);
// Set the window title and boxes
mvwprintw(ui->win, 1, ui->width / 2 - 9, "Stats Information");
wattron(ui->win, COLOR_PAIR(CP_BLUE_ON_DEF));
title_foot_box(ui->panel);
mvwhline(ui->win, 8, 1, ACS_HLINE, ui->width - 1);
mvwaddch(ui->win, 8, 0, ACS_LTEE);
mvwaddch(ui->win, 8, ui->width - 1, ACS_RTEE);
mvwhline(ui->win, 10, 1, ACS_HLINE, ui->width - 1);
mvwaddch(ui->win, 10, 0, ACS_LTEE);
mvwaddch(ui->win, 10, ui->width - 1, ACS_RTEE);
mvwprintw(ui->win, ui->height - 2, ui->width / 2 - 9, "Press ESC to leave");
wattroff(ui->win, COLOR_PAIR(CP_BLUE_ON_DEF));
......@@ -120,6 +121,8 @@ stats_create(ui_t *ui)
case SIP_CALLSTATE_INCALL: stats.incall++; break;
case SIP_CALLSTATE_CANCELLED: stats.cancelled++; break;
case SIP_CALLSTATE_REJECTED: stats.rejected++; break;
case SIP_CALLSTATE_BUSY: stats.busy++; break;
case SIP_CALLSTATE_DIVERTED: stats.diverted++; break;
case SIP_CALLSTATE_COMPLETED: stats.completed++; break;
}
}
......@@ -169,27 +172,29 @@ stats_create(ui_t *ui)
mvwprintw(ui->win, 4, 33, "CANCELLED: %d (%.1f\%)", stats.cancelled, (float) stats.cancelled * 100 / stats.dcalls);
mvwprintw(ui->win, 5, 33, "IN CALL: %d (%.1f\%)", stats.incall, (float) stats.incall * 100 / stats.dcalls);
mvwprintw(ui->win, 6, 33, "REJECTED: %d (%.1f\%)", stats.rejected, (float) stats.rejected * 100 / stats.dcalls);
mvwprintw(ui->win, 7, 33, "CALL SETUP: %d (%.1f\%)", stats.setup, (float) stats.setup * 100 / stats.dcalls);
mvwprintw(ui->win, 7, 33, "BUSY: %d (%.1f\%)", stats.busy, (float) stats.busy * 100 / stats.dcalls);
mvwprintw(ui->win, 8, 33, "DIVERTED: %d (%.1f\%)", stats.diverted, (float) stats.diverted * 100 / stats.dcalls);
mvwprintw(ui->win, 9, 33, "CALL SETUP: %d (%.1f\%)", stats.setup, (float) stats.setup * 100 / stats.dcalls);
}
mvwprintw(ui->win, 9, 3, "INVITE: %d (%.1f\%)", stats.invite, (float) stats.invite * 100 / stats.mtotal);
mvwprintw(ui->win, 10, 3, "REGISTER: %d (%.1f\%)", stats.regist, (float) stats.regist * 100 / stats.mtotal);
mvwprintw(ui->win, 11, 3, "SUBSCRIBE: %d (%.1f\%)", stats.subscribe, (float) stats.subscribe * 100 / stats.mtotal);
mvwprintw(ui->win, 12, 3, "UPDATE: %d (%.1f\%)", stats.update, (float) stats.update * 100 / stats.mtotal);
mvwprintw(ui->win, 13, 3, "NOTIFY: %d (%.1f\%)", stats.notify, (float) stats.notify * 100 / stats.mtotal);
mvwprintw(ui->win, 14, 3, "OPTIONS: %d (%.1f\%)", stats.options, (float) stats.options * 100 / stats.mtotal);
mvwprintw(ui->win, 15, 3, "PUBLISH: %d (%.1f\%)", stats.publish, (float) stats.publish * 100 / stats.mtotal);
mvwprintw(ui->win, 16, 3, "MESSAGE: %d (%.1f\%)", stats.message, (float) stats.message * 100 / stats.mtotal);
mvwprintw(ui->win, 17, 3, "INFO: %d (%.1f\%)", stats.info, (float) stats.info * 100 / stats.mtotal);
mvwprintw(ui->win, 18, 3, "BYE: %d (%.1f\%)", stats.bye, (float) stats.bye * 100 / stats.mtotal);
mvwprintw(ui->win, 19, 3, "CANCEL: %d (%.1f\%)", stats.cancel, (float) stats.cancel * 100 / stats.mtotal);
mvwprintw(ui->win, 11, 3, "INVITE: %d (%.1f\%)", stats.invite, (float) stats.invite * 100 / stats.mtotal);
mvwprintw(ui->win, 12, 3, "REGISTER: %d (%.1f\%)", stats.regist, (float) stats.regist * 100 / stats.mtotal);
mvwprintw(ui->win, 13, 3, "SUBSCRIBE: %d (%.1f\%)", stats.subscribe, (float) stats.subscribe * 100 / stats.mtotal);
mvwprintw(ui->win, 14, 3, "UPDATE: %d (%.1f\%)", stats.update, (float) stats.update * 100 / stats.mtotal);
mvwprintw(ui->win, 15, 3, "NOTIFY: %d (%.1f\%)", stats.notify, (float) stats.notify * 100 / stats.mtotal);
mvwprintw(ui->win, 16, 3, "OPTIONS: %d (%.1f\%)", stats.options, (float) stats.options * 100 / stats.mtotal);
mvwprintw(ui->win, 17, 3, "PUBLISH: %d (%.1f\%)", stats.publish, (float) stats.publish * 100 / stats.mtotal);
mvwprintw(ui->win, 18, 3, "MESSAGE: %d (%.1f\%)", stats.message, (float) stats.message * 100 / stats.mtotal);
mvwprintw(ui->win, 19, 3, "INFO: %d (%.1f\%)", stats.info, (float) stats.info * 100 / stats.mtotal);
mvwprintw(ui->win, 20, 3, "BYE: %d (%.1f\%)", stats.bye, (float) stats.bye * 100 / stats.mtotal);
mvwprintw(ui->win, 21, 3, "CANCEL: %d (%.1f\%)", stats.cancel, (float) stats.cancel * 100 / stats.mtotal);
mvwprintw(ui->win, 9, 33, "1XX: %d (%.1f\%)", stats.r100, (float) stats.r100 * 100 / stats.mtotal);
mvwprintw(ui->win, 10, 33, "2XX: %d (%.1f\%)", stats.r200, (float) stats.r200 * 100 / stats.mtotal);
mvwprintw(ui->win, 11, 33, "3XX: %d (%.1f\%)", stats.r300, (float) stats.r300 * 100 / stats.mtotal);
mvwprintw(ui->win, 12, 33, "4XX: %d (%.1f\%)", stats.r400, (float) stats.r400 * 100 / stats.mtotal);
mvwprintw(ui->win, 13, 33, "5XX: %d (%.1f\%)", stats.r500, (float) stats.r500 * 100 / stats.mtotal);
mvwprintw(ui->win, 14, 33, "6XX: %d (%.1f\%)", stats.r600, (float) stats.r600 * 100 / stats.mtotal);
mvwprintw(ui->win, 15, 33, "7XX: %d (%.1f\%)", stats.r700, (float) stats.r700 * 100 / stats.mtotal);
mvwprintw(ui->win, 16, 33, "8XX: %d (%.1f\%)", stats.r800, (float) stats.r800 * 100 / stats.mtotal);
mvwprintw(ui->win, 11, 33, "1XX: %d (%.1f\%)", stats.r100, (float) stats.r100 * 100 / stats.mtotal);
mvwprintw(ui->win, 12, 33, "2XX: %d (%.1f\%)", stats.r200, (float) stats.r200 * 100 / stats.mtotal);
mvwprintw(ui->win, 13, 33, "3XX: %d (%.1f\%)", stats.r300, (float) stats.r300 * 100 / stats.mtotal);
mvwprintw(ui->win, 14, 33, "4XX: %d (%.1f\%)", stats.r400, (float) stats.r400 * 100 / stats.mtotal);
mvwprintw(ui->win, 15, 33, "5XX: %d (%.1f\%)", stats.r500, (float) stats.r500 * 100 / stats.mtotal);
mvwprintw(ui->win, 16, 33, "6XX: %d (%.1f\%)", stats.r600, (float) stats.r600 * 100 / stats.mtotal);
mvwprintw(ui->win, 17, 33, "7XX: %d (%.1f\%)", stats.r700, (float) stats.r700 * 100 / stats.mtotal);
mvwprintw(ui->win, 18, 33, "8XX: %d (%.1f\%)", stats.r800, (float) stats.r800 * 100 / stats.mtotal);
}
......@@ -111,7 +111,7 @@ read_options(const char *fname)
continue;
// Get configuration option from setting line
if (sscanf(line, "%s %s %s", type, option, value) == 3) {
if (sscanf(line, "%s %s %[^\t\n]", type, option, value) == 3) {
if (!strcasecmp(type, "set")) {
if ((id = setting_id(option)) >= 0) {
setting_set_value(id, value);
......
......@@ -78,6 +78,10 @@ struct packet {
address_t dst;
//! Packet IP id
uint16_t ip_id;
//! Packet IP fragmentation captured data
uint32_t ip_cap_len;
//! Packet IP fragmentation expected data
uint32_t ip_exp_len;
//! Last TCP sequence frame
uint32_t tcp_seq;
//! PCAP Packet payload when it can not be get from data
......
......@@ -458,6 +458,10 @@ stream_is_older(rtp_stream_t *one, rtp_stream_t *two)
if (!two)
return 1;
// No, you are not older than yourself
if (one == two)
return 0;
// Otherwise
return timeval_is_older(one->time, two->time);
}
......
......@@ -68,6 +68,7 @@ setting_t settings[SETTING_COUNT] = {
{ SETTING_CF_MEDIA, "cf.media", SETTING_FMT_ENUM, SETTING_OFF, SETTING_ENUM_ONOFF },
{ SETTING_CF_DELTA, "cf.deltatime", SETTING_FMT_ENUM, SETTING_ON, SETTING_ENUM_ONOFF },
{ SETTING_CR_SCROLLSTEP, "cr.scrollstep", SETTING_FMT_NUMBER, "10", NULL },
{ SETTING_FILTER_PAYLOAD, "filter.payload", SETTING_FMT_STRING, "", NULL },
{ SETTING_FILTER_METHODS, "filter.methods", SETTING_FMT_STRING, "", NULL },
#ifdef USE_EEP
{ SETTING_EEP_SEND, "eep.send", SETTING_FMT_ENUM, SETTING_OFF, SETTING_ENUM_ONOFF },
......
......@@ -98,6 +98,7 @@ enum setting_id {
SETTING_CF_MEDIA,
SETTING_CF_DELTA,
SETTING_CR_SCROLLSTEP,
SETTING_FILTER_PAYLOAD,
SETTING_FILTER_METHODS,
#ifdef USE_EEP
SETTING_EEP_SEND,
......
......@@ -162,16 +162,18 @@ sip_init(int limit, int only_calls, int no_incomplete)
// Initialize payload parsing regexp
match_flags = REG_EXTENDED | REG_ICASE | REG_NEWLINE;
regcomp(&calls.reg_method, "^([a-zA-Z]+) sips?:[^ ]+ SIP/2.0\r", match_flags & ~REG_NEWLINE);
regcomp(&calls.reg_method, "^([a-zA-Z]+) [a-zA-Z]+:[^ ]+ SIP/2.0\r", match_flags & ~REG_NEWLINE);
regcomp(&calls.reg_callid, "^(Call-ID|i):[ ]*([^ ]+)\r$", match_flags);
regcomp(&calls.reg_xcallid, "^(X-Call-ID|X-CID):[ ]*([^ ]+)\r$", match_flags);
regcomp(&calls.reg_response, "^SIP/2.0[ ]*(([0-9]{3}) [^\r]*)\r", match_flags & ~REG_NEWLINE);
regcomp(&calls.reg_cseq, "^CSeq:[ ]*([0-9]+) .+\r$", match_flags);
regcomp(&calls.reg_from, "^(From|f):[ ]*[^:]*:(([^@]+)@?[^\r>;]+)", match_flags);
regcomp(&calls.reg_to, "^(To|t):[ ]*[^:]*:(([^@]+)@?[^\r>;]+)", match_flags);
regcomp(&calls.reg_valid, "^([A-Z]+ sip:|SIP/2.0 [0-9]{3})", match_flags & ~REG_NEWLINE);
regcomp(&calls.reg_valid, "^([A-Z]+ [a-zA-Z]+:|SIP/2.0 [0-9]{3})", match_flags & ~REG_NEWLINE);
regcomp(&calls.reg_cl, "^(Content-Length|l):[ ]*([0-9]+)\r$", match_flags);
regcomp(&calls.reg_body, "\r\n\r\n(.*)", match_flags & ~REG_NEWLINE);
regcomp(&calls.reg_reason, "Reason:[ ]*[^\r]*;text=\"([^\r]+)\"", match_flags);
regcomp(&calls.reg_warning, "Warning:[ ]*([0-9]*)", match_flags);
}
......@@ -196,6 +198,8 @@ sip_deinit()
regfree(&calls.reg_valid);
regfree(&calls.reg_cl);
regfree(&calls.reg_body);
regfree(&calls.reg_reason);
regfree(&calls.reg_warning);
}
......@@ -378,6 +382,8 @@ sip_check_packet(packet_t *packet)
sip_parse_msg_media(msg, payload);
// Update Call State
call_update_state(call, msg);
// Parse extra fields
sip_parse_extra_headers(msg, payload);
// Check if this call should be in active call list
if (call_is_active(call)) {
if (sip_call_is_active(call)) {
......@@ -676,6 +682,24 @@ sip_parse_msg_media(sip_msg_t *msg, const u_char *payload)
#undef ADD_STREAM
}
void
sip_parse_extra_headers(sip_msg_t *msg, const u_char *payload)
{
regmatch_t pmatch[4];
char warning[10];
// Reason text
if (regexec(&calls.reg_reason, (const char *)payload, 2, pmatch, 0) == 0) {
msg->call->reasontxt = sng_malloc((int)pmatch[1].rm_eo - pmatch[1].rm_so + 1);
strncpy(msg->call->reasontxt, (const char *)payload + pmatch[1].rm_so, (int)pmatch[1].rm_eo - pmatch[1].rm_so);
}
// Warning code
if (regexec(&calls.reg_warning, (const char *)payload, 2, pmatch, 0) == 0) {
strncpy(warning, (const char *)payload + pmatch[1].rm_so, (int)pmatch[1].rm_eo - pmatch[1].rm_so);
msg->call->warning = atoi(warning);
}
}
void
sip_calls_clear()
......
......@@ -157,6 +157,8 @@ struct sip_call_list {
regex_t reg_valid;
regex_t reg_cl;
regex_t reg_body;
regex_t reg_reason;
regex_t reg_warning;
};
/**
......@@ -309,6 +311,18 @@ sip_find_by_index(int index);
sip_call_t *
sip_find_by_callid(const char *callid);
/**
* @brief Parse extra fields only for dialogs strarting with invite
*
* @note This function assumes the msg is already part of a call
*
* @param msg SIP message structure
* @param payload SIP message payload
*/
void
sip_parse_extra_headers(sip_msg_t *msg, const u_char *payload);
/**
* @brief Remove al calls
*
......
......@@ -52,7 +52,9 @@ static sip_attr_hdr_t attrs[SIP_ATTR_COUNT] = {
{ SIP_ATTR_MSGCNT, "msgcnt", "Msgs", "Message Count", 5 },
{ SIP_ATTR_CALLSTATE, "state", NULL, "Call State", 10, sip_attr_color_state },
{ SIP_ATTR_CONVDUR, "convdur", "ConvDur", "Conversation Duration", 7 },
{ SIP_ATTR_TOTALDUR, "totaldur", "TotalDur", "Total Duration", 8 }
{ SIP_ATTR_TOTALDUR, "totaldur", "TotalDur", "Total Duration", 8 },
{ SIP_ATTR_REASON_TXT, "reason", "Reason Text", "Reason Text", 25 },
{ SIP_ATTR_WARNING, "warning", "Warning", "Warning code", 4 }
};
sip_attr_hdr_t *
......@@ -163,5 +165,9 @@ sip_attr_color_state(const char *value)
return COLOR_PAIR(CP_RED_ON_DEF);
if (!strcmp(value, call_state_to_str(SIP_CALLSTATE_REJECTED)))
return COLOR_PAIR(CP_RED_ON_DEF);
if (!strcmp(value, call_state_to_str(SIP_CALLSTATE_BUSY)))
return COLOR_PAIR(CP_MAGENTA_ON_DEF);
if (!strcmp(value, call_state_to_str(SIP_CALLSTATE_DIVERTED)))
return COLOR_PAIR(CP_CYAN_ON_DEF);
return 0;
}
......@@ -81,6 +81,10 @@ enum sip_attr_id {
SIP_ATTR_CONVDUR,
//! Total call duration
SIP_ATTR_TOTALDUR,
//! Text from SIP Reason header
SIP_ATTR_REASON_TXT,
//! Warning Header
SIP_ATTR_WARNING,
//! SIP Attribute count
SIP_ATTR_COUNT
};
......
......@@ -83,6 +83,7 @@ call_destroy(sip_call_t *call)
// Deallocate call memory
sng_free(call->callid);
sng_free(call->xcallid);
sng_free(call->reasontxt);
sng_free(call);
}
......@@ -217,9 +218,15 @@ call_update_state(sip_call_t *call, sip_msg_t *msg)
} else if (reqresp == SIP_METHOD_CANCEL) {
// Alice is not in the mood
call->state = SIP_CALLSTATE_CANCELLED;
} else if ((reqresp == 480) || (reqresp == 486)) {
// Bob is busy
call->state = SIP_CALLSTATE_BUSY;
} else if (reqresp > 400 && call->invitecseq == msg->cseq) {
// Bob is not in the mood
call->state = SIP_CALLSTATE_REJECTED;
} else if (reqresp > 300) {
// Bob has diversion
call->state = SIP_CALLSTATE_DIVERTED;
}
} else if (call->state == SIP_CALLSTATE_INCALL) {
if (reqresp == SIP_METHOD_BYE) {
......@@ -277,6 +284,14 @@ call_get_attribute(sip_call_t *call, enum sip_attr_id id, char *value)
last = vector_last(call->msgs);
timeval_to_duration(msg_get_time(first), msg_get_time(last), value);
break;
case SIP_ATTR_REASON_TXT:
if (call->reasontxt)
sprintf(value, "%s", call->reasontxt);
break;
case SIP_ATTR_WARNING:
if (call->warning)
sprintf(value, "%d", call->warning);
break;
default:
return msg_get_attribute(vector_first(call->msgs), id, value);
break;
......@@ -297,6 +312,10 @@ call_state_to_str(int state)
return "CANCELLED";
case SIP_CALLSTATE_REJECTED:
return "REJECTED";
case SIP_CALLSTATE_BUSY:
return "BUSY";
case SIP_CALLSTATE_DIVERTED:
return "DIVERTED";
case SIP_CALLSTATE_COMPLETED:
return "COMPLETED";
}
......
......@@ -47,6 +47,8 @@ enum call_state
SIP_CALLSTATE_INCALL,
SIP_CALLSTATE_CANCELLED,
SIP_CALLSTATE_REJECTED,
SIP_CALLSTATE_DIVERTED,
SIP_CALLSTATE_BUSY,
SIP_CALLSTATE_COMPLETED
};
......@@ -72,6 +74,10 @@ struct sip_call {
bool changed;
//! Locked flag. Calls locked are never deleted
bool locked;
//! Last reason text value for this call
char *reasontxt;
//! Last warning text value for this call
int warning;
//! List of calls with with this call as X-Call-Id
vector_t *xcalls;
//! Cseq from invite startint the call
......
......@@ -166,6 +166,10 @@ msg_is_older(sip_msg_t *one, sip_msg_t *two)
if (!two)
return 1;
// No, you are not older than yourself
if (one == two)
return 0;
// Otherwise
return timeval_is_older(msg_get_time(one), msg_get_time(two));
}
......@@ -82,7 +82,7 @@ timeval_is_older(struct timeval t1, struct timeval t2)
t1sec = t1sec * 1000000;
t2sec = t2.tv_sec;
t2sec = t2sec * 1000000;
return ((t2sec + t2.tv_usec) - (t1sec + t1.tv_usec) < 0);
return ((t2sec + t2.tv_usec) - (t1sec + t1.tv_usec) <= 0);
}
const char *
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment