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 <epan/epan_dissect.h>
41 /* Update the progress bar this many times when scanning the packet list. */
42 #define N_PROGBAR_UPDATES 100
44 #define STAT_NODE_STATS(n) ((ph_stats_node_t*)(n)->data)
45 #define STAT_NODE_HFINFO(n) (STAT_NODE_STATS(n)->hfinfo)
49 find_stat_node(GNode *parent_stat_node, header_field_info *needle_hfinfo)
51 GNode *needle_stat_node;
52 header_field_info *hfinfo;
53 ph_stats_node_t *stats;
55 needle_stat_node = g_node_first_child(parent_stat_node);
57 while (needle_stat_node) {
58 hfinfo = STAT_NODE_HFINFO(needle_stat_node);
59 if (hfinfo && hfinfo->id == needle_hfinfo->id) {
60 return needle_stat_node;
62 needle_stat_node = g_node_next_sibling(needle_stat_node);
65 /* None found. Create one. */
66 stats = g_new(ph_stats_node_t, 1);
68 /* Intialize counters */
69 stats->hfinfo = needle_hfinfo;
70 stats->num_pkts_total = 0;
71 stats->num_pkts_last = 0;
72 stats->num_bytes_total = 0;
73 stats->num_bytes_last = 0;
75 needle_stat_node = g_node_new(stats);
76 g_node_append(parent_stat_node, needle_stat_node);
77 return needle_stat_node;
82 process_node(proto_node *ptree_node, GNode *parent_stat_node, ph_stats_t *ps, guint pkt_len)
85 ph_stats_node_t *stats;
86 proto_node *proto_sibling_node;
89 finfo = PNODE_FINFO(ptree_node);
90 /* We don't fake protocol nodes we expect them to have a field_info */
91 g_assert(finfo && "dissection with faked proto tree?");
93 /* If the field info isn't related to a protocol but to a field,
94 * don't count them, as they don't belong to any protocol.
95 * (happens e.g. for toplevel tree item of desegmentation "[Reassembled TCP Segments]") */
96 if (finfo->hfinfo->parent != -1) {
97 /* Skip this element, use parent status node */
98 stat_node = parent_stat_node;
99 stats = STAT_NODE_STATS(stat_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;
108 proto_sibling_node = ptree_node->next;
110 if (proto_sibling_node) {
111 /* If the name does not exist for this proto_sibling_node, then it is
112 * not a normal protocol in the top-level tree. It was instead
113 * added as a normal tree such as IPv6's Hop-by-hop Option Header and
114 * should be skipped when creating the protocol hierarchy display. */
115 if(strlen(PNODE_FINFO(proto_sibling_node)->hfinfo->name) == 0 && ptree_node->next)
116 proto_sibling_node = proto_sibling_node->next;
118 process_node(proto_sibling_node, stat_node, ps, pkt_len);
120 stats->num_pkts_last++;
121 stats->num_bytes_last += pkt_len;
128 process_tree(proto_tree *protocol_tree, ph_stats_t* ps, guint pkt_len)
130 proto_node *ptree_node;
132 ptree_node = ((proto_node *)protocol_tree)->first_child;
137 process_node(ptree_node, ps->stats_tree, ps, pkt_len);
141 process_frame(frame_data *frame, column_info *cinfo, ph_stats_t* ps)
144 union wtap_pseudo_header phdr;
145 guint8 pd[WTAP_MAX_PACKET_SIZE];
148 /* Load the frame from the capture file */
149 if (!cf_read_frame_r(&cfile, frame, &phdr, pd))
150 return FALSE; /* failure */
152 /* Dissect the frame tree not visible */
153 epan_dissect_init(&edt, TRUE, FALSE);
154 /* Don't fake protocols. We need them for the protocol hierarchy */
155 epan_dissect_fake_protocols(&edt, 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 = nstime_to_sec(&frame->abs_ts);
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_cleanup(&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. */
206 /* Progress so far. */
210 g_get_current_time(&start_time);
215 for (frame = cfile.plist_start; frame != NULL; frame = frame->next) {
216 /* Create the progress bar if necessary.
217 We check on every iteration of the loop, so that
218 it takes no longer than the standard time to create
219 it (otherwise, for a large file, we might take
220 considerably longer than that standard time in order
221 to get to the next progress bar step). */
223 progbar = delayed_create_progress_dlg(
224 "Computing", "protocol hierarchy statistics",
225 TRUE, &stop_flag, &start_time, progbar_val);
227 /* Update the progress bar, but do it only N_PROGBAR_UPDATES
228 times; when we update it, we have to run the GTK+ main
229 loop to get it to repaint what's pending, and doing so
230 may involve an "ioctl()" to see if there's any pending
231 input from an X server, and doing that for every packet
232 can be costly, especially on a big file. */
233 if (count >= progbar_nextstep) {
234 /* let's not divide by zero. I should never be started
235 * with count == 0, so let's assert that
237 g_assert(cfile.count > 0);
239 progbar_val = (gfloat) count / cfile.count;
241 if (progbar != NULL) {
242 g_snprintf(status_str, sizeof(status_str),
243 "%4u of %u frames", count, cfile.count);
244 update_progress_dlg(progbar, progbar_val, status_str);
247 progbar_nextstep += progbar_quantum;
251 /* Well, the user decided to abort the statistics.
252 computation process Just stop. */
256 /* Skip frames that are hidden due to the display filter.
257 XXX - should the progress bar count only packets that
258 passed the display filter? If so, it should
259 probably do so for other loops (see "file.c") that
260 look only at those packets. */
261 if (frame->flags.passed_dfilter) {
263 if (tot_packets == 0) {
264 double cur_time = nstime_to_sec(&frame->abs_ts);
265 ps->first_time = cur_time;
266 ps->last_time = cur_time;
269 /* we don't care about colinfo */
270 if (!process_frame(frame, NULL, ps)) {
272 * Give up, and set "stop_flag" so we
273 * just abort rather than popping up
274 * the statistics window.
281 tot_bytes += frame->pkt_len;
287 /* We're done calculating the statistics; destroy the progress bar
288 if it was created. */
290 destroy_progress_dlg(progbar);
294 * We quit in the middle; throw away the statistics
295 * and return NULL, so our caller doesn't pop up a
296 * window with the incomplete statistics.
302 ps->tot_packets = tot_packets;
303 ps->tot_bytes = tot_bytes;
309 stat_node_free(GNode *node, gpointer data _U_)
311 ph_stats_node_t *stats = (ph_stats_node_t *)node->data;
320 ph_stats_free(ph_stats_t *ps)
323 if (ps->stats_tree) {
324 g_node_traverse(ps->stats_tree, G_IN_ORDER,
326 stat_node_free, NULL);
327 g_node_destroy(ps->stats_tree);