2 * Routines for calculating statistics based on protocol.
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
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)
47 find_stat_node(GNode *parent_stat_node, header_field_info *needle_hfinfo)
49 GNode *needle_stat_node;
50 header_field_info *hfinfo;
51 ph_stats_node_t *stats;
53 needle_stat_node = g_node_first_child(parent_stat_node);
55 while (needle_stat_node) {
56 hfinfo = STAT_NODE_HFINFO(needle_stat_node);
57 if (hfinfo && hfinfo->id == needle_hfinfo->id) {
58 return needle_stat_node;
60 needle_stat_node = g_node_next_sibling(needle_stat_node);
63 /* None found. Create one. */
64 stats = g_new(ph_stats_node_t, 1);
66 /* Intialize counters */
67 stats->hfinfo = needle_hfinfo;
68 stats->num_pkts_total = 0;
69 stats->num_pkts_last = 0;
70 stats->num_bytes_total = 0;
71 stats->num_bytes_last = 0;
73 needle_stat_node = g_node_new(stats);
74 g_node_append(parent_stat_node, needle_stat_node);
75 return needle_stat_node;
80 process_node(proto_node *ptree_node, GNode *parent_stat_node, ph_stats_t *ps, guint pkt_len)
83 ph_stats_node_t *stats;
84 proto_node *proto_sibling_node;
87 finfo = PITEM_FINFO(ptree_node);
90 /* if the field info isn't related to a protocol but to a field, don't count them,
91 * as they don't belong to any protocol.
92 * (happens e.g. for toplevel tree item of desegmentation "[Reassembled TCP Segments]") */
93 if(finfo->hfinfo->parent != -1) {
94 /* there are some cases where helpful generated items are added
95 * to the decode tree so do not test for it any more
96 *g_assert(PROTO_ITEM_IS_GENERATED(ptree_node));
101 stat_node = find_stat_node(parent_stat_node, finfo->hfinfo);
103 stats = STAT_NODE_STATS(stat_node);
104 stats->num_pkts_total++;
105 stats->num_bytes_total += pkt_len;
107 proto_sibling_node = ptree_node->next;
109 if (proto_sibling_node) {
110 process_node(proto_sibling_node, stat_node, ps, pkt_len);
113 stats->num_pkts_last++;
114 stats->num_bytes_last += pkt_len;
121 process_tree(proto_tree *protocol_tree, ph_stats_t* ps, guint pkt_len)
123 proto_node *ptree_node;
125 ptree_node = ((proto_node *)protocol_tree)->first_child;
130 process_node(ptree_node, ps->stats_tree, ps, pkt_len);
134 process_frame(frame_data *frame, column_info *cinfo, ph_stats_t* ps)
137 union wtap_pseudo_header phdr;
138 guint8 pd[WTAP_MAX_PACKET_SIZE];
143 /* Load the frame from the capture file */
144 if (!wtap_seek_read(cfile.wth, frame->file_off, &phdr, pd,
145 frame->cap_len, &err, &err_info)) {
146 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
147 cf_read_error_message(err, err_info), cfile.filename);
148 return FALSE; /* failure */
151 /* Dissect the frame tree not visible */
152 edt = epan_dissect_new(TRUE, FALSE);
153 epan_dissect_run(edt, &phdr, pd, frame, cinfo);
155 /* Get stats from this protocol tree */
156 process_tree(edt->tree, ps, frame->pkt_len);
159 cur_time = nstime_to_sec(&frame->abs_ts);
160 if (cur_time < ps->first_time) {
161 ps->first_time = cur_time;
163 if (cur_time > ps->last_time){
164 ps->last_time = cur_time;
167 /* Free our memory. */
168 epan_dissect_free(edt);
170 return TRUE; /* success */
178 guint tot_packets, tot_bytes;
179 progdlg_t *progbar = NULL;
184 gchar status_str[100];
185 int progbar_nextstep;
188 /* Initialize the data */
189 ps = g_new(ph_stats_t, 1);
192 ps->stats_tree = g_node_new(NULL);
193 ps->first_time = 0.0;
196 /* Update the progress bar when it gets to this value. */
197 progbar_nextstep = 0;
198 /* When we reach the value that triggers a progress bar update,
199 bump that value by this amount. */
200 progbar_quantum = cfile.count/N_PROGBAR_UPDATES;
201 /* Count of packets at which we've looked. */
203 /* Progress so far. */
207 g_get_current_time(&start_time);
212 for (frame = cfile.plist; frame != NULL; frame = frame->next) {
213 /* Create the progress bar if necessary.
214 We check on every iteration of the loop, so that
215 it takes no longer than the standard time to create
216 it (otherwise, for a large file, we might take
217 considerably longer than that standard time in order
218 to get to the next progress bar step). */
220 progbar = delayed_create_progress_dlg(
221 "Computing", "protocol hierarchy statistics",
222 TRUE, &stop_flag, &start_time, progbar_val);
224 /* Update the progress bar, but do it only N_PROGBAR_UPDATES
225 times; when we update it, we have to run the GTK+ main
226 loop to get it to repaint what's pending, and doing so
227 may involve an "ioctl()" to see if there's any pending
228 input from an X server, and doing that for every packet
229 can be costly, especially on a big file. */
230 if (count >= progbar_nextstep) {
231 /* let's not divide by zero. I should never be started
232 * with count == 0, so let's assert that
234 g_assert(cfile.count > 0);
236 progbar_val = (gfloat) count / cfile.count;
238 if (progbar != NULL) {
239 g_snprintf(status_str, sizeof(status_str),
240 "%4u of %u frames", count, cfile.count);
241 update_progress_dlg(progbar, progbar_val, status_str);
244 progbar_nextstep += progbar_quantum;
248 /* Well, the user decided to abort the statistics.
249 computation process Just stop. */
253 /* Skip frames that are hidden due to the display filter.
254 XXX - should the progress bar count only packets that
255 passed the display filter? If so, it should
256 probably do so for other loops (see "file.c") that
257 look only at those packets. */
258 if (frame->flags.passed_dfilter) {
260 if (tot_packets == 0) {
261 double cur_time = nstime_to_sec(&frame->abs_ts);
262 ps->first_time = cur_time;
263 ps->last_time = cur_time;
266 /* we don't care about colinfo */
267 if (!process_frame(frame, NULL, ps)) {
269 * Give up, and set "stop_flag" so we
270 * just abort rather than popping up
271 * the statistics window.
278 tot_bytes += frame->pkt_len;
284 /* We're done calculating the statistics; destroy the progress bar
285 if it was created. */
287 destroy_progress_dlg(progbar);
291 * We quit in the middle; throw away the statistics
292 * and return NULL, so our caller doesn't pop up a
293 * window with the incomplete statistics.
299 ps->tot_packets = tot_packets;
300 ps->tot_bytes = tot_bytes;
306 stat_node_free(GNode *node, gpointer data _U_)
308 ph_stats_node_t *stats = node->data;
317 ph_stats_free(ph_stats_t *ps)
320 if (ps->stats_tree) {
321 g_node_traverse(ps->stats_tree, G_IN_ORDER,
323 stat_node_free, NULL);
324 g_node_destroy(ps->stats_tree);