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);
91 /* If the field info isn't related to a protocol but to a field,
92 * don't count them, as they don't belong to any protocol.
93 * (happens e.g. for toplevel tree item of desegmentation "[Reassembled TCP Segments]") */
94 if (finfo->hfinfo->parent != -1) {
95 /* Skip this element, use parent status node */
96 stat_node = parent_stat_node;
97 stats = STAT_NODE_STATS(stat_node);
99 stat_node = find_stat_node(parent_stat_node, finfo->hfinfo);
101 stats = STAT_NODE_STATS(stat_node);
102 stats->num_pkts_total++;
103 stats->num_bytes_total += pkt_len;
106 proto_sibling_node = ptree_node->next;
108 if (proto_sibling_node) {
109 /* If the name does not exist for this proto_sibling_node, then it is
110 * not a normal protocol in the top-level tree. It was instead
111 * added as a normal tree such as IPv6's Hop-by-hop Option Header and
112 * should be skipped when creating the protocol hierarchy display. */
113 if(strlen(PNODE_FINFO(proto_sibling_node)->hfinfo->name) == 0 && ptree_node->next)
114 proto_sibling_node = proto_sibling_node->next;
116 process_node(proto_sibling_node, stat_node, ps, pkt_len);
118 stats->num_pkts_last++;
119 stats->num_bytes_last += pkt_len;
126 process_tree(proto_tree *protocol_tree, ph_stats_t* ps, guint pkt_len)
128 proto_node *ptree_node;
130 ptree_node = ((proto_node *)protocol_tree)->first_child;
135 process_node(ptree_node, ps->stats_tree, ps, pkt_len);
139 process_frame(frame_data *frame, column_info *cinfo, ph_stats_t* ps)
142 union wtap_pseudo_header phdr;
143 guint8 pd[WTAP_MAX_PACKET_SIZE];
148 /* Load the frame from the capture file */
149 if (!wtap_seek_read(cfile.wth, frame->file_off, &phdr, pd,
150 frame->cap_len, &err, &err_info)) {
151 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
152 cf_read_error_message(err, err_info), cfile.filename);
153 return FALSE; /* failure */
156 /* Dissect the frame tree not visible */
157 edt = epan_dissect_new(TRUE, FALSE);
158 /* Don't fake protocols. We need them for the protocol hierarchy */
159 epan_dissect_fake_protocols(edt, FALSE);
160 epan_dissect_run(edt, &phdr, pd, frame, cinfo);
162 /* Get stats from this protocol tree */
163 process_tree(edt->tree, ps, frame->pkt_len);
166 cur_time = nstime_to_sec(&frame->abs_ts);
167 if (cur_time < ps->first_time) {
168 ps->first_time = cur_time;
170 if (cur_time > ps->last_time){
171 ps->last_time = cur_time;
174 /* Free our memory. */
175 epan_dissect_free(edt);
177 return TRUE; /* success */
185 guint tot_packets, tot_bytes;
186 progdlg_t *progbar = NULL;
191 gchar status_str[100];
192 int progbar_nextstep;
195 /* Initialize the data */
196 ps = g_new(ph_stats_t, 1);
199 ps->stats_tree = g_node_new(NULL);
200 ps->first_time = 0.0;
203 /* Update the progress bar when it gets to this value. */
204 progbar_nextstep = 0;
205 /* When we reach the value that triggers a progress bar update,
206 bump that value by this amount. */
207 progbar_quantum = cfile.count/N_PROGBAR_UPDATES;
208 /* Count of packets at which we've looked. */
210 /* Progress so far. */
214 g_get_current_time(&start_time);
219 for (frame = cfile.plist; frame != NULL; frame = frame->next) {
220 /* Create the progress bar if necessary.
221 We check on every iteration of the loop, so that
222 it takes no longer than the standard time to create
223 it (otherwise, for a large file, we might take
224 considerably longer than that standard time in order
225 to get to the next progress bar step). */
227 progbar = delayed_create_progress_dlg(
228 "Computing", "protocol hierarchy statistics",
229 TRUE, &stop_flag, &start_time, progbar_val);
231 /* Update the progress bar, but do it only N_PROGBAR_UPDATES
232 times; when we update it, we have to run the GTK+ main
233 loop to get it to repaint what's pending, and doing so
234 may involve an "ioctl()" to see if there's any pending
235 input from an X server, and doing that for every packet
236 can be costly, especially on a big file. */
237 if (count >= progbar_nextstep) {
238 /* let's not divide by zero. I should never be started
239 * with count == 0, so let's assert that
241 g_assert(cfile.count > 0);
243 progbar_val = (gfloat) count / cfile.count;
245 if (progbar != NULL) {
246 g_snprintf(status_str, sizeof(status_str),
247 "%4u of %u frames", count, cfile.count);
248 update_progress_dlg(progbar, progbar_val, status_str);
251 progbar_nextstep += progbar_quantum;
255 /* Well, the user decided to abort the statistics.
256 computation process Just stop. */
260 /* Skip frames that are hidden due to the display filter.
261 XXX - should the progress bar count only packets that
262 passed the display filter? If so, it should
263 probably do so for other loops (see "file.c") that
264 look only at those packets. */
265 if (frame->flags.passed_dfilter) {
267 if (tot_packets == 0) {
268 double cur_time = nstime_to_sec(&frame->abs_ts);
269 ps->first_time = cur_time;
270 ps->last_time = cur_time;
273 /* we don't care about colinfo */
274 if (!process_frame(frame, NULL, ps)) {
276 * Give up, and set "stop_flag" so we
277 * just abort rather than popping up
278 * the statistics window.
285 tot_bytes += frame->pkt_len;
291 /* We're done calculating the statistics; destroy the progress bar
292 if it was created. */
294 destroy_progress_dlg(progbar);
298 * We quit in the middle; throw away the statistics
299 * and return NULL, so our caller doesn't pop up a
300 * window with the incomplete statistics.
306 ps->tot_packets = tot_packets;
307 ps->tot_bytes = tot_bytes;
313 stat_node_free(GNode *node, gpointer data _U_)
315 ph_stats_node_t *stats = node->data;
324 ph_stats_free(ph_stats_t *ps)
327 if (ps->stats_tree) {
328 g_node_traverse(ps->stats_tree, G_IN_ORDER,
330 stat_node_free, NULL);
331 g_node_destroy(ps->stats_tree);