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.
32 #include "proto_hier_stats.h"
33 #include "progress_dlg.h"
34 #include "simple_dialog.h"
35 #include <epan/epan_dissect.h>
42 /* Update the progress bar this many times when scanning the packet list. */
43 #define N_PROGBAR_UPDATES 100
45 #define STAT_NODE_STATS(n) ((ph_stats_node_t*)(n)->data)
46 #define STAT_NODE_HFINFO(n) (STAT_NODE_STATS(n)->hfinfo)
50 find_stat_node(GNode *parent_stat_node, header_field_info *needle_hfinfo)
52 GNode *needle_stat_node;
53 header_field_info *hfinfo;
54 ph_stats_node_t *stats;
56 needle_stat_node = g_node_first_child(parent_stat_node);
58 while (needle_stat_node) {
59 hfinfo = STAT_NODE_HFINFO(needle_stat_node);
60 if (hfinfo && hfinfo->id == needle_hfinfo->id) {
61 return needle_stat_node;
63 needle_stat_node = g_node_next_sibling(needle_stat_node);
66 /* None found. Create one. */
67 stats = g_new(ph_stats_node_t, 1);
69 /* Intialize counters */
70 stats->hfinfo = needle_hfinfo;
71 stats->num_pkts_total = 0;
72 stats->num_pkts_last = 0;
73 stats->num_bytes_total = 0;
74 stats->num_bytes_last = 0;
76 needle_stat_node = g_node_new(stats);
77 g_node_append(parent_stat_node, needle_stat_node);
78 return needle_stat_node;
83 process_node(proto_node *ptree_node, GNode *parent_stat_node, ph_stats_t *ps, guint pkt_len)
86 ph_stats_node_t *stats;
87 proto_node *proto_sibling_node;
90 finfo = PNODE_FINFO(ptree_node);
91 /* We don't fake protocol nodes we expect them to have a field_info */
92 g_assert(finfo && "dissection with faked proto tree?");
94 /* If the field info isn't related to a protocol but to a field,
95 * don't count them, as they don't belong to any protocol.
96 * (happens e.g. for toplevel tree item of desegmentation "[Reassembled TCP Segments]") */
97 if (finfo->hfinfo->parent != -1) {
98 /* Skip this element, use parent status node */
99 stat_node = parent_stat_node;
100 stats = STAT_NODE_STATS(stat_node);
102 stat_node = find_stat_node(parent_stat_node, finfo->hfinfo);
104 stats = STAT_NODE_STATS(stat_node);
105 stats->num_pkts_total++;
106 stats->num_bytes_total += pkt_len;
109 proto_sibling_node = ptree_node->next;
111 if (proto_sibling_node) {
112 /* If the name does not exist for this proto_sibling_node, then it is
113 * not a normal protocol in the top-level tree. It was instead
114 * added as a normal tree such as IPv6's Hop-by-hop Option Header and
115 * should be skipped when creating the protocol hierarchy display. */
116 if(strlen(PNODE_FINFO(proto_sibling_node)->hfinfo->name) == 0 && ptree_node->next)
117 proto_sibling_node = proto_sibling_node->next;
119 process_node(proto_sibling_node, stat_node, ps, pkt_len);
121 stats->num_pkts_last++;
122 stats->num_bytes_last += pkt_len;
129 process_tree(proto_tree *protocol_tree, ph_stats_t* ps, guint pkt_len)
131 proto_node *ptree_node;
133 ptree_node = ((proto_node *)protocol_tree)->first_child;
138 process_node(ptree_node, ps->stats_tree, ps, pkt_len);
142 process_frame(frame_data *frame, column_info *cinfo, ph_stats_t* ps)
145 union wtap_pseudo_header phdr;
146 guint8 pd[WTAP_MAX_PACKET_SIZE];
151 /* Load the frame from the capture file */
152 if (!wtap_seek_read(cfile.wth, frame->file_off, &phdr, pd,
153 frame->cap_len, &err, &err_info)) {
154 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
155 cf_read_error_message(err, err_info), cfile.filename);
156 return FALSE; /* failure */
159 /* Dissect the frame tree not visible */
160 epan_dissect_init(&edt, TRUE, FALSE);
161 /* Don't fake protocols. We need them for the protocol hierarchy */
162 epan_dissect_fake_protocols(&edt, FALSE);
163 epan_dissect_run(&edt, &phdr, pd, frame, cinfo);
165 /* Get stats from this protocol tree */
166 process_tree(edt.tree, ps, frame->pkt_len);
169 cur_time = nstime_to_sec(&frame->abs_ts);
170 if (cur_time < ps->first_time) {
171 ps->first_time = cur_time;
173 if (cur_time > ps->last_time){
174 ps->last_time = cur_time;
177 /* Free our memory. */
178 epan_dissect_cleanup(&edt);
180 return TRUE; /* success */
188 guint tot_packets, tot_bytes;
189 progdlg_t *progbar = NULL;
194 gchar status_str[100];
195 int progbar_nextstep;
198 /* Initialize the data */
199 ps = g_new(ph_stats_t, 1);
202 ps->stats_tree = g_node_new(NULL);
203 ps->first_time = 0.0;
206 /* Update the progress bar when it gets to this value. */
207 progbar_nextstep = 0;
208 /* When we reach the value that triggers a progress bar update,
209 bump that value by this amount. */
210 progbar_quantum = cfile.count/N_PROGBAR_UPDATES;
211 /* Count of packets at which we've looked. */
213 /* Progress so far. */
217 g_get_current_time(&start_time);
222 for (frame = cfile.plist_start; frame != NULL; frame = frame->next) {
223 /* Create the progress bar if necessary.
224 We check on every iteration of the loop, so that
225 it takes no longer than the standard time to create
226 it (otherwise, for a large file, we might take
227 considerably longer than that standard time in order
228 to get to the next progress bar step). */
230 progbar = delayed_create_progress_dlg(
231 "Computing", "protocol hierarchy statistics",
232 TRUE, &stop_flag, &start_time, progbar_val);
234 /* Update the progress bar, but do it only N_PROGBAR_UPDATES
235 times; when we update it, we have to run the GTK+ main
236 loop to get it to repaint what's pending, and doing so
237 may involve an "ioctl()" to see if there's any pending
238 input from an X server, and doing that for every packet
239 can be costly, especially on a big file. */
240 if (count >= progbar_nextstep) {
241 /* let's not divide by zero. I should never be started
242 * with count == 0, so let's assert that
244 g_assert(cfile.count > 0);
246 progbar_val = (gfloat) count / cfile.count;
248 if (progbar != NULL) {
249 g_snprintf(status_str, sizeof(status_str),
250 "%4u of %u frames", count, cfile.count);
251 update_progress_dlg(progbar, progbar_val, status_str);
254 progbar_nextstep += progbar_quantum;
258 /* Well, the user decided to abort the statistics.
259 computation process Just stop. */
263 /* Skip frames that are hidden due to the display filter.
264 XXX - should the progress bar count only packets that
265 passed the display filter? If so, it should
266 probably do so for other loops (see "file.c") that
267 look only at those packets. */
268 if (frame->flags.passed_dfilter) {
270 if (tot_packets == 0) {
271 double cur_time = nstime_to_sec(&frame->abs_ts);
272 ps->first_time = cur_time;
273 ps->last_time = cur_time;
276 /* we don't care about colinfo */
277 if (!process_frame(frame, NULL, ps)) {
279 * Give up, and set "stop_flag" so we
280 * just abort rather than popping up
281 * the statistics window.
288 tot_bytes += frame->pkt_len;
294 /* We're done calculating the statistics; destroy the progress bar
295 if it was created. */
297 destroy_progress_dlg(progbar);
301 * We quit in the middle; throw away the statistics
302 * and return NULL, so our caller doesn't pop up a
303 * window with the incomplete statistics.
309 ps->tot_packets = tot_packets;
310 ps->tot_bytes = tot_bytes;
316 stat_node_free(GNode *node, gpointer data _U_)
318 ph_stats_node_t *stats = (ph_stats_node_t *)node->data;
327 ph_stats_free(ph_stats_t *ps)
330 if (ps->stats_tree) {
331 g_node_traverse(ps->stats_tree, G_IN_ORDER,
333 stat_node_free, NULL);
334 g_node_destroy(ps->stats_tree);