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>
40 /* Update the progress bar this many times when scanning the packet list. */
41 #define N_PROGBAR_UPDATES 100
43 #define STAT_NODE_STATS(n) ((ph_stats_node_t*)(n)->data)
44 #define STAT_NODE_HFINFO(n) (STAT_NODE_STATS(n)->hfinfo)
48 find_stat_node(GNode *parent_stat_node, header_field_info *needle_hfinfo)
50 GNode *needle_stat_node;
51 header_field_info *hfinfo;
52 ph_stats_node_t *stats;
54 needle_stat_node = g_node_first_child(parent_stat_node);
56 while (needle_stat_node) {
57 hfinfo = STAT_NODE_HFINFO(needle_stat_node);
58 if (hfinfo && hfinfo->id == needle_hfinfo->id) {
59 return needle_stat_node;
61 needle_stat_node = g_node_next_sibling(needle_stat_node);
64 /* None found. Create one. */
65 stats = g_new(ph_stats_node_t, 1);
67 /* Intialize counters */
68 stats->hfinfo = needle_hfinfo;
69 stats->num_pkts_total = 0;
70 stats->num_pkts_last = 0;
71 stats->num_bytes_total = 0;
72 stats->num_bytes_last = 0;
74 needle_stat_node = g_node_new(stats);
75 g_node_append(parent_stat_node, needle_stat_node);
76 return needle_stat_node;
81 process_node(proto_node *ptree_node, GNode *parent_stat_node, ph_stats_t *ps, guint pkt_len)
84 ph_stats_node_t *stats;
85 proto_node *proto_sibling_node;
88 finfo = PNODE_FINFO(ptree_node);
89 /* We don't fake protocol nodes we expect them to have a field_info */
90 g_assert(finfo && "dissection with faked proto tree?");
92 /* If the field info isn't related to a protocol but to a field,
93 * don't count them, as they don't belong to any protocol.
94 * (happens e.g. for toplevel tree item of desegmentation "[Reassembled TCP Segments]") */
95 if (finfo->hfinfo->parent != -1) {
96 /* Skip this element, use parent status node */
97 stat_node = parent_stat_node;
98 stats = STAT_NODE_STATS(stat_node);
100 stat_node = find_stat_node(parent_stat_node, finfo->hfinfo);
102 stats = STAT_NODE_STATS(stat_node);
103 stats->num_pkts_total++;
104 stats->num_bytes_total += pkt_len;
107 proto_sibling_node = ptree_node->next;
109 if (proto_sibling_node) {
110 /* If the name does not exist for this proto_sibling_node, then it is
111 * not a normal protocol in the top-level tree. It was instead
112 * added as a normal tree such as IPv6's Hop-by-hop Option Header and
113 * should be skipped when creating the protocol hierarchy display. */
114 if(strlen(PNODE_FINFO(proto_sibling_node)->hfinfo->name) == 0 && ptree_node->next)
115 proto_sibling_node = proto_sibling_node->next;
117 process_node(proto_sibling_node, stat_node, ps, pkt_len);
119 stats->num_pkts_last++;
120 stats->num_bytes_last += pkt_len;
127 process_tree(proto_tree *protocol_tree, ph_stats_t* ps, guint pkt_len)
129 proto_node *ptree_node;
131 ptree_node = ((proto_node *)protocol_tree)->first_child;
136 process_node(ptree_node, ps->stats_tree, ps, pkt_len);
140 process_frame(frame_data *frame, column_info *cinfo, ph_stats_t* ps)
143 union wtap_pseudo_header phdr;
144 guint8 pd[WTAP_MAX_PACKET_SIZE];
149 /* Load the frame from the capture file */
150 if (!wtap_seek_read(cfile.wth, frame->file_off, &phdr, pd,
151 frame->cap_len, &err, &err_info)) {
152 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
153 cf_read_error_message(err, err_info), cfile.filename);
154 return FALSE; /* failure */
157 /* Dissect the frame tree not visible */
158 epan_dissect_init(&edt, TRUE, FALSE);
159 /* Don't fake protocols. We need them for the protocol hierarchy */
160 epan_dissect_fake_protocols(&edt, FALSE);
161 epan_dissect_run(&edt, &phdr, pd, frame, cinfo);
163 /* Get stats from this protocol tree */
164 process_tree(edt.tree, ps, frame->pkt_len);
167 cur_time = nstime_to_sec(&frame->abs_ts);
168 if (cur_time < ps->first_time) {
169 ps->first_time = cur_time;
171 if (cur_time > ps->last_time){
172 ps->last_time = cur_time;
175 /* Free our memory. */
176 epan_dissect_cleanup(&edt);
178 return TRUE; /* success */
186 guint tot_packets, tot_bytes;
187 progdlg_t *progbar = NULL;
192 gchar status_str[100];
193 int progbar_nextstep;
196 /* Initialize the data */
197 ps = g_new(ph_stats_t, 1);
200 ps->stats_tree = g_node_new(NULL);
201 ps->first_time = 0.0;
204 /* Update the progress bar when it gets to this value. */
205 progbar_nextstep = 0;
206 /* When we reach the value that triggers a progress bar update,
207 bump that value by this amount. */
208 progbar_quantum = cfile.count/N_PROGBAR_UPDATES;
209 /* Count of packets at which we've looked. */
211 /* Progress so far. */
215 g_get_current_time(&start_time);
220 for (frame = cfile.plist; frame != NULL; frame = frame->next) {
221 /* Create the progress bar if necessary.
222 We check on every iteration of the loop, so that
223 it takes no longer than the standard time to create
224 it (otherwise, for a large file, we might take
225 considerably longer than that standard time in order
226 to get to the next progress bar step). */
228 progbar = delayed_create_progress_dlg(
229 "Computing", "protocol hierarchy statistics",
230 TRUE, &stop_flag, &start_time, progbar_val);
232 /* Update the progress bar, but do it only N_PROGBAR_UPDATES
233 times; when we update it, we have to run the GTK+ main
234 loop to get it to repaint what's pending, and doing so
235 may involve an "ioctl()" to see if there's any pending
236 input from an X server, and doing that for every packet
237 can be costly, especially on a big file. */
238 if (count >= progbar_nextstep) {
239 /* let's not divide by zero. I should never be started
240 * with count == 0, so let's assert that
242 g_assert(cfile.count > 0);
244 progbar_val = (gfloat) count / cfile.count;
246 if (progbar != NULL) {
247 g_snprintf(status_str, sizeof(status_str),
248 "%4u of %u frames", count, cfile.count);
249 update_progress_dlg(progbar, progbar_val, status_str);
252 progbar_nextstep += progbar_quantum;
256 /* Well, the user decided to abort the statistics.
257 computation process Just stop. */
261 /* Skip frames that are hidden due to the display filter.
262 XXX - should the progress bar count only packets that
263 passed the display filter? If so, it should
264 probably do so for other loops (see "file.c") that
265 look only at those packets. */
266 if (frame->flags.passed_dfilter) {
268 if (tot_packets == 0) {
269 double cur_time = nstime_to_sec(&frame->abs_ts);
270 ps->first_time = cur_time;
271 ps->last_time = cur_time;
274 /* we don't care about colinfo */
275 if (!process_frame(frame, NULL, ps)) {
277 * Give up, and set "stop_flag" so we
278 * just abort rather than popping up
279 * the statistics window.
286 tot_bytes += frame->pkt_len;
292 /* We're done calculating the statistics; destroy the progress bar
293 if it was created. */
295 destroy_progress_dlg(progbar);
299 * We quit in the middle; throw away the statistics
300 * and return NULL, so our caller doesn't pop up a
301 * window with the incomplete statistics.
307 ps->tot_packets = tot_packets;
308 ps->tot_bytes = tot_bytes;
314 stat_node_free(GNode *node, gpointer data _U_)
316 ph_stats_node_t *stats = node->data;
325 ph_stats_free(ph_stats_t *ps)
328 if (ps->stats_tree) {
329 g_node_traverse(ps->stats_tree, G_IN_ORDER,
331 stat_node_free, NULL);
332 g_node_destroy(ps->stats_tree);