diff options
author | Jeff Morriss <jeff.morriss.ws@gmail.com> | 2013-06-26 02:12:12 +0000 |
---|---|---|
committer | Jeff Morriss <jeff.morriss.ws@gmail.com> | 2013-06-26 02:12:12 +0000 |
commit | 500d3993934d988fa5231333dd8c484513a81473 (patch) | |
tree | 6f8c32c4345dc2d7279a4d1b77e717d9ad9fbdc7 /ui | |
parent | bbf6a3766e65ebc66f06f936e530e79ec2d5b31b (diff) | |
download | wireshark-500d3993934d988fa5231333dd8c484513a81473.tar.gz wireshark-500d3993934d988fa5231333dd8c484513a81473.tar.bz2 wireshark-500d3993934d988fa5231333dd8c484513a81473.zip |
Move tap-*-common.{h,c} into ui/ since that's the home for common UI functions.
svn path=/trunk/; revision=50165
Diffstat (limited to 'ui')
-rw-r--r-- | ui/CMakeLists.txt | 2 | ||||
-rw-r--r-- | ui/Makefile.common | 6 | ||||
-rw-r--r-- | ui/cli/tap-megacostat.c | 2 | ||||
-rw-r--r-- | ui/cli/tap-rtp.c | 2 | ||||
-rw-r--r-- | ui/gtk/megaco_stat.c | 2 | ||||
-rw-r--r-- | ui/gtk/rtp_stream.c | 2 | ||||
-rw-r--r-- | ui/qt/QtShark.pro | 2 | ||||
-rw-r--r-- | ui/tap-megaco-common.c | 192 | ||||
-rw-r--r-- | ui/tap-megaco-common.h | 95 | ||||
-rw-r--r-- | ui/tap-rtp-common.c | 733 | ||||
-rw-r--r-- | ui/tap-rtp-common.h | 43 |
11 files changed, 1074 insertions, 7 deletions
diff --git a/ui/CMakeLists.txt b/ui/CMakeLists.txt index 14e1ed2c10..bb60ba8505 100644 --- a/ui/CMakeLists.txt +++ b/ui/CMakeLists.txt @@ -35,6 +35,8 @@ set(COMMON_UI_SRC recent.c ssl_key_export.c software_update.c + tap-megaco-common.c + tap-rtp-common.c text_import.c time_shift.c util.c diff --git a/ui/Makefile.common b/ui/Makefile.common index d7d4381d5f..0c513092cf 100644 --- a/ui/Makefile.common +++ b/ui/Makefile.common @@ -45,7 +45,7 @@ GENERATOR_FILES = \ WIRESHARK_UI_SRC = \ alert_box.c \ - export_object.c \ + export_object.c \ export_object_dicom.c \ export_object_http.c \ export_object_smb.c \ @@ -56,6 +56,8 @@ WIRESHARK_UI_SRC = \ recent.c \ software_update.c \ ssl_key_export.c \ + tap-megaco-common.c \ + tap-rtp-common.c \ text_import.c \ time_shift.c \ util.c @@ -77,6 +79,8 @@ noinst_HEADERS = \ simple_dialog.h \ software_update.h \ ssl_key_export.h \ + tap-megaco-common.h \ + tap-rtp-common.h \ text_import.h \ text_import_scanner.h \ time_shift.h \ diff --git a/ui/cli/tap-megacostat.c b/ui/cli/tap-megacostat.c index a56756e9eb..546d2c65b8 100644 --- a/ui/cli/tap-megacostat.c +++ b/ui/cli/tap-megacostat.c @@ -37,7 +37,7 @@ #include "epan/timestats.h" #include <epan/prefs-int.h> -#include "tap-megaco-common.h" +#include "ui/tap-megaco-common.h" diff --git a/ui/cli/tap-rtp.c b/ui/cli/tap-rtp.c index f81966bbe0..c07b1a29f3 100644 --- a/ui/cli/tap-rtp.c +++ b/ui/cli/tap-rtp.c @@ -45,7 +45,7 @@ #include <epan/rtp_pt.h> #include <epan/stat_cmd_args.h> #include <epan/addr_resolv.h> -#include "tap-rtp-common.h" +#include "ui/tap-rtp-common.h" /* The one and only global rtpstream_tapinfo_t structure for tshark and wireshark. */ diff --git a/ui/gtk/megaco_stat.c b/ui/gtk/megaco_stat.c index 4f4ea35340..6e6a9b2914 100644 --- a/ui/gtk/megaco_stat.c +++ b/ui/gtk/megaco_stat.c @@ -49,7 +49,7 @@ #include "ui/gtk/gui_utils.h" #include "ui/gtk/main.h" -#include "tap-megaco-common.h" +#include "ui/tap-megaco-common.h" #include "ui/gtk/old-gtk-compat.h" diff --git a/ui/gtk/rtp_stream.c b/ui/gtk/rtp_stream.c index c3d9dee37d..766e7c97dc 100644 --- a/ui/gtk/rtp_stream.c +++ b/ui/gtk/rtp_stream.c @@ -43,7 +43,7 @@ #include "../globals.h" #include "ui/alert_box.h" #include "ui/simple_dialog.h" -#include "../tap-rtp-common.h" +#include "ui/tap-rtp-common.h" #include <wsutil/file_util.h> #include "ui/gtk/rtp_stream.h" diff --git a/ui/qt/QtShark.pro b/ui/qt/QtShark.pro index d5474a8fdd..deed489c79 100644 --- a/ui/qt/QtShark.pro +++ b/ui/qt/QtShark.pro @@ -185,8 +185,6 @@ SOURCES_WS_C = \ ../../ps.c \ ../../summary.c \ ../../sync_pipe_write.c \ - ../../tap-megaco-common.c \ - ../../tap-rtp-common.c \ ../../u3.c \ ../../version_info.c diff --git a/ui/tap-megaco-common.c b/ui/tap-megaco-common.c new file mode 100644 index 0000000000..4da9654fc7 --- /dev/null +++ b/ui/tap-megaco-common.c @@ -0,0 +1,192 @@ +/* megaco_stat.c + * megaco-statistics for Wireshark + * Copyright 2003 Lars Roland + * Copyright 2008 Ericsson AB + * By Balint Reczey <balint.reczey@ericsson.com> + * + * $Id$ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" + +#include <string.h> + +#include <epan/packet_info.h> +#include <epan/epan.h> +#include <epan/value_string.h> +#include <epan/tap.h> +#include "epan/gcp.h" + +#include "epan/timestats.h" +#include "file.h" +#include "globals.h" +#include "stat_menu.h" + +#include "tap-megaco-common.h" + +static gboolean +megacostat_is_duplicate_reply(const gcp_cmd_t* cmd) +{ + switch (cmd->type) { + + GCP_CMD_REPLY_CASE + { + gcp_cmd_msg_t *cmd_msg; + /* cycle through commands to find same command in the transaction */ + for (cmd_msg = cmd->trx->cmds; + (cmd_msg != NULL) && (cmd_msg->cmd->msg->framenum != cmd->msg->framenum); + cmd_msg = cmd_msg->next) { + if (cmd_msg->cmd->type == cmd->type) + return TRUE; + } + + return FALSE; + } + break; + default: + return FALSE; + break; + } + + +} + +static gboolean +megacostat_had_request(const gcp_cmd_t* cmd) +{ + switch (cmd->type) { + + GCP_CMD_REPLY_CASE + { + gcp_cmd_msg_t *cmd_msg; + /* cycle through commands to find a request in the transaction */ + for (cmd_msg = cmd->trx->cmds; + (cmd_msg != NULL) && (cmd_msg->cmd->msg->framenum != cmd->msg->framenum); + cmd_msg = cmd_msg->next) { + + switch (cmd_msg->cmd->type) { + + GCP_CMD_REQ_CASE + return TRUE; + break; + default: + return FALSE; + break; + } + } + + return FALSE; + } + break; + default: + return FALSE; + break; + } +} + +int +megacostat_packet(void *pms, packet_info *pinfo, epan_dissect_t *edt _U_, const void *pmi) +{ + megacostat_t *ms=(megacostat_t *)pms; + const gcp_cmd_t *mi=(const gcp_cmd_t*)pmi; + nstime_t delta; + int ret = 0; + + switch (mi->type) { + + GCP_CMD_REQ_CASE + if(!mi->trx->initial) { + /* Track Context is probably disabled, we cannot + * measure service response time */ + return 0; + } + + else if(mi->trx->initial->framenum != mi->msg->framenum){ + /* Duplicate is ignored */ + ms->req_dup_num++; + } + else { + ms->open_req_num++; + } + break; + + GCP_CMD_REPLY_CASE + if(megacostat_is_duplicate_reply(mi)){ + /* Duplicate is ignored */ + ms->rsp_dup_num++; + } + else if (!megacostat_had_request(mi)) { + /* no request was seen */ + ms->disc_rsp_num++; + } + else { + ms->open_req_num--; + /* calculate time delta between request and response */ + nstime_delta(&delta, &pinfo->fd->abs_ts, &mi->trx->initial->time); + + switch(mi->type) { + + case GCP_CMD_ADD_REPLY: + time_stat_update(&(ms->rtd[0]),&delta, pinfo); + break; + case GCP_CMD_MOVE_REPLY: + time_stat_update(&(ms->rtd[1]),&delta, pinfo); + break; + case GCP_CMD_MOD_REPLY: + time_stat_update(&(ms->rtd[2]),&delta, pinfo); + break; + case GCP_CMD_SUB_REPLY: + time_stat_update(&(ms->rtd[3]),&delta, pinfo); + break; + case GCP_CMD_AUDITCAP_REPLY: + time_stat_update(&(ms->rtd[4]),&delta, pinfo); + break; + case GCP_CMD_AUDITVAL_REPLY: + time_stat_update(&(ms->rtd[5]),&delta, pinfo); + break; + case GCP_CMD_NOTIFY_REPLY: + time_stat_update(&(ms->rtd[6]),&delta, pinfo); + break; + case GCP_CMD_SVCCHG_REPLY: + time_stat_update(&(ms->rtd[7]),&delta, pinfo); + break; + case GCP_CMD_TOPOLOGY_REPLY: + time_stat_update(&(ms->rtd[8]),&delta, pinfo); + break; + case GCP_CMD_REPLY: + time_stat_update(&(ms->rtd[9]),&delta, pinfo); + break; + default: + time_stat_update(&(ms->rtd[11]),&delta, pinfo); + } + time_stat_update(&(ms->rtd[10]),&delta, pinfo); + + ret = 1; + } + break; + + default: + break; + } + + return ret; +} + diff --git a/ui/tap-megaco-common.h b/ui/tap-megaco-common.h new file mode 100644 index 0000000000..801abacd9a --- /dev/null +++ b/ui/tap-megaco-common.h @@ -0,0 +1,95 @@ +/* tap-rtp-common.h + * MEGACO statistics handler functions used by tshark and wireshark + * + * $Id$ + * + * Copyright 2008, Ericsson AB + * By Balint Reczey <balint.reczey@ericsson.com> + * + * most functions are copied from ui/gtk/rtp_stream.c and ui/gtk/rtp_analysis.c + * Copyright 2003, Alcatel Business Systems + * By Lars Ruoff <lars.ruoff@gmx.net> + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef TAP_MEGACO_COMMON_H +#define TAP_MEGACO_COMMON_H + +#define NUM_TIMESTATS 12 + +#define GCP_CMD_REPLY_CASE \ + case GCP_CMD_ADD_REPLY: \ + case GCP_CMD_MOVE_REPLY: \ + case GCP_CMD_MOD_REPLY: \ + case GCP_CMD_SUB_REPLY: \ + case GCP_CMD_AUDITCAP_REPLY: \ + case GCP_CMD_AUDITVAL_REPLY: \ + case GCP_CMD_NOTIFY_REPLY: \ + case GCP_CMD_SVCCHG_REPLY: \ + case GCP_CMD_TOPOLOGY_REPLY: \ + case GCP_CMD_REPLY: + +#define GCP_CMD_REQ_CASE \ + case GCP_CMD_ADD_REQ: \ + case GCP_CMD_MOVE_REQ: \ + case GCP_CMD_MOD_REQ: \ + case GCP_CMD_SUB_REQ: \ + case GCP_CMD_AUDITCAP_REQ: \ + case GCP_CMD_AUDITVAL_REQ: \ + case GCP_CMD_NOTIFY_REQ: \ + case GCP_CMD_SVCCHG_REQ: \ + case GCP_CMD_TOPOLOGY_REQ: \ + case GCP_CMD_CTX_ATTR_AUDIT_REQ: \ + case GCP_CMD_OTHER_REQ: + +/* used to keep track of the statistics for an entire program interface */ +typedef struct _megacostat_t { + char *filter; + timestat_t rtd[NUM_TIMESTATS]; + guint32 open_req_num; + guint32 disc_rsp_num; + guint32 req_dup_num; + guint32 rsp_dup_num; +#ifdef __GTK_H__ + GtkWidget *win; + GtkWidget *vbox; + GtkWidget *scrolled_window; + GtkTreeView *table; +#endif /*__GHTK_H__*/ +} megacostat_t; + +static const value_string megaco_message_type[] = { + { 0, "ADD "}, + { 1, "MOVE"}, + { 2, "MDFY"}, + { 3, "SUBT"}, + { 4, "AUCP"}, + { 5, "AUVL"}, + { 6, "NTFY"}, + { 7, "SVCC"}, + { 8, "TOPO"}, + { 9, "NONE"}, + { 10,"ALL "}, + { 0, NULL} +}; + +int megacostat_packet(void *pms, packet_info *pinfo, epan_dissect_t *edt _U_, const void *pmi); + +#endif /*TAP_MEGACO_COMMON_H*/ diff --git a/ui/tap-rtp-common.c b/ui/tap-rtp-common.c new file mode 100644 index 0000000000..0a93675bd0 --- /dev/null +++ b/ui/tap-rtp-common.c @@ -0,0 +1,733 @@ +/* tap-rtp-common.c + * RTP stream handler functions used by tshark and wireshark + * + * $Id$ + * + * Copyright 2008, Ericsson AB + * By Balint Reczey <balint.reczey@ericsson.com> + * + * most functions are copied from ui/gtk/rtp_stream.c and ui/gtk/rtp_analisys.c + * Copyright 2003, Alcatel Business Systems + * By Lars Ruoff <lars.ruoff@gmx.net> + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" + +#include <stdio.h> +#include <math.h> +#include "globals.h" + +#include <epan/tap.h> +#include <string.h> +#include <epan/rtp_pt.h> +#include <epan/addr_resolv.h> +#include <epan/dissectors/packet-rtp.h> +#include "ui/gtk/rtp_stream.h" +#include "tap-rtp-common.h" + +/* XXX: are changes needed to properly handle situations where + info_all_data_present == FALSE ? + E.G., when captured frames are truncated. + */ + +/****************************************************************************/ +/* GCompareFunc style comparison function for _rtp_stream_info */ +gint rtp_stream_info_cmp(gconstpointer aa, gconstpointer bb) +{ + const struct _rtp_stream_info* a = (const struct _rtp_stream_info*)aa; + const struct _rtp_stream_info* b = (const struct _rtp_stream_info*)bb; + + if (a==b) + return 0; + if (a==NULL || b==NULL) + return 1; + if (ADDRESSES_EQUAL(&(a->src_addr), &(b->src_addr)) + && (a->src_port == b->src_port) + && ADDRESSES_EQUAL(&(a->dest_addr), &(b->dest_addr)) + && (a->dest_port == b->dest_port) + && (a->ssrc == b->ssrc)) + return 0; + else + return 1; +} + + +/****************************************************************************/ +/* when there is a [re]reading of packet's */ +void rtpstream_reset(rtpstream_tapinfo_t *tapinfo) +{ + GList* list; + + if (tapinfo->mode == TAP_ANALYSE) { + /* free the data items first */ + list = g_list_first(tapinfo->strinfo_list); + while (list) + { + g_free(list->data); + list = g_list_next(list); + } + g_list_free(tapinfo->strinfo_list); + tapinfo->strinfo_list = NULL; + tapinfo->nstreams = 0; + tapinfo->npackets = 0; + } + + ++(tapinfo->launch_count); + + return; +} + +void rtpstream_reset_cb(void *arg) +{ + rtpstream_reset((rtpstream_tapinfo_t *)arg); +} + +/* +* rtpdump file format +* +* The file starts with the tool to be used for playing this file, +* the multicast/unicast receive address and the port. +* +* #!rtpplay1.0 224.2.0.1/3456\n +* +* This is followed by one binary header (RD_hdr_t) and one RD_packet_t +* structure for each received packet. All fields are in network byte +* order. We don't need the source IP address since we can do mapping +* based on SSRC. This saves (a little) space, avoids non-IPv4 +* problems and privacy/security concerns. The header is followed by +* the RTP/RTCP header and (optionally) the actual payload. +*/ + +#define RTPFILE_VERSION "1.0" + +/* +* Write a header to the current output file. +* The header consists of an identifying string, followed +* by a binary structure. +*/ +void rtp_write_header(rtp_stream_info_t *strinfo, FILE *file) +{ + guint32 start_sec; /* start of recording (GMT) (seconds) */ + guint32 start_usec; /* start of recording (GMT) (microseconds)*/ + guint32 source; /* network source (multicast address) */ + size_t sourcelen; + guint16 port; /* UDP port */ + guint16 padding; /* 2 padding bytes */ + + fprintf(file, "#!rtpplay%s %s/%u\n", RTPFILE_VERSION, + get_addr_name(&(strinfo->dest_addr)), + strinfo->dest_port); + + start_sec = g_htonl(strinfo->start_sec); + start_usec = g_htonl(strinfo->start_usec); + /* rtpdump only accepts guint32 as source, will be fake for IPv6 */ + memset(&source, 0, sizeof source); + sourcelen = strinfo->src_addr.len; + if (sourcelen > sizeof source) + sourcelen = sizeof source; + memcpy(&source, strinfo->src_addr.data, sourcelen); + port = g_htons(strinfo->src_port); + padding = 0; + + if (fwrite(&start_sec, 4, 1, file) == 0) + return; + if (fwrite(&start_usec, 4, 1, file) == 0) + return; + if (fwrite(&source, 4, 1, file) == 0) + return; + if (fwrite(&port, 2, 1, file) == 0) + return; + if (fwrite(&padding, 2, 1, file) == 0) + return; +} + +/* utility function for writing a sample to file in rtpdump -F dump format (.rtp)*/ +void rtp_write_sample(rtp_sample_t* sample, FILE* file) +{ + guint16 length; /* length of packet, including this header (may + be smaller than plen if not whole packet recorded) */ + guint16 plen; /* actual header+payload length for RTP, 0 for RTCP */ + guint32 offset; /* milliseconds since the start of recording */ + + length = g_htons(sample->header.frame_length + 8); + plen = g_htons(sample->header.frame_length); + offset = g_htonl(sample->header.rec_time); + + if (fwrite(&length, 2, 1, file) == 0) + return; + if (fwrite(&plen, 2, 1, file) == 0) + return; + if (fwrite(&offset, 4, 1, file) == 0) + return; + if (fwrite(sample->frame, sample->header.frame_length, 1, file) == 0) + return; +} + + +/****************************************************************************/ +/* whenever a RTP packet is seen by the tap listener */ +int rtpstream_packet(void *arg, packet_info *pinfo, epan_dissect_t *edt _U_, const void *arg2) +{ + rtpstream_tapinfo_t *tapinfo = (rtpstream_tapinfo_t *)arg; + const struct _rtp_info *rtpinfo = (const struct _rtp_info *)arg2; + rtp_stream_info_t tmp_strinfo; + rtp_stream_info_t *strinfo = NULL; + GList* list; + rtp_sample_t sample; + + struct _rtp_conversation_info *p_conv_data = NULL; + + /* gather infos on the stream this packet is part of */ + COPY_ADDRESS(&(tmp_strinfo.src_addr), &(pinfo->src)); + tmp_strinfo.src_port = pinfo->srcport; + COPY_ADDRESS(&(tmp_strinfo.dest_addr), &(pinfo->dst)); + tmp_strinfo.dest_port = pinfo->destport; + tmp_strinfo.ssrc = rtpinfo->info_sync_src; + tmp_strinfo.pt = rtpinfo->info_payload_type; + tmp_strinfo.info_payload_type_str = rtpinfo->info_payload_type_str; + + if (tapinfo->mode == TAP_ANALYSE) { + /* check whether we already have a stream with these parameters in the list */ + list = g_list_first(tapinfo->strinfo_list); + while (list) + { + if (rtp_stream_info_cmp(&tmp_strinfo, (rtp_stream_info_t*)(list->data))==0) + { + strinfo = (rtp_stream_info_t*)(list->data); /*found!*/ + break; + } + list = g_list_next(list); + } + + /* not in the list? then create a new entry */ + if (!strinfo) { + tmp_strinfo.npackets = 0; + tmp_strinfo.first_frame_num = pinfo->fd->num; + tmp_strinfo.start_sec = (guint32) pinfo->fd->abs_ts.secs; + tmp_strinfo.start_usec = pinfo->fd->abs_ts.nsecs/1000; + tmp_strinfo.start_rel_sec = (guint32) pinfo->fd->rel_ts.secs; + tmp_strinfo.start_rel_usec = pinfo->fd->rel_ts.nsecs/1000; + tmp_strinfo.tag_vlan_error = 0; + tmp_strinfo.tag_diffserv_error = 0; + tmp_strinfo.vlan_id = 0; + tmp_strinfo.problem = FALSE; + + /* reset RTP stats */ + tmp_strinfo.rtp_stats.first_packet = TRUE; + tmp_strinfo.rtp_stats.max_delta = 0; + tmp_strinfo.rtp_stats.max_jitter = 0; + tmp_strinfo.rtp_stats.mean_jitter = 0; + tmp_strinfo.rtp_stats.delta = 0; + tmp_strinfo.rtp_stats.diff = 0; + tmp_strinfo.rtp_stats.jitter = 0; + tmp_strinfo.rtp_stats.bandwidth = 0; + tmp_strinfo.rtp_stats.total_bytes = 0; + tmp_strinfo.rtp_stats.bw_start_index = 0; + tmp_strinfo.rtp_stats.bw_index = 0; + tmp_strinfo.rtp_stats.timestamp = 0; + tmp_strinfo.rtp_stats.max_nr = 0; + tmp_strinfo.rtp_stats.total_nr = 0; + tmp_strinfo.rtp_stats.sequence = 0; + tmp_strinfo.rtp_stats.start_seq_nr = 0; + tmp_strinfo.rtp_stats.stop_seq_nr = 0; + tmp_strinfo.rtp_stats.cycles = 0; + tmp_strinfo.rtp_stats.under = FALSE; + tmp_strinfo.rtp_stats.start_time = 0; + tmp_strinfo.rtp_stats.time = 0; + tmp_strinfo.rtp_stats.reg_pt = PT_UNDEFINED; + + /* Get the Setup frame number who set this RTP stream */ + p_conv_data = (struct _rtp_conversation_info *)p_get_proto_data(pinfo->fd, proto_get_id_by_filter_name("rtp"), 0); + if (p_conv_data) + tmp_strinfo.setup_frame_number = p_conv_data->frame_number; + else + tmp_strinfo.setup_frame_number = 0xFFFFFFFF; + + strinfo = g_new(rtp_stream_info_t,1); + *strinfo = tmp_strinfo; /* memberwise copy of struct */ + tapinfo->strinfo_list = g_list_append(tapinfo->strinfo_list, strinfo); + } + + /* get RTP stats for the packet */ + rtp_packet_analyse(&(strinfo->rtp_stats), pinfo, rtpinfo); + if (strinfo->rtp_stats.flags & STAT_FLAG_WRONG_TIMESTAMP + || strinfo->rtp_stats.flags & STAT_FLAG_WRONG_SEQ) + strinfo->problem = TRUE; + + + /* increment the packets counter for this stream */ + ++(strinfo->npackets); + strinfo->stop_rel_sec = (guint32) pinfo->fd->rel_ts.secs; + strinfo->stop_rel_usec = pinfo->fd->rel_ts.nsecs/1000; + + /* increment the packets counter of all streams */ + ++(tapinfo->npackets); + + return 1; /* refresh output */ + } + else if (tapinfo->mode == TAP_SAVE) { + if (rtp_stream_info_cmp(&tmp_strinfo, tapinfo->filter_stream_fwd)==0) { + /* XXX - what if rtpinfo->info_all_data_present is + FALSE, so that we don't *have* all the data? */ + sample.header.rec_time = + (pinfo->fd->abs_ts.nsecs/1000 + 1000000 - tapinfo->filter_stream_fwd->start_usec)/1000 + + (guint32) (pinfo->fd->abs_ts.secs - tapinfo->filter_stream_fwd->start_sec - 1)*1000; + sample.header.frame_length = rtpinfo->info_data_len; + sample.frame = rtpinfo->info_data; + rtp_write_sample(&sample, tapinfo->save_file); + } + } +#ifdef __GTK_H__ + else if (tapinfo->mode == TAP_MARK) { + if (rtp_stream_info_cmp(&tmp_strinfo, tapinfo->filter_stream_fwd)==0 + || rtp_stream_info_cmp(&tmp_strinfo, tapinfo->filter_stream_rev)==0) + { + cf_mark_frame(&cfile, pinfo->fd); + } + } +#endif + return 0; +} + + +typedef struct _key_value { + guint32 key; + guint32 value; +} key_value; + + +/* RTP sampling clock rates for fixed payload types as defined in + http://www.iana.org/assignments/rtp-parameters */ +static const key_value clock_map[] = { + {PT_PCMU, 8000}, + {PT_1016, 8000}, + {PT_G721, 8000}, + {PT_GSM, 8000}, + {PT_G723, 8000}, + {PT_DVI4_8000, 8000}, + {PT_DVI4_16000, 16000}, + {PT_LPC, 8000}, + {PT_PCMA, 8000}, + {PT_G722, 8000}, + {PT_L16_STEREO, 44100}, + {PT_L16_MONO, 44100}, + {PT_QCELP, 8000}, + {PT_CN, 8000}, + {PT_MPA, 90000}, + {PT_G728, 8000}, + {PT_G728, 8000}, + {PT_DVI4_11025, 11025}, + {PT_DVI4_22050, 22050}, + {PT_G729, 8000}, + {PT_CN_OLD, 8000}, + {PT_CELB, 90000}, + {PT_JPEG, 90000}, + {PT_NV, 90000}, + {PT_H261, 90000}, + {PT_MPV, 90000}, + {PT_MP2T, 90000}, + {PT_H263, 90000}, +}; + +#define NUM_CLOCK_VALUES (sizeof clock_map / sizeof clock_map[0]) + +static guint32 +get_clock_rate(guint32 key) +{ + size_t i; + + for (i = 0; i < NUM_CLOCK_VALUES; i++) { + if (clock_map[i].key == key) + return clock_map[i].value; + } + return 0; +} + +typedef struct _mimetype_and_clock { + const gchar *pt_mime_name_str; + guint32 value; +} mimetype_and_clock; +/* RTP sampling clock rates for + "In addition to the RTP payload formats (encodings) listed in the RTP + Payload Types table, there are additional payload formats that do not + have static RTP payload types assigned but instead use dynamic payload + type number assignment. Each payload format is named by a registered + MIME subtype" + http://www.iana.org/assignments/rtp-parameters. + + NOTE: Please keep the mimetypes in case insensitive alphabetical order. +*/ +static const mimetype_and_clock mimetype_and_clock_map[] = { + {"AMR", 8000}, /* [RFC4867][RFC3267] */ + {"AMR-WB", 16000}, /* [RFC4867][RFC3267] */ + {"BMPEG", 90000}, /* [RFC2343],[RFC3555] */ + {"BT656", 90000}, /* [RFC2431],[RFC3555] */ + {"DV", 90000}, /* [RFC3189] */ + {"EVRC", 8000}, /* [RFC3558] */ + {"EVRC0", 8000}, /* [RFC4788] */ + {"EVRC1", 8000}, /* [RFC4788] */ + {"EVRCB", 8000}, /* [RFC4788] */ + {"EVRCB0", 8000}, /* [RFC4788] */ + {"EVRCB1", 8000}, /* [RFC4788] */ + {"EVRCWB", 16000}, /* [RFC5188] */ + {"EVRCWB0", 16000}, /* [RFC5188] */ + {"EVRCWB1", 16000}, /* [RFC5188] */ + {"G7221", 16000}, /* [RFC3047] */ + {"G726-16", 8000}, /* [RFC3551][RFC4856] */ + {"G726-24", 8000}, /* [RFC3551][RFC4856] */ + {"G726-32", 8000}, /* [RFC3551][RFC4856] */ + {"G726-40", 8000}, /* [RFC3551][RFC4856] */ + {"G729D", 8000}, /* [RFC3551][RFC4856] */ + {"G729E", 8000}, /* [RFC3551][RFC4856] */ + {"GSM-EFR", 8000}, /* [RFC3551] */ + {"H263-1998", 90000}, /* [RFC2429],[RFC3555] */ + {"H263-2000", 90000}, /* [RFC2429],[RFC3555] */ + {"H264", 90000}, /* [RFC3984] */ + {"MP1S", 90000}, /* [RFC2250],[RFC3555] */ + {"MP2P", 90000}, /* [RFC2250],[RFC3555] */ + {"MP4V-ES", 90000}, /* [RFC3016] */ + {"mpa-robust", 90000}, /* [RFC3119] */ + {"pointer", 90000}, /* [RFC2862] */ + {"raw", 90000}, /* [RFC4175] */ + {"red", 1000}, /* [RFC4102] */ + {"SMV", 8000}, /* [RFC3558] */ + {"SMV0", 8000}, /* [RFC3558] */ + {"t140", 1000}, /* [RFC4103] */ + {"telephone-event", 8000}, /* [RFC4733] */ +}; + +#define NUM_DYN_CLOCK_VALUES (sizeof mimetype_and_clock_map / sizeof mimetype_and_clock_map[0]) + +static guint32 +get_dyn_pt_clock_rate(gchar *payload_type_str) +{ + int i; + + /* Search for matching mimetype in reverse order to avoid false matches + * when pt_mime_name_str is the prefix of payload_type_str */ + for (i = NUM_DYN_CLOCK_VALUES - 1; i > -1 ; i--) { + if (g_ascii_strncasecmp(mimetype_and_clock_map[i].pt_mime_name_str,payload_type_str,(strlen(mimetype_and_clock_map[i].pt_mime_name_str))) == 0) + return mimetype_and_clock_map[i].value; + } + + return 0; +} + +/****************************************************************************/ +int rtp_packet_analyse(tap_rtp_stat_t *statinfo, + packet_info *pinfo, + const struct _rtp_info *rtpinfo) +{ + double current_time; + double current_jitter; + double current_diff = 0; + double nominaltime; + double arrivaltime; /* Time relative to start_time */ + double expected_time; + double absskew; + guint32 clock_rate; + + /* Store the current time */ + current_time = nstime_to_msec(&pinfo->fd->rel_ts); + + /* Is this the first packet we got in this direction? */ + if (statinfo->first_packet) { + /* Save the MAC address of the first RTP frame */ + if( pinfo->dl_src.type == AT_ETHER){ + COPY_ADDRESS(&(statinfo->first_packet_mac_addr), &(pinfo->dl_src)); + } + statinfo->start_seq_nr = rtpinfo->info_seq_num; + statinfo->stop_seq_nr = rtpinfo->info_seq_num; + statinfo->seq_num = rtpinfo->info_seq_num; + statinfo->start_time = current_time; + statinfo->timestamp = rtpinfo->info_timestamp; + statinfo->first_timestamp = rtpinfo->info_timestamp; + statinfo->time = current_time; + statinfo->lastnominaltime = 0; + statinfo->pt = rtpinfo->info_payload_type; + statinfo->reg_pt = rtpinfo->info_payload_type; + statinfo->bw_history[statinfo->bw_index].bytes = rtpinfo->info_data_len + 28; + statinfo->bw_history[statinfo->bw_index].time = current_time; + statinfo->bw_index++; + statinfo->total_bytes += rtpinfo->info_data_len + 28; + statinfo->bandwidth = (double)(statinfo->total_bytes*8)/1000; + /* Not needed ? initialised to zero? */ + statinfo->delta = 0; + statinfo->jitter = 0; + statinfo->diff = 0; + + statinfo->total_nr++; + statinfo->flags |= STAT_FLAG_FIRST; + if (rtpinfo->info_marker_set) { + statinfo->flags |= STAT_FLAG_MARKER; + } + statinfo->first_packet = FALSE; + return 0; + } + + /* Reset flags */ + statinfo->flags = 0; + + /* Chek for duplicates (src mac differs from first_packet_mac_addr) */ + if( pinfo->dl_src.type == AT_ETHER){ + if(!ADDRESSES_EQUAL(&(statinfo->first_packet_mac_addr), &(pinfo->dl_src))){ + statinfo->flags |= STAT_FLAG_DUP_PKT; + statinfo->delta = current_time-(statinfo->time); + return 0; + } + } + + /* When calculating expected rtp packets the seq number can wrap around + * so we have to count the number of cycles + * Variable cycles counts the wraps around in forwarding connection and + * under is flag that indicates where we are + * + * XXX How to determine number of cycles with all possible lost, late + * and duplicated packets without any doubt? It seems to me, that + * because of all possible combination of late, duplicated or lost + * packets, this can only be more or less good approximation + * + * There are some combinations (rare but theoretically possible), + * where below code won't work correctly - statistic may be wrong then. + */ + + /* So if the current sequence number is less than the start one + * we assume, that there is another cycle running + */ + if ((rtpinfo->info_seq_num < statinfo->start_seq_nr) && (statinfo->under == FALSE)){ + statinfo->cycles++; + statinfo->under = TRUE; + } + /* what if the start seq nr was 0? Then the above condition will never + * be true, so we add another condition. XXX The problem would arise + * if one of the packets with seq nr 0 or 65535 would be lost or late + */ + else if ((rtpinfo->info_seq_num == 0) && (statinfo->stop_seq_nr == 65535) && + (statinfo->under == FALSE)){ + statinfo->cycles++; + statinfo->under = TRUE; + } + /* the whole round is over, so reset the flag */ + else if ((rtpinfo->info_seq_num > statinfo->start_seq_nr) && (statinfo->under != FALSE)) { + statinfo->under = FALSE; + } + + /* Since it is difficult to count lost, duplicate or late packets separately, + * we would like to know at least how many times the sequence number was not ok + */ + + /* If the current seq number equals the last one or if we are here for + * the first time, then it is ok, we just store the current one as the last one + */ + if ( (statinfo->seq_num+1 == rtpinfo->info_seq_num) || (statinfo->flags & STAT_FLAG_FIRST) ) + statinfo->seq_num = rtpinfo->info_seq_num; + /* If the first one is 65535 we wrap */ + else if ( (statinfo->seq_num == 65535) && (rtpinfo->info_seq_num == 0) ) + statinfo->seq_num = rtpinfo->info_seq_num; + /* Lost packets. If the prev seq is enourmously larger than the cur seq + * we assume that instead of being massively late we lost the packet(s) + * that would have indicated the sequence number wrapping. An imprecise + * heuristic at best, but it seems to work well enough. + * https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=5958 */ + else if (statinfo->seq_num+1 < rtpinfo->info_seq_num || statinfo->seq_num - rtpinfo->info_seq_num > 0xFF00) { + statinfo->seq_num = rtpinfo->info_seq_num; + statinfo->sequence++; + statinfo->flags |= STAT_FLAG_WRONG_SEQ; + } + /* Late or duplicated */ + else if (statinfo->seq_num+1 > rtpinfo->info_seq_num) { + statinfo->sequence++; + statinfo->flags |= STAT_FLAG_WRONG_SEQ; + } + + /* Check payload type */ + if (rtpinfo->info_payload_type == PT_CN + || rtpinfo->info_payload_type == PT_CN_OLD) + statinfo->flags |= STAT_FLAG_PT_CN; + if (statinfo->pt == PT_CN + || statinfo->pt == PT_CN_OLD) + statinfo->flags |= STAT_FLAG_FOLLOW_PT_CN; + if (rtpinfo->info_payload_type != statinfo->pt) + statinfo->flags |= STAT_FLAG_PT_CHANGE; + statinfo->pt = rtpinfo->info_payload_type; + + /* + * Return 0 for unknown payload types + * Ignore jitter calculation for clockrate = 0 + */ + if (statinfo->pt < 96 ){ + clock_rate = get_clock_rate(statinfo->pt); + }else{ /* Dynamic PT */ + if ( rtpinfo->info_payload_type_str != NULL ){ + /* Is it a "telephone-event" ? + * Timestamp is not increased for telepone-event packets impacting + * calculation of Jitter Skew and clock drift. + * see 2.2.1 of RFC 4733 + */ + if (g_ascii_strncasecmp("telephone-event",rtpinfo->info_payload_type_str,(strlen("telephone-event")))==0){ + clock_rate = 0; + statinfo->flags |= STAT_FLAG_PT_T_EVENT; + }else{ + if(rtpinfo->info_payload_rate !=0){ + clock_rate = rtpinfo->info_payload_rate; + }else{ + clock_rate = get_dyn_pt_clock_rate(rtpinfo-> info_payload_type_str); + } + } + }else{ + clock_rate = 0; + } + } + + /* Handle wraparound ? */ + arrivaltime = current_time - statinfo->start_time; + + if (statinfo->first_timestamp > rtpinfo->info_timestamp){ + /* Handle wraparound */ + nominaltime = (double)(rtpinfo->info_timestamp + 0xffffffff - statinfo->first_timestamp + 1); + }else{ + nominaltime = (double)(rtpinfo->info_timestamp - statinfo->first_timestamp); + } + + /* Can only analyze defined sampling rates */ + if (clock_rate != 0) { + statinfo->clock_rate = clock_rate; + /* Convert from sampling clock to ms */ + nominaltime = nominaltime /(clock_rate/1000); + + /* Calculate the current jitter(in ms) */ + if (!statinfo->first_packet) { + expected_time = statinfo->time + (nominaltime - statinfo->lastnominaltime); + current_diff = fabs(current_time - expected_time); + current_jitter = (15 * statinfo->jitter + current_diff) / 16; + + statinfo->delta = current_time-(statinfo->time); + statinfo->jitter = current_jitter; + statinfo->diff = current_diff; + } + statinfo->lastnominaltime = nominaltime; + /* Calculate skew, i.e. absolute jitter that also catches clock drift + * Skew is positive if TS (nominal) is too fast + */ + statinfo->skew = nominaltime - arrivaltime; + absskew = fabs(statinfo->skew); + if(absskew > fabs(statinfo->max_skew)){ + statinfo->max_skew = statinfo->skew; + } + /* Gather data for calculation of average, minimum and maximum framerate based on timestamp */ +#if 0 + if (numPackets > 0 && (!hardPayloadType || !alternatePayloadType)) { + /* Skip first packet and possibly alternate payload type packets */ + double dt; + dt = nominaltime - statinfo->lastnominaltime; + sumdt += 1.0 * dt; + numdt += (dt != 0 ? 1 : 0); + mindt = (dt < mindt ? dt : mindt); + maxdt = (dt > maxdt ? dt : maxdt); + } +#endif + /* Gather data for calculation of skew least square */ + statinfo->sumt += 1.0 * current_time; + statinfo->sumTS += 1.0 * nominaltime; + statinfo->sumt2 += 1.0 * current_time * current_time; + statinfo->sumtTS += 1.0 * current_time * nominaltime; + } + + /* Calculate the BW in Kbps adding the IP+UDP header to the RTP -> IP header+8bytes(UDP) */ + statinfo->bw_history[statinfo->bw_index].bytes = rtpinfo->info_data_len + pinfo->iphdrlen + 8; + statinfo->bw_history[statinfo->bw_index].time = current_time; + + /* Check if there are more than 1sec in the history buffer to calculate BW in bps. If so, remove those for the calculation */ + while ((statinfo->bw_history[statinfo->bw_start_index].time+1000/* ms */)<current_time){ + statinfo->total_bytes -= statinfo->bw_history[statinfo->bw_start_index].bytes; + statinfo->bw_start_index++; + if (statinfo->bw_start_index == BUFF_BW) statinfo->bw_start_index=0; + }; + /* IP hdr + UDP + RTP */ + statinfo->total_bytes += rtpinfo->info_data_len + pinfo->iphdrlen + 8; + statinfo->bandwidth = (double)(statinfo->total_bytes*8)/1000; + statinfo->bw_index++; + if (statinfo->bw_index == BUFF_BW) statinfo->bw_index = 0; + + + /* Is it a packet with the mark bit set? */ + if (rtpinfo->info_marker_set) { + statinfo->delta_timestamp = rtpinfo->info_timestamp - statinfo->timestamp; + if (rtpinfo->info_timestamp > statinfo->timestamp){ + statinfo->flags |= STAT_FLAG_MARKER; + } + else{ + statinfo->flags |= STAT_FLAG_WRONG_TIMESTAMP; + } + } + /* Is it a regular packet? */ + if (!(statinfo->flags & STAT_FLAG_FIRST) + && !(statinfo->flags & STAT_FLAG_MARKER) + && !(statinfo->flags & STAT_FLAG_PT_CN) + && !(statinfo->flags & STAT_FLAG_WRONG_TIMESTAMP) + && !(statinfo->flags & STAT_FLAG_FOLLOW_PT_CN)) { + /* Include it in maximum delta calculation */ + if (statinfo->delta > statinfo->max_delta) { + statinfo->max_delta = statinfo->delta; + statinfo->max_nr = pinfo->fd->num; + } + if (clock_rate != 0) { + /* Maximum and mean jitter calculation */ + if (statinfo->jitter > statinfo->max_jitter) { + statinfo->max_jitter = statinfo->jitter; + } + statinfo->mean_jitter = (statinfo->mean_jitter*statinfo->total_nr + current_diff) / (statinfo->total_nr+1); + } + } + /* Regular payload change? (CN ignored) */ + if (!(statinfo->flags & STAT_FLAG_FIRST) + && !(statinfo->flags & STAT_FLAG_PT_CN)) { + if ((statinfo->pt != statinfo->reg_pt) + && (statinfo->reg_pt != PT_UNDEFINED)) { + statinfo->flags |= STAT_FLAG_REG_PT_CHANGE; + } + } + + /* Set regular payload*/ + if (!(statinfo->flags & STAT_FLAG_PT_CN)) { + statinfo->reg_pt = statinfo->pt; + } + + statinfo->time = current_time; + statinfo->timestamp = rtpinfo->info_timestamp; + statinfo->stop_seq_nr = rtpinfo->info_seq_num; + statinfo->total_nr++; + + return 0; +} + +/* + * Editor modelines - http://www.wireshark.org/tools/modelines.html + * + * Local variables: + * c-basic-offset: 8 + * tab-width: 8 + * indent-tabs-mode: t + * End: + * + * vi: set shiftwidth=8 tabstop=8 noexpandtab: + * :indentSize=8:tabSize=8:noTabs=false: + */ diff --git a/ui/tap-rtp-common.h b/ui/tap-rtp-common.h new file mode 100644 index 0000000000..003f4f4771 --- /dev/null +++ b/ui/tap-rtp-common.h @@ -0,0 +1,43 @@ +/* tap-rtp-common.h + * RTP streams handler functions used by tshark and wireshark + * + * $Id$ + * + * Copyright 2008, Ericsson AB + * By Balint Reczey <balint.reczey@ericsson.com> + * + * most functions are copied from ui/gtk/rtp_stream.c and ui/gtk/rtp_analisys.c + * Copyright 2003, Alcatel Business Systems + * By Lars Ruoff <lars.ruoff@gmx.net> + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef TAP_RTP_COMMON_H_INCLUDED +#define TAP_RTP_COMMON_H_INCLUDED + +#include "ui/gtk/rtp_stream.h" + +gint rtp_stream_info_cmp(gconstpointer, gconstpointer); +void rtpstream_reset_cb(void*); +void rtp_write_header(rtp_stream_info_t*, FILE*); +void rtp_write_sample(rtp_sample_t*, FILE*); +int rtpstream_packet(void*, packet_info*, epan_dissect_t *, const void *); + +#endif /*TAP_RTP_COMMON_H_INCLUDED*/ |