/* proto_hier_stats.c
* Routines for calculating statistics based on protocol.
*
- * $Id: proto_hier_stats.c,v 1.9 2001/12/31 20:40:32 gerald Exp $
+ * $Id$
*
- * Ethereal - Network traffic analyzer
- * By Gerald Combs <gerald@ethereal.com>
+ * 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
*
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
+#include "config.h"
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
+#include <stdio.h>
#include "globals.h"
#include "proto_hier_stats.h"
-#include "progress_dlg.h"
-#include "epan_dissect.h"
+#include "ui/progress_dlg.h"
+#include <epan/epan_dissect.h>
#include <wtap.h>
#include <stdio.h>
+#include <string.h>
#include <glib.h>
/* Update the progress bar this many times when scanning the packet list. */
#define N_PROGBAR_UPDATES 100
+#define STAT_NODE_STATS(n) ((ph_stats_node_t*)(n)->data)
+#define STAT_NODE_HFINFO(n) (STAT_NODE_STATS(n)->hfinfo)
+
+
static GNode*
-find_stat_node(GNode *parent_node, header_field_info *needle_hfinfo)
+find_stat_node(GNode *parent_stat_node, header_field_info *needle_hfinfo)
{
- GNode *needle_node;
- field_info *finfo;
- ph_stats_node_t *stats;
+ GNode *needle_stat_node;
+ header_field_info *hfinfo;
+ ph_stats_node_t *stats;
- needle_node = g_node_first_child(parent_node);
+ needle_stat_node = g_node_first_child(parent_stat_node);
- while (needle_node) {
- finfo = GNODE_PNODE(needle_node);
- if (finfo && finfo->hfinfo && finfo->hfinfo->id == needle_hfinfo->id) {
- return needle_node;
+ while (needle_stat_node) {
+ hfinfo = STAT_NODE_HFINFO(needle_stat_node);
+ if (hfinfo && hfinfo->id == needle_hfinfo->id) {
+ return needle_stat_node;
}
- needle_node = g_node_next_sibling(needle_node);
+ needle_stat_node = g_node_next_sibling(needle_stat_node);
}
/* None found. Create one. */
stats->num_bytes_total = 0;
stats->num_bytes_last = 0;
- needle_node = g_node_new(stats);
- g_node_append(parent_node, needle_node);
- return needle_node;
+ needle_stat_node = g_node_new(stats);
+ g_node_append(parent_stat_node, needle_stat_node);
+ return needle_stat_node;
}
static void
-process_node(proto_item *ptree_node, GNode *parent_stat_node, ph_stats_t *ps, guint pkt_len)
+process_node(proto_node *ptree_node, GNode *parent_stat_node, ph_stats_t *ps, guint pkt_len)
{
field_info *finfo;
- ph_stats_node_t *stats;
- proto_item *proto_sibling_node;
+ ph_stats_node_t *stats;
+ proto_node *proto_sibling_node;
GNode *stat_node;
- finfo = PITEM_FINFO(ptree_node);
+ finfo = PNODE_FINFO(ptree_node);
+ /* We don't fake protocol nodes we expect them to have a field_info.
+ * Dissection with faked proto tree? */
g_assert(finfo);
- stat_node = find_stat_node(parent_stat_node, finfo->hfinfo);
-
- /* Assert that the finfo is related to a protocol, not a field. */
- g_assert(finfo->hfinfo->parent == -1);
-
- stats = stat_node->data;
- stats->num_pkts_total++;
- stats->num_bytes_total += pkt_len;
+ /* If the field info isn't related to a protocol but to a field,
+ * don't count them, as they don't belong to any protocol.
+ * (happens e.g. for toplevel tree item of desegmentation "[Reassembled TCP Segments]") */
+ if (finfo->hfinfo->parent != -1) {
+ /* Skip this element, use parent status node */
+ stat_node = parent_stat_node;
+ stats = STAT_NODE_STATS(stat_node);
+ } else {
+ stat_node = find_stat_node(parent_stat_node, finfo->hfinfo);
+
+ stats = STAT_NODE_STATS(stat_node);
+ stats->num_pkts_total++;
+ stats->num_bytes_total += pkt_len;
+ }
- proto_sibling_node = g_node_next_sibling(ptree_node);
+ proto_sibling_node = ptree_node->next;
if (proto_sibling_node) {
+ /* If the name does not exist for this proto_sibling_node, then it is
+ * not a normal protocol in the top-level tree. It was instead
+ * added as a normal tree such as IPv6's Hop-by-hop Option Header and
+ * should be skipped when creating the protocol hierarchy display. */
+ if(strlen(PNODE_FINFO(proto_sibling_node)->hfinfo->name) == 0 && ptree_node->next)
+ proto_sibling_node = proto_sibling_node->next;
+
process_node(proto_sibling_node, stat_node, ps, pkt_len);
- }
- else {
+ } else {
stats->num_pkts_last++;
stats->num_bytes_last += pkt_len;
}
static void
process_tree(proto_tree *protocol_tree, ph_stats_t* ps, guint pkt_len)
{
- proto_item *ptree_node;
+ proto_node *ptree_node;
- ptree_node = g_node_first_child(protocol_tree);
+ ptree_node = ((proto_node *)protocol_tree)->first_child;
if (!ptree_node) {
return;
}
process_node(ptree_node, ps->stats_tree, ps, pkt_len);
}
-static void
+static gboolean
process_frame(frame_data *frame, column_info *cinfo, ph_stats_t* ps)
{
- epan_dissect_t *edt;
- union wtap_pseudo_header phdr;
+ epan_dissect_t edt;
+ struct wtap_pkthdr phdr;
guint8 pd[WTAP_MAX_PACKET_SIZE];
+ double cur_time;
/* Load the frame from the capture file */
- wtap_seek_read(cfile.wth, frame->file_off, &phdr,
- pd, frame->cap_len);
+ if (!cf_read_frame_r(&cfile, frame, &phdr, pd))
+ return FALSE; /* failure */
- /* Dissect the frame */
- edt = epan_dissect_new(TRUE, FALSE);
- epan_dissect_run(edt, &phdr, pd, frame, cinfo);
+ /* Dissect the frame tree not visible */
+ epan_dissect_init(&edt, TRUE, FALSE);
+ /* Don't fake protocols. We need them for the protocol hierarchy */
+ epan_dissect_fake_protocols(&edt, FALSE);
+ epan_dissect_run(&edt, &phdr, pd, frame, cinfo);
/* Get stats from this protocol tree */
- process_tree(edt->tree, ps, frame->pkt_len);
+ process_tree(edt.tree, ps, frame->pkt_len);
- /* Free our memory. */
- epan_dissect_free(edt);
-}
+ /* Update times */
+ cur_time = nstime_to_sec(&frame->abs_ts);
+ if (cur_time < ps->first_time) {
+ ps->first_time = cur_time;
+ }
+ if (cur_time > ps->last_time){
+ ps->last_time = cur_time;
+ }
+ /* Free our memory. */
+ epan_dissect_cleanup(&edt);
+ return TRUE; /* success */
+}
ph_stats_t*
ph_stats_new(void)
{
ph_stats_t *ps;
+ guint32 framenum;
frame_data *frame;
guint tot_packets, tot_bytes;
- progdlg_t *progbar;
+ progdlg_t *progbar = NULL;
gboolean stop_flag;
- guint32 progbar_quantum;
- guint32 progbar_nextstep;
- unsigned int count;
+ int count;
+ float progbar_val;
+ GTimeVal start_time;
+ gchar status_str[100];
+ int progbar_nextstep;
+ int progbar_quantum;
/* Initialize the data */
ps = g_new(ph_stats_t, 1);
ps->tot_packets = 0;
ps->tot_bytes = 0;
ps->stats_tree = g_node_new(NULL);
+ ps->first_time = 0.0;
+ ps->last_time = 0.0;
/* Update the progress bar when it gets to this value. */
progbar_nextstep = 0;
progbar_quantum = cfile.count/N_PROGBAR_UPDATES;
/* Count of packets at which we've looked. */
count = 0;
+ /* Progress so far. */
+ progbar_val = 0.0f;
stop_flag = FALSE;
- progbar = create_progress_dlg("Computing protocol statistics", "Stop",
- &stop_flag);
+ g_get_current_time(&start_time);
tot_packets = 0;
tot_bytes = 0;
- for (frame = cfile.plist; frame != NULL; frame = frame->next) {
+ for (framenum = 1; framenum <= cfile.count; framenum++) {
+ frame = frame_data_sequence_find(cfile.frames, framenum);
+
+ /* Create the progress bar if necessary.
+ We check on every iteration of the loop, so that
+ it takes no longer than the standard time to create
+ it (otherwise, for a large file, we might take
+ considerably longer than that standard time in order
+ to get to the next progress bar step). */
+ if (progbar == NULL)
+ progbar = delayed_create_progress_dlg(
+ cfile.window, "Computing",
+ "protocol hierarchy statistics",
+ TRUE, &stop_flag, &start_time, progbar_val);
+
/* Update the progress bar, but do it only N_PROGBAR_UPDATES
times; when we update it, we have to run the GTK+ main
loop to get it to repaint what's pending, and doing so
*/
g_assert(cfile.count > 0);
- update_progress_dlg(progbar,
- (gfloat) count / cfile.count);
+ progbar_val = (gfloat) count / cfile.count;
+
+ if (progbar != NULL) {
+ g_snprintf(status_str, sizeof(status_str),
+ "%4u of %u frames", count, cfile.count);
+ update_progress_dlg(progbar, progbar_val, status_str);
+ }
progbar_nextstep += progbar_quantum;
}
probably do so for other loops (see "file.c") that
look only at those packets. */
if (frame->flags.passed_dfilter) {
- process_frame(frame, &cfile.cinfo, ps);
+
+ if (tot_packets == 0) {
+ double cur_time = nstime_to_sec(&frame->abs_ts);
+ ps->first_time = cur_time;
+ ps->last_time = cur_time;
+ }
+
+ /* we don't care about colinfo */
+ if (!process_frame(frame, NULL, ps)) {
+ /*
+ * Give up, and set "stop_flag" so we
+ * just abort rather than popping up
+ * the statistics window.
+ */
+ stop_flag = TRUE;
+ break;
+ }
tot_packets++;
tot_bytes += frame->pkt_len;
count++;
}
- /* We're done calculating the statistics; destroy the progress bar. */
- destroy_progress_dlg(progbar);
+ /* We're done calculating the statistics; destroy the progress bar
+ if it was created. */
+ if (progbar != NULL)
+ destroy_progress_dlg(progbar);
if (stop_flag) {
/*
}
static gboolean
-stat_node_free(GNode *node, gpointer data)
+stat_node_free(GNode *node, gpointer data _U_)
{
- ph_stats_node_t *stats = node->data;
+ ph_stats_node_t *stats = (ph_stats_node_t *)node->data;
if (stats) {
g_free(stats);