2 * Routines for calculating statistics based on protocol.
4 * $Id: proto_hier_stats.c,v 1.3 2001/03/24 02:07:20 guy Exp $
6 * Ethereal - Network traffic analyzer
7 * By Gerald Combs <gerald@zing.org>
8 * Copyright 1998 Gerald Combs
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version 2
14 * of the License, or (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
32 #include "proto_hier_stats.h"
33 #include "progress_dlg.h"
39 /* Update the progress bar this many times when scanning the packet list. */
40 #define N_PROGBAR_UPDATES 100
43 find_stat_node(GNode *parent_node, header_field_info *needle_hfinfo)
47 ph_stats_node_t *stats;
49 needle_node = g_node_first_child(parent_node);
52 finfo = needle_node->data;
53 if (finfo && finfo->hfinfo && finfo->hfinfo->id == needle_hfinfo->id) {
56 needle_node = g_node_next_sibling(needle_node);
59 /* None found. Create one. */
60 stats = g_new(ph_stats_node_t, 1);
62 /* Intialize counters */
63 stats->hfinfo = needle_hfinfo;
64 stats->num_pkts_total = 0;
65 stats->num_pkts_last = 0;
66 stats->num_bytes_total = 0;
67 stats->num_bytes_last = 0;
69 needle_node = g_node_new(stats);
70 g_node_append(parent_node, needle_node);
76 process_node(proto_item *proto_node, GNode *parent_stat_node, ph_stats_t *ps, guint pkt_len)
79 ph_stats_node_t *stats;
80 proto_item *proto_sibling_node;
83 finfo = proto_node->data;
86 stat_node = find_stat_node(parent_stat_node, finfo->hfinfo);
88 /* Assert that the finfo is related to a protocol, not a field. */
89 g_assert(finfo->hfinfo->parent == -1);
91 stats = stat_node->data;
92 stats->num_pkts_total++;
93 stats->num_bytes_total += pkt_len;
95 proto_sibling_node = g_node_next_sibling(proto_node);
97 if (proto_sibling_node) {
98 process_node(proto_sibling_node, stat_node, ps, pkt_len);
101 stats->num_pkts_last++;
102 stats->num_bytes_last += pkt_len;
109 process_tree(proto_tree *protocol_tree, ph_stats_t* ps, guint pkt_len)
111 proto_item *proto_node;
113 proto_node = g_node_first_child(protocol_tree);
118 process_node(proto_node, ps->stats_tree, ps, pkt_len);
122 process_frame(frame_data *frame, ph_stats_t* ps)
125 union wtap_pseudo_header phdr;
126 proto_tree *protocol_tree;
127 guint8 pd[WTAP_MAX_PACKET_SIZE];
129 protocol_tree = proto_tree_create_root();
131 /* Load the frame from the capture file */
132 wtap_seek_read(cfile.wth, frame->file_off, &phdr,
135 /* Dissect the frame */
136 edt = epan_dissect_new(&phdr, pd, frame, protocol_tree);
138 /* Get stats from this protocol tree */
139 process_tree(protocol_tree, ps, frame->pkt_len);
141 /* Free our memory. */
142 epan_dissect_free(edt);
143 proto_tree_free(protocol_tree);
153 guint tot_packets, tot_bytes;
156 guint32 progbar_quantum;
157 guint32 progbar_nextstep;
160 /* Initialize the data */
161 ps = g_new(ph_stats_t, 1);
164 ps->stats_tree = g_node_new(NULL);
166 /* Update the progress bar when it gets to this value. */
167 progbar_nextstep = 0;
168 /* When we reach the value that triggers a progress bar update,
169 bump that value by this amount. */
170 progbar_quantum = cfile.count/N_PROGBAR_UPDATES;
171 /* Count of packets at which we've looked. */
175 progbar = create_progress_dlg("Computing protocol statistics", "Stop",
181 for (frame = cfile.plist; frame != NULL; frame = frame->next) {
182 /* Update the progress bar, but do it only N_PROGBAR_UPDATES
183 times; when we update it, we have to run the GTK+ main
184 loop to get it to repaint what's pending, and doing so
185 may involve an "ioctl()" to see if there's any pending
186 input from an X server, and doing that for every packet
187 can be costly, especially on a big file. */
188 if (count >= progbar_nextstep) {
189 /* let's not divide by zero. I should never be started
190 * with count == 0, so let's assert that
192 g_assert(cfile.count > 0);
194 update_progress_dlg(progbar,
195 (gfloat) count / cfile.count);
197 progbar_nextstep += progbar_quantum;
201 /* Well, the user decided to abort the statistics.
202 computation process Just stop. */
206 /* Skip frames that are hidden due to the display filter.
207 XXX - should the progress bar count only packets that
208 passed the display filter? If so, it should
209 probably do so for other loops (see "file.c") that
210 look only at those packets. */
211 if (frame->flags.passed_dfilter) {
212 process_frame(frame, ps);
215 tot_bytes += frame->pkt_len;
221 /* We're done calculating the statistics; destroy the progress bar. */
222 destroy_progress_dlg(progbar);
226 * We quit in the middle; throw away the statistics
227 * and return NULL, so our caller doesn't pop up a
228 * window with the incomplete statistics.
234 ps->tot_packets = tot_packets;
235 ps->tot_bytes = tot_bytes;
241 stat_node_free(GNode *node, gpointer data)
243 ph_stats_node_t *stats = node->data;
252 ph_stats_free(ph_stats_t *ps)
255 if (ps->stats_tree) {
256 g_node_traverse(ps->stats_tree, G_IN_ORDER,
258 stat_node_free, NULL);
259 g_node_destroy(ps->stats_tree);