2 * Routines for calculating statistics based on protocol.
4 * Wireshark - Network traffic analyzer
5 * By Gerald Combs <gerald@wireshark.org>
6 * Copyright 1998 Gerald Combs
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27 #include "frame_tvbuff.h"
28 #include "ui/proto_hier_stats.h"
29 #include "ui/progress_dlg.h"
30 #include <epan/epan_dissect.h>
34 /* Update the progress bar this many times when scanning the packet list. */
35 #define N_PROGBAR_UPDATES 100
37 #define STAT_NODE_STATS(n) ((ph_stats_node_t*)(n)->data)
38 #define STAT_NODE_HFINFO(n) (STAT_NODE_STATS(n)->hfinfo)
42 find_stat_node(GNode *parent_stat_node, header_field_info *needle_hfinfo)
44 GNode *needle_stat_node;
45 header_field_info *hfinfo;
46 ph_stats_node_t *stats;
48 needle_stat_node = g_node_first_child(parent_stat_node);
50 while (needle_stat_node) {
51 hfinfo = STAT_NODE_HFINFO(needle_stat_node);
52 if (hfinfo && hfinfo->id == needle_hfinfo->id) {
53 return needle_stat_node;
55 needle_stat_node = g_node_next_sibling(needle_stat_node);
58 /* None found. Create one. */
59 stats = g_new(ph_stats_node_t, 1);
61 /* Intialize counters */
62 stats->hfinfo = needle_hfinfo;
63 stats->num_pkts_total = 0;
64 stats->num_pkts_last = 0;
65 stats->num_bytes_total = 0;
66 stats->num_bytes_last = 0;
68 needle_stat_node = g_node_new(stats);
69 g_node_append(parent_stat_node, needle_stat_node);
70 return needle_stat_node;
75 process_node(proto_node *ptree_node, GNode *parent_stat_node, ph_stats_t *ps, guint pkt_len)
78 ph_stats_node_t *stats;
79 proto_node *proto_sibling_node;
82 finfo = PNODE_FINFO(ptree_node);
83 /* We don't fake protocol nodes we expect them to have a field_info.
84 * Dissection with faked proto tree? */
87 /* If the field info isn't related to a protocol but to a field,
88 * don't count them, as they don't belong to any protocol.
89 * (happens e.g. for toplevel tree item of desegmentation "[Reassembled TCP Segments]") */
90 if (finfo->hfinfo->parent != -1) {
91 /* Skip this element, use parent status node */
92 stat_node = parent_stat_node;
93 stats = STAT_NODE_STATS(stat_node);
95 stat_node = find_stat_node(parent_stat_node, finfo->hfinfo);
97 stats = STAT_NODE_STATS(stat_node);
98 stats->num_pkts_total++;
99 stats->num_bytes_total += pkt_len;
102 proto_sibling_node = ptree_node->next;
104 if (proto_sibling_node) {
105 /* If the name does not exist for this proto_sibling_node, then it is
106 * not a normal protocol in the top-level tree. It was instead
107 * added as a normal tree such as IPv6's Hop-by-hop Option Header and
108 * should be skipped when creating the protocol hierarchy display. */
109 if(strlen(PNODE_FINFO(proto_sibling_node)->hfinfo->name) == 0 && ptree_node->next)
110 proto_sibling_node = proto_sibling_node->next;
112 process_node(proto_sibling_node, stat_node, ps, pkt_len);
114 stats->num_pkts_last++;
115 stats->num_bytes_last += pkt_len;
122 process_tree(proto_tree *protocol_tree, ph_stats_t* ps, guint pkt_len)
124 proto_node *ptree_node;
126 ptree_node = ((proto_node *)protocol_tree)->first_child;
131 process_node(ptree_node, ps->stats_tree, ps, pkt_len);
135 process_record(frame_data *frame, column_info *cinfo, ph_stats_t* ps)
138 struct wtap_pkthdr phdr;
142 wtap_phdr_init(&phdr);
144 /* Load the record from the capture file */
145 ws_buffer_init(&buf, 1500);
146 if (!cf_read_record_r(&cfile, frame, &phdr, &buf))
147 return FALSE; /* failure */
149 /* Dissect the record tree not visible */
150 epan_dissect_init(&edt, cfile.epan, TRUE, FALSE);
151 /* Don't fake protocols. We need them for the protocol hierarchy */
152 epan_dissect_fake_protocols(&edt, FALSE);
153 epan_dissect_run(&edt, cfile.cd_t, &phdr, frame_tvbuff_new_buffer(frame, &buf), frame, cinfo);
155 /* Get stats from this protocol tree */
156 process_tree(edt.tree, ps, frame->pkt_len);
158 if (frame->flags.has_ts) {
160 cur_time = nstime_to_sec(&frame->abs_ts);
161 if (cur_time < ps->first_time)
162 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_cleanup(&edt);
169 wtap_phdr_cleanup(&phdr);
170 ws_buffer_free(&buf);
172 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 (framenum = 1; framenum <= cfile.count; framenum++) {
216 frame = frame_data_sequence_find(cfile.frames, framenum);
218 /* Create the progress bar if necessary.
219 We check on every iteration of the loop, so that
220 it takes no longer than the standard time to create
221 it (otherwise, for a large file, we might take
222 considerably longer than that standard time in order
223 to get to the next progress bar step). */
225 progbar = delayed_create_progress_dlg(
226 cfile.window, "Computing",
227 "protocol hierarchy statistics",
228 TRUE, &stop_flag, &start_time, progbar_val);
230 /* Update the progress bar, but do it only N_PROGBAR_UPDATES
231 times; when we update it, we have to run the GTK+ main
232 loop to get it to repaint what's pending, and doing so
233 may involve an "ioctl()" to see if there's any pending
234 input from an X server, and doing that for every packet
235 can be costly, especially on a big file. */
236 if (count >= progbar_nextstep) {
237 /* let's not divide by zero. I should never be started
238 * with count == 0, so let's assert that
240 g_assert(cfile.count > 0);
242 progbar_val = (gfloat) count / cfile.count;
244 if (progbar != NULL) {
245 g_snprintf(status_str, sizeof(status_str),
246 "%4u of %u frames", count, cfile.count);
247 update_progress_dlg(progbar, progbar_val, status_str);
250 progbar_nextstep += progbar_quantum;
254 /* Well, the user decided to abort the statistics.
255 computation process Just stop. */
259 /* Skip frames that are hidden due to the display filter.
260 XXX - should the progress bar count only packets that
261 passed the display filter? If so, it should
262 probably do so for other loops (see "file.c") that
263 look only at those packets. */
264 if (frame->flags.passed_dfilter) {
266 if (frame->flags.has_ts) {
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;
274 /* we don't care about colinfo */
275 if (!process_record(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 = (ph_stats_node_t *)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);
339 * Editor modelines - http://www.wireshark.org/tools/modelines.html
344 * indent-tabs-mode: t
347 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
348 * :indentSize=8:tabSize=8:noTabs=false: