Try to improve the "Kerberos requested but not OpenSSL" message.
[jelmer/wireshark.git] / proto_hier_stats.c
1 /* proto_hier_stats.c
2  * Routines for calculating statistics based on protocol.
3  *
4  * Wireshark - Network traffic analyzer
5  * By Gerald Combs <gerald@wireshark.org>
6  * Copyright 1998 Gerald Combs
7  *
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.
12  *
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.
17  *
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.
21  */
22
23 #include "config.h"
24
25 #include <stdio.h>
26
27 #include "globals.h"
28 #include "proto_hier_stats.h"
29 #include "frame_tvbuff.h"
30 #include "ui/progress_dlg.h"
31 #include <epan/epan_dissect.h>
32 #include <wtap.h>
33
34 #include <stdio.h>
35 #include <string.h>
36 #include <glib.h>
37
38 /* Update the progress bar this many times when scanning the packet list. */
39 #define N_PROGBAR_UPDATES       100
40
41 #define STAT_NODE_STATS(n)   ((ph_stats_node_t*)(n)->data)
42 #define STAT_NODE_HFINFO(n)  (STAT_NODE_STATS(n)->hfinfo)
43
44
45 static GNode*
46 find_stat_node(GNode *parent_stat_node, header_field_info *needle_hfinfo)
47 {
48         GNode                   *needle_stat_node;
49         header_field_info       *hfinfo;
50         ph_stats_node_t         *stats;
51
52         needle_stat_node = g_node_first_child(parent_stat_node);
53
54         while (needle_stat_node) {
55                 hfinfo = STAT_NODE_HFINFO(needle_stat_node);
56                 if (hfinfo &&  hfinfo->id == needle_hfinfo->id) {
57                         return needle_stat_node;
58                 }
59                 needle_stat_node = g_node_next_sibling(needle_stat_node);
60         }
61
62         /* None found. Create one. */
63         stats = g_new(ph_stats_node_t, 1);
64
65         /* Intialize counters */
66         stats->hfinfo = needle_hfinfo;
67         stats->num_pkts_total = 0;
68         stats->num_pkts_last = 0;
69         stats->num_bytes_total = 0;
70         stats->num_bytes_last = 0;
71
72         needle_stat_node = g_node_new(stats);
73         g_node_append(parent_stat_node, needle_stat_node);
74         return needle_stat_node;
75 }
76
77
78 static void
79 process_node(proto_node *ptree_node, GNode *parent_stat_node, ph_stats_t *ps, guint pkt_len)
80 {
81         field_info              *finfo;
82         ph_stats_node_t         *stats;
83         proto_node              *proto_sibling_node;
84         GNode                   *stat_node;
85
86         finfo = PNODE_FINFO(ptree_node);
87         /* We don't fake protocol nodes we expect them to have a field_info.
88          * Dissection with faked proto tree? */
89         g_assert(finfo);
90
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);
98         } else {
99                 stat_node = find_stat_node(parent_stat_node, finfo->hfinfo);
100
101                 stats = STAT_NODE_STATS(stat_node);
102                 stats->num_pkts_total++;
103                 stats->num_bytes_total += pkt_len;
104         }
105
106         proto_sibling_node = ptree_node->next;
107
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;
115
116                 process_node(proto_sibling_node, stat_node, ps, pkt_len);
117         } else {
118                 stats->num_pkts_last++;
119                 stats->num_bytes_last += pkt_len;
120         }
121 }
122
123
124
125 static void
126 process_tree(proto_tree *protocol_tree, ph_stats_t* ps, guint pkt_len)
127 {
128         proto_node      *ptree_node;
129
130         ptree_node = ((proto_node *)protocol_tree)->first_child;
131         if (!ptree_node) {
132                 return;
133         }
134
135         process_node(ptree_node, ps->stats_tree, ps, pkt_len);
136 }
137
138 static gboolean
139 process_frame(frame_data *frame, column_info *cinfo, ph_stats_t* ps)
140 {
141         epan_dissect_t                  edt;
142         struct wtap_pkthdr              phdr;
143         Buffer                          buf;
144         double                          cur_time;
145
146         /* Load the frame from the capture file */
147         buffer_init(&buf, 1500);
148         if (!cf_read_frame_r(&cfile, frame, &phdr, &buf))
149                 return FALSE;   /* failure */
150
151         /* Dissect the frame   tree  not visible */
152         epan_dissect_init(&edt, cfile.epan, TRUE, FALSE);
153         /* Don't fake protocols. We need them for the protocol hierarchy */
154         epan_dissect_fake_protocols(&edt, FALSE);
155         epan_dissect_run(&edt, &phdr, frame_tvbuff_new_buffer(frame, &buf), frame, cinfo);
156
157         /* Get stats from this protocol tree */
158         process_tree(edt.tree, ps, frame->pkt_len);
159
160         /* Update times */
161         cur_time = nstime_to_sec(&frame->abs_ts);
162         if (cur_time < ps->first_time) {
163           ps->first_time = cur_time;
164         }
165         if (cur_time > ps->last_time){
166           ps->last_time = cur_time;
167         }
168
169         /* Free our memory. */
170         epan_dissect_cleanup(&edt);
171         buffer_free(&buf);
172
173         return TRUE;    /* success */
174 }
175
176 ph_stats_t*
177 ph_stats_new(void)
178 {
179         ph_stats_t      *ps;
180         guint32         framenum;
181         frame_data      *frame;
182         guint           tot_packets, tot_bytes;
183         progdlg_t       *progbar = NULL;
184         gboolean        stop_flag;
185         int             count;
186         float           progbar_val;
187         GTimeVal        start_time;
188         gchar           status_str[100];
189         int             progbar_nextstep;
190         int             progbar_quantum;
191
192         /* Initialize the data */
193         ps = g_new(ph_stats_t, 1);
194         ps->tot_packets = 0;
195         ps->tot_bytes = 0;
196         ps->stats_tree = g_node_new(NULL);
197         ps->first_time = 0.0;
198         ps->last_time = 0.0;
199
200         /* Update the progress bar when it gets to this value. */
201         progbar_nextstep = 0;
202         /* When we reach the value that triggers a progress bar update,
203            bump that value by this amount. */
204         progbar_quantum = cfile.count/N_PROGBAR_UPDATES;
205         /* Count of packets at which we've looked. */
206         count = 0;
207         /* Progress so far. */
208         progbar_val = 0.0f;
209
210         stop_flag = FALSE;
211         g_get_current_time(&start_time);
212
213         tot_packets = 0;
214         tot_bytes = 0;
215
216         for (framenum = 1; framenum <= cfile.count; framenum++) {
217                 frame = frame_data_sequence_find(cfile.frames, framenum);
218
219                 /* Create the progress bar if necessary.
220                    We check on every iteration of the loop, so that
221                    it takes no longer than the standard time to create
222                    it (otherwise, for a large file, we might take
223                    considerably longer than that standard time in order
224                    to get to the next progress bar step). */
225                 if (progbar == NULL)
226                         progbar = delayed_create_progress_dlg(
227                             cfile.window, "Computing",
228                             "protocol hierarchy statistics",
229                             TRUE, &stop_flag, &start_time, progbar_val);
230
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
240                          */
241                         g_assert(cfile.count > 0);
242
243                         progbar_val = (gfloat) count / cfile.count;
244
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);
249                         }
250
251                         progbar_nextstep += progbar_quantum;
252                 }
253
254                 if (stop_flag) {
255                         /* Well, the user decided to abort the statistics.
256                            computation process  Just stop. */
257                         break;
258                 }
259
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) {
266
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;
271                         }
272
273                         /* we don't care about colinfo */
274                         if (!process_frame(frame, NULL, ps)) {
275                                 /*
276                                  * Give up, and set "stop_flag" so we
277                                  * just abort rather than popping up
278                                  * the statistics window.
279                                  */
280                                 stop_flag = TRUE;
281                                 break;
282                         }
283
284                         tot_packets++;
285                         tot_bytes += frame->pkt_len;
286                 }
287
288                 count++;
289         }
290
291         /* We're done calculating the statistics; destroy the progress bar
292            if it was created. */
293         if (progbar != NULL)
294                 destroy_progress_dlg(progbar);
295
296         if (stop_flag) {
297                 /*
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.
301                  */
302                 ph_stats_free(ps);
303                 return NULL;
304         }
305
306         ps->tot_packets = tot_packets;
307         ps->tot_bytes = tot_bytes;
308
309         return ps;
310 }
311
312 static gboolean
313 stat_node_free(GNode *node, gpointer data _U_)
314 {
315         ph_stats_node_t *stats = (ph_stats_node_t *)node->data;
316
317         if (stats) {
318                 g_free(stats);
319         }
320         return FALSE;
321 }
322
323 void
324 ph_stats_free(ph_stats_t *ps)
325 {
326
327         if (ps->stats_tree) {
328                 g_node_traverse(ps->stats_tree, G_IN_ORDER,
329                                 G_TRAVERSE_ALL, -1,
330                                 stat_node_free, NULL);
331                 g_node_destroy(ps->stats_tree);
332         }
333
334         g_free(ps);
335 }