2 * Routines for calculating statistics based on protocol.
4 * $Id: proto_hier_stats.c,v 1.23 2004/01/25 21:55:10 guy Exp $
6 * Ethereal - Network traffic analyzer
7 * By Gerald Combs <gerald@ethereal.com>
8 * Copyright 1998 Gerald Combs
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
30 #include "proto_hier_stats.h"
31 #include "progress_dlg.h"
32 #include "simple_dialog.h"
33 #include <epan/epan_dissect.h>
39 /* Update the progress bar this many times when scanning the packet list. */
40 #define N_PROGBAR_UPDATES 100
42 #define STAT_NODE_STATS(n) ((ph_stats_node_t*)(n)->data)
43 #define STAT_NODE_HFINFO(n) (STAT_NODE_STATS(n)->hfinfo)
46 find_stat_node(GNode *parent_stat_node, header_field_info *needle_hfinfo)
48 GNode *needle_stat_node;
49 header_field_info *hfinfo;
50 ph_stats_node_t *stats;
52 needle_stat_node = g_node_first_child(parent_stat_node);
54 while (needle_stat_node) {
55 hfinfo = STAT_NODE_HFINFO(needle_stat_node);
56 if (hfinfo && hfinfo->id == needle_hfinfo->id) {
57 return needle_stat_node;
59 needle_stat_node = g_node_next_sibling(needle_stat_node);
62 /* None found. Create one. */
63 stats = g_new(ph_stats_node_t, 1);
65 /* Intialize counters */
66 stats->hfinfo = needle_hfinfo;
67 stats->num_pkts_total = 0;
68 stats->num_pkts_last = 0;
69 stats->num_bytes_total = 0;
70 stats->num_bytes_last = 0;
72 needle_stat_node = g_node_new(stats);
73 g_node_append(parent_stat_node, needle_stat_node);
74 return needle_stat_node;
79 process_node(proto_node *ptree_node, GNode *parent_stat_node, ph_stats_t *ps, guint pkt_len)
82 ph_stats_node_t *stats;
83 proto_node *proto_sibling_node;
86 finfo = PITEM_FINFO(ptree_node);
89 stat_node = find_stat_node(parent_stat_node, finfo->hfinfo);
91 /* Assert that the finfo is related to a protocol, not a field. */
92 g_assert(finfo->hfinfo->parent == -1);
94 stats = STAT_NODE_STATS(stat_node);
95 stats->num_pkts_total++;
96 stats->num_bytes_total += pkt_len;
98 proto_sibling_node = ptree_node->next;
100 if (proto_sibling_node) {
101 process_node(proto_sibling_node, stat_node, ps, pkt_len);
104 stats->num_pkts_last++;
105 stats->num_bytes_last += pkt_len;
112 process_tree(proto_tree *protocol_tree, ph_stats_t* ps, guint pkt_len)
114 proto_node *ptree_node;
116 ptree_node = ((proto_node *)protocol_tree)->first_child;
121 process_node(ptree_node, ps->stats_tree, ps, pkt_len);
125 process_frame(frame_data *frame, column_info *cinfo, ph_stats_t* ps)
128 union wtap_pseudo_header phdr;
129 guint8 pd[WTAP_MAX_PACKET_SIZE];
133 /* Load the frame from the capture file */
134 if (!wtap_seek_read(cfile.wth, frame->file_off, &phdr, pd,
135 frame->cap_len, &err, &err_info)) {
136 simple_dialog(ESD_TYPE_CRIT, NULL,
137 cf_read_error_message(err, err_info), cfile.filename);
138 return FALSE; /* failure */
141 /* Dissect the frame */
142 edt = epan_dissect_new(TRUE, FALSE);
143 epan_dissect_run(edt, &phdr, pd, frame, cinfo);
145 /* Get stats from this protocol tree */
146 process_tree(edt->tree, ps, frame->pkt_len);
148 /* Free our memory. */
149 epan_dissect_free(edt);
151 return TRUE; /* success */
161 guint tot_packets, tot_bytes;
162 progdlg_t *progbar = NULL;
167 gchar status_str[100];
168 int progbar_nextstep;
171 /* Initialize the data */
172 ps = g_new(ph_stats_t, 1);
175 ps->stats_tree = g_node_new(NULL);
177 /* Update the progress bar when it gets to this value. */
178 progbar_nextstep = 0;
179 /* When we reach the value that triggers a progress bar update,
180 bump that value by this amount. */
181 progbar_quantum = cfile.count/N_PROGBAR_UPDATES;
182 /* Count of packets at which we've looked. */
186 g_get_current_time(&start_time);
191 for (frame = cfile.plist; frame != NULL; frame = frame->next) {
192 /* Update the progress bar, but do it only N_PROGBAR_UPDATES
193 times; when we update it, we have to run the GTK+ main
194 loop to get it to repaint what's pending, and doing so
195 may involve an "ioctl()" to see if there's any pending
196 input from an X server, and doing that for every packet
197 can be costly, especially on a big file. */
198 if (count >= progbar_nextstep) {
199 /* let's not divide by zero. I should never be started
200 * with count == 0, so let's assert that
202 g_assert(cfile.count > 0);
204 prog_val = (gfloat) count / cfile.count;
207 /* Create the progress bar if necessary */
208 progbar = delayed_create_progress_dlg(
209 "Computing", "protocol hierarchy statistics",
210 &stop_flag, &start_time, prog_val);
212 if (progbar != NULL) {
213 g_snprintf(status_str, sizeof(status_str),
214 "%4u of %u frames", count, cfile.count);
215 update_progress_dlg(progbar, prog_val, status_str);
218 progbar_nextstep += progbar_quantum;
222 /* Well, the user decided to abort the statistics.
223 computation process Just stop. */
227 /* Skip frames that are hidden due to the display filter.
228 XXX - should the progress bar count only packets that
229 passed the display filter? If so, it should
230 probably do so for other loops (see "file.c") that
231 look only at those packets. */
232 if (frame->flags.passed_dfilter) {
233 if (!process_frame(frame, &cfile.cinfo, ps)) {
235 * Give up, and set "stop_flag" so we
236 * just abort rather than popping up
237 * the statistics window.
244 tot_bytes += frame->pkt_len;
250 /* We're done calculating the statistics; destroy the progress bar
251 if it was created. */
253 destroy_progress_dlg(progbar);
257 * We quit in the middle; throw away the statistics
258 * and return NULL, so our caller doesn't pop up a
259 * window with the incomplete statistics.
265 ps->tot_packets = tot_packets;
266 ps->tot_bytes = tot_bytes;
272 stat_node_free(GNode *node, gpointer data _U_)
274 ph_stats_node_t *stats = node->data;
283 ph_stats_free(ph_stats_t *ps)
286 if (ps->stats_tree) {
287 g_node_traverse(ps->stats_tree, G_IN_ORDER,
289 stat_node_free, NULL);
290 g_node_destroy(ps->stats_tree);