2 * Routines for calculating statistics based on protocol.
4 * $Id: proto_hier_stats.c,v 1.10 2002/01/02 20:23:46 gram 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.
31 #include "proto_hier_stats.h"
32 #include "progress_dlg.h"
33 #include "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_item *ptree_node, GNode *parent_stat_node, ph_stats_t *ps, guint pkt_len)
82 ph_stats_node_t *stats;
83 proto_item *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 = g_node_next_sibling(ptree_node);
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_item *ptree_node;
116 ptree_node = g_node_first_child(protocol_tree);
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];
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(TRUE, FALSE);
137 epan_dissect_run(edt, &phdr, pd, frame, cinfo);
139 /* Get stats from this protocol tree */
140 process_tree(edt->tree, ps, frame->pkt_len);
142 /* Free our memory. */
143 epan_dissect_free(edt);
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, &cfile.cinfo, 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);