epan/dissectors/packet-xml.c try to decrypt data, but the data doesn't look correct yet
[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  * SPDX-License-Identifier: GPL-2.0-or-later
9  */
10
11 #include "config.h"
12
13 #include <string.h>
14
15 #include "file.h"
16 #include "frame_tvbuff.h"
17 #include "ui/proto_hier_stats.h"
18 #include "ui/progress_dlg.h"
19 #include "epan/epan_dissect.h"
20 #include "epan/proto.h"
21
22 /* Update the progress bar this many times when scanning the packet list. */
23 #define N_PROGBAR_UPDATES       100
24
25 #define STAT_NODE_STATS(n)   ((ph_stats_node_t*)(n)->data)
26 #define STAT_NODE_HFINFO(n)  (STAT_NODE_STATS(n)->hfinfo)
27
28 static int pc_proto_id = -1;
29
30 static GNode*
31 find_stat_node(GNode *parent_stat_node, header_field_info *needle_hfinfo)
32 {
33     GNode               *needle_stat_node, *up_parent_stat_node;
34     header_field_info   *hfinfo;
35     ph_stats_node_t     *stats;
36
37     /* Look down the tree */
38     needle_stat_node = g_node_first_child(parent_stat_node);
39
40     while (needle_stat_node) {
41         hfinfo = STAT_NODE_HFINFO(needle_stat_node);
42         if (hfinfo &&  hfinfo->id == needle_hfinfo->id) {
43             return needle_stat_node;
44         }
45         needle_stat_node = g_node_next_sibling(needle_stat_node);
46     }
47
48     /* Look up the tree */
49     up_parent_stat_node = parent_stat_node;
50     while (up_parent_stat_node && up_parent_stat_node->parent)
51     {
52         needle_stat_node = g_node_first_child(up_parent_stat_node->parent);
53         while (needle_stat_node) {
54             hfinfo = STAT_NODE_HFINFO(needle_stat_node);
55             if (hfinfo &&  hfinfo->id == needle_hfinfo->id) {
56                 return needle_stat_node;
57             }
58             needle_stat_node = g_node_next_sibling(needle_stat_node);
59         }
60
61         up_parent_stat_node = up_parent_stat_node->parent;
62     }
63
64     /* None found. Create one. */
65     stats = g_new(ph_stats_node_t, 1);
66
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;
73
74     needle_stat_node = g_node_new(stats);
75     g_node_append(parent_stat_node, needle_stat_node);
76     return needle_stat_node;
77 }
78
79
80     static void
81 process_node(proto_node *ptree_node, GNode *parent_stat_node, ph_stats_t *ps)
82 {
83     field_info          *finfo;
84     ph_stats_node_t     *stats;
85     proto_node          *proto_sibling_node;
86     GNode               *stat_node;
87
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);
92
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);
102
103         stats = STAT_NODE_STATS(stat_node);
104         stats->num_pkts_total++;
105         stats->num_bytes_total += finfo->length;
106     }
107
108     proto_sibling_node = ptree_node->next;
109
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;
117
118         process_node(proto_sibling_node, stat_node, ps);
119     } else {
120         stats->num_pkts_last++;
121         stats->num_bytes_last += finfo->length;
122     }
123 }
124
125
126
127     static void
128 process_tree(proto_tree *protocol_tree, ph_stats_t* ps)
129 {
130     proto_node  *ptree_node;
131
132     /*
133      * If our first item is a comment, skip over it. This keeps
134      * us from having a top-level "Packet comments" item that
135      * steals items from "Frame".
136      */
137     ptree_node = ((proto_node *)protocol_tree)->first_child;
138     if (ptree_node && ptree_node->finfo->hfinfo->id == pc_proto_id) {
139         ptree_node = ptree_node->next;
140     }
141
142     if (!ptree_node) {
143         return;
144     }
145
146     process_node(ptree_node, ps->stats_tree, ps);
147 }
148
149     static gboolean
150 process_record(capture_file *cf, frame_data *frame, column_info *cinfo, ph_stats_t* ps)
151 {
152     epan_dissect_t      edt;
153     wtap_rec            rec;
154     Buffer              buf;
155     double              cur_time;
156
157     wtap_rec_init(&rec);
158
159     /* Load the record from the capture file */
160     ws_buffer_init(&buf, 1500);
161     if (!cf_read_record_r(cf, frame, &rec, &buf))
162         return FALSE;   /* failure */
163
164     /* Dissect the record   tree  not visible */
165     epan_dissect_init(&edt, cf->epan, TRUE, FALSE);
166     /* Don't fake protocols. We need them for the protocol hierarchy */
167     epan_dissect_fake_protocols(&edt, FALSE);
168     epan_dissect_run(&edt, cf->cd_t, &rec,
169                      frame_tvbuff_new_buffer(&cf->provider, frame, &buf),
170                      frame, cinfo);
171
172     /* Get stats from this protocol tree */
173     process_tree(edt.tree, ps);
174
175     if (frame->has_ts) {
176         /* Update times */
177         cur_time = nstime_to_sec(&frame->abs_ts);
178         if (cur_time < ps->first_time)
179             ps->first_time = cur_time;
180         if (cur_time > ps->last_time)
181             ps->last_time = cur_time;
182     }
183
184     /* Free our memory. */
185     epan_dissect_cleanup(&edt);
186     wtap_rec_cleanup(&rec);
187     ws_buffer_free(&buf);
188
189     return TRUE;        /* success */
190 }
191
192     ph_stats_t*
193 ph_stats_new(capture_file *cf)
194 {
195     ph_stats_t  *ps;
196     guint32     framenum;
197     frame_data  *frame;
198     guint       tot_packets, tot_bytes;
199     progdlg_t   *progbar = NULL;
200     gboolean    stop_flag;
201     int         count;
202     float       progbar_val;
203     GTimeVal    start_time;
204     gchar       status_str[100];
205     int         progbar_nextstep;
206     int         progbar_quantum;
207
208     if (!cf) return NULL;
209
210     pc_proto_id = proto_registrar_get_id_byname("pkt_comment");
211
212     /* Initialize the data */
213     ps = g_new(ph_stats_t, 1);
214     ps->tot_packets = 0;
215     ps->tot_bytes = 0;
216     ps->stats_tree = g_node_new(NULL);
217     ps->first_time = 0.0;
218     ps->last_time = 0.0;
219
220     /* Update the progress bar when it gets to this value. */
221     progbar_nextstep = 0;
222     /* When we reach the value that triggers a progress bar update,
223        bump that value by this amount. */
224     progbar_quantum = cf->count/N_PROGBAR_UPDATES;
225     /* Count of packets at which we've looked. */
226     count = 0;
227     /* Progress so far. */
228     progbar_val = 0.0f;
229
230     stop_flag = FALSE;
231     g_get_current_time(&start_time);
232
233     tot_packets = 0;
234     tot_bytes = 0;
235
236     for (framenum = 1; framenum <= cf->count; framenum++) {
237         frame = frame_data_sequence_find(cf->provider.frames, framenum);
238
239         /* Create the progress bar if necessary.
240            We check on every iteration of the loop, so that
241            it takes no longer than the standard time to create
242            it (otherwise, for a large file, we might take
243            considerably longer than that standard time in order
244            to get to the next progress bar step). */
245         if (progbar == NULL)
246             progbar = delayed_create_progress_dlg(
247                     cf->window, "Computing",
248                     "protocol hierarchy statistics",
249                     TRUE, &stop_flag, &start_time, progbar_val);
250
251         /* Update the progress bar, but do it only N_PROGBAR_UPDATES
252            times; when we update it, we have to run the GTK+ main
253            loop to get it to repaint what's pending, and doing so
254            may involve an "ioctl()" to see if there's any pending
255            input from an X server, and doing that for every packet
256            can be costly, especially on a big file. */
257         if (count >= progbar_nextstep) {
258             /* let's not divide by zero. I should never be started
259              * with count == 0, so let's assert that
260              */
261             g_assert(cf->count > 0);
262
263             progbar_val = (gfloat) count / cf->count;
264
265             if (progbar != NULL) {
266                 g_snprintf(status_str, sizeof(status_str),
267                         "%4u of %u frames", count, cf->count);
268                 update_progress_dlg(progbar, progbar_val, status_str);
269             }
270
271             progbar_nextstep += progbar_quantum;
272         }
273
274         if (stop_flag) {
275             /* Well, the user decided to abort the statistics.
276                computation process  Just stop. */
277             break;
278         }
279
280         /* Skip frames that are hidden due to the display filter.
281            XXX - should the progress bar count only packets that
282            passed the display filter?  If so, it should
283            probably do so for other loops (see "file.c") that
284            look only at those packets. */
285         if (frame->passed_dfilter) {
286
287             if (frame->has_ts) {
288                 if (tot_packets == 0) {
289                     double cur_time = nstime_to_sec(&frame->abs_ts);
290                     ps->first_time = cur_time;
291                     ps->last_time = cur_time;
292                 }
293             }
294
295             /* we don't care about colinfo */
296             if (!process_record(cf, frame, NULL, ps)) {
297                 /*
298                  * Give up, and set "stop_flag" so we
299                  * just abort rather than popping up
300                  * the statistics window.
301                  */
302                 stop_flag = TRUE;
303                 break;
304             }
305
306             tot_packets++;
307             tot_bytes += frame->pkt_len;
308         }
309
310         count++;
311     }
312
313     /* We're done calculating the statistics; destroy the progress bar
314        if it was created. */
315     if (progbar != NULL)
316         destroy_progress_dlg(progbar);
317
318     if (stop_flag) {
319         /*
320          * We quit in the middle; throw away the statistics
321          * and return NULL, so our caller doesn't pop up a
322          * window with the incomplete statistics.
323          */
324         ph_stats_free(ps);
325         return NULL;
326     }
327
328     ps->tot_packets = tot_packets;
329     ps->tot_bytes = tot_bytes;
330
331     return ps;
332 }
333
334     static gboolean
335 stat_node_free(GNode *node, gpointer data _U_)
336 {
337     ph_stats_node_t     *stats = (ph_stats_node_t *)node->data;
338     g_free(stats);
339     return FALSE;
340 }
341
342     void
343 ph_stats_free(ph_stats_t *ps)
344 {
345     if (ps->stats_tree) {
346         g_node_traverse(ps->stats_tree, G_IN_ORDER,
347                 G_TRAVERSE_ALL, -1,
348                 stat_node_free, NULL);
349         g_node_destroy(ps->stats_tree);
350     }
351
352     g_free(ps);
353 }
354
355 /*
356  * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
357  *
358  * Local Variables:
359  * c-basic-offset: 4
360  * tab-width: 8
361  * indent-tabs-mode: nil
362  * End:
363  *
364  * ex: set shiftwidth=4 tabstop=8 expandtab:
365  * :indentSize=4:tabSize=8:noTabs=true:
366  */