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 stat_node = find_stat_node(parent_stat_node, finfo->hfinfo);
97 /* Assert that the finfo is related to a protocol, not a field. */
98 g_assert(finfo->hfinfo->parent == -1);
100 stats = STAT_NODE_STATS(stat_node);
101 stats->num_pkts_total++;
102 stats->num_bytes_total += pkt_len;
104 proto_sibling_node = ptree_node->next;
106 if (proto_sibling_node) {
107 process_node(proto_sibling_node, stat_node, ps, pkt_len);
110 stats->num_pkts_last++;
111 stats->num_bytes_last += pkt_len;
118 process_tree(proto_tree *protocol_tree, ph_stats_t* ps, guint pkt_len)
120 proto_node *ptree_node;
122 ptree_node = ((proto_node *)protocol_tree)->first_child;
127 process_node(ptree_node, ps->stats_tree, ps, pkt_len);
131 process_frame(frame_data *frame, column_info *cinfo, ph_stats_t* ps)
134 union wtap_pseudo_header phdr;
135 guint8 pd[WTAP_MAX_PACKET_SIZE];
140 /* Load the frame from the capture file */
141 if (!wtap_seek_read(cfile.wth, frame->file_off, &phdr, pd,
142 frame->cap_len, &err, &err_info)) {
143 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
144 cf_read_error_message(err, err_info), cfile.filename);
145 return FALSE; /* failure */
148 /* Dissect the frame */
149 edt = epan_dissect_new(TRUE, FALSE);
150 epan_dissect_run(edt, &phdr, pd, frame, cinfo);
152 /* Get stats from this protocol tree */
153 process_tree(edt->tree, ps, frame->pkt_len);
156 cur_time = secs_usecs(frame->abs_secs, frame->abs_usecs);
157 if (cur_time < ps->first_time) {
158 ps->first_time = cur_time;
160 if (cur_time > ps->last_time){
161 ps->last_time = cur_time;
164 /* Free our memory. */
165 epan_dissect_free(edt);
167 return TRUE; /* success */
175 guint tot_packets, tot_bytes;
176 progdlg_t *progbar = NULL;
181 gchar status_str[100];
182 int progbar_nextstep;
185 /* Initialize the data */
186 ps = g_new(ph_stats_t, 1);
189 ps->stats_tree = g_node_new(NULL);
190 ps->first_time = 0.0;
193 /* Update the progress bar when it gets to this value. */
194 progbar_nextstep = 0;
195 /* When we reach the value that triggers a progress bar update,
196 bump that value by this amount. */
197 progbar_quantum = cfile.count/N_PROGBAR_UPDATES;
198 /* Count of packets at which we've looked. */
202 g_get_current_time(&start_time);
207 for (frame = cfile.plist; frame != NULL; frame = frame->next) {
208 /* Update the progress bar, but do it only N_PROGBAR_UPDATES
209 times; when we update it, we have to run the GTK+ main
210 loop to get it to repaint what's pending, and doing so
211 may involve an "ioctl()" to see if there's any pending
212 input from an X server, and doing that for every packet
213 can be costly, especially on a big file. */
214 if (count >= progbar_nextstep) {
215 /* let's not divide by zero. I should never be started
216 * with count == 0, so let's assert that
218 g_assert(cfile.count > 0);
220 prog_val = (gfloat) count / cfile.count;
223 /* Create the progress bar if necessary */
224 progbar = delayed_create_progress_dlg(
225 "Computing", "protocol hierarchy statistics",
226 &stop_flag, &start_time, prog_val);
228 if (progbar != NULL) {
229 g_snprintf(status_str, sizeof(status_str),
230 "%4u of %u frames", count, cfile.count);
231 update_progress_dlg(progbar, prog_val, status_str);
234 progbar_nextstep += progbar_quantum;
238 /* Well, the user decided to abort the statistics.
239 computation process Just stop. */
243 /* Skip frames that are hidden due to the display filter.
244 XXX - should the progress bar count only packets that
245 passed the display filter? If so, it should
246 probably do so for other loops (see "file.c") that
247 look only at those packets. */
248 if (frame->flags.passed_dfilter) {
250 if (tot_packets == 0) {
251 double cur_time = secs_usecs(frame->abs_secs,
253 ps->first_time = cur_time;
254 ps->last_time = cur_time;
257 if (!process_frame(frame, &cfile.cinfo, ps)) {
259 * Give up, and set "stop_flag" so we
260 * just abort rather than popping up
261 * the statistics window.
268 tot_bytes += frame->pkt_len;
274 /* We're done calculating the statistics; destroy the progress bar
275 if it was created. */
277 destroy_progress_dlg(progbar);
281 * We quit in the middle; throw away the statistics
282 * and return NULL, so our caller doesn't pop up a
283 * window with the incomplete statistics.
289 ps->tot_packets = tot_packets;
290 ps->tot_bytes = tot_bytes;
296 stat_node_free(GNode *node, gpointer data _U_)
298 ph_stats_node_t *stats = node->data;
307 ph_stats_free(ph_stats_t *ps)
310 if (ps->stats_tree) {
311 g_node_traverse(ps->stats_tree, G_IN_ORDER,
313 stat_node_free, NULL);
314 g_node_destroy(ps->stats_tree);