Remove unneeded includes from ui folder
[metze/wireshark/wip.git] / ui / 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
26 #include "globals.h"
27 #include "frame_tvbuff.h"
28 #include "ui/proto_hier_stats.h"
29 #include "ui/progress_dlg.h"
30 #include <epan/epan_dissect.h>
31
32 #include <string.h>
33
34 /* Update the progress bar this many times when scanning the packet list. */
35 #define N_PROGBAR_UPDATES       100
36
37 #define STAT_NODE_STATS(n)   ((ph_stats_node_t*)(n)->data)
38 #define STAT_NODE_HFINFO(n)  (STAT_NODE_STATS(n)->hfinfo)
39
40
41 static GNode*
42 find_stat_node(GNode *parent_stat_node, header_field_info *needle_hfinfo)
43 {
44         GNode                   *needle_stat_node;
45         header_field_info       *hfinfo;
46         ph_stats_node_t         *stats;
47
48         needle_stat_node = g_node_first_child(parent_stat_node);
49
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;
54                 }
55                 needle_stat_node = g_node_next_sibling(needle_stat_node);
56         }
57
58         /* None found. Create one. */
59         stats = g_new(ph_stats_node_t, 1);
60
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;
67
68         needle_stat_node = g_node_new(stats);
69         g_node_append(parent_stat_node, needle_stat_node);
70         return needle_stat_node;
71 }
72
73
74 static void
75 process_node(proto_node *ptree_node, GNode *parent_stat_node, ph_stats_t *ps, guint pkt_len)
76 {
77         field_info              *finfo;
78         ph_stats_node_t         *stats;
79         proto_node              *proto_sibling_node;
80         GNode                   *stat_node;
81
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? */
85         g_assert(finfo);
86
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);
94         } else {
95                 stat_node = find_stat_node(parent_stat_node, finfo->hfinfo);
96
97                 stats = STAT_NODE_STATS(stat_node);
98                 stats->num_pkts_total++;
99                 stats->num_bytes_total += pkt_len;
100         }
101
102         proto_sibling_node = ptree_node->next;
103
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;
111
112                 process_node(proto_sibling_node, stat_node, ps, pkt_len);
113         } else {
114                 stats->num_pkts_last++;
115                 stats->num_bytes_last += pkt_len;
116         }
117 }
118
119
120
121 static void
122 process_tree(proto_tree *protocol_tree, ph_stats_t* ps, guint pkt_len)
123 {
124         proto_node      *ptree_node;
125
126         ptree_node = ((proto_node *)protocol_tree)->first_child;
127         if (!ptree_node) {
128                 return;
129         }
130
131         process_node(ptree_node, ps->stats_tree, ps, pkt_len);
132 }
133
134 static gboolean
135 process_record(frame_data *frame, column_info *cinfo, ph_stats_t* ps)
136 {
137         epan_dissect_t                  edt;
138         struct wtap_pkthdr              phdr;
139         Buffer                          buf;
140         double                          cur_time;
141
142         wtap_phdr_init(&phdr);
143
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 */
148
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);
154
155         /* Get stats from this protocol tree */
156         process_tree(edt.tree, ps, frame->pkt_len);
157
158         if (frame->flags.has_ts) {
159                 /* Update times */
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;
165         }
166
167         /* Free our memory. */
168         epan_dissect_cleanup(&edt);
169         wtap_phdr_cleanup(&phdr);
170         ws_buffer_free(&buf);
171
172         return TRUE;    /* success */
173 }
174
175 ph_stats_t*
176 ph_stats_new(void)
177 {
178         ph_stats_t      *ps;
179         guint32         framenum;
180         frame_data      *frame;
181         guint           tot_packets, tot_bytes;
182         progdlg_t       *progbar = NULL;
183         gboolean        stop_flag;
184         int             count;
185         float           progbar_val;
186         GTimeVal        start_time;
187         gchar           status_str[100];
188         int             progbar_nextstep;
189         int             progbar_quantum;
190
191         /* Initialize the data */
192         ps = g_new(ph_stats_t, 1);
193         ps->tot_packets = 0;
194         ps->tot_bytes = 0;
195         ps->stats_tree = g_node_new(NULL);
196         ps->first_time = 0.0;
197         ps->last_time = 0.0;
198
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. */
205         count = 0;
206         /* Progress so far. */
207         progbar_val = 0.0f;
208
209         stop_flag = FALSE;
210         g_get_current_time(&start_time);
211
212         tot_packets = 0;
213         tot_bytes = 0;
214
215         for (framenum = 1; framenum <= cfile.count; framenum++) {
216                 frame = frame_data_sequence_find(cfile.frames, framenum);
217
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). */
224                 if (progbar == NULL)
225                         progbar = delayed_create_progress_dlg(
226                             cfile.window, "Computing",
227                             "protocol hierarchy statistics",
228                             TRUE, &stop_flag, &start_time, progbar_val);
229
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
239                          */
240                         g_assert(cfile.count > 0);
241
242                         progbar_val = (gfloat) count / cfile.count;
243
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);
248                         }
249
250                         progbar_nextstep += progbar_quantum;
251                 }
252
253                 if (stop_flag) {
254                         /* Well, the user decided to abort the statistics.
255                            computation process  Just stop. */
256                         break;
257                 }
258
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) {
265
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;
271                                 }
272                         }
273
274                         /* we don't care about colinfo */
275                         if (!process_record(frame, NULL, ps)) {
276                                 /*
277                                  * Give up, and set "stop_flag" so we
278                                  * just abort rather than popping up
279                                  * the statistics window.
280                                  */
281                                 stop_flag = TRUE;
282                                 break;
283                         }
284
285                         tot_packets++;
286                         tot_bytes += frame->pkt_len;
287                 }
288
289                 count++;
290         }
291
292         /* We're done calculating the statistics; destroy the progress bar
293            if it was created. */
294         if (progbar != NULL)
295                 destroy_progress_dlg(progbar);
296
297         if (stop_flag) {
298                 /*
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.
302                  */
303                 ph_stats_free(ps);
304                 return NULL;
305         }
306
307         ps->tot_packets = tot_packets;
308         ps->tot_bytes = tot_bytes;
309
310         return ps;
311 }
312
313 static gboolean
314 stat_node_free(GNode *node, gpointer data _U_)
315 {
316         ph_stats_node_t *stats = (ph_stats_node_t *)node->data;
317
318         if (stats) {
319                 g_free(stats);
320         }
321         return FALSE;
322 }
323
324 void
325 ph_stats_free(ph_stats_t *ps)
326 {
327
328         if (ps->stats_tree) {
329                 g_node_traverse(ps->stats_tree, G_IN_ORDER,
330                                 G_TRAVERSE_ALL, -1,
331                                 stat_node_free, NULL);
332                 g_node_destroy(ps->stats_tree);
333         }
334
335         g_free(ps);
336 }
337
338 /*
339  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
340  *
341  * Local variables:
342  * c-basic-offset: 8
343  * tab-width: 8
344  * indent-tabs-mode: t
345  * End:
346  *
347  * vi: set shiftwidth=8 tabstop=8 noexpandtab:
348  * :indentSize=8:tabSize=8:noTabs=false:
349  */