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 /* this should only happen for generated items */
100 g_assert(PROTO_ITEM_IS_GENERATED(ptree_node));
104 stat_node = find_stat_node(parent_stat_node, finfo->hfinfo);
106 stats = STAT_NODE_STATS(stat_node);
107 stats->num_pkts_total++;
108 stats->num_bytes_total += pkt_len;
110 proto_sibling_node = ptree_node->next;
112 if (proto_sibling_node) {
113 process_node(proto_sibling_node, stat_node, ps, pkt_len);
116 stats->num_pkts_last++;
117 stats->num_bytes_last += pkt_len;
124 process_tree(proto_tree *protocol_tree, ph_stats_t* ps, guint pkt_len)
126 proto_node *ptree_node;
128 ptree_node = ((proto_node *)protocol_tree)->first_child;
133 process_node(ptree_node, ps->stats_tree, ps, pkt_len);
137 process_frame(frame_data *frame, column_info *cinfo, ph_stats_t* ps)
140 union wtap_pseudo_header phdr;
141 guint8 pd[WTAP_MAX_PACKET_SIZE];
146 /* Load the frame from the capture file */
147 if (!wtap_seek_read(cfile.wth, frame->file_off, &phdr, pd,
148 frame->cap_len, &err, &err_info)) {
149 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
150 cf_read_error_message(err, err_info), cfile.filename);
151 return FALSE; /* failure */
154 /* Dissect the frame tree not visible */
155 edt = epan_dissect_new(TRUE, FALSE);
156 epan_dissect_run(edt, &phdr, pd, frame, cinfo);
158 /* Get stats from this protocol tree */
159 process_tree(edt->tree, ps, frame->pkt_len);
162 cur_time = secs_usecs(frame->abs_secs, frame->abs_usecs);
163 if (cur_time < ps->first_time) {
164 ps->first_time = cur_time;
166 if (cur_time > ps->last_time){
167 ps->last_time = cur_time;
170 /* Free our memory. */
171 epan_dissect_free(edt);
173 return TRUE; /* success */
181 guint tot_packets, tot_bytes;
182 progdlg_t *progbar = NULL;
187 gchar status_str[100];
188 int progbar_nextstep;
191 /* Initialize the data */
192 ps = g_new(ph_stats_t, 1);
195 ps->stats_tree = g_node_new(NULL);
196 ps->first_time = 0.0;
199 /* Update the progress bar when it gets to this value. */
200 progbar_nextstep = 0;
201 /* When we reach the value that triggers a progress bar update,
202 bump that value by this amount. */
203 progbar_quantum = cfile.count/N_PROGBAR_UPDATES;
204 /* Count of packets at which we've looked. */
208 g_get_current_time(&start_time);
213 for (frame = cfile.plist; frame != NULL; frame = frame->next) {
214 /* Update the progress bar, but do it only N_PROGBAR_UPDATES
215 times; when we update it, we have to run the GTK+ main
216 loop to get it to repaint what's pending, and doing so
217 may involve an "ioctl()" to see if there's any pending
218 input from an X server, and doing that for every packet
219 can be costly, especially on a big file. */
220 if (count >= progbar_nextstep) {
221 /* let's not divide by zero. I should never be started
222 * with count == 0, so let's assert that
224 g_assert(cfile.count > 0);
226 prog_val = (gfloat) count / cfile.count;
229 /* Create the progress bar if necessary */
230 progbar = delayed_create_progress_dlg(
231 "Computing", "protocol hierarchy statistics",
232 &stop_flag, &start_time, prog_val);
234 if (progbar != NULL) {
235 g_snprintf(status_str, sizeof(status_str),
236 "%4u of %u frames", count, cfile.count);
237 update_progress_dlg(progbar, prog_val, status_str);
240 progbar_nextstep += progbar_quantum;
244 /* Well, the user decided to abort the statistics.
245 computation process Just stop. */
249 /* Skip frames that are hidden due to the display filter.
250 XXX - should the progress bar count only packets that
251 passed the display filter? If so, it should
252 probably do so for other loops (see "file.c") that
253 look only at those packets. */
254 if (frame->flags.passed_dfilter) {
256 if (tot_packets == 0) {
257 double cur_time = secs_usecs(frame->abs_secs,
259 ps->first_time = cur_time;
260 ps->last_time = cur_time;
263 /* we don't care about colinfo */
264 if (!process_frame(frame, NULL, ps)) {
266 * Give up, and set "stop_flag" so we
267 * just abort rather than popping up
268 * the statistics window.
275 tot_bytes += frame->pkt_len;
281 /* We're done calculating the statistics; destroy the progress bar
282 if it was created. */
284 destroy_progress_dlg(progbar);
288 * We quit in the middle; throw away the statistics
289 * and return NULL, so our caller doesn't pop up a
290 * window with the incomplete statistics.
296 ps->tot_packets = tot_packets;
297 ps->tot_bytes = tot_bytes;
303 stat_node_free(GNode *node, gpointer data _U_)
305 ph_stats_node_t *stats = node->data;
314 ph_stats_free(ph_stats_t *ps)
317 if (ps->stats_tree) {
318 g_node_traverse(ps->stats_tree, G_IN_ORDER,
320 stat_node_free, NULL);
321 g_node_destroy(ps->stats_tree);