HTTPS (almost) everywhere.
[metze/wireshark/wip.git] / ui / packet_range.c
1 /* packet_range.c
2  * Packet range routines (save, print, ...)
3  *
4  * Dick Gooris <gooris@lucent.com>
5  * Ulf Lamping <ulf.lamping@web.de>
6  *
7  * Wireshark - Network traffic analyzer
8  * By Gerald Combs <gerald@wireshark.org>
9  * Copyright 1998 Gerald Combs
10  *
11  * SPDX-License-Identifier: GPL-2.0-or-later
12  */
13
14 #include "config.h"
15
16 #include <string.h>
17
18 #include <glib.h>
19
20 #include <epan/frame_data.h>
21
22 #include "packet_range.h"
23
24 /* (re-)calculate the packet counts (except the user specified range) */
25 static void packet_range_calc(packet_range_t *range) {
26     guint32       framenum;
27     guint32       mark_low;
28     guint32       mark_high;
29     guint32       displayed_mark_low;
30     guint32       displayed_mark_high;
31     frame_data    *packet;
32
33
34     range->selected_packet                  = 0;
35
36     mark_low                                = 0;
37     mark_high                               = 0;
38     range->mark_range_cnt                   = 0;
39     range->ignored_cnt                      = 0;
40     range->ignored_marked_cnt               = 0;
41     range->ignored_mark_range_cnt           = 0;
42     range->ignored_user_range_cnt           = 0;
43
44     displayed_mark_low                      = 0;
45     displayed_mark_high                     = 0;
46
47     range->displayed_cnt                    = 0;
48     range->displayed_marked_cnt             = 0;
49     range->displayed_mark_range_cnt         = 0;
50     range->displayed_plus_dependents_cnt    = 0;
51     range->displayed_ignored_cnt            = 0;
52     range->displayed_ignored_marked_cnt     = 0;
53     range->displayed_ignored_mark_range_cnt = 0;
54     range->displayed_ignored_user_range_cnt = 0;
55
56     g_assert(range->cf != NULL);
57
58     /* XXX - this doesn't work unless you have a full set of frame_data
59      * structures for all packets in the capture, which is not,
60      * for example, the case when TShark is doing a one-pass
61      * read of a file or a live capture.
62      *
63      * It's also horribly slow on large captures, causing it to
64      * take a long time for the Save As dialog to pop up, for
65      * example.  We should really keep these statistics in
66      * the capture_file structure, updating them whenever we
67      * filter the display, etc..
68      */
69     if (range->cf->provider.frames != NULL) {
70         /* The next for-loop is used to obtain the amount of packets
71          * to be processed and is used to present the information in
72          * the Save/Print As widget.
73          * We have different types of ranges: All the packets, the number
74          * of packets of a marked range, a single packet, and a user specified
75          * packet range. The last one is not calculated here since this
76          * data must be entered in the widget by the user.
77          */
78
79         for(framenum = 1; framenum <= range->cf->count; framenum++) {
80             packet = frame_data_sequence_find(range->cf->provider.frames, framenum);
81
82             if (range->cf->current_frame == packet) {
83                 range->selected_packet = framenum;
84             }
85             if (packet->passed_dfilter) {
86                 range->displayed_cnt++;
87             }
88             if (packet->passed_dfilter ||
89                 packet->dependent_of_displayed) {
90                 range->displayed_plus_dependents_cnt++;
91             }
92             if (packet->marked) {
93                 if (packet->ignored) {
94                     range->ignored_marked_cnt++;
95                 }
96                 if (packet->passed_dfilter) {
97                     range->displayed_marked_cnt++;
98                     if (packet->ignored) {
99                         range->displayed_ignored_marked_cnt++;
100                     }
101                     if (displayed_mark_low == 0) {
102                        displayed_mark_low = framenum;
103                     }
104                     if (framenum > displayed_mark_high) {
105                        displayed_mark_high = framenum;
106                     }
107                 }
108
109                 if (mark_low == 0) {
110                    mark_low = framenum;
111                 }
112                 if (framenum > mark_high) {
113                    mark_high = framenum;
114                 }
115             }
116             if (packet->ignored) {
117                 range->ignored_cnt++;
118                 if (packet->passed_dfilter) {
119                     range->displayed_ignored_cnt++;
120                 }
121             }
122         }
123
124         for(framenum = 1; framenum <= range->cf->count; framenum++) {
125             packet = frame_data_sequence_find(range->cf->provider.frames, framenum);
126
127             if (framenum >= mark_low &&
128                 framenum <= mark_high)
129             {
130                 range->mark_range_cnt++;
131                 if (packet->ignored) {
132                     range->ignored_mark_range_cnt++;
133                 }
134             }
135
136             if (framenum >= displayed_mark_low &&
137                 framenum <= displayed_mark_high)
138             {
139                 if (packet->passed_dfilter) {
140                     range->displayed_mark_range_cnt++;
141                     if (packet->ignored) {
142                         range->displayed_ignored_mark_range_cnt++;
143                     }
144                 }
145             }
146         }
147
148 #if 0
149         /* in case we marked just one packet, we add 1. */
150         if (range->cf->marked_count != 0) {
151             range->mark_range = mark_high - mark_low + 1;
152         }
153
154         /* in case we marked just one packet, we add 1. */
155         if (range->displayed_marked_cnt != 0) {
156             range->displayed_mark_range = displayed_mark_high - displayed_mark_low + 1;
157         }
158 #endif
159     }
160 }
161
162
163 /* (re-)calculate the user specified packet range counts */
164 static void packet_range_calc_user(packet_range_t *range) {
165     guint32       framenum;
166     frame_data    *packet;
167
168     range->user_range_cnt                   = 0;
169     range->ignored_user_range_cnt           = 0;
170     range->displayed_user_range_cnt         = 0;
171     range->displayed_ignored_user_range_cnt = 0;
172
173     g_assert(range->cf != NULL);
174
175     /* XXX - this doesn't work unless you have a full set of frame_data
176      * structures for all packets in the capture, which is not,
177      * for example, the case when TShark is doing a one-pass
178      * read of a file or a live capture.
179      *
180      * It's also horribly slow on large captures, causing it to
181      * take a long time for the Save As dialog to pop up, for
182      * example.  This obviously can't be kept in the capture_file
183      * structure and recalculated whenever we filter the display
184      * or mark frames as ignored, as the results of this depend
185      * on what the user specifies.  In some cases, limiting the
186      * frame_data structures at which we look to the ones specified
187      * by the user might help, but if most of the frames are in
188      * the range, that won't help.  In that case, if we could
189      * examine the *complement* of the range, and *subtract* them
190      * from the statistics for the capture as a whole, that might
191      * help, but if the user specified about *half* the packets in
192      * the range, that won't help, either.
193      */
194     if (range->cf->provider.frames != NULL) {
195         for(framenum = 1; framenum <= range->cf->count; framenum++) {
196             packet = frame_data_sequence_find(range->cf->provider.frames, framenum);
197
198             if (value_is_in_range(range->user_range, framenum)) {
199                 range->user_range_cnt++;
200                 if (packet->ignored) {
201                     range->ignored_user_range_cnt++;
202                 }
203                 if (packet->passed_dfilter) {
204                     range->displayed_user_range_cnt++;
205                     if (packet->ignored) {
206                         range->displayed_ignored_user_range_cnt++;
207                     }
208                 }
209             }
210         }
211     }
212 }
213
214
215 /* init the range struct */
216 void packet_range_init(packet_range_t *range, capture_file *cf) {
217
218     memset(range, 0, sizeof(packet_range_t));
219     range->process    = range_process_all;
220     range->user_range = NULL;
221     range->cf         = cf;
222
223     /* calculate all packet range counters */
224     packet_range_calc(range);
225     packet_range_calc_user(range);
226 }
227
228 void packet_range_cleanup(packet_range_t *range) {
229     wmem_free(NULL, range->user_range);
230 }
231
232 /* check whether the packet range is OK */
233 convert_ret_t packet_range_check(packet_range_t *range) {
234     if (range->process == range_process_user_range && range->user_range == NULL) {
235         /* Not valid - return the error. */
236         return range->user_range_status;
237     }
238     return CVT_NO_ERROR;
239 }
240
241 /* init the processing run */
242 void packet_range_process_init(packet_range_t *range) {
243     /* Check that, if an explicit range was selected, it's valid. */
244     /* "enumeration" values */
245     range->marked_range_active    = FALSE;
246     range->selected_done          = FALSE;
247
248     if (range->process_filtered == FALSE) {
249         range->marked_range_left = range->mark_range_cnt;
250     } else {
251         range->marked_range_left = range->displayed_mark_range_cnt;
252     }
253 }
254
255 /* do we have to process all packets? */
256 gboolean packet_range_process_all(packet_range_t *range) {
257     return range->process == range_process_all && !range->process_filtered && !range->remove_ignored;
258 }
259
260 /* do we have to process this packet? */
261 range_process_e packet_range_process_packet(packet_range_t *range, frame_data *fdata) {
262
263     if (range->remove_ignored && fdata->ignored) {
264         return range_process_next;
265     }
266
267     g_assert(range->cf != NULL);
268
269     switch(range->process) {
270     case(range_process_all):
271         break;
272     case(range_process_selected):
273         if (range->selected_done) {
274           return range_processing_finished;
275         }
276         if (fdata->num != range->cf->current_frame->num) {
277           return range_process_next;
278         }
279         range->selected_done = TRUE;
280         break;
281     case(range_process_marked):
282         if (fdata->marked == FALSE) {
283           return range_process_next;
284         }
285         break;
286     case(range_process_marked_range):
287         if (range->marked_range_left == 0) {
288           return range_processing_finished;
289         }
290         if (fdata->marked == TRUE) {
291           range->marked_range_active = TRUE;
292         }
293         if (range->marked_range_active == FALSE ) {
294           return range_process_next;
295         }
296         if (!range->process_filtered ||
297           (range->process_filtered && fdata->passed_dfilter == TRUE))
298         {
299           range->marked_range_left--;
300         }
301         break;
302     case(range_process_user_range):
303         if (value_is_in_range(range->user_range, fdata->num) == FALSE) {
304           return range_process_next;
305         }
306         break;
307     default:
308         g_assert_not_reached();
309     }
310
311     /* This packet has to pass the display filter but didn't?
312      * Try next, but only if we're not including dependent packets and this
313      * packet happens to be a dependency on something that is displayed.
314      */
315     if ((range->process_filtered && fdata->passed_dfilter == FALSE) &&
316         !(range->include_dependents && fdata->dependent_of_displayed)) {
317         return range_process_next;
318     }
319
320     /* We fell through the conditions above, so we accept this packet */
321     return range_process_this;
322 }
323
324
325 /******************** Range Entry Parser *********************************/
326
327 /* Converts a range string to a user range.
328  * The parameter 'es' points to the string to be converted, and is defined in
329  * the Save/Print-As widget.
330  */
331
332 void packet_range_convert_str(packet_range_t *range, const gchar *es)
333 {
334     range_t *new_range;
335     convert_ret_t ret;
336
337     if (range->user_range != NULL)
338         wmem_free(NULL, range->user_range);
339
340     g_assert(range->cf != NULL);
341
342     ret = range_convert_str(NULL, &new_range, es, range->cf->count);
343     if (ret != CVT_NO_ERROR) {
344         /* range isn't valid */
345         range->user_range                       = NULL;
346         range->user_range_status                = ret;
347         range->user_range_cnt                   = 0;
348         range->ignored_user_range_cnt           = 0;
349         range->displayed_user_range_cnt         = 0;
350         range->displayed_ignored_user_range_cnt = 0;
351         return;
352     }
353     range->user_range = new_range;
354
355     /* calculate new user specified packet range counts */
356     packet_range_calc_user(range);
357 } /* packet_range_convert_str */
358
359
360 /*
361  * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
362  *
363  * Local variables:
364  * c-basic-offset: 4
365  * tab-width: 8
366  * indent-tabs-mode: nil
367  * End:
368  *
369  * vi: set shiftwidth=4 tabstop=8 expandtab:
370  * :indentSize=4:tabSize=8:noTabs=true:
371  */