2 * Routines for calculating statistics based on protocol.
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 secs_usecs(guint32 s, guint32 us)
48 return (us / 1000000.0) + (double)s;
52 find_stat_node(GNode *parent_stat_node, header_field_info *needle_hfinfo)
54 GNode *needle_stat_node;
55 header_field_info *hfinfo;
56 ph_stats_node_t *stats;
58 needle_stat_node = g_node_first_child(parent_stat_node);
60 while (needle_stat_node) {
61 hfinfo = STAT_NODE_HFINFO(needle_stat_node);
62 if (hfinfo && hfinfo->id == needle_hfinfo->id) {
63 return needle_stat_node;
65 needle_stat_node = g_node_next_sibling(needle_stat_node);
68 /* None found. Create one. */
69 stats = g_new(ph_stats_node_t, 1);
71 /* Intialize counters */
72 stats->hfinfo = needle_hfinfo;
73 stats->num_pkts_total = 0;
74 stats->num_pkts_last = 0;
75 stats->num_bytes_total = 0;
76 stats->num_bytes_last = 0;
78 needle_stat_node = g_node_new(stats);
79 g_node_append(parent_stat_node, needle_stat_node);
80 return needle_stat_node;
85 process_node(proto_node *ptree_node, GNode *parent_stat_node, ph_stats_t *ps, guint pkt_len)
88 ph_stats_node_t *stats;
89 proto_node *proto_sibling_node;
92 finfo = PITEM_FINFO(ptree_node);
95 /* if the field info isn't related to a protocol but to a field, don't count them,
96 * as they don't belong to any protocol.
97 * (happens e.g. for toplevel tree item of desegmentation "[Reassembled TCP Segments]") */
98 if(finfo->hfinfo->parent != -1) {
99 /* there are some cases where helpful generated items are added
100 * to the decode tree so do not test for it any more
101 *g_assert(PROTO_ITEM_IS_GENERATED(ptree_node));
106 stat_node = find_stat_node(parent_stat_node, finfo->hfinfo);
108 stats = STAT_NODE_STATS(stat_node);
109 stats->num_pkts_total++;
110 stats->num_bytes_total += pkt_len;
112 proto_sibling_node = ptree_node->next;
114 if (proto_sibling_node) {
115 process_node(proto_sibling_node, stat_node, ps, pkt_len);
118 stats->num_pkts_last++;
119 stats->num_bytes_last += pkt_len;
126 process_tree(proto_tree *protocol_tree, ph_stats_t* ps, guint pkt_len)
128 proto_node *ptree_node;
130 ptree_node = ((proto_node *)protocol_tree)->first_child;
135 process_node(ptree_node, ps->stats_tree, ps, pkt_len);
139 process_frame(frame_data *frame, column_info *cinfo, ph_stats_t* ps)
142 union wtap_pseudo_header phdr;
143 guint8 pd[WTAP_MAX_PACKET_SIZE];
148 /* Load the frame from the capture file */
149 if (!wtap_seek_read(cfile.wth, frame->file_off, &phdr, pd,
150 frame->cap_len, &err, &err_info)) {
151 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
152 cf_read_error_message(err, err_info), cfile.filename);
153 return FALSE; /* failure */
156 /* Dissect the frame tree not visible */
157 edt = epan_dissect_new(TRUE, FALSE);
158 epan_dissect_run(edt, &phdr, pd, frame, cinfo);
160 /* Get stats from this protocol tree */
161 process_tree(edt->tree, ps, frame->pkt_len);
164 cur_time = secs_usecs(frame->abs_secs, frame->abs_usecs);
165 if (cur_time < ps->first_time) {
166 ps->first_time = cur_time;
168 if (cur_time > ps->last_time){
169 ps->last_time = cur_time;
172 /* Free our memory. */
173 epan_dissect_free(edt);
175 return TRUE; /* success */
183 guint tot_packets, tot_bytes;
184 progdlg_t *progbar = NULL;
189 gchar status_str[100];
190 int progbar_nextstep;
193 /* Initialize the data */
194 ps = g_new(ph_stats_t, 1);
197 ps->stats_tree = g_node_new(NULL);
198 ps->first_time = 0.0;
201 /* Update the progress bar when it gets to this value. */
202 progbar_nextstep = 0;
203 /* When we reach the value that triggers a progress bar update,
204 bump that value by this amount. */
205 progbar_quantum = cfile.count/N_PROGBAR_UPDATES;
206 /* Count of packets at which we've looked. */
210 g_get_current_time(&start_time);
215 for (frame = cfile.plist; frame != NULL; frame = frame->next) {
216 /* Update the progress bar, but do it only N_PROGBAR_UPDATES
217 times; when we update it, we have to run the GTK+ main
218 loop to get it to repaint what's pending, and doing so
219 may involve an "ioctl()" to see if there's any pending
220 input from an X server, and doing that for every packet
221 can be costly, especially on a big file. */
222 if (count >= progbar_nextstep) {
223 /* let's not divide by zero. I should never be started
224 * with count == 0, so let's assert that
226 g_assert(cfile.count > 0);
228 prog_val = (gfloat) count / cfile.count;
231 /* Create the progress bar if necessary */
232 progbar = delayed_create_progress_dlg(
233 "Computing", "protocol hierarchy statistics",
234 &stop_flag, &start_time, prog_val);
236 if (progbar != NULL) {
237 g_snprintf(status_str, sizeof(status_str),
238 "%4u of %u frames", count, cfile.count);
239 update_progress_dlg(progbar, prog_val, status_str);
242 progbar_nextstep += progbar_quantum;
246 /* Well, the user decided to abort the statistics.
247 computation process Just stop. */
251 /* Skip frames that are hidden due to the display filter.
252 XXX - should the progress bar count only packets that
253 passed the display filter? If so, it should
254 probably do so for other loops (see "file.c") that
255 look only at those packets. */
256 if (frame->flags.passed_dfilter) {
258 if (tot_packets == 0) {
259 double cur_time = secs_usecs(frame->abs_secs,
261 ps->first_time = cur_time;
262 ps->last_time = cur_time;
265 /* we don't care about colinfo */
266 if (!process_frame(frame, NULL, ps)) {
268 * Give up, and set "stop_flag" so we
269 * just abort rather than popping up
270 * the statistics window.
277 tot_bytes += frame->pkt_len;
283 /* We're done calculating the statistics; destroy the progress bar
284 if it was created. */
286 destroy_progress_dlg(progbar);
290 * We quit in the middle; throw away the statistics
291 * and return NULL, so our caller doesn't pop up a
292 * window with the incomplete statistics.
298 ps->tot_packets = tot_packets;
299 ps->tot_bytes = tot_bytes;
305 stat_node_free(GNode *node, gpointer data _U_)
307 ph_stats_node_t *stats = node->data;
316 ph_stats_free(ph_stats_t *ps)
319 if (ps->stats_tree) {
320 g_node_traverse(ps->stats_tree, G_IN_ORDER,
322 stat_node_free, NULL);
323 g_node_destroy(ps->stats_tree);