HACK: pinfo->private_data points to smb_info again
[wireshark-wip.git] / proto_hier_stats.c
blobd1ac0232b6872e4c2aa806dbd12fa80a75d47e12
1 /* proto_hier_stats.c
2 * Routines for calculating statistics based on protocol.
4 * $Id$
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 #include "config.h"
27 #include <stdio.h>
29 #include "globals.h"
30 #include "proto_hier_stats.h"
31 #include "frame_tvbuff.h"
32 #include "ui/progress_dlg.h"
33 #include <epan/epan_dissect.h>
34 #include <wtap.h>
36 #include <stdio.h>
37 #include <string.h>
38 #include <glib.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)
47 static GNode*
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;
80 static void
81 process_node(proto_node *ptree_node, GNode *parent_stat_node, ph_stats_t *ps, guint pkt_len)
83 field_info *finfo;
84 ph_stats_node_t *stats;
85 proto_node *proto_sibling_node;
86 GNode *stat_node;
88 finfo = PNODE_FINFO(ptree_node);
89 /* We don't fake protocol nodes we expect them to have a field_info.
90 * Dissection with faked proto tree? */
91 g_assert(finfo);
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);
100 } else {
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);
119 } else {
120 stats->num_pkts_last++;
121 stats->num_bytes_last += pkt_len;
127 static void
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;
133 if (!ptree_node) {
134 return;
137 process_node(ptree_node, ps->stats_tree, ps, pkt_len);
140 static gboolean
141 process_frame(frame_data *frame, column_info *cinfo, ph_stats_t* ps)
143 epan_dissect_t edt;
144 struct wtap_pkthdr phdr;
145 Buffer buf;
146 double cur_time;
148 /* Load the frame from the capture file */
149 buffer_init(&buf, 1500);
150 if (!cf_read_frame_r(&cfile, frame, &phdr, &buf))
151 return FALSE; /* failure */
153 /* Dissect the frame tree not visible */
154 epan_dissect_init(&edt, cfile.epan, TRUE, FALSE);
155 /* Don't fake protocols. We need them for the protocol hierarchy */
156 epan_dissect_fake_protocols(&edt, FALSE);
157 epan_dissect_run(&edt, &phdr, frame_tvbuff_new_buffer(frame, &buf), frame, cinfo);
159 /* Get stats from this protocol tree */
160 process_tree(edt.tree, ps, frame->pkt_len);
162 /* Update times */
163 cur_time = nstime_to_sec(&frame->abs_ts);
164 if (cur_time < ps->first_time) {
165 ps->first_time = cur_time;
167 if (cur_time > ps->last_time){
168 ps->last_time = cur_time;
171 /* Free our memory. */
172 epan_dissect_cleanup(&edt);
173 buffer_free(&buf);
175 return TRUE; /* success */
178 ph_stats_t*
179 ph_stats_new(void)
181 ph_stats_t *ps;
182 guint32 framenum;
183 frame_data *frame;
184 guint tot_packets, tot_bytes;
185 progdlg_t *progbar = NULL;
186 gboolean stop_flag;
187 int count;
188 float progbar_val;
189 GTimeVal start_time;
190 gchar status_str[100];
191 int progbar_nextstep;
192 int progbar_quantum;
194 /* Initialize the data */
195 ps = g_new(ph_stats_t, 1);
196 ps->tot_packets = 0;
197 ps->tot_bytes = 0;
198 ps->stats_tree = g_node_new(NULL);
199 ps->first_time = 0.0;
200 ps->last_time = 0.0;
202 /* Update the progress bar when it gets to this value. */
203 progbar_nextstep = 0;
204 /* When we reach the value that triggers a progress bar update,
205 bump that value by this amount. */
206 progbar_quantum = cfile.count/N_PROGBAR_UPDATES;
207 /* Count of packets at which we've looked. */
208 count = 0;
209 /* Progress so far. */
210 progbar_val = 0.0f;
212 stop_flag = FALSE;
213 g_get_current_time(&start_time);
215 tot_packets = 0;
216 tot_bytes = 0;
218 for (framenum = 1; framenum <= cfile.count; framenum++) {
219 frame = frame_data_sequence_find(cfile.frames, framenum);
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). */
227 if (progbar == NULL)
228 progbar = delayed_create_progress_dlg(
229 cfile.window, "Computing",
230 "protocol hierarchy statistics",
231 TRUE, &stop_flag, &start_time, progbar_val);
233 /* Update the progress bar, but do it only N_PROGBAR_UPDATES
234 times; when we update it, we have to run the GTK+ main
235 loop to get it to repaint what's pending, and doing so
236 may involve an "ioctl()" to see if there's any pending
237 input from an X server, and doing that for every packet
238 can be costly, especially on a big file. */
239 if (count >= progbar_nextstep) {
240 /* let's not divide by zero. I should never be started
241 * with count == 0, so let's assert that
243 g_assert(cfile.count > 0);
245 progbar_val = (gfloat) count / cfile.count;
247 if (progbar != NULL) {
248 g_snprintf(status_str, sizeof(status_str),
249 "%4u of %u frames", count, cfile.count);
250 update_progress_dlg(progbar, progbar_val, status_str);
253 progbar_nextstep += progbar_quantum;
256 if (stop_flag) {
257 /* Well, the user decided to abort the statistics.
258 computation process Just stop. */
259 break;
262 /* Skip frames that are hidden due to the display filter.
263 XXX - should the progress bar count only packets that
264 passed the display filter? If so, it should
265 probably do so for other loops (see "file.c") that
266 look only at those packets. */
267 if (frame->flags.passed_dfilter) {
269 if (tot_packets == 0) {
270 double cur_time = nstime_to_sec(&frame->abs_ts);
271 ps->first_time = cur_time;
272 ps->last_time = cur_time;
275 /* we don't care about colinfo */
276 if (!process_frame(frame, NULL, ps)) {
278 * Give up, and set "stop_flag" so we
279 * just abort rather than popping up
280 * the statistics window.
282 stop_flag = TRUE;
283 break;
286 tot_packets++;
287 tot_bytes += frame->pkt_len;
290 count++;
293 /* We're done calculating the statistics; destroy the progress bar
294 if it was created. */
295 if (progbar != NULL)
296 destroy_progress_dlg(progbar);
298 if (stop_flag) {
300 * We quit in the middle; throw away the statistics
301 * and return NULL, so our caller doesn't pop up a
302 * window with the incomplete statistics.
304 ph_stats_free(ps);
305 return NULL;
308 ps->tot_packets = tot_packets;
309 ps->tot_bytes = tot_bytes;
311 return ps;
314 static gboolean
315 stat_node_free(GNode *node, gpointer data _U_)
317 ph_stats_node_t *stats = (ph_stats_node_t *)node->data;
319 if (stats) {
320 g_free(stats);
322 return FALSE;
325 void
326 ph_stats_free(ph_stats_t *ps)
329 if (ps->stats_tree) {
330 g_node_traverse(ps->stats_tree, G_IN_ORDER,
331 G_TRAVERSE_ALL, -1,
332 stat_node_free, NULL);
333 g_node_destroy(ps->stats_tree);
336 g_free(ps);