2 * Routines for calculating statistics based on protocol.
4 * $Id: proto_hier_stats.c,v 1.16 2002/08/28 21:00:41 jmayer 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 <epan/epan_dissect.h>
38 /* Update the progress bar this many times when scanning the packet list. */
39 #define N_PROGBAR_UPDATES 100
41 #define STAT_NODE_STATS(n) ((ph_stats_node_t*)(n)->data)
42 #define STAT_NODE_HFINFO(n) (STAT_NODE_STATS(n)->hfinfo)
45 find_stat_node(GNode *parent_stat_node, header_field_info *needle_hfinfo)
47 GNode *needle_stat_node;
48 header_field_info *hfinfo;
49 ph_stats_node_t *stats;
51 needle_stat_node = g_node_first_child(parent_stat_node);
53 while (needle_stat_node) {
54 hfinfo = STAT_NODE_HFINFO(needle_stat_node);
55 if (hfinfo && hfinfo->id == needle_hfinfo->id) {
56 return needle_stat_node;
58 needle_stat_node = g_node_next_sibling(needle_stat_node);
61 /* None found. Create one. */
62 stats = g_new(ph_stats_node_t, 1);
64 /* Intialize counters */
65 stats->hfinfo = needle_hfinfo;
66 stats->num_pkts_total = 0;
67 stats->num_pkts_last = 0;
68 stats->num_bytes_total = 0;
69 stats->num_bytes_last = 0;
71 needle_stat_node = g_node_new(stats);
72 g_node_append(parent_stat_node, needle_stat_node);
73 return needle_stat_node;
78 process_node(proto_item *ptree_node, GNode *parent_stat_node, ph_stats_t *ps, guint pkt_len)
81 ph_stats_node_t *stats;
82 proto_item *proto_sibling_node;
85 finfo = PITEM_FINFO(ptree_node);
88 stat_node = find_stat_node(parent_stat_node, finfo->hfinfo);
90 /* Assert that the finfo is related to a protocol, not a field. */
91 g_assert(finfo->hfinfo->parent == -1);
93 stats = STAT_NODE_STATS(stat_node);
94 stats->num_pkts_total++;
95 stats->num_bytes_total += pkt_len;
97 proto_sibling_node = g_node_next_sibling(ptree_node);
99 if (proto_sibling_node) {
100 process_node(proto_sibling_node, stat_node, ps, pkt_len);
103 stats->num_pkts_last++;
104 stats->num_bytes_last += pkt_len;
111 process_tree(proto_tree *protocol_tree, ph_stats_t* ps, guint pkt_len)
113 proto_item *ptree_node;
115 ptree_node = g_node_first_child(protocol_tree);
120 process_node(ptree_node, ps->stats_tree, ps, pkt_len);
124 process_frame(frame_data *frame, column_info *cinfo, ph_stats_t* ps)
127 union wtap_pseudo_header phdr;
128 guint8 pd[WTAP_MAX_PACKET_SIZE];
131 /* Load the frame from the capture file */
132 /* XX - do something with "err" */
133 wtap_seek_read(cfile.wth, frame->file_off, &phdr,
134 pd, frame->cap_len, &err);
136 /* Dissect the frame */
137 edt = epan_dissect_new(TRUE, FALSE);
138 epan_dissect_run(edt, &phdr, pd, frame, cinfo);
140 /* Get stats from this protocol tree */
141 process_tree(edt->tree, ps, frame->pkt_len);
143 /* Free our memory. */
144 epan_dissect_free(edt);
154 guint tot_packets, tot_bytes;
155 progdlg_t *progbar = NULL;
160 gchar status_str[100];
162 /* Initialize the data */
163 ps = g_new(ph_stats_t, 1);
166 ps->stats_tree = g_node_new(NULL);
168 /* Update the progress bar when it gets to this value. */
169 cfile.progbar_nextstep = 0;
170 /* When we reach the value that triggers a progress bar update,
171 bump that value by this amount. */
172 cfile.progbar_quantum = cfile.count/N_PROGBAR_UPDATES;
173 /* Count of packets at which we've looked. */
177 g_get_current_time(&start_time);
182 for (frame = cfile.plist; frame != NULL; frame = frame->next) {
183 /* Update the progress bar, but do it only N_PROGBAR_UPDATES
184 times; when we update it, we have to run the GTK+ main
185 loop to get it to repaint what's pending, and doing so
186 may involve an "ioctl()" to see if there's any pending
187 input from an X server, and doing that for every packet
188 can be costly, especially on a big file. */
189 if (count >= cfile.progbar_nextstep) {
190 /* let's not divide by zero. I should never be started
191 * with count == 0, so let's assert that
193 g_assert(cfile.count > 0);
195 prog_val = (gfloat) count / cfile.count;
198 /* Create the progress bar if necessary */
199 progbar = delayed_create_progress_dlg(
200 "Computing", "protocol hierarchy statistics", "Stop",
201 &stop_flag, &start_time, prog_val);
203 if (progbar != NULL) {
204 g_snprintf(status_str, sizeof(status_str),
205 "%4u of %u frames", count, cfile.count);
206 update_progress_dlg(progbar, prog_val, status_str);
209 cfile.progbar_nextstep += cfile.progbar_quantum;
213 /* Well, the user decided to abort the statistics.
214 computation process Just stop. */
218 /* Skip frames that are hidden due to the display filter.
219 XXX - should the progress bar count only packets that
220 passed the display filter? If so, it should
221 probably do so for other loops (see "file.c") that
222 look only at those packets. */
223 if (frame->flags.passed_dfilter) {
224 process_frame(frame, &cfile.cinfo, ps);
227 tot_bytes += frame->pkt_len;
233 /* We're done calculating the statistics; destroy the progress bar
234 if it was created. */
236 destroy_progress_dlg(progbar);
240 * We quit in the middle; throw away the statistics
241 * and return NULL, so our caller doesn't pop up a
242 * window with the incomplete statistics.
248 ps->tot_packets = tot_packets;
249 ps->tot_bytes = tot_bytes;
255 stat_node_free(GNode *node, gpointer data _U_)
257 ph_stats_node_t *stats = node->data;
266 ph_stats_free(ph_stats_t *ps)
269 if (ps->stats_tree) {
270 g_node_traverse(ps->stats_tree, G_IN_ORDER,
272 stat_node_free, NULL);
273 g_node_destroy(ps->stats_tree);