4 * Wireshark - Network traffic analyzer
5 * By Gerald Combs <gerald@wireshark.org>
6 * Copyright 1998 Gerald Combs
8 * SPDX-License-Identifier: GPL-2.0-or-later
12 #define WS_LOG_DOMAIN LOG_DOMAIN_CAPTURE
22 #include <wsutil/file_util.h>
23 #include <wsutil/filesystem.h>
24 #include <wsutil/json_dumper.h>
25 #include <wsutil/wslog.h>
26 #include <wsutil/ws_assert.h>
27 #include <wsutil/version_info.h>
28 #include <wsutil/report_message.h>
30 #include <wiretap/merge.h>
32 #include <epan/exceptions.h>
33 #include <epan/epan.h>
34 #include <epan/column.h>
35 #include <epan/packet.h>
36 #include <epan/column-utils.h>
37 #include <epan/expert.h>
38 #include <epan/prefs.h>
39 #include <epan/dfilter/dfilter.h>
40 #include <epan/epan_dissect.h>
42 #include <epan/timestamp.h>
43 #include <epan/strutil.h>
44 #include <epan/addr_resolv.h>
45 #include <epan/color_filters.h>
46 #include <epan/secrets.h>
51 #include "frame_tvbuff.h"
53 #include "ui/simple_dialog.h"
54 #include "ui/main_statusbar.h"
55 #include "ui/progress_dlg.h"
57 #include "ui/ws_ui_util.h"
58 #include "ui/packet_list_utils.h"
60 /* Needed for addrinfo */
61 #include <sys/types.h>
63 #ifdef HAVE_SYS_SOCKET_H
64 #include <sys/socket.h>
67 #ifdef HAVE_NETINET_IN_H
68 # include <netinet/in.h>
72 # include <winsock2.h>
73 # include <ws2tcpip.h>
76 static bool read_record(capture_file
*cf
, wtap_rec
*rec
, Buffer
*buf
,
77 dfilter_t
*dfcode
, epan_dissect_t
*edt
, column_info
*cinfo
, int64_t offset
,
78 fifo_string_cache_t
*frame_dup_cache
, GChecksum
*frame_cksum
);
80 static void rescan_packets(capture_file
*cf
, const char *action
, const char *action_item
, bool redissect
);
87 typedef match_result (*ws_match_function
)(capture_file
*, frame_data
*,
88 wtap_rec
*, Buffer
*, void *);
89 static match_result
match_protocol_tree(capture_file
*cf
, frame_data
*fdata
,
90 wtap_rec
*, Buffer
*, void *criterion
);
91 static void match_subtree_text(proto_node
*node
, void *data
);
92 static void match_subtree_text_reverse(proto_node
*node
, void *data
);
93 static match_result
match_summary_line(capture_file
*cf
, frame_data
*fdata
,
94 wtap_rec
*, Buffer
*, void *criterion
);
95 static match_result
match_narrow_and_wide(capture_file
*cf
, frame_data
*fdata
,
96 wtap_rec
*, Buffer
*, void *criterion
);
97 static match_result
match_narrow_and_wide_reverse(capture_file
*cf
, frame_data
*fdata
,
98 wtap_rec
*, Buffer
*, void *criterion
);
99 static match_result
match_narrow_and_wide_case(capture_file
*cf
, frame_data
*fdata
,
100 wtap_rec
*, Buffer
*, void *criterion
);
101 static match_result
match_narrow_and_wide_case_reverse(capture_file
*cf
, frame_data
*fdata
,
102 wtap_rec
*, Buffer
*, void *criterion
);
103 static match_result
match_narrow_case(capture_file
*cf
, frame_data
*fdata
,
104 wtap_rec
*, Buffer
*, void *criterion
);
105 static match_result
match_narrow_case_reverse(capture_file
*cf
, frame_data
*fdata
,
106 wtap_rec
*, Buffer
*, void *criterion
);
107 static match_result
match_wide(capture_file
*cf
, frame_data
*fdata
,
108 wtap_rec
*, Buffer
*, void *criterion
);
109 static match_result
match_wide_reverse(capture_file
*cf
, frame_data
*fdata
,
110 wtap_rec
*, Buffer
*, void *criterion
);
111 static match_result
match_wide_case(capture_file
*cf
, frame_data
*fdata
,
112 wtap_rec
*, Buffer
*, void *criterion
);
113 static match_result
match_wide_case_reverse(capture_file
*cf
, frame_data
*fdata
,
114 wtap_rec
*, Buffer
*, void *criterion
);
115 static match_result
match_binary(capture_file
*cf
, frame_data
*fdata
,
116 wtap_rec
*, Buffer
*, void *criterion
);
117 static match_result
match_binary_reverse(capture_file
*cf
, frame_data
*fdata
,
118 wtap_rec
*, Buffer
*, void *criterion
);
119 static match_result
match_regex(capture_file
*cf
, frame_data
*fdata
,
120 wtap_rec
*, Buffer
*, void *criterion
);
121 static match_result
match_regex_reverse(capture_file
*cf
, frame_data
*fdata
,
122 wtap_rec
*, Buffer
*, void *criterion
);
123 static match_result
match_dfilter(capture_file
*cf
, frame_data
*fdata
,
124 wtap_rec
*, Buffer
*, void *criterion
);
125 static match_result
match_marked(capture_file
*cf
, frame_data
*fdata
,
126 wtap_rec
*, Buffer
*, void *criterion
);
127 static match_result
match_time_reference(capture_file
*cf
, frame_data
*fdata
,
128 wtap_rec
*, Buffer
*, void *criterion
);
129 static bool find_packet(capture_file
*cf
, ws_match_function match_function
,
130 void *criterion
, search_direction dir
);
132 /* Seconds spent processing packets between pushing UI updates. */
133 #define PROGBAR_UPDATE_INTERVAL 0.150
135 /* Show the progress bar after this many seconds. */
136 #define PROGBAR_SHOW_DELAY 0.5
139 * Maximum number of records we support in a file.
141 * It is, at most, the maximum value of a uint32_t, as we use a uint32_t
142 * for the frame number.
144 * We allow it to be set to a lower value; see issue #16908 for why
145 * we're doing this. Thanks, Qt!
147 static uint32_t max_records
= UINT32_MAX
;
150 cf_set_max_records(unsigned max_records_arg
)
152 max_records
= max_records_arg
;
156 * We could probably use g_signal_...() instead of the callbacks below but that
157 * would require linking our CLI programs to libgobject and creating an object
158 * instance for the signals.
161 cf_callback_t cb_fct
;
163 } cf_callback_data_t
;
165 static GList
*cf_callbacks
;
168 cf_callback_invoke(int event
, void *data
)
170 cf_callback_data_t
*cb
;
171 GList
*cb_item
= cf_callbacks
;
173 /* there should be at least one interested */
174 ws_assert(cb_item
!= NULL
);
176 while (cb_item
!= NULL
) {
177 cb
= (cf_callback_data_t
*)cb_item
->data
;
178 cb
->cb_fct(event
, data
, cb
->user_data
);
179 cb_item
= g_list_next(cb_item
);
184 cf_callback_add(cf_callback_t func
, void *user_data
)
186 cf_callback_data_t
*cb
;
188 cb
= g_new(cf_callback_data_t
,1);
190 cb
->user_data
= user_data
;
192 cf_callbacks
= g_list_prepend(cf_callbacks
, cb
);
196 cf_callback_remove(cf_callback_t func
, void *user_data
)
198 cf_callback_data_t
*cb
;
199 GList
*cb_item
= cf_callbacks
;
201 while (cb_item
!= NULL
) {
202 cb
= (cf_callback_data_t
*)cb_item
->data
;
203 if (cb
->cb_fct
== func
&& cb
->user_data
== user_data
) {
204 cf_callbacks
= g_list_remove(cf_callbacks
, cb
);
208 cb_item
= g_list_next(cb_item
);
211 ws_assert_not_reached();
215 cf_get_computed_elapsed(capture_file
*cf
)
217 return cf
->computed_elapsed
;
221 compute_elapsed(capture_file
*cf
, int64_t start_time
)
223 int64_t delta_time
= g_get_monotonic_time() - start_time
;
225 cf
->computed_elapsed
= (unsigned long) (delta_time
/ 1000); /* ms */
229 ws_epan_new(capture_file
*cf
)
231 static const struct packet_provider_funcs funcs
= {
232 cap_file_provider_get_frame_ts
,
233 cap_file_provider_get_interface_name
,
234 cap_file_provider_get_interface_description
,
235 cap_file_provider_get_modified_block
238 return epan_new(&cf
->provider
, &funcs
);
242 cf_open(capture_file
*cf
, const char *fname
, unsigned int type
, bool is_tempfile
, int *err
)
247 wth
= wtap_open_offline(fname
, type
, err
, &err_info
, true);
251 /* The open succeeded. Close whatever capture file we had open,
252 and fill in the information for this file. */
255 /* Initialize the record metadata. */
256 wtap_rec_init(&cf
->rec
);
258 /* XXX - we really want to initialize this after we've read all
259 the packets, so we know how much we'll ultimately need. */
260 ws_buffer_init(&cf
->buf
, 1514);
262 /* We're about to start reading the file. */
263 cf
->state
= FILE_READ_IN_PROGRESS
;
265 /* If there was a pending redissection for the old file (there
266 * shouldn't be), clear it. cf_close() should have failed if the
267 * old file's read lock was held, but it doesn't hurt to clear it. */
268 cf
->read_lock
= false;
269 cf
->redissection_queued
= RESCAN_NONE
;
271 cf
->provider
.wth
= wth
;
274 /* Set the file name because we need it to set the follow stream filter.
275 XXX - is that still true? We need it for other reasons, though,
277 cf
->filename
= g_strdup(fname
);
279 /* Indicate whether it's a permanent or temporary file. */
280 cf
->is_tempfile
= is_tempfile
;
282 /* No user changes yet. */
283 cf
->unsaved_changes
= false;
285 cf
->computed_elapsed
= 0;
287 cf
->cd_t
= wtap_file_type_subtype(cf
->provider
.wth
);
288 cf
->open_type
= type
;
289 cf
->linktypes
= g_array_sized_new(FALSE
, FALSE
, (unsigned) sizeof(int), 1);
291 cf
->packet_comment_count
= 0;
292 cf
->displayed_count
= 0;
293 cf
->marked_count
= 0;
294 cf
->ignored_count
= 0;
295 cf
->ref_time_count
= 0;
296 cf
->drops_known
= false;
298 cf
->snap
= wtap_snapshot_length(cf
->provider
.wth
);
300 /* Allocate a frame_data_sequence for the frames in this file */
301 cf
->provider
.frames
= new_frame_data_sequence();
303 nstime_set_zero(&cf
->elapsed_time
);
304 cf
->provider
.ref
= NULL
;
305 cf
->provider
.prev_dis
= NULL
;
306 cf
->provider
.prev_cap
= NULL
;
309 /* Create new epan session for dissection.
310 * (The old one was freed in cf_close().)
312 cf
->epan
= ws_epan_new(cf
);
314 packet_list_queue_draw();
315 cf_callback_invoke(cf_cb_file_opened
, cf
);
317 wtap_set_cb_new_ipv4(cf
->provider
.wth
, add_ipv4_name
);
318 wtap_set_cb_new_ipv6(cf
->provider
.wth
, (wtap_new_ipv6_callback_t
) add_ipv6_name
);
319 wtap_set_cb_new_secrets(cf
->provider
.wth
, secrets_wtap_callback
);
324 report_cfile_open_failure(fname
, *err
, err_info
);
329 * Add an encapsulation type to cf->linktypes.
332 cf_add_encapsulation_type(capture_file
*cf
, int encap
)
336 for (i
= 0; i
< cf
->linktypes
->len
; i
++) {
337 if (g_array_index(cf
->linktypes
, int, i
) == encap
)
338 return; /* it's already there */
340 /* It's not already there - add it. */
341 g_array_append_val(cf
->linktypes
, encap
);
344 /* Reset everything to a pristine state */
346 cf_close(capture_file
*cf
)
348 cf
->stop_flag
= false;
349 if (cf
->state
== FILE_CLOSED
|| cf
->state
== FILE_READ_PENDING
)
350 return; /* Nothing to do */
352 /* Die if we're in the middle of reading a file. */
353 ws_assert(cf
->state
!= FILE_READ_IN_PROGRESS
);
354 ws_assert(!cf
->read_lock
);
356 cf_callback_invoke(cf_cb_file_closing
, cf
);
358 /* close things, if not already closed before */
359 color_filters_cleanup();
361 if (cf
->provider
.wth
) {
362 wtap_close(cf
->provider
.wth
);
363 cf
->provider
.wth
= NULL
;
365 /* We have no file open... */
366 if (cf
->filename
!= NULL
) {
367 /* If it's a temporary file, remove it. */
369 ws_unlink(cf
->filename
);
370 g_free(cf
->filename
);
373 /* ...which means we have no changes to that file to save. */
374 cf
->unsaved_changes
= false;
376 /* no open_routine type */
377 cf
->open_type
= WTAP_TYPE_AUTO
;
379 /* Clean up the record metadata. */
380 wtap_rec_cleanup(&cf
->rec
);
382 /* Clear the packet list. */
383 packet_list_freeze();
387 /* Free up the packet buffer. */
388 ws_buffer_free(&cf
->buf
);
390 dfilter_free(cf
->rfcode
);
392 if (cf
->provider
.frames
!= NULL
) {
393 free_frame_data_sequence(cf
->provider
.frames
);
394 cf
->provider
.frames
= NULL
;
396 if (cf
->provider
.frames_modified_blocks
) {
397 g_tree_destroy(cf
->provider
.frames_modified_blocks
);
398 cf
->provider
.frames_modified_blocks
= NULL
;
400 cf_unselect_packet(cf
); /* nothing to select */
401 cf
->first_displayed
= 0;
402 cf
->last_displayed
= 0;
404 /* No frames, no frame selected, no field in that frame selected. */
406 cf
->current_frame
= NULL
;
407 cf
->finfo_selected
= NULL
;
409 /* No frame link-layer types, either. */
410 if (cf
->linktypes
!= NULL
) {
411 g_array_free(cf
->linktypes
, TRUE
);
412 cf
->linktypes
= NULL
;
416 nstime_set_zero(&cf
->elapsed_time
);
418 reset_tap_listeners();
423 /* We have no file open. */
424 cf
->state
= FILE_CLOSED
;
426 cf_callback_invoke(cf_cb_file_closed
, cf
);
430 * true if the progress dialog doesn't exist and it looks like we'll
431 * take > PROGBAR_SHOW_DELAY (500ms) to load, false otherwise.
434 progress_is_slow(progdlg_t
*progdlg
, GTimer
*prog_timer
, int64_t size
, int64_t pos
)
438 if (progdlg
) return false;
439 elapsed
= g_timer_elapsed(prog_timer
, NULL
);
440 /* This only gets checked between reading records, which doesn't help if
441 * a single record takes a very long time, e.g., the first TLS packet if
442 * the SSLKEYLOGFILE is very large. (#17051) */
443 if ((elapsed
* 2 > PROGBAR_SHOW_DELAY
&& (size
/ pos
) >= 2) /* It looks like we're going to be slow. */
444 || elapsed
> PROGBAR_SHOW_DELAY
) { /* We are indeed slow. */
451 calc_progbar_val(capture_file
*cf
, int64_t size
, int64_t file_pos
, char *status_str
, unsigned long status_size
)
455 progbar_val
= (float) file_pos
/ (float) size
;
456 if (progbar_val
> 1.0) {
458 /* The file probably grew while we were reading it.
459 * Update file size, and try again.
461 size
= wtap_file_size(cf
->provider
.wth
, NULL
);
464 progbar_val
= (float) file_pos
/ (float) size
;
466 /* If it's still > 1, either "wtap_file_size()" failed (in which
467 * case there's not much we can do about it), or the file
468 * *shrank* (in which case there's not much we can do about
469 * it); just clip the progress value at 1.0.
471 if (progbar_val
> 1.0f
)
475 snprintf(status_str
, status_size
,
476 "%" PRId64
"KB of %" PRId64
"KB",
477 file_pos
/ 1024, size
/ 1024);
483 cf_read(capture_file
*cf
, bool reloading
)
486 char *err_info
= NULL
;
487 volatile bool too_many_records
= false;
489 progdlg_t
*volatile progbar
= NULL
;
490 GTimer
*prog_timer
= g_timer_new();
496 dfilter_t
*dfcode
= NULL
;
498 volatile bool create_proto_tree
;
501 volatile bool is_read_aborted
= false;
503 /* The update_progress_dlg call below might end up accepting a user request to
504 * trigger redissection/rescans which can modify/destroy the dissection
505 * context ("cf->epan"). That condition should be prevented by callers, but in
506 * case it occurs let's fail gracefully.
509 ws_warning("Failing due to recursive cf_read(\"%s\", %d) call!",
510 cf
->filename
, reloading
);
511 return CF_READ_ERROR
;
513 /* This is a full dissection, so clear any pending request for one. */
514 cf
->redissection_queued
= RESCAN_NONE
;
515 cf
->read_lock
= true;
517 /* Compile the current display filter.
518 * The code it compiles to might have changed, e.g. if a display
519 * filter macro used has changed.
521 * We assume this will not fail since cf->dfilter is only set in
522 * cf_filter IFF the filter was valid.
523 * XXX - This is not necessarily true, if the filter has a FT_IPv4
524 * or FT_IPv6 field compared to a resolved hostname in it, because
525 * we do a new host lookup, and that *could* timeout this time
526 * (though with the read lock above we shouldn't have many lookups at
527 * once, reducing the chances of that)... (#19612)
530 compiled
= dfilter_compile(cf
->dfilter
, &dfcode
, NULL
);
531 ws_assert(compiled
&& dfcode
);
534 dfilter_free(cf
->dfcode
);
537 /* The compiled dfilter might have a field reference; recompiling it
538 * means that the field references won't match anything. That's what
539 * we want since this is a new sequential read and we don't have
540 * a selected frame with a tree. (Will taps with filters with display
541 * references also have cleared display references?)
544 /* Get the union of the flags for all tap listeners. */
545 tap_flags
= union_of_tap_listener_flags();
548 * Determine whether we need to create a protocol tree.
551 * we're going to apply a display filter;
553 * one of the tap listeners is going to apply a filter;
555 * one of the tap listeners requires a protocol tree;
557 * a postdissector wants field values or protocols on
561 (cf
->dfcode
!= NULL
|| have_filtering_tap_listeners() ||
562 (tap_flags
& TL_REQUIRES_PROTO_TREE
) || postdissectors_want_hfids());
564 reset_tap_listeners();
566 name_ptr
= g_filename_display_basename(cf
->filename
);
569 cf_callback_invoke(cf_cb_file_reload_started
, cf
);
571 cf_callback_invoke(cf_cb_file_read_started
, cf
);
573 /* Record the file's compression type.
574 XXX - do we know this at open time? */
575 cf
->compression_type
= wtap_get_compression_type(cf
->provider
.wth
);
577 /* The packet list window will be empty until the file is completely loaded */
578 packet_list_freeze();
580 cf
->stop_flag
= false;
581 start_time
= g_get_monotonic_time();
583 epan_dissect_init(&edt
, cf
->epan
, create_proto_tree
, false);
585 /* If the display filter or any tap listeners require the columns,
587 cinfo
= (tap_listeners_require_columns() ||
588 dfilter_requires_columns(cf
->dfcode
)) ? &cf
->cinfo
: NULL
;
590 /* Find the size of the file. */
591 size
= wtap_file_size(cf
->provider
.wth
, NULL
);
593 /* If we are to ignore duplicate frames, we need a container to store
594 * hashes frame contents */
595 fifo_string_cache_t frame_dup_cache
;
596 GChecksum
*volatile cksum
= NULL
;
598 if (prefs
.ignore_dup_frames
) {
599 fifo_string_cache_init(&frame_dup_cache
, prefs
.ignore_dup_frames_cache_entries
, g_free
);
600 cksum
= g_checksum_new(G_CHECKSUM_SHA256
);
603 g_timer_start(prog_timer
);
606 ws_buffer_init(&buf
, 1514);
613 char status_str
[100];
615 while ((wtap_read(cf
->provider
.wth
, &rec
, &buf
, &err
, &err_info
,
618 if (cf
->count
== max_records
) {
620 * Quit if we've already read the maximum number of
623 too_many_records
= true;
626 file_pos
= wtap_read_so_far(cf
->provider
.wth
);
628 /* Create the progress bar if necessary. */
629 if (progress_is_slow(progbar
, prog_timer
, size
, file_pos
)) {
630 progbar_val
= calc_progbar_val(cf
, size
, file_pos
, status_str
, sizeof(status_str
));
631 progbar
= delayed_create_progress_dlg(cf
->window
, NULL
, NULL
, true,
632 &cf
->stop_flag
, progbar_val
);
636 * Update the progress bar, but do it only after
637 * PROGBAR_UPDATE_INTERVAL has elapsed. Calling update_progress_dlg
638 * and packets_bar_update will likely trigger UI paint events, which
639 * might take a while depending on the platform and display. Reset
640 * our timer *after* painting.
642 if (progbar
&& g_timer_elapsed(prog_timer
, NULL
) > PROGBAR_UPDATE_INTERVAL
) {
643 progbar_val
= calc_progbar_val(cf
, size
, file_pos
, status_str
, sizeof(status_str
));
644 /* update the packet bar content on the first run or frequently on very large files */
645 update_progress_dlg(progbar
, progbar_val
, status_str
);
646 compute_elapsed(cf
, start_time
);
647 packets_bar_update();
648 g_timer_start(prog_timer
);
651 * The previous GUI triggers should not have destroyed the running
652 * session. If that did happen, it could blow up when read_record tries
653 * to use the destroyed edt.session, so detect it right here.
655 ws_assert(edt
.session
== cf
->epan
);
658 if (cf
->state
== FILE_READ_ABORTED
) {
659 /* Well, the user decided to exit Wireshark. Break out of the
660 loop, and let the code below (which is called even if there
661 aren't any packets left to read) exit. */
662 is_read_aborted
= true;
666 /* Well, the user decided to abort the read. He/She will be warned and
667 it might be enough for him/her to work with the already loaded
669 This is especially true for very large capture files, where you don't
670 want to wait loading the whole file (which may last minutes or even
671 hours even on fast machines) just to see that it was the wrong file. */
674 read_record(cf
, &rec
, &buf
, cf
->dfcode
, &edt
, cinfo
, data_offset
, &frame_dup_cache
, cksum
);
675 wtap_rec_reset(&rec
);
678 CATCH(OutOfMemoryError
) {
679 simple_message_box(ESD_TYPE_ERROR
, NULL
,
680 "More information and workarounds can be found at\n"
681 WS_WIKI_URL("KnownBugs/OutOfMemory"),
682 "Sorry, but Wireshark has run out of memory and has to terminate now.");
684 /* Could we close the current capture and free up memory from that? */
686 /* we have to terminate, as we cannot recover from the memory error */
692 // If we're ignoring duplicate frames, clear the data structures.
693 // We really could look at prefs.ignore_dup_frames here, but it's even
694 // safer to check if we had allocated 'cksum'.
696 fifo_string_cache_free(&frame_dup_cache
);
697 g_checksum_free(cksum
);
700 /* We're done reading sequentially through the file. */
701 cf
->state
= FILE_READ_DONE
;
703 /* Destroy the progress bar if it was created. */
705 destroy_progress_dlg(progbar
);
706 g_timer_destroy(prog_timer
);
708 /* Free the display name */
711 epan_dissect_cleanup(&edt
);
712 wtap_rec_cleanup(&rec
);
713 ws_buffer_free(&buf
);
715 /* Close the sequential I/O side, to free up memory it requires. */
716 wtap_sequential_close(cf
->provider
.wth
);
718 /* Allow the protocol dissectors to free up memory that they
719 * don't need after the sequential run-through of the packets. */
720 postseq_cleanup_all_protocols();
722 /* compute the time it took to load the file */
723 compute_elapsed(cf
, start_time
);
725 /* Set the file encapsulation type now; we don't know what it is until
726 we've looked at all the packets, as we don't know until then whether
727 there's more than one type (and thus whether it's
728 WTAP_ENCAP_PER_PACKET). */
729 cf
->lnk_t
= wtap_file_encap(cf
->provider
.wth
);
731 cf
->current_frame
= frame_data_sequence_find(cf
->provider
.frames
, cf
->first_displayed
);
735 /* It is safe again to execute redissections or sort. */
736 ws_assert(cf
->read_lock
);
737 cf
->read_lock
= false;
740 cf_callback_invoke(cf_cb_file_reload_finished
, cf
);
742 cf_callback_invoke(cf_cb_file_read_finished
, cf
);
744 /* If we have any displayed packets to select, select the first of those
745 packets by making the first row the selected row. */
746 if (cf
->first_displayed
!= 0) {
747 packet_list_select_row_from_data(NULL
);
750 if (is_read_aborted
) {
752 * Well, the user decided to exit Wireshark while reading this *offline*
753 * capture file (Live captures are handled by something like
754 * cf_continue_tail). Clean up accordingly.
757 cf
->redissection_queued
= RESCAN_NONE
;
758 return CF_READ_ABORTED
;
761 if (cf
->redissection_queued
!= RESCAN_NONE
) {
762 /* Redissection was queued up. Clear the request and perform it now. */
763 bool redissect
= cf
->redissection_queued
== RESCAN_REDISSECT
;
764 rescan_packets(cf
, NULL
, NULL
, redissect
);
768 simple_message_box(ESD_TYPE_WARN
, NULL
,
769 "The remaining packets in the file were discarded.\n"
771 "As a lot of packets from the original file will be missing,\n"
772 "remember to be careful when saving the current content to a file.\n",
773 "File loading was cancelled.");
774 return CF_READ_ERROR
;
778 /* Put up a message box noting that the read failed somewhere along
779 the line. Don't throw out the stuff we managed to read, though,
781 report_cfile_read_failure(NULL
, err
, err_info
);
782 return CF_READ_ERROR
;
783 } else if (too_many_records
) {
784 simple_message_box(ESD_TYPE_WARN
, NULL
,
785 "The remaining packets in the file were discarded.\n"
787 "As a lot of packets from the original file will be missing,\n"
788 "remember to be careful when saving the current content to a file.\n"
790 "The command-line utility editcap can be used to split "
791 "the file into multiple smaller files",
792 "The file contains more records than the maximum "
793 "supported number of records, %u.", max_records
);
794 return CF_READ_ERROR
;
801 cf_continue_tail(capture_file
*cf
, volatile int to_read
, wtap_rec
*rec
,
802 Buffer
*buf
, int *err
, fifo_string_cache_t
*frame_dup_cache
, GChecksum
*frame_cksum
)
805 volatile int newly_displayed_packets
= 0;
807 bool create_proto_tree
;
810 /* Don't compile the current display filter. The current display filter
811 * text might compile to different code than when the capture started:
813 * If it has a IP address resolved name, calling get_host_ipaddr every
814 * time new packets arrive can mean a *lot* of gethostbyname calls
815 * in flight at once, eventually leading to a timeout (#19612).
816 * addr_resolv.c says that ares_gethostbyname is "usually interactive",
817 * unlike ares_gethostbyaddr (used in dissection), and violating that
818 * expectation is bad.
820 * If it has a display filter macro, the definition might have changed.
822 * If it has a field reference, the selected frame / current proto tree
823 * might have changed, and we don't have the old one. If we recompile,
824 * we can't set the field references to the old values.
826 * For a rescan, redissection, reload, retap, or opening a new file, we
827 * want to compile. What about here, when new frames have arrived in a live
828 * capture? We might be able to cache the host lookup, and a user might want
829 * the new display filter macro definition, but the user almost surely wants
830 * the field references to refer to values from the proto tree when the
831 * filter was applied, not whatever it happens to be now if the user has
832 * clicked on a different packet.
834 * To get the new compiled filter, the user should refilter.
837 /* Get the union of the flags for all tap listeners. */
838 tap_flags
= union_of_tap_listener_flags();
841 * Determine whether we need to create a protocol tree.
844 * we're going to apply a display filter;
846 * one of the tap listeners is going to apply a filter;
848 * one of the tap listeners requires a protocol tree;
850 * a postdissector wants field values or protocols on
854 (cf
->dfcode
!= NULL
|| have_filtering_tap_listeners() ||
855 (tap_flags
& TL_REQUIRES_PROTO_TREE
) || postdissectors_want_hfids());
859 /* Don't freeze/thaw the list when doing live capture */
860 /*packet_list_freeze();*/
862 epan_dissect_init(&edt
, cf
->epan
, create_proto_tree
, false);
865 int64_t data_offset
= 0;
868 /* If the display filter or any tap listeners require the columns,
870 cinfo
= (tap_listeners_require_columns() ||
871 dfilter_requires_columns(cf
->dfcode
)) ? &cf
->cinfo
: NULL
;
873 while (to_read
!= 0) {
874 wtap_cleareof(cf
->provider
.wth
);
875 if (!wtap_read(cf
->provider
.wth
, rec
, buf
, err
, &err_info
,
879 if (cf
->state
== FILE_READ_ABORTED
) {
880 /* Well, the user decided to exit Wireshark. Break out of the
881 loop, and let the code below (which is called even if there
882 aren't any packets left to read) exit. */
885 if (read_record(cf
, rec
, buf
, cf
->dfcode
, &edt
, cinfo
, data_offset
, frame_dup_cache
, frame_cksum
)) {
886 newly_displayed_packets
++;
892 CATCH(OutOfMemoryError
) {
893 simple_message_box(ESD_TYPE_ERROR
, NULL
,
894 "More information and workarounds can be found at\n"
895 WS_WIKI_URL("KnownBugs/OutOfMemory"),
896 "Sorry, but Wireshark has run out of memory and has to terminate now.");
898 /* Could we close the current capture and free up memory from that? */
899 return CF_READ_ABORTED
;
901 /* we have to terminate, as we cannot recover from the memory error */
907 /* Update the file encapsulation; it might have changed based on the
908 packets we've read. */
909 cf
->lnk_t
= wtap_file_encap(cf
->provider
.wth
);
911 epan_dissect_cleanup(&edt
);
913 /* Don't freeze/thaw the list when doing live capture */
914 /*packet_list_thaw();*/
915 /* With the new packet list the first packet
916 * isn't automatically selected.
918 if (!cf
->current_frame
&& !packet_list_multi_select_active())
919 packet_list_select_row_from_data(NULL
);
921 if (cf
->state
== FILE_READ_ABORTED
) {
922 /* Well, the user decided to exit Wireshark. Return CF_READ_ABORTED
923 so that our caller can kill off the capture child process;
924 this will cause an EOF on the pipe from the child, so
925 "cf_finish_tail()" will be called, and it will clean up
927 return CF_READ_ABORTED
;
928 } else if (*err
!= 0) {
929 /* We got an error reading the capture file.
930 XXX - pop up a dialog box instead? */
931 if (err_info
!= NULL
) {
932 ws_warning("Error \"%s\" while reading \"%s\" (\"%s\")",
933 wtap_strerror(*err
), cf
->filename
, err_info
);
936 ws_warning("Error \"%s\" while reading \"%s\"",
937 wtap_strerror(*err
), cf
->filename
);
939 return CF_READ_ERROR
;
945 cf_fake_continue_tail(capture_file
*cf
)
947 if (cf
->state
== FILE_CLOSED
) {
948 cf
->state
= FILE_READ_PENDING
;
953 cf_finish_tail(capture_file
*cf
, wtap_rec
*rec
, Buffer
*buf
, int *err
,
954 fifo_string_cache_t
*frame_dup_cache
, GChecksum
*frame_cksum
)
960 bool create_proto_tree
;
963 /* All the comments above in cf_continue_tail apply regarding the
964 * current display filter.
967 /* Get the union of the flags for all tap listeners. */
968 tap_flags
= union_of_tap_listener_flags();
970 /* If the display filter or any tap listeners require the columns,
972 cinfo
= (tap_listeners_require_columns() ||
973 dfilter_requires_columns(cf
->dfcode
)) ? &cf
->cinfo
: NULL
;
976 * Determine whether we need to create a protocol tree.
979 * we're going to apply a display filter;
981 * one of the tap listeners is going to apply a filter;
983 * one of the tap listeners requires a protocol tree;
985 * a postdissector wants field values or protocols on
989 (cf
->dfcode
!= NULL
|| have_filtering_tap_listeners() ||
990 (tap_flags
& TL_REQUIRES_PROTO_TREE
) || postdissectors_want_hfids());
992 if (cf
->provider
.wth
== NULL
) {
994 return CF_READ_ERROR
;
997 /* Don't freeze/thaw the list when doing live capture */
998 /*packet_list_freeze();*/
1000 epan_dissect_init(&edt
, cf
->epan
, create_proto_tree
, false);
1002 while ((wtap_read(cf
->provider
.wth
, rec
, buf
, err
, &err_info
, &data_offset
))) {
1003 if (cf
->state
== FILE_READ_ABORTED
) {
1004 /* Well, the user decided to abort the read. Break out of the
1005 loop, and let the code below (which is called even if there
1006 aren't any packets left to read) exit. */
1009 read_record(cf
, rec
, buf
, cf
->dfcode
, &edt
, cinfo
, data_offset
, frame_dup_cache
, frame_cksum
);
1010 wtap_rec_reset(rec
);
1013 epan_dissect_cleanup(&edt
);
1015 /* Don't freeze/thaw the list when doing live capture */
1016 /*packet_list_thaw();*/
1018 if (cf
->state
== FILE_READ_ABORTED
) {
1019 /* Well, the user decided to abort the read. We're only called
1020 when the child capture process closes the pipe to us (meaning
1021 it's probably exited), so we can just close the capture
1022 file; we return CF_READ_ABORTED so our caller can do whatever
1023 is appropriate when that happens. */
1025 return CF_READ_ABORTED
;
1028 /* We're done reading sequentially through the file. */
1029 cf
->state
= FILE_READ_DONE
;
1031 /* We're done reading sequentially through the file; close the
1032 sequential I/O side, to free up memory it requires. */
1033 wtap_sequential_close(cf
->provider
.wth
);
1035 /* Allow the protocol dissectors to free up memory that they
1036 * don't need after the sequential run-through of the packets. */
1037 postseq_cleanup_all_protocols();
1039 /* Update the file encapsulation; it might have changed based on the
1040 packets we've read. */
1041 cf
->lnk_t
= wtap_file_encap(cf
->provider
.wth
);
1043 /* Update the details in the file-set dialog, as the capture file
1044 * has likely grown since we first stat-ed it */
1045 fileset_update_file(cf
->filename
);
1048 /* We got an error reading the capture file.
1049 XXX - pop up a dialog box? */
1050 if (err_info
!= NULL
) {
1051 ws_warning("Error \"%s\" while reading \"%s\" (\"%s\")",
1052 wtap_strerror(*err
), cf
->filename
, err_info
);
1055 ws_warning("Error \"%s\" while reading \"%s\"",
1056 wtap_strerror(*err
), cf
->filename
);
1058 return CF_READ_ERROR
;
1063 #endif /* HAVE_LIBPCAP */
1066 cf_get_display_name(capture_file
*cf
)
1070 /* Return a name to use in displays */
1071 if (!cf
->is_tempfile
) {
1072 /* Get the last component of the file name, and use that. */
1074 displayname
= g_filename_display_basename(cf
->filename
);
1076 displayname
=g_strdup("(No file)");
1079 /* The file we read is a temporary file from a live capture or
1080 a merge operation; we don't mention its name, but, if it's
1081 from a capture, give the source of the capture. */
1083 displayname
= g_strdup(cf
->source
);
1085 displayname
= g_strdup("(Untitled)");
1092 cf_get_basename(capture_file
*cf
)
1096 /* Return a name to use in the GUI for the basename for files to
1097 which we save statistics */
1098 if (!cf
->is_tempfile
) {
1099 /* Get the last component of the file name, and use that. */
1101 displayname
= g_filename_display_basename(cf
->filename
);
1103 /* If the file name ends with any extension that corresponds
1104 to a file type we support - including compressed versions
1105 of those files - strip it off. */
1106 size_t displayname_len
= strlen(displayname
);
1107 GSList
*extensions
= wtap_get_all_file_extensions_list();
1109 for (suffix
= extensions
; suffix
!= NULL
; suffix
= g_slist_next(suffix
)) {
1110 /* Does the file name end with that extension? */
1111 const char *extension
= (char *)suffix
->data
;
1112 size_t extension_len
= strlen(extension
);
1113 if (displayname_len
> extension_len
&&
1114 displayname
[displayname_len
- extension_len
- 1] == '.' &&
1115 strcmp(&displayname
[displayname_len
- extension_len
], extension
) == 0) {
1116 /* Yes. Strip the extension off, and return the result. */
1117 displayname
[displayname_len
- extension_len
- 1] = '\0';
1121 wtap_free_extensions_list(extensions
);
1123 displayname
=g_strdup("");
1126 /* The file we read is a temporary file from a live capture or
1127 a merge operation; we don't mention its name, but, if it's
1128 from a capture, give the source of the capture. */
1130 displayname
= g_strdup(cf
->source
);
1132 displayname
= g_strdup("");
1139 cf_set_tempfile_source(capture_file
*cf
, char *source
)
1146 cf
->source
= g_strdup(source
);
1148 cf
->source
= g_strdup("");
1153 cf_get_tempfile_source(capture_file
*cf
)
1162 /* XXX - use a macro instead? */
1164 cf_get_packet_count(capture_file
*cf
)
1169 /* XXX - use a macro instead? */
1171 cf_is_tempfile(capture_file
*cf
)
1173 return cf
->is_tempfile
;
1177 cf_set_tempfile(capture_file
*cf
, bool is_tempfile
)
1179 cf
->is_tempfile
= is_tempfile
;
1183 /* XXX - use a macro instead? */
1185 cf_set_drops_known(capture_file
*cf
, bool drops_known
)
1187 cf
->drops_known
= drops_known
;
1190 /* XXX - use a macro instead? */
1192 cf_set_drops(capture_file
*cf
, uint32_t drops
)
1197 /* XXX - use a macro instead? */
1199 cf_get_drops_known(capture_file
*cf
)
1201 return cf
->drops_known
;
1204 /* XXX - use a macro instead? */
1206 cf_get_drops(capture_file
*cf
)
1212 cf_set_rfcode(capture_file
*cf
, dfilter_t
*rfcode
)
1214 cf
->rfcode
= rfcode
;
1218 add_packet_to_packet_list(frame_data
*fdata
, capture_file
*cf
,
1219 epan_dissect_t
*edt
, dfilter_t
*dfcode
, column_info
*cinfo
,
1220 wtap_rec
*rec
, Buffer
*buf
, bool add_to_packet_list
)
1222 frame_data_set_before_dissect(fdata
, &cf
->elapsed_time
,
1223 &cf
->provider
.ref
, cf
->provider
.prev_dis
);
1224 cf
->provider
.prev_cap
= fdata
;
1226 if (dfcode
!= NULL
) {
1227 epan_dissect_prime_with_dfilter(edt
, dfcode
);
1230 /* Prepare coloring rules, this ensures that display filter rules containing
1231 * frame.color_rule references are still processed.
1232 * TODO: actually detect that situation or maybe apply other optimizations? */
1233 if (edt
->tree
&& color_filters_used()) {
1234 color_filters_prime_edt(edt
);
1235 fdata
->need_colorize
= 1;
1239 if (!fdata
->visited
) {
1240 /* This is the first pass, so prime the epan_dissect_t with the
1241 hfids postdissectors want on the first pass. */
1242 prime_epan_dissect_with_postdissector_wanted_hfids(edt
);
1245 /* Initialize passed_dfilter here so that dissectors can hide packets. */
1246 /* XXX We might want to add a separate "visible" bit to frame_data instead. */
1247 fdata
->passed_dfilter
= 1;
1249 /* Dissect the frame. */
1250 epan_dissect_run_with_taps(edt
, cf
->cd_t
, rec
,
1251 frame_tvbuff_new_buffer(&cf
->provider
, fdata
, buf
),
1254 if (fdata
->passed_dfilter
&& dfcode
!= NULL
) {
1255 fdata
->passed_dfilter
= dfilter_apply_edt(dfcode
, edt
) ? 1 : 0;
1257 if (fdata
->passed_dfilter
&& edt
->pi
.fd
->dependent_frames
) {
1258 /* This frame passed the display filter but it may depend on other
1259 * (potentially not displayed) frames. Find those frames and mark them
1262 g_hash_table_foreach(edt
->pi
.fd
->dependent_frames
, find_and_mark_frame_depended_upon
, cf
->provider
.frames
);
1266 if (fdata
->passed_dfilter
|| fdata
->ref_time
) {
1267 cf
->displayed_count
++;
1268 fdata
->dis_num
= cf
->displayed_count
;
1271 if (add_to_packet_list
) {
1272 /* We fill the needed columns from new_packet_list */
1273 packet_list_append(cinfo
, fdata
);
1276 if (fdata
->passed_dfilter
|| fdata
->ref_time
)
1278 frame_data_set_after_dissect(fdata
, &cf
->cum_bytes
);
1279 /* The only way we use prev_dis is to get the time stamp of
1280 * the previous displayed frame, so ignore it if it doesn't
1281 * have a time stamp, because we're presumably interested in
1282 * the timestamp of the previously displayed frame with a
1283 * time. XXX: What if in the future we want to use the previously
1284 * displayed frame for something else, too?
1286 if (fdata
->has_ts
) {
1287 cf
->provider
.prev_dis
= fdata
;
1290 /* If we haven't yet seen the first frame, this is it. */
1291 if (cf
->first_displayed
== 0)
1292 cf
->first_displayed
= fdata
->num
;
1294 /* This is the last frame we've seen so far. */
1295 cf
->last_displayed
= fdata
->num
;
1298 epan_dissect_reset(edt
);
1302 * Read in a new record.
1303 * Returns true if the packet was added to the packet (record) list,
1307 read_record(capture_file
*cf
, wtap_rec
*rec
, Buffer
*buf
, dfilter_t
*dfcode
,
1308 epan_dissect_t
*edt
, column_info
*cinfo
, int64_t offset
,
1309 fifo_string_cache_t
*frame_dup_cache
, GChecksum
*frame_cksum
)
1315 const char *cksum_string
;
1318 /* Add this packet's link-layer encapsulation type to cf->linktypes, if
1319 it's not already there.
1320 XXX - yes, this is O(N), so if every packet had a different
1321 link-layer encapsulation type, it'd be O(N^2) to read the file, but
1322 there are probably going to be a small number of encapsulation types
1324 if (rec
->rec_type
== REC_TYPE_PACKET
) {
1325 cf_add_encapsulation_type(cf
, rec
->rec_header
.packet_header
.pkt_encap
);
1328 /* The frame number of this packet, if we add it to the set of frames,
1329 would be one more than the count of frames in the file so far. */
1330 frame_data_init(&fdlocal
, cf
->count
+ 1, rec
, offset
, cf
->cum_bytes
);
1333 epan_dissect_t rf_edt
;
1334 column_info
*rf_cinfo
= NULL
;
1336 epan_dissect_init(&rf_edt
, cf
->epan
, true, false);
1337 epan_dissect_prime_with_dfilter(&rf_edt
, cf
->rfcode
);
1338 if (dfilter_requires_columns(cf
->rfcode
)) {
1339 rf_cinfo
= &cf
->cinfo
;
1341 epan_dissect_run(&rf_edt
, cf
->cd_t
, rec
,
1342 frame_tvbuff_new_buffer(&cf
->provider
, &fdlocal
, buf
),
1343 &fdlocal
, rf_cinfo
);
1344 passed
= dfilter_apply_edt(cf
->rfcode
, &rf_edt
);
1345 epan_dissect_cleanup(&rf_edt
);
1351 /* This does a shallow copy of fdlocal, which is good enough. */
1352 fdata
= frame_data_sequence_add(cf
->provider
.frames
, &fdlocal
);
1355 if (rec
->block
!= NULL
)
1356 cf
->packet_comment_count
+= wtap_block_count_option(rec
->block
, OPT_COMMENT
);
1357 cf
->f_datalen
= offset
+ fdlocal
.cap_len
;
1359 // Should we check if the frame data is a duplicate, and thus, ignore
1361 if (frame_cksum
!= NULL
&& rec
->rec_type
== REC_TYPE_PACKET
) {
1362 g_checksum_reset(frame_cksum
);
1363 g_checksum_update(frame_cksum
, ws_buffer_start_ptr(buf
), ws_buffer_length(buf
));
1364 cksum_string
= g_strdup(g_checksum_get_string(frame_cksum
));
1365 was_in_cache
= fifo_string_cache_insert(frame_dup_cache
, cksum_string
);
1367 g_free((void *)cksum_string
);
1368 fdata
->ignored
= true;
1369 cf
->ignored_count
++;
1373 /* When a redissection is in progress (or queued), do not process packets.
1374 * This will be done once all (new) packets have been scanned. */
1375 if (!cf
->redissecting
&& cf
->redissection_queued
== RESCAN_NONE
) {
1376 add_packet_to_packet_list(fdata
, cf
, edt
, dfcode
, cinfo
, rec
, buf
, true);
1384 typedef struct _callback_data_t
{
1394 merge_callback(merge_event event
, int num _U_
,
1395 const merge_in_file_t in_files
[], const unsigned in_file_count
,
1399 callback_data_t
*cb_data
= (callback_data_t
*) data
;
1401 ws_assert(cb_data
!= NULL
);
1405 case MERGE_EVENT_INPUT_FILES_OPENED
:
1409 case MERGE_EVENT_FRAME_TYPE_SELECTED
:
1413 case MERGE_EVENT_READY_TO_MERGE
:
1414 /* Get the sum of the sizes of all the files. */
1415 for (i
= 0; i
< in_file_count
; i
++)
1416 cb_data
->f_len
+= in_files
[i
].size
;
1418 cb_data
->prog_timer
= g_timer_new();
1419 g_timer_start(cb_data
->prog_timer
);
1422 case MERGE_EVENT_RECORD_WAS_READ
:
1424 /* Create the progress bar if necessary.
1425 We check on every iteration of the loop, so that it takes no
1426 longer than the standard time to create it (otherwise, for a
1427 large file, we might take considerably longer than that standard
1428 time in order to get to the next progress bar step). */
1429 if (cb_data
->progbar
== NULL
) {
1430 cb_data
->progbar
= delayed_create_progress_dlg(cb_data
->pd_window
, NULL
, NULL
,
1431 false, &cb_data
->stop_flag
, 0.0f
);
1435 * Update the progress bar, but do it only after
1436 * PROGBAR_UPDATE_INTERVAL has elapsed. Calling update_progress_dlg
1437 * and packets_bar_update will likely trigger UI paint events, which
1438 * might take a while depending on the platform and display. Reset
1439 * our timer *after* painting.
1441 if (g_timer_elapsed(cb_data
->prog_timer
, NULL
) > PROGBAR_UPDATE_INTERVAL
) {
1443 int64_t file_pos
= 0;
1444 /* Get the sum of the seek positions in all of the files. */
1445 for (i
= 0; i
< in_file_count
; i
++)
1446 file_pos
+= wtap_read_so_far(in_files
[i
].wth
);
1448 progbar_val
= (float) file_pos
/ (float) cb_data
->f_len
;
1449 if (progbar_val
> 1.0f
) {
1450 /* Some file probably grew while we were reading it.
1451 That "shouldn't happen", so we'll just clip the progress
1456 if (cb_data
->progbar
!= NULL
) {
1457 char status_str
[100];
1458 snprintf(status_str
, sizeof(status_str
),
1459 "%" PRId64
"KB of %" PRId64
"KB",
1460 file_pos
/ 1024, cb_data
->f_len
/ 1024);
1461 update_progress_dlg(cb_data
->progbar
, progbar_val
, status_str
);
1463 g_timer_start(cb_data
->prog_timer
);
1468 case MERGE_EVENT_DONE
:
1469 /* We're done merging the files; destroy the progress bar if it was created. */
1470 if (cb_data
->progbar
!= NULL
)
1471 destroy_progress_dlg(cb_data
->progbar
);
1472 g_timer_destroy(cb_data
->prog_timer
);
1476 return cb_data
->stop_flag
;
1482 cf_merge_files_to_tempfile(void *pd_window
, const char *temp_dir
, char **out_filenamep
,
1483 int in_file_count
, const char *const *in_filenames
,
1484 int file_type
, bool do_append
)
1487 merge_progress_callback_t cb
;
1488 callback_data_t
*cb_data
= g_new0(callback_data_t
, 1);
1490 /* prepare our callback routine */
1491 cb_data
->pd_window
= pd_window
;
1492 cb
.callback_func
= merge_callback
;
1495 cf_callback_invoke(cf_cb_file_merge_started
, NULL
);
1497 /* merge the files */
1498 status
= merge_files_to_tempfile(temp_dir
, out_filenamep
, "wireshark", file_type
,
1500 in_file_count
, do_append
,
1501 IDB_MERGE_MODE_ALL_SAME
, 0 /* snaplen */,
1506 cf_callback_invoke(cf_cb_file_merge_finished
, NULL
);
1509 /* Callers aren't expected to treat an error or an explicit abort
1510 differently - the merge code puts up error dialogs itself, so
1511 they don't have to. */
1518 cf_filter_packets(capture_file
*cf
, char *dftext
, bool force
)
1520 const char *filter_new
= dftext
? dftext
: "";
1521 const char *filter_old
= cf
->dfilter
? cf
->dfilter
: "";
1525 /* if new filter equals old one, do nothing unless told to do so */
1526 /* XXX - The text can be the same without compiling to the same code.
1527 * (Macros, field references, etc.)
1529 if (!force
&& strcmp(filter_new
, filter_old
) == 0) {
1535 if (dftext
== NULL
) {
1536 /* The new filter is an empty filter (i.e., display all packets).
1537 * so leave dfcode==NULL
1541 * We have a filter; make a copy of it (as we'll be saving it),
1542 * and try to compile it.
1544 dftext
= g_strdup(dftext
);
1545 if (!dfilter_compile(dftext
, &dfcode
, &df_err
)) {
1546 /* The attempt failed; report an error. */
1547 simple_message_box(ESD_TYPE_ERROR
, NULL
,
1548 "See the help for a description of the display filter syntax.",
1549 "\"%s\" isn't a valid display filter: %s",
1550 dftext
, df_err
->msg
);
1551 df_error_free(&df_err
);
1557 if (dfcode
== NULL
) {
1558 /* Yes - free the filter text, and set it to null. */
1564 /* We have a valid filter. Replace the current filter. */
1565 g_free(cf
->dfilter
);
1566 cf
->dfilter
= dftext
;
1568 /* We'll recompile this when the rescan starts, or in cf_read()
1569 * if no file is open currently. However, if no file is open and
1570 * we start a new capture, we want to use this rather than
1571 * recompiling in cf_continue_tail() */
1572 dfilter_free(cf
->dfcode
);
1573 cf
->dfcode
= dfcode
;
1575 /* Now rescan the packet list, applying the new filter, but not
1576 * throwing away information constructed on a previous pass.
1577 * If a dissection is already in progress, queue it.
1579 if (cf
->redissection_queued
== RESCAN_NONE
) {
1580 if (cf
->read_lock
) {
1581 cf
->redissection_queued
= RESCAN_SCAN
;
1582 } else if (cf
->state
!= FILE_CLOSED
) {
1583 if (dftext
== NULL
) {
1584 rescan_packets(cf
, "Resetting", "filter", false);
1586 rescan_packets(cf
, "Filtering", dftext
, false);
1595 cf_redissect_packets(capture_file
*cf
)
1597 if (cf
->read_lock
|| cf
->redissection_queued
== RESCAN_SCAN
) {
1598 /* Dissection in progress, signal redissection rather than rescanning. That
1599 * would destroy the current (in-progress) dissection in "cf_read" which
1600 * will cause issues when "cf_read" tries to add packets to the list.
1601 * If a previous rescan was requested, "upgrade" it to a full redissection.
1603 cf
->redissection_queued
= RESCAN_REDISSECT
;
1605 if (cf
->redissection_queued
!= RESCAN_NONE
) {
1606 /* Redissection is (already) queued, wait for "cf_read" to finish. */
1607 /* XXX - what if whatever set and later clears read_lock is *not*
1608 * cf_read, e.g. process_specified_records ? We need to handle a
1609 * queued redissection there too like we do in cf_read.
1614 if (cf
->state
!= FILE_CLOSED
) {
1615 /* Restart dissection in case no cf_read is pending. */
1616 rescan_packets(cf
, "Reprocessing", "all packets", true);
1621 cf_read_record(capture_file
*cf
, const frame_data
*fdata
,
1622 wtap_rec
*rec
, Buffer
*buf
)
1627 if (!wtap_seek_read(cf
->provider
.wth
, fdata
->file_off
, rec
, buf
, &err
, &err_info
)) {
1628 report_cfile_read_failure(cf
->filename
, err
, err_info
);
1635 cf_read_record_no_alert(capture_file
*cf
, const frame_data
*fdata
,
1636 wtap_rec
*rec
, Buffer
*buf
)
1641 if (!wtap_seek_read(cf
->provider
.wth
, fdata
->file_off
, rec
, buf
, &err
, &err_info
)) {
1649 cf_read_current_record(capture_file
*cf
)
1651 return cf_read_record(cf
, cf
->current_frame
, &cf
->rec
, &cf
->buf
);
1654 /* Rescan the list of packets, reconstructing the CList.
1656 "action" describes why we're doing this; it's used in the progress
1659 "action_item" describes what we're doing; it's used in the progress
1662 "redissect" is true if we need to make the dissectors reconstruct
1663 any state information they have (because a preference that affects
1664 some dissector has changed, meaning some dissector might construct
1665 its state differently from the way it was constructed the last time). */
1667 rescan_packets(capture_file
*cf
, const char *action
, const char *action_item
, bool redissect
)
1669 /* Rescan packets new packet list */
1674 progdlg_t
*progbar
= NULL
;
1675 GTimer
*prog_timer
= g_timer_new();
1677 frame_data
*selected_frame
, *preceding_frame
, *following_frame
, *prev_frame
;
1678 int selected_frame_num
, preceding_frame_num
, following_frame_num
, prev_frame_num
;
1679 bool selected_frame_seen
;
1682 char status_str
[100];
1684 dfilter_t
*dfcode
= NULL
;
1686 bool create_proto_tree
;
1687 bool filtering_tap_listeners
= false;
1689 bool add_to_packet_list
= false;
1691 uint32_t frames_count
;
1692 rescan_type queued_rescan_type
= RESCAN_NONE
;
1694 if (cf
->state
== FILE_CLOSED
|| cf
->state
== FILE_READ_PENDING
) {
1698 /* Rescan in progress, clear pending actions. */
1699 cf
->redissection_queued
= RESCAN_NONE
;
1700 ws_assert(!cf
->read_lock
);
1701 cf
->read_lock
= true;
1703 wtap_rec_init(&rec
);
1704 ws_buffer_init(&buf
, 1514);
1706 /* Compile the current display filter.
1707 * The code it compiles to might have changed, e.g. if a display
1708 * filter macro used has changed.
1710 * We assume this will not fail since cf->dfilter is only set in
1711 * cf_filter IFF the filter was valid.
1712 * XXX - This is not necessarily true, if the filter has a FT_IPv4
1713 * or FT_IPv6 field compared to a resolved hostname in it, because
1714 * we do a new host lookup, and that *could* timeout this time
1715 * (though with the read lock above we shouldn't have many lookups at
1716 * once, reducing the chances of that)... (#19612)
1719 compiled
= dfilter_compile(cf
->dfilter
, &dfcode
, NULL
);
1720 ws_assert(compiled
&& dfcode
);
1723 dfilter_free(cf
->dfcode
);
1724 cf
->dfcode
= dfcode
;
1726 /* Do we have any tap listeners with filters? */
1727 filtering_tap_listeners
= have_filtering_tap_listeners();
1729 /* Update references in filters (if any) for the protocol
1730 * tree corresponding to the currently selected frame in the GUI. */
1731 if (cf
->edt
!= NULL
&& cf
->edt
->tree
!= NULL
) {
1733 dfilter_load_field_references(cf
->dfcode
, cf
->edt
->tree
);
1734 if (filtering_tap_listeners
)
1735 tap_listeners_load_field_references(cf
->edt
);
1738 if (cf
->dfcode
!= NULL
) {
1739 dfilter_log_full(LOG_DOMAIN_DFILTER
, LOG_LEVEL_NOISY
, NULL
, -1, NULL
,
1740 cf
->dfcode
, "Rescanning packets with display filter");
1743 /* Get the union of the flags for all tap listeners. */
1744 tap_flags
= union_of_tap_listener_flags();
1746 /* If the display filter or any tap listeners require the columns,
1747 * construct them. */
1748 cinfo
= (tap_listeners_require_columns() ||
1749 dfilter_requires_columns(cf
->dfcode
)) ? &cf
->cinfo
: NULL
;
1752 * Determine whether we need to create a protocol tree.
1755 * we're going to apply a display filter;
1757 * one of the tap listeners is going to apply a filter;
1759 * one of the tap listeners requires a protocol tree;
1761 * we're redissecting and a postdissector wants field
1762 * values or protocols on the first pass.
1765 (cf
->dfcode
!= NULL
|| filtering_tap_listeners
||
1766 (tap_flags
& TL_REQUIRES_PROTO_TREE
) ||
1767 (redissect
&& postdissectors_want_hfids()));
1769 reset_tap_listeners();
1770 /* Which frame, if any, is the currently selected frame?
1771 XXX - should the selected frame or the focus frame be the "current"
1772 frame, that frame being the one from which "Find Frame" searches
1774 selected_frame
= cf
->current_frame
;
1776 /* Mark frame num as not found */
1777 selected_frame_num
= -1;
1779 /* Freeze the packet list while we redo it, so we don't get any
1780 screen updates while it happens. */
1781 packet_list_freeze();
1784 /* We need to re-initialize all the state information that protocols
1785 keep, because some preference that controls a dissector has changed,
1786 which might cause the state information to be constructed differently
1787 by that dissector. */
1789 /* We might receive new packets while redissecting, and we don't
1790 want to dissect those before their time. */
1791 cf
->redissecting
= true;
1793 /* 'reset' dissection session */
1794 epan_free(cf
->epan
);
1795 if (cf
->edt
&& cf
->edt
->pi
.fd
) {
1796 /* All pointers in "per frame proto data" for the currently selected
1797 packet are allocated in wmem_file_scope() and deallocated in epan_free().
1798 Free them here to avoid unintended usage in packet_list_clear(). */
1799 frame_data_destroy(cf
->edt
->pi
.fd
);
1801 cf
->epan
= ws_epan_new(cf
);
1802 cf
->cinfo
.epan
= cf
->epan
;
1804 /* A new Lua tap listener may be registered in lua_prime_all_fields()
1805 called via epan_new() / init_dissection() when reloading Lua plugins. */
1806 if (!create_proto_tree
&& have_filtering_tap_listeners()) {
1807 create_proto_tree
= true;
1809 if (!cinfo
&& tap_listeners_require_columns()) {
1813 /* We need to redissect the packets so we have to discard our old
1814 * packet list store. */
1815 packet_list_clear();
1816 add_to_packet_list
= true;
1819 /* We don't yet know which will be the first and last frames displayed. */
1820 cf
->first_displayed
= 0;
1821 cf
->last_displayed
= 0;
1823 /* We currently don't display any packets */
1824 cf
->displayed_count
= 0;
1826 /* Iterate through the list of frames. Call a routine for each frame
1827 to check whether it should be displayed and, if so, add it to
1828 the display list. */
1829 cf
->provider
.ref
= NULL
;
1830 cf
->provider
.prev_dis
= NULL
;
1831 cf
->provider
.prev_cap
= NULL
;
1834 cf_callback_invoke(cf_cb_file_rescan_started
, cf
);
1836 g_timer_start(prog_timer
);
1837 /* Count of packets at which we've looked. */
1839 /* Progress so far. */
1842 cf
->stop_flag
= false;
1843 start_time
= g_get_monotonic_time();
1845 /* no previous row yet */
1846 prev_frame_num
= -1;
1849 preceding_frame_num
= -1;
1850 preceding_frame
= NULL
;
1851 following_frame_num
= -1;
1852 following_frame
= NULL
;
1854 selected_frame_seen
= false;
1856 frames_count
= cf
->count
;
1858 epan_dissect_init(&edt
, cf
->epan
, create_proto_tree
, false);
1862 * Decryption secrets and name resolution blocks are read while
1863 * sequentially processing records and then passed to the dissector.
1864 * During redissection, the previous information is lost (see epan_free
1865 * above), but they are not read again from the file as only packet
1866 * records are re-read. Therefore reset the wtap secrets and name
1867 * resolution callbacks such that wtap resupplies the callbacks with
1868 * previously read information.
1870 wtap_set_cb_new_ipv4(cf
->provider
.wth
, add_ipv4_name
);
1871 wtap_set_cb_new_ipv6(cf
->provider
.wth
, (wtap_new_ipv6_callback_t
) add_ipv6_name
);
1872 wtap_set_cb_new_secrets(cf
->provider
.wth
, secrets_wtap_callback
);
1875 for (framenum
= 1; framenum
<= frames_count
; framenum
++) {
1876 fdata
= frame_data_sequence_find(cf
->provider
.frames
, framenum
);
1878 /* Create the progress bar if necessary.
1879 We check on every iteration of the loop, so that it takes no
1880 longer than the standard time to create it (otherwise, for a
1881 large file, we might take considerably longer than that standard
1882 time in order to get to the next progress bar step). */
1883 if (progbar
== NULL
)
1884 progbar
= delayed_create_progress_dlg(cf
->window
, action
, action_item
, true,
1889 * Update the progress bar, but do it only after PROGBAR_UPDATE_INTERVAL
1890 * has elapsed. Calling update_progress_dlg and packets_bar_update will
1891 * likely trigger UI paint events, which might take a while depending on
1892 * the platform and display. Reset our timer *after* painting.
1894 if (g_timer_elapsed(prog_timer
, NULL
) > PROGBAR_UPDATE_INTERVAL
) {
1895 /* let's not divide by zero. I should never be started
1896 * with count == 0, so let's assert that
1898 ws_assert(cf
->count
> 0);
1899 progbar_val
= (float) count
/ frames_count
;
1901 if (progbar
!= NULL
) {
1902 snprintf(status_str
, sizeof(status_str
),
1903 "%4u of %u frames", count
, frames_count
);
1904 update_progress_dlg(progbar
, progbar_val
, status_str
);
1907 g_timer_start(prog_timer
);
1910 queued_rescan_type
= cf
->redissection_queued
;
1911 if (queued_rescan_type
!= RESCAN_NONE
) {
1912 /* A redissection was requested while an existing redissection was
1917 if (cf
->stop_flag
) {
1918 /* Well, the user decided to abort the filtering. Just stop.
1920 XXX - go back to the previous filter? Users probably just
1921 want not to wait for a filtering operation to finish;
1922 unless we cancel by having no filter, reverting to the
1923 previous filter will probably be even more expensive than
1924 continuing the filtering, as it involves going back to the
1925 beginning and filtering, and even with no filter we currently
1926 have to re-generate the entire clist, which is also expensive.
1928 I'm not sure what Network Monitor does, but it doesn't appear
1929 to give you an unfiltered display if you cancel. */
1936 /* Since all state for the frame was destroyed, mark the frame
1937 * as not visited, free the GSList referring to the state
1938 * data (the per-frame data itself was freed by
1939 * "init_dissection()"), and null out the GSList pointer. */
1940 frame_data_reset(fdata
);
1941 frames_count
= cf
->count
;
1944 /* Frame dependencies from the previous dissection/filtering are no longer valid. */
1945 fdata
->dependent_of_displayed
= 0;
1947 if (!cf_read_record(cf
, fdata
, &rec
, &buf
))
1948 break; /* error reading the frame */
1950 /* If the previous frame is displayed, and we haven't yet seen the
1951 selected frame, remember that frame - it's the closest one we've
1952 yet seen before the selected frame. */
1953 if (prev_frame_num
!= -1 && !selected_frame_seen
&& prev_frame
->passed_dfilter
) {
1954 preceding_frame_num
= prev_frame_num
;
1955 preceding_frame
= prev_frame
;
1958 add_packet_to_packet_list(fdata
, cf
, &edt
, cf
->dfcode
,
1960 add_to_packet_list
);
1962 /* If this frame is displayed, and this is the first frame we've
1963 seen displayed after the selected frame, remember this frame -
1964 it's the closest one we've yet seen at or after the selected
1966 if (fdata
->passed_dfilter
&& selected_frame_seen
&& following_frame_num
== -1) {
1967 following_frame_num
= fdata
->num
;
1968 following_frame
= fdata
;
1970 if (fdata
== selected_frame
) {
1971 selected_frame_seen
= true;
1972 if (fdata
->passed_dfilter
)
1973 selected_frame_num
= fdata
->num
;
1976 /* Remember this frame - it'll be the previous frame
1977 on the next pass through the loop. */
1978 prev_frame_num
= fdata
->num
;
1980 wtap_rec_reset(&rec
);
1983 epan_dissect_cleanup(&edt
);
1984 wtap_rec_cleanup(&rec
);
1985 ws_buffer_free(&buf
);
1987 /* We are done redissecting the packet list. */
1988 cf
->redissecting
= false;
1991 frames_count
= cf
->count
;
1992 /* Clear out what remains of the visited flags and per-frame data
1995 XXX - that may cause various forms of bogosity when dissecting
1996 these frames, as they won't have been seen by this sequential
1997 pass, but the only alternative I see is to keep scanning them
1998 even though the user requested that the scan stop, and that
1999 would leave the user stuck with an Wireshark grinding on
2000 until it finishes. Should we just stick them with that? */
2001 for (; framenum
<= frames_count
; framenum
++) {
2002 fdata
= frame_data_sequence_find(cf
->provider
.frames
, framenum
);
2003 frame_data_reset(fdata
);
2007 /* We're done filtering the packets; destroy the progress bar if it
2009 if (progbar
!= NULL
)
2010 destroy_progress_dlg(progbar
);
2011 g_timer_destroy(prog_timer
);
2013 /* Unfreeze the packet list. */
2014 if (!add_to_packet_list
)
2015 packet_list_recreate_visible_rows();
2017 /* Compute the time it took to filter the file */
2018 compute_elapsed(cf
, start_time
);
2022 /* It is safe again to execute redissections or sort. */
2023 ws_assert(cf
->read_lock
);
2024 cf
->read_lock
= false;
2026 cf_callback_invoke(cf_cb_file_rescan_finished
, cf
);
2028 if (selected_frame_num
== -1) {
2029 /* The selected frame didn't pass the filter. */
2030 if (selected_frame
== NULL
) {
2031 /* That's because there *was* no selected frame. Make the first
2032 displayed frame the current frame. */
2033 selected_frame_num
= 0;
2035 /* Find the nearest displayed frame to the selected frame (whether
2036 it's before or after that frame) and make that the current frame.
2037 If the next and previous displayed frames are equidistant from the
2038 selected frame, choose the next one. */
2039 ws_assert(following_frame
== NULL
||
2040 following_frame
->num
>= selected_frame
->num
);
2041 ws_assert(preceding_frame
== NULL
||
2042 preceding_frame
->num
<= selected_frame
->num
);
2043 if (following_frame
== NULL
) {
2044 /* No frame after the selected frame passed the filter, so we
2045 have to select the last displayed frame before the selected
2047 selected_frame_num
= preceding_frame_num
;
2048 selected_frame
= preceding_frame
;
2049 } else if (preceding_frame
== NULL
) {
2050 /* No frame before the selected frame passed the filter, so we
2051 have to select the first displayed frame after the selected
2053 selected_frame_num
= following_frame_num
;
2054 selected_frame
= following_frame
;
2056 /* Frames before and after the selected frame passed the filter, so
2057 we'll select the previous frame */
2058 selected_frame_num
= preceding_frame_num
;
2059 selected_frame
= preceding_frame
;
2064 if (selected_frame_num
== -1) {
2065 /* There are no frames displayed at all. */
2066 cf_unselect_packet(cf
);
2068 /* Either the frame that was selected passed the filter, or we've
2069 found the nearest displayed frame to that frame. Select it, make
2070 it the focus row, and make it visible. */
2071 /* Set to invalid to force update of packet list and packet details */
2072 if (selected_frame_num
== 0) {
2073 packet_list_select_row_from_data(NULL
);
2075 if (!packet_list_select_row_from_data(selected_frame
)) {
2076 /* We didn't find a row corresponding to this frame.
2077 This means that the frame isn't being displayed currently,
2078 so we can't select it. */
2079 simple_message_box(ESD_TYPE_INFO
, NULL
,
2080 "The capture file is probably not fully dissected.",
2081 "End of capture exceeded.");
2086 /* If another rescan (due to dfilter change) or redissection (due to profile
2087 * change) was requested, the rescan above is aborted and restarted here. */
2088 if (queued_rescan_type
!= RESCAN_NONE
) {
2089 redissect
= redissect
|| queued_rescan_type
== RESCAN_REDISSECT
;
2090 rescan_packets(cf
, "Reprocessing", "all packets", redissect
);
2096 * Scan through all frame data and recalculate the ref time
2097 * without rereading the file.
2098 * XXX - do we need a progress bar or is this fast enough?
2101 cf_reftime_packets(capture_file
* cf
)
2107 cf
->provider
.ref
= NULL
;
2108 cf
->provider
.prev_dis
= NULL
;
2111 for (framenum
= 1; framenum
<= cf
->count
; framenum
++) {
2112 fdata
= frame_data_sequence_find(cf
->provider
.frames
, framenum
);
2114 /* just add some value here until we know if it is being displayed or not */
2115 fdata
->cum_bytes
= cf
->cum_bytes
+ fdata
->pkt_len
;
2121 if (fdata
->has_ts
) {
2122 /* If we don't have the time stamp of the first packet in the
2123 capture, it's because this is the first packet. Save the time
2124 stamp of this packet as the time stamp of the first packet. */
2125 if (cf
->provider
.ref
== NULL
)
2126 cf
->provider
.ref
= fdata
;
2127 /* if this frames is marked as a reference time frame, reset
2128 firstsec and firstusec to this frame */
2129 if (fdata
->ref_time
)
2130 cf
->provider
.ref
= fdata
;
2132 /* Get the time elapsed between the first packet and this one. */
2133 fdata
->frame_ref_num
= (fdata
!= cf
->provider
.ref
) ? cf
->provider
.ref
->num
: 0;
2134 nstime_delta(&rel_ts
, &fdata
->abs_ts
, &cf
->provider
.ref
->abs_ts
);
2136 /* If it's greater than the current elapsed time, set the elapsed
2137 time to it (we check for "greater than" so as not to be
2138 confused by time moving backwards). */
2139 if ((int32_t)cf
->elapsed_time
.secs
< rel_ts
.secs
2140 || ((int32_t)cf
->elapsed_time
.secs
== rel_ts
.secs
&& (int32_t)cf
->elapsed_time
.nsecs
< rel_ts
.nsecs
)) {
2141 cf
->elapsed_time
= rel_ts
;
2144 /* If this frame is displayed, get the time elapsed between the
2145 previous displayed packet and this packet. */
2146 /* XXX: What if in the future we want to use the previously
2147 * displayed frame for something else, too? Then we'd want
2148 * to store this frame as prev_dis even if it doesn't have a
2150 if ( fdata
->passed_dfilter
) {
2151 /* If we don't have the time stamp of the previous displayed
2152 packet, it's because this is the first displayed packet.
2153 Save the time stamp of this packet as the time stamp of
2154 the previous displayed packet. */
2155 if (cf
->provider
.prev_dis
== NULL
) {
2156 cf
->provider
.prev_dis
= fdata
;
2159 fdata
->prev_dis_num
= cf
->provider
.prev_dis
->num
;
2160 cf
->provider
.prev_dis
= fdata
;
2163 /* If this frame doesn't have a timestamp, don't calculate
2164 anything with relative times. */
2165 /* However, if this frame is marked as a reference time frame,
2166 clear the reference frame so that the next frame with a
2167 timestamp becomes the reference frame. */
2168 if (fdata
->ref_time
) {
2169 cf
->provider
.ref
= NULL
;
2176 if ( (fdata
->passed_dfilter
) || (fdata
->ref_time
) ) {
2177 /* This frame either passed the display filter list or is marked as
2178 a time reference frame. All time reference frames are displayed
2179 even if they don't pass the display filter */
2180 if (fdata
->ref_time
) {
2181 /* if this was a TIME REF frame we should reset the cum_bytes field */
2182 cf
->cum_bytes
= fdata
->pkt_len
;
2183 fdata
->cum_bytes
= cf
->cum_bytes
;
2185 /* increase cum_bytes with this packets length */
2186 cf
->cum_bytes
+= fdata
->pkt_len
;
2199 process_specified_records(capture_file
*cf
, packet_range_t
*range
,
2200 const char *string1
, const char *string2
, bool terminate_is_stop
,
2201 bool (*callback
)(capture_file
*, frame_data
*,
2202 wtap_rec
*, Buffer
*, void *),
2203 void *callback_args
,
2204 bool show_progress_bar
)
2210 psp_return_t ret
= PSP_FINISHED
;
2212 progdlg_t
*progbar
= NULL
;
2213 GTimer
*prog_timer
= g_timer_new();
2216 char progbar_status_str
[100];
2217 range_process_e process_this
;
2219 wtap_rec_init(&rec
);
2220 ws_buffer_init(&buf
, 1514);
2222 g_timer_start(prog_timer
);
2223 /* Count of packets at which we've looked. */
2225 /* Progress so far. */
2228 /* XXX - It should be ok to have multiple readers, so long as nothing
2229 * frees the epan context, e.g. rescan_packets with redissect true,
2230 * or anything that closes the file (including reload and certain forms
2231 * of saving.) This is mostly to stop cf_save_records but should probably
2232 * be handled by callers in order to allow multiple readers (e.g.,
2233 * restarting taps after adding or changing one.) We should probably
2234 * make this a real reader-writer lock.
2236 if (cf
->read_lock
) {
2237 ws_warning("Failing due to nested process_specified_records(\"%s\") call!", cf
->filename
);
2240 cf
->read_lock
= true;
2242 cf
->stop_flag
= false;
2245 packet_range_process_init(range
);
2247 /* Iterate through all the packets, printing the packets that
2248 were selected by the current display filter. */
2249 for (framenum
= 1; framenum
<= cf
->count
; framenum
++) {
2250 fdata
= frame_data_sequence_find(cf
->provider
.frames
, framenum
);
2252 /* Create the progress bar if necessary.
2253 We check on every iteration of the loop, so that it takes no
2254 longer than the standard time to create it (otherwise, for a
2255 large file, we might take considerably longer than that standard
2256 time in order to get to the next progress bar step). */
2257 if (show_progress_bar
&& progbar
== NULL
)
2258 progbar
= delayed_create_progress_dlg(cf
->window
, string1
, string2
,
2264 * Update the progress bar, but do it only after PROGBAR_UPDATE_INTERVAL
2265 * has elapsed. Calling update_progress_dlg and packets_bar_update will
2266 * likely trigger UI paint events, which might take a while depending on
2267 * the platform and display. Reset our timer *after* painting.
2269 if (progbar
&& g_timer_elapsed(prog_timer
, NULL
) > PROGBAR_UPDATE_INTERVAL
) {
2270 /* let's not divide by zero. I should never be started
2271 * with count == 0, so let's assert that
2273 ws_assert(cf
->count
> 0);
2274 progbar_val
= (float) progbar_count
/ cf
->count
;
2276 snprintf(progbar_status_str
, sizeof(progbar_status_str
),
2277 "%4u of %u packets", progbar_count
, cf
->count
);
2278 update_progress_dlg(progbar
, progbar_val
, progbar_status_str
);
2280 g_timer_start(prog_timer
);
2283 if (cf
->stop_flag
) {
2284 /* Well, the user decided to abort the operation. Just stop,
2285 and arrange to return PSP_STOPPED to our caller, so they know
2286 it was stopped explicitly. */
2293 if (range
!= NULL
) {
2294 /* do we have to process this packet? */
2295 process_this
= packet_range_process_packet(range
, fdata
);
2296 if (process_this
== range_process_next
) {
2297 /* this packet uninteresting, continue with next one */
2299 } else if (process_this
== range_processing_finished
) {
2300 /* all interesting packets processed, stop the loop */
2305 /* Get the packet */
2306 if (!cf_read_record(cf
, fdata
, &rec
, &buf
)) {
2307 /* Attempt to get the packet failed. */
2311 /* Process the packet */
2312 if (!callback(cf
, fdata
, &rec
, &buf
, callback_args
)) {
2313 /* Callback failed. We assume it reported the error appropriately. */
2317 wtap_rec_reset(&rec
);
2320 /* We're done printing the packets; destroy the progress bar if
2322 if (progbar
!= NULL
)
2323 destroy_progress_dlg(progbar
);
2324 g_timer_destroy(prog_timer
);
2326 ws_assert(cf
->read_lock
);
2327 cf
->read_lock
= false;
2329 wtap_rec_cleanup(&rec
);
2330 ws_buffer_free(&buf
);
2338 } retap_callback_args_t
;
2341 retap_packet(capture_file
*cf
, frame_data
*fdata
, wtap_rec
*rec
, Buffer
*buf
,
2344 retap_callback_args_t
*args
= (retap_callback_args_t
*)argsp
;
2346 epan_dissect_run_with_taps(&args
->edt
, cf
->cd_t
, rec
,
2347 frame_tvbuff_new_buffer(&cf
->provider
, fdata
, buf
),
2348 fdata
, args
->cinfo
);
2349 epan_dissect_reset(&args
->edt
);
2355 cf_retap_packets(capture_file
*cf
)
2357 packet_range_t range
;
2358 retap_callback_args_t callback_args
;
2359 bool create_proto_tree
;
2360 bool filtering_tap_listeners
;
2364 /* Presumably the user closed the capture file. */
2366 return CF_READ_ABORTED
;
2369 /* XXX - If cf->read_lock is true, process_specified_records will fail
2370 * due to a nested call. We fail here so that we don't reset the tap
2371 * listeners if this tap isn't going to succeed.
2373 if (cf
->read_lock
) {
2374 ws_warning("Failing due to nested process_specified_records(\"%s\") call!", cf
->filename
);
2375 return CF_READ_ERROR
;
2378 cf_callback_invoke(cf_cb_file_retap_started
, cf
);
2380 /* Do we have any tap listeners with filters? */
2381 filtering_tap_listeners
= have_filtering_tap_listeners();
2383 /* Update references in filters (if any) for the protocol
2384 * tree corresponding to the currently selected frame in the GUI. */
2385 /* XXX - What if we *don't* have a currently selected frame in the GUI,
2386 * but we did the last time we loaded field references? Then they'll
2387 * match something instead of nothing (unless they've been recompiled).
2388 * Should we have a way to clear the field references even with a NULL tree?
2390 if (cf
->edt
!= NULL
&& cf
->edt
->tree
!= NULL
) {
2391 if (filtering_tap_listeners
)
2392 tap_listeners_load_field_references(cf
->edt
);
2395 /* Get the union of the flags for all tap listeners. */
2396 tap_flags
= union_of_tap_listener_flags();
2398 /* If any tap listeners require the columns, construct them. */
2399 callback_args
.cinfo
= (tap_listeners_require_columns()) ? &cf
->cinfo
: NULL
;
2402 * Determine whether we need to create a protocol tree.
2405 * one of the tap listeners is going to apply a filter;
2407 * one of the tap listeners requires a protocol tree.
2410 (filtering_tap_listeners
|| (tap_flags
& TL_REQUIRES_PROTO_TREE
));
2412 /* Reset the tap listeners. */
2413 reset_tap_listeners();
2414 uint32_t count
= cf
->count
;
2416 epan_dissect_init(&callback_args
.edt
, cf
->epan
, create_proto_tree
, false);
2418 /* Iterate through the list of packets, dissecting all packets and
2419 re-running the taps. */
2420 packet_range_init(&range
, cf
);
2421 packet_range_process_init(&range
);
2423 if (cf
->state
== FILE_READ_IN_PROGRESS
) {
2424 /* We're not done with the sequential read of the file and might
2425 * add more frames while process_specified_records is going. We
2426 * don't want to tap new frames twice, so limit the range to the
2427 * frames already here.
2429 * cf_read sets read_lock so we don't tap in case of an offline
2430 * file, but cf_continue_tail and cf_finish_tail don't, and we
2431 * don't want them to, because tapping new packets in a live
2432 * capture is a common use case.
2434 * Note that most other users of process_specified_records (saving,
2435 * printing) do want to process new packets, unlike taps.
2438 char* range_str
= g_strdup_printf("-%u", count
);
2439 packet_range_convert_str(&range
, range_str
);
2442 /* range_t treats a missing number as meaning 1, not 0, and
2443 * reverses the order if backwards; thus the syntax -0 means
2444 * 0-1, so to only take zero packets we do this.
2446 packet_range_convert_str(&range
, "0");
2448 range
.process
= range_process_user_range
;
2451 ret
= process_specified_records(cf
, &range
, "Recalculating statistics on",
2452 "all packets", true, retap_packet
,
2453 &callback_args
, true);
2455 packet_range_cleanup(&range
);
2456 epan_dissect_cleanup(&callback_args
.edt
);
2458 cf_callback_invoke(cf_cb_file_retap_finished
, cf
);
2462 /* Completed successfully. */
2466 /* Well, the user decided to abort the refiltering.
2467 Return CF_READ_ABORTED so our caller knows they did that. */
2468 return CF_READ_ABORTED
;
2471 /* Error while retapping. */
2472 return CF_READ_ERROR
;
2475 ws_assert_not_reached();
2480 print_args_t
*print_args
;
2481 bool print_header_line
;
2482 char *header_line_buf
;
2483 int header_line_buf_len
;
2484 bool print_formfeed
;
2485 bool print_separator
;
2489 int num_visible_cols
;
2492 } print_callback_args_t
;
2495 print_packet(capture_file
*cf
, frame_data
*fdata
, wtap_rec
*rec
, Buffer
*buf
,
2498 print_callback_args_t
*args
= (print_callback_args_t
*)argsp
;
2504 char bookmark_name
[9+10+1]; /* "__frameNNNNNNNNNN__\0" */
2505 char bookmark_title
[6+10+1]; /* "Frame NNNNNNNNNN__\0" */
2506 col_item_t
* col_item
;
2507 const char* col_text
;
2509 /* Fill in the column information if we're printing the summary
2511 if (args
->print_args
->print_summary
) {
2512 col_custom_prime_edt(&args
->edt
, &cf
->cinfo
);
2513 epan_dissect_run(&args
->edt
, cf
->cd_t
, rec
,
2514 frame_tvbuff_new_buffer(&cf
->provider
, fdata
, buf
),
2516 epan_dissect_fill_in_columns(&args
->edt
, false, true);
2518 epan_dissect_run(&args
->edt
, cf
->cd_t
, rec
,
2519 frame_tvbuff_new_buffer(&cf
->provider
, fdata
, buf
),
2522 if (args
->print_formfeed
) {
2523 if (!new_page(args
->print_args
->stream
))
2527 * Print another header line if we print a packet summary on the
2530 if (args
->print_args
->print_col_headings
)
2531 args
->print_header_line
= true;
2533 if (args
->print_separator
) {
2534 if (!print_line(args
->print_args
->stream
, 0, ""))
2540 * We generate bookmarks, if the output format supports them.
2541 * The name is "__frameN__".
2543 snprintf(bookmark_name
, sizeof bookmark_name
, "__frame%u__", fdata
->num
);
2545 if (args
->print_args
->print_summary
) {
2546 if (!args
->print_args
->print_col_headings
)
2547 args
->print_header_line
= false;
2548 if (args
->print_header_line
) {
2549 if (!print_line(args
->print_args
->stream
, 0, args
->header_line_buf
))
2551 args
->print_header_line
= false; /* we might not need to print any more */
2553 cp
= &args
->line_buf
[0];
2555 for (i
= 0; i
< args
->num_visible_cols
; i
++) {
2556 col_item
= &cf
->cinfo
.columns
[args
->visible_cols
[i
]];
2557 col_text
= get_column_text(&cf
->cinfo
, args
->visible_cols
[i
]);
2558 /* Find the length of the string for this column. */
2559 column_len
= (int) strlen(col_text
);
2560 if (args
->col_widths
[i
] > column_len
)
2561 column_len
= args
->col_widths
[i
];
2563 /* Make sure there's room in the line buffer for the column; if not,
2564 double its length. */
2565 line_len
+= column_len
+ 1; /* "+1" for space */
2566 if (line_len
> args
->line_buf_len
) {
2567 cp_off
= (int) (cp
- args
->line_buf
);
2568 args
->line_buf_len
= 2 * line_len
;
2569 args
->line_buf
= (char *)g_realloc(args
->line_buf
, args
->line_buf_len
+ 1);
2570 cp
= args
->line_buf
+ cp_off
;
2573 /* Right-justify the packet number column. */
2574 if (col_item
->col_fmt
== COL_NUMBER
|| col_item
->col_fmt
== COL_NUMBER_DIS
)
2575 snprintf(cp
, column_len
+1, "%*s", args
->col_widths
[i
], col_text
);
2577 snprintf(cp
, column_len
+1, "%-*s", args
->col_widths
[i
], col_text
);
2579 if (i
!= args
->num_visible_cols
- 1)
2585 * Generate a bookmark, using the summary line as the title.
2587 if (!print_bookmark(args
->print_args
->stream
, bookmark_name
,
2591 if (!print_line(args
->print_args
->stream
, 0, args
->line_buf
))
2595 * Generate a bookmark, using "Frame N" as the title, as we're not
2596 * printing the summary line.
2598 snprintf(bookmark_title
, sizeof bookmark_title
, "Frame %u", fdata
->num
);
2599 if (!print_bookmark(args
->print_args
->stream
, bookmark_name
,
2602 } /* if (print_summary) */
2604 if (args
->print_args
->print_dissections
!= print_dissections_none
) {
2605 if (args
->print_args
->print_summary
) {
2606 /* Separate the summary line from the tree with a blank line. */
2607 if (!print_line(args
->print_args
->stream
, 0, ""))
2611 /* Print the information in that tree. */
2612 if (!proto_tree_print(args
->print_args
->print_dissections
,
2613 args
->print_args
->print_hex
, &args
->edt
, NULL
,
2614 args
->print_args
->stream
))
2617 /* Print a blank line if we print anything after this (aka more than one packet). */
2618 args
->print_separator
= true;
2620 /* Print a header line if we print any more packet summaries */
2621 if (args
->print_args
->print_col_headings
)
2622 args
->print_header_line
= true;
2625 if (args
->print_args
->print_hex
) {
2626 if (args
->print_args
->print_summary
|| (args
->print_args
->print_dissections
!= print_dissections_none
)) {
2627 if (!print_line(args
->print_args
->stream
, 0, ""))
2630 /* Print the full packet data as hex. */
2631 if (!print_hex_data(args
->print_args
->stream
, &args
->edt
, args
->print_args
->hexdump_options
))
2634 /* Print a blank line if we print anything after this (aka more than one packet). */
2635 args
->print_separator
= true;
2637 /* Print a header line if we print any more packet summaries */
2638 if (args
->print_args
->print_col_headings
)
2639 args
->print_header_line
= true;
2640 } /* if (args->print_args->print_dissections != print_dissections_none) */
2642 epan_dissect_reset(&args
->edt
);
2644 /* do we want to have a formfeed between each packet from now on? */
2645 if (args
->print_args
->print_formfeed
) {
2646 args
->print_formfeed
= true;
2652 epan_dissect_reset(&args
->edt
);
2657 cf_print_packets(capture_file
*cf
, print_args_t
*print_args
,
2658 bool show_progress_bar
)
2660 print_callback_args_t callback_args
;
2663 int i
, cp_off
, column_len
, line_len
;
2664 int num_visible_col
= 0, last_visible_col
= 0, visible_col_count
;
2668 bool proto_tree_needed
;
2670 callback_args
.print_args
= print_args
;
2671 callback_args
.print_header_line
= print_args
->print_col_headings
;
2672 callback_args
.header_line_buf
= NULL
;
2673 callback_args
.header_line_buf_len
= 256;
2674 callback_args
.print_formfeed
= false;
2675 callback_args
.print_separator
= false;
2676 callback_args
.line_buf
= NULL
;
2677 callback_args
.line_buf_len
= 256;
2678 callback_args
.col_widths
= NULL
;
2679 callback_args
.num_visible_cols
= 0;
2680 callback_args
.visible_cols
= NULL
;
2682 if (!print_preamble(print_args
->stream
, cf
->filename
, get_ws_vcs_version_info())) {
2683 destroy_print_stream(print_args
->stream
);
2684 return CF_PRINT_WRITE_ERROR
;
2687 if (print_args
->print_summary
) {
2688 /* We're printing packet summaries. Allocate the header line buffer
2689 and get the column widths. */
2690 callback_args
.header_line_buf
= (char *)g_malloc(callback_args
.header_line_buf_len
+ 1);
2692 /* Find the number of visible columns and the last visible column */
2693 for (i
= 0; i
< prefs
.num_cols
; i
++) {
2695 clp
= g_list_nth(prefs
.col_list
, i
);
2696 if (clp
== NULL
) /* Sanity check, Invalid column requested */
2699 cfmt
= (fmt_data
*) clp
->data
;
2700 if (cfmt
->visible
) {
2702 last_visible_col
= i
;
2706 /* if num_visible_col is 0, we are done */
2707 if (num_visible_col
== 0) {
2708 g_free(callback_args
.header_line_buf
);
2712 /* Find the widths for each of the columns - maximum of the
2713 width of the title and the width of the data - and construct
2714 a buffer with a line containing the column titles. */
2715 callback_args
.num_visible_cols
= num_visible_col
;
2716 callback_args
.col_widths
= g_new(int, num_visible_col
);
2717 callback_args
.visible_cols
= g_new(int, num_visible_col
);
2718 cp
= &callback_args
.header_line_buf
[0];
2720 visible_col_count
= 0;
2721 for (i
= 0; i
< cf
->cinfo
.num_cols
; i
++) {
2723 clp
= g_list_nth(prefs
.col_list
, i
);
2724 if (clp
== NULL
) /* Sanity check, Invalid column requested */
2727 cfmt
= (fmt_data
*) clp
->data
;
2728 if (cfmt
->visible
== false)
2731 /* Save the order of visible columns */
2732 callback_args
.visible_cols
[visible_col_count
] = i
;
2734 /* Don't pad the last column. */
2735 if (i
== last_visible_col
)
2736 callback_args
.col_widths
[visible_col_count
] = 0;
2738 callback_args
.col_widths
[visible_col_count
] = (int) strlen(cf
->cinfo
.columns
[i
].col_title
);
2739 data_width
= get_column_char_width(get_column_format(i
));
2740 if (data_width
> callback_args
.col_widths
[visible_col_count
])
2741 callback_args
.col_widths
[visible_col_count
] = data_width
;
2744 /* Find the length of the string for this column. */
2745 column_len
= (int) strlen(cf
->cinfo
.columns
[i
].col_title
);
2746 if (callback_args
.col_widths
[visible_col_count
] > column_len
)
2747 column_len
= callback_args
.col_widths
[visible_col_count
];
2749 /* Make sure there's room in the line buffer for the column; if not,
2750 double its length. */
2751 line_len
+= column_len
+ 1; /* "+1" for space */
2752 if (line_len
> callback_args
.header_line_buf_len
) {
2753 cp_off
= (int) (cp
- callback_args
.header_line_buf
);
2754 callback_args
.header_line_buf_len
= 2 * line_len
;
2755 callback_args
.header_line_buf
= (char *)g_realloc(callback_args
.header_line_buf
,
2756 callback_args
.header_line_buf_len
+ 1);
2757 cp
= callback_args
.header_line_buf
+ cp_off
;
2760 /* Right-justify the packet number column. */
2761 /* if (cf->cinfo.col_fmt[i] == COL_NUMBER || cf->cinfo.col_fmt[i] == COL_NUMBER_DIS)
2762 snprintf(cp, column_len+1, "%*s", callback_args.col_widths[visible_col_count], cf->cinfo.columns[i].col_title);
2764 snprintf(cp
, column_len
+1, "%-*s", callback_args
.col_widths
[visible_col_count
], cf
->cinfo
.columns
[i
].col_title
);
2766 if (i
!= cf
->cinfo
.num_cols
- 1)
2769 visible_col_count
++;
2773 /* Now start out the main line buffer with the same length as the
2774 header line buffer. */
2775 callback_args
.line_buf_len
= callback_args
.header_line_buf_len
;
2776 callback_args
.line_buf
= (char *)g_malloc(callback_args
.line_buf_len
+ 1);
2777 } /* if (print_summary) */
2779 /* Create the protocol tree, and make it visible, if we're printing
2780 the dissection or the hex data.
2781 XXX - do we need it if we're just printing the hex data? */
2783 callback_args
.print_args
->print_dissections
!= print_dissections_none
||
2784 callback_args
.print_args
->print_hex
||
2785 have_custom_cols(&cf
->cinfo
) || have_field_extractors();
2786 epan_dissect_init(&callback_args
.edt
, cf
->epan
, proto_tree_needed
, proto_tree_needed
);
2788 /* Iterate through the list of packets, printing the packets we were
2790 ret
= process_specified_records(cf
, &print_args
->range
, "Printing",
2791 "selected packets", true, print_packet
,
2792 &callback_args
, show_progress_bar
);
2793 epan_dissect_cleanup(&callback_args
.edt
);
2794 g_free(callback_args
.header_line_buf
);
2795 g_free(callback_args
.line_buf
);
2796 g_free(callback_args
.col_widths
);
2797 g_free(callback_args
.visible_cols
);
2802 /* Completed successfully. */
2806 /* Well, the user decided to abort the printing.
2808 XXX - note that what got generated before they did that
2809 will get printed if we're piping to a print program; we'd
2810 have to write to a file and then hand that to the print
2811 program to make it actually not print anything. */
2815 /* Error while printing.
2817 XXX - note that what got generated before they did that
2818 will get printed if we're piping to a print program; we'd
2819 have to write to a file and then hand that to the print
2820 program to make it actually not print anything. */
2821 destroy_print_stream(print_args
->stream
);
2822 return CF_PRINT_WRITE_ERROR
;
2825 if (!print_finale(print_args
->stream
)) {
2826 destroy_print_stream(print_args
->stream
);
2827 return CF_PRINT_WRITE_ERROR
;
2830 if (!destroy_print_stream(print_args
->stream
))
2831 return CF_PRINT_WRITE_ERROR
;
2839 print_args_t
*print_args
;
2840 json_dumper jdumper
;
2841 } write_packet_callback_args_t
;
2844 write_pdml_packet(capture_file
*cf
, frame_data
*fdata
, wtap_rec
*rec
,
2845 Buffer
*buf
, void *argsp
)
2847 write_packet_callback_args_t
*args
= (write_packet_callback_args_t
*)argsp
;
2849 /* Create the protocol tree, but don't fill in the column information. */
2850 epan_dissect_run(&args
->edt
, cf
->cd_t
, rec
,
2851 frame_tvbuff_new_buffer(&cf
->provider
, fdata
, buf
),
2854 /* Write out the information in that tree. */
2855 write_pdml_proto_tree(NULL
, &args
->edt
, &cf
->cinfo
, args
->fh
, false);
2857 epan_dissect_reset(&args
->edt
);
2859 return !ferror(args
->fh
);
2863 cf_write_pdml_packets(capture_file
*cf
, print_args_t
*print_args
)
2865 write_packet_callback_args_t callback_args
;
2869 fh
= ws_fopen(print_args
->file
, "w");
2871 return CF_PRINT_OPEN_ERROR
; /* attempt to open destination failed */
2873 write_pdml_preamble(fh
, cf
->filename
);
2876 return CF_PRINT_WRITE_ERROR
;
2879 callback_args
.fh
= fh
;
2880 callback_args
.print_args
= print_args
;
2881 epan_dissect_init(&callback_args
.edt
, cf
->epan
, true, true);
2883 /* Iterate through the list of packets, printing the packets we were
2885 ret
= process_specified_records(cf
, &print_args
->range
, "Writing PDML",
2886 "selected packets", true,
2887 write_pdml_packet
, &callback_args
, true);
2889 epan_dissect_cleanup(&callback_args
.edt
);
2894 /* Completed successfully. */
2898 /* Well, the user decided to abort the printing. */
2902 /* Error while printing. */
2904 return CF_PRINT_WRITE_ERROR
;
2907 write_pdml_finale(fh
);
2910 return CF_PRINT_WRITE_ERROR
;
2913 /* XXX - check for an error */
2920 write_psml_packet(capture_file
*cf
, frame_data
*fdata
, wtap_rec
*rec
,
2921 Buffer
*buf
, void *argsp
)
2923 write_packet_callback_args_t
*args
= (write_packet_callback_args_t
*)argsp
;
2925 /* Fill in the column information */
2926 col_custom_prime_edt(&args
->edt
, &cf
->cinfo
);
2927 epan_dissect_run(&args
->edt
, cf
->cd_t
, rec
,
2928 frame_tvbuff_new_buffer(&cf
->provider
, fdata
, buf
),
2930 epan_dissect_fill_in_columns(&args
->edt
, false, true);
2932 /* Write out the column information. */
2933 write_psml_columns(&args
->edt
, args
->fh
, false);
2935 epan_dissect_reset(&args
->edt
);
2937 return !ferror(args
->fh
);
2941 cf_write_psml_packets(capture_file
*cf
, print_args_t
*print_args
)
2943 write_packet_callback_args_t callback_args
;
2947 bool proto_tree_needed
;
2949 fh
= ws_fopen(print_args
->file
, "w");
2951 return CF_PRINT_OPEN_ERROR
; /* attempt to open destination failed */
2953 write_psml_preamble(&cf
->cinfo
, fh
);
2956 return CF_PRINT_WRITE_ERROR
;
2959 callback_args
.fh
= fh
;
2960 callback_args
.print_args
= print_args
;
2962 /* Fill in the column information, only create the protocol tree
2963 if having custom columns or field extractors. */
2964 proto_tree_needed
= have_custom_cols(&cf
->cinfo
) || have_field_extractors();
2965 epan_dissect_init(&callback_args
.edt
, cf
->epan
, proto_tree_needed
, proto_tree_needed
);
2967 /* Iterate through the list of packets, printing the packets we were
2969 ret
= process_specified_records(cf
, &print_args
->range
, "Writing PSML",
2970 "selected packets", true,
2971 write_psml_packet
, &callback_args
, true);
2973 epan_dissect_cleanup(&callback_args
.edt
);
2978 /* Completed successfully. */
2982 /* Well, the user decided to abort the printing. */
2986 /* Error while printing. */
2988 return CF_PRINT_WRITE_ERROR
;
2991 write_psml_finale(fh
);
2994 return CF_PRINT_WRITE_ERROR
;
2997 /* XXX - check for an error */
3004 write_csv_packet(capture_file
*cf
, frame_data
*fdata
, wtap_rec
*rec
,
3005 Buffer
*buf
, void *argsp
)
3007 write_packet_callback_args_t
*args
= (write_packet_callback_args_t
*)argsp
;
3009 /* Fill in the column information */
3010 col_custom_prime_edt(&args
->edt
, &cf
->cinfo
);
3011 epan_dissect_run(&args
->edt
, cf
->cd_t
, rec
,
3012 frame_tvbuff_new_buffer(&cf
->provider
, fdata
, buf
),
3014 epan_dissect_fill_in_columns(&args
->edt
, false, true);
3016 /* Write out the column information. */
3017 write_csv_columns(&args
->edt
, args
->fh
);
3019 epan_dissect_reset(&args
->edt
);
3021 return !ferror(args
->fh
);
3025 cf_write_csv_packets(capture_file
*cf
, print_args_t
*print_args
)
3027 write_packet_callback_args_t callback_args
;
3028 bool proto_tree_needed
;
3032 fh
= ws_fopen(print_args
->file
, "w");
3034 return CF_PRINT_OPEN_ERROR
; /* attempt to open destination failed */
3036 write_csv_column_titles(&cf
->cinfo
, fh
);
3039 return CF_PRINT_WRITE_ERROR
;
3042 callback_args
.fh
= fh
;
3043 callback_args
.print_args
= print_args
;
3045 /* only create the protocol tree if having custom columns or field extractors. */
3046 proto_tree_needed
= have_custom_cols(&cf
->cinfo
) || have_field_extractors();
3047 epan_dissect_init(&callback_args
.edt
, cf
->epan
, proto_tree_needed
, proto_tree_needed
);
3049 /* Iterate through the list of packets, printing the packets we were
3051 ret
= process_specified_records(cf
, &print_args
->range
, "Writing CSV",
3052 "selected packets", true,
3053 write_csv_packet
, &callback_args
, true);
3055 epan_dissect_cleanup(&callback_args
.edt
);
3060 /* Completed successfully. */
3064 /* Well, the user decided to abort the printing. */
3068 /* Error while printing. */
3070 return CF_PRINT_WRITE_ERROR
;
3073 /* XXX - check for an error */
3080 carrays_write_packet(capture_file
*cf
, frame_data
*fdata
, wtap_rec
*rec
,
3081 Buffer
*buf
, void *argsp
)
3083 write_packet_callback_args_t
*args
= (write_packet_callback_args_t
*)argsp
;
3085 epan_dissect_run(&args
->edt
, cf
->cd_t
, rec
,
3086 frame_tvbuff_new_buffer(&cf
->provider
, fdata
, buf
),
3088 write_carrays_hex_data(fdata
->num
, args
->fh
, &args
->edt
);
3089 epan_dissect_reset(&args
->edt
);
3091 return !ferror(args
->fh
);
3095 cf_write_carrays_packets(capture_file
*cf
, print_args_t
*print_args
)
3097 write_packet_callback_args_t callback_args
;
3101 fh
= ws_fopen(print_args
->file
, "w");
3104 return CF_PRINT_OPEN_ERROR
; /* attempt to open destination failed */
3108 return CF_PRINT_WRITE_ERROR
;
3111 callback_args
.fh
= fh
;
3112 callback_args
.print_args
= print_args
;
3113 epan_dissect_init(&callback_args
.edt
, cf
->epan
, true, true);
3115 /* Iterate through the list of packets, printing the packets we were
3117 ret
= process_specified_records(cf
, &print_args
->range
,
3119 "selected packets", true,
3120 carrays_write_packet
, &callback_args
, true);
3122 epan_dissect_cleanup(&callback_args
.edt
);
3126 /* Completed successfully. */
3129 /* Well, the user decided to abort the printing. */
3132 /* Error while printing. */
3134 return CF_PRINT_WRITE_ERROR
;
3142 write_json_packet(capture_file
*cf
, frame_data
*fdata
, wtap_rec
*rec
,
3143 Buffer
*buf
, void *argsp
)
3145 write_packet_callback_args_t
*args
= (write_packet_callback_args_t
*)argsp
;
3147 /* Create the protocol tree, but don't fill in the column information. */
3148 epan_dissect_run(&args
->edt
, cf
->cd_t
, rec
,
3149 frame_tvbuff_new_buffer(&cf
->provider
, fdata
, buf
),
3152 /* Write out the information in that tree. */
3153 write_json_proto_tree(NULL
, args
->print_args
->print_dissections
,
3154 args
->print_args
->print_hex
,
3155 &args
->edt
, &cf
->cinfo
, proto_node_group_children_by_unique
,
3158 epan_dissect_reset(&args
->edt
);
3160 return !ferror(args
->fh
);
3164 cf_write_json_packets(capture_file
*cf
, print_args_t
*print_args
)
3166 write_packet_callback_args_t callback_args
;
3170 fh
= ws_fopen(print_args
->file
, "w");
3172 return CF_PRINT_OPEN_ERROR
; /* attempt to open destination failed */
3174 callback_args
.jdumper
= write_json_preamble(fh
);
3177 return CF_PRINT_WRITE_ERROR
;
3180 callback_args
.fh
= fh
;
3181 callback_args
.print_args
= print_args
;
3182 epan_dissect_init(&callback_args
.edt
, cf
->epan
, true, true);
3184 /* Iterate through the list of packets, printing the packets we were
3186 ret
= process_specified_records(cf
, &print_args
->range
, "Writing JSON",
3187 "selected packets", true,
3188 write_json_packet
, &callback_args
, true);
3190 epan_dissect_cleanup(&callback_args
.edt
);
3195 /* Completed successfully. */
3199 /* Well, the user decided to abort the printing. */
3203 /* Error while printing. */
3205 return CF_PRINT_WRITE_ERROR
;
3208 write_json_finale(&callback_args
.jdumper
);
3211 return CF_PRINT_WRITE_ERROR
;
3214 /* XXX - check for an error */
3221 cf_find_packet_protocol_tree(capture_file
*cf
, const char *string
,
3222 search_direction dir
, bool multiple
)
3226 mdata
.frame_matched
= false;
3228 mdata
.string
= string
;
3229 mdata
.string_len
= strlen(string
);
3231 mdata
.prev_finfo
= cf
->finfo_selected
;
3232 if (multiple
&& cf
->finfo_selected
&& cf
->edt
) {
3233 if (dir
== SD_FORWARD
) {
3234 proto_tree_children_foreach(cf
->edt
->tree
, match_subtree_text
, &mdata
);
3236 proto_tree_children_foreach(cf
->edt
->tree
, match_subtree_text_reverse
, &mdata
);
3238 if (mdata
.frame_matched
) {
3239 packet_list_select_finfo(mdata
.finfo
);
3243 return find_packet(cf
, match_protocol_tree
, &mdata
, dir
);
3247 cf_find_string_protocol_tree(capture_file
*cf
, proto_tree
*tree
)
3250 mdata
.frame_matched
= false;
3252 mdata
.string
= convert_string_case(cf
->sfilter
, cf
->case_type
);
3253 mdata
.string_len
= strlen(mdata
.string
);
3255 mdata
.prev_finfo
= NULL
;
3256 /* Iterate through all the nodes looking for matching text */
3257 if (cf
->dir
== SD_FORWARD
) {
3258 proto_tree_children_foreach(tree
, match_subtree_text
, &mdata
);
3260 proto_tree_children_foreach(tree
, match_subtree_text_reverse
, &mdata
);
3262 g_free((char *)mdata
.string
);
3263 return mdata
.frame_matched
? mdata
.finfo
: NULL
;
3267 match_protocol_tree(capture_file
*cf
, frame_data
*fdata
,
3268 wtap_rec
*rec
, Buffer
*buf
, void *criterion
)
3270 match_data
*mdata
= (match_data
*)criterion
;
3273 /* Load the frame's data. */
3274 if (!cf_read_record(cf
, fdata
, rec
, buf
)) {
3275 /* Attempt to get the packet failed. */
3279 /* Construct the protocol tree, including the displayed text */
3280 epan_dissect_init(&edt
, cf
->epan
, true, true);
3281 /* We don't need the column information */
3282 epan_dissect_run(&edt
, cf
->cd_t
, rec
,
3283 frame_tvbuff_new_buffer(&cf
->provider
, fdata
, buf
),
3286 /* Iterate through all the nodes, seeing if they have text that matches. */
3288 mdata
->frame_matched
= false;
3289 mdata
->halt
= false;
3290 mdata
->prev_finfo
= NULL
;
3291 /* We don't care about the direction here, because we're just looking
3292 * for one match and we'll destroy this tree anyway. (We find the actual
3293 * field later in PacketList::selectionChanged().) Forwards is faster.
3295 proto_tree_children_foreach(edt
.tree
, match_subtree_text
, mdata
);
3296 epan_dissect_cleanup(&edt
);
3297 return mdata
->frame_matched
? MR_MATCHED
: MR_NOTMATCHED
;
3301 match_subtree_text(proto_node
*node
, void *data
)
3303 match_data
*mdata
= (match_data
*) data
;
3304 const char *string
= mdata
->string
;
3305 size_t string_len
= mdata
->string_len
;
3306 capture_file
*cf
= mdata
->cf
;
3307 field_info
*fi
= PNODE_FINFO(node
);
3308 char label_str
[ITEM_LABEL_LENGTH
];
3311 uint32_t i
, i_restart
;
3315 /* dissection with an invisible proto tree? */
3318 if (mdata
->frame_matched
) {
3319 /* We already had a match; don't bother doing any more work. */
3323 /* Don't match invisible entries. */
3324 if (proto_item_is_hidden(node
))
3327 if (mdata
->prev_finfo
) {
3328 /* Haven't found the old match, so don't match this node. */
3329 if (fi
== mdata
->prev_finfo
) {
3330 /* Found the old match, look for the next one after this. */
3331 mdata
->prev_finfo
= NULL
;
3334 /* was a free format label produced? */
3336 label_ptr
= fi
->rep
->representation
;
3338 /* no, make a generic label */
3339 label_ptr
= label_str
;
3340 proto_item_fill_label(fi
, label_str
, NULL
);
3344 if (ws_regex_matches(cf
->regex
, label_ptr
)) {
3345 mdata
->frame_matched
= true;
3349 } else if (cf
->case_type
) {
3350 /* Case insensitive match */
3351 label_len
= strlen(label_ptr
);
3353 for (i
= 0; i
< label_len
; i
++) {
3354 if (i_restart
== 0 && c_match
== 0 && (label_len
- i
< string_len
))
3356 c_char
= label_ptr
[i
];
3357 c_char
= g_ascii_toupper(c_char
);
3358 /* If c_match is non-zero, save candidate for retrying full match. */
3359 if (c_match
> 0 && i_restart
== 0 && c_char
== string
[0])
3361 if (c_char
== string
[c_match
]) {
3363 if (c_match
== string_len
) {
3364 mdata
->frame_matched
= true;
3366 /* No need to look further; we have a match */
3369 } else if (i_restart
) {
3376 } else if (strstr(label_ptr
, string
) != NULL
) {
3377 /* Case sensitive match */
3378 mdata
->frame_matched
= true;
3384 /* Recurse into the subtree, if it exists */
3385 if (node
->first_child
!= NULL
)
3386 proto_tree_children_foreach(node
, match_subtree_text
, mdata
);
3390 match_subtree_text_reverse(proto_node
*node
, void *data
)
3392 match_data
*mdata
= (match_data
*) data
;
3393 const char *string
= mdata
->string
;
3394 size_t string_len
= mdata
->string_len
;
3395 capture_file
*cf
= mdata
->cf
;
3396 field_info
*fi
= PNODE_FINFO(node
);
3397 char label_str
[ITEM_LABEL_LENGTH
];
3400 uint32_t i
, i_restart
;
3404 /* dissection with an invisible proto tree? */
3407 /* We don't have an easy way to search backwards in the tree
3408 * (see also, proto_find_field_from_offset()) because we don't
3409 * have a previous node pointer, so we search backwards by
3410 * searching forwards, only stopping if we see the old match
3418 /* Don't match invisible entries. */
3419 if (proto_item_is_hidden(node
))
3422 if (mdata
->prev_finfo
&& fi
== mdata
->prev_finfo
) {
3423 /* Found the old match, use the previous match. */
3428 /* was a free format label produced? */
3430 label_ptr
= fi
->rep
->representation
;
3432 /* no, make a generic label */
3433 label_ptr
= label_str
;
3434 proto_item_fill_label(fi
, label_str
, NULL
);
3438 if (ws_regex_matches(cf
->regex
, label_ptr
)) {
3439 mdata
->frame_matched
= true;
3442 } else if (cf
->case_type
) {
3443 /* Case insensitive match */
3444 label_len
= strlen(label_ptr
);
3446 for (i
= 0; i
< label_len
; i
++) {
3447 if (i_restart
== 0 && c_match
== 0 && (label_len
- i
< string_len
))
3449 c_char
= label_ptr
[i
];
3450 c_char
= g_ascii_toupper(c_char
);
3451 /* If c_match is non-zero, save candidate for retrying full match. */
3452 if (c_match
> 0 && i_restart
== 0 && c_char
== string
[0])
3454 if (c_char
== string
[c_match
]) {
3456 if (c_match
== string_len
) {
3457 mdata
->frame_matched
= true;
3461 } else if (i_restart
) {
3468 } else if (strstr(label_ptr
, string
) != NULL
) {
3469 /* Case sensitive match */
3470 mdata
->frame_matched
= true;
3474 /* Recurse into the subtree, if it exists */
3475 if (node
->first_child
!= NULL
)
3476 proto_tree_children_foreach(node
, match_subtree_text_reverse
, mdata
);
3480 cf_find_packet_summary_line(capture_file
*cf
, const char *string
,
3481 search_direction dir
)
3485 mdata
.string
= string
;
3486 mdata
.string_len
= strlen(string
);
3487 return find_packet(cf
, match_summary_line
, &mdata
, dir
);
3491 match_summary_line(capture_file
*cf
, frame_data
*fdata
,
3492 wtap_rec
*rec
, Buffer
*buf
, void *criterion
)
3494 match_data
*mdata
= (match_data
*)criterion
;
3495 const char *string
= mdata
->string
;
3496 size_t string_len
= mdata
->string_len
;
3498 const char *info_column
;
3499 size_t info_column_len
;
3500 match_result result
= MR_NOTMATCHED
;
3502 uint32_t i
, i_restart
;
3506 /* Load the frame's data. */
3507 if (!cf_read_record(cf
, fdata
, rec
, buf
)) {
3508 /* Attempt to get the packet failed. */
3512 /* Don't bother constructing the protocol tree */
3513 epan_dissect_init(&edt
, cf
->epan
, false, false);
3514 /* Get the column information */
3515 epan_dissect_run(&edt
, cf
->cd_t
, rec
,
3516 frame_tvbuff_new_buffer(&cf
->provider
, fdata
, buf
),
3519 /* Find the Info column */
3520 for (colx
= 0; colx
< cf
->cinfo
.num_cols
; colx
++) {
3521 if (cf
->cinfo
.columns
[colx
].fmt_matx
[COL_INFO
]) {
3522 /* Found it. See if we match. */
3523 info_column
= get_column_text(edt
.pi
.cinfo
, colx
);
3524 info_column_len
= strlen(info_column
);
3526 if (ws_regex_matches(cf
->regex
, info_column
)) {
3527 result
= MR_MATCHED
;
3530 } else if (cf
->case_type
) {
3531 /* Case insensitive match */
3533 for (i
= 0; i
< info_column_len
; i
++) {
3534 if (i_restart
== 0 && c_match
== 0 && (info_column_len
- i
< string_len
))
3536 c_char
= info_column
[i
];
3537 c_char
= g_ascii_toupper(c_char
);
3538 /* If c_match is non-zero, save candidate for retrying full match. */
3539 if (c_match
> 0 && i_restart
== 0 && c_char
== string
[0])
3541 if (c_char
== string
[c_match
]) {
3543 if (c_match
== string_len
) {
3544 result
= MR_MATCHED
;
3547 } else if (i_restart
) {
3554 } else if (strstr(info_column
, string
) != NULL
) {
3555 /* Case sensitive match */
3556 result
= MR_MATCHED
;
3561 epan_dissect_cleanup(&edt
);
3566 const uint8_t *data
;
3568 ws_mempbrk_pattern
*pattern
;
3569 } cbs_t
; /* "Counted byte string" */
3573 * The current match_* routines only support ASCII case insensitivity and don't
3574 * convert UTF-8 inputs to UTF-16 for matching. The UTF-16 support just
3575 * interleaves with \0 bytes, which works for 7 bit ASCII.
3577 * We could modify them to use the GLib Unicode routines or the International
3578 * Components for Unicode library but it's not apparent that we could do so
3579 * without consuming a lot more CPU and memory or that searching would be
3580 * significantly better.
3582 * XXX: We could test the search string to see if it's all ASCII, and if not
3583 * use Unicode aware routines for case insensitive searches or any UTF-16
3588 cf_find_packet_data(capture_file
*cf
, const uint8_t *string
, size_t string_size
,
3589 search_direction dir
, bool multiple
)
3593 ws_mempbrk_pattern pattern
= {0};
3594 ws_match_function match_function
;
3597 info
.data_len
= string_size
;
3599 /* Regex, String or hex search? */
3601 /* Regular Expression search */
3602 match_function
= (cf
->dir
== SD_FORWARD
) ? match_regex
: match_regex_reverse
;
3603 } else if (cf
->string
) {
3604 /* String search - what type of string? */
3605 if (cf
->case_type
) {
3606 needles
[0] = string
[0];
3607 needles
[1] = g_ascii_tolower(needles
[0]);
3609 ws_mempbrk_compile(&pattern
, needles
);
3610 info
.pattern
= &pattern
;
3611 switch (cf
->scs_type
) {
3613 case SCS_NARROW_AND_WIDE
:
3614 match_function
= (cf
->dir
== SD_FORWARD
) ? match_narrow_and_wide_case
: match_narrow_and_wide_case_reverse
;
3618 match_function
= (cf
->dir
== SD_FORWARD
) ? match_narrow_case
: match_narrow_case_reverse
;
3622 match_function
= (cf
->dir
== SD_FORWARD
) ? match_wide_case
: match_wide_case_reverse
;
3626 ws_assert_not_reached();
3631 switch (cf
->scs_type
) {
3633 case SCS_NARROW_AND_WIDE
:
3634 match_function
= (cf
->dir
== SD_FORWARD
) ? match_narrow_and_wide
: match_narrow_and_wide_reverse
;
3638 /* Narrow, case-sensitive match is the same as looking
3639 * for a converted hexstring. */
3640 match_function
= (cf
->dir
== SD_FORWARD
) ? match_binary
: match_binary_reverse
;
3644 match_function
= (cf
->dir
== SD_FORWARD
) ? match_wide
: match_wide_reverse
;
3648 ws_assert_not_reached();
3653 match_function
= (cf
->dir
== SD_FORWARD
) ? match_binary
: match_binary_reverse
;
3656 if (multiple
&& cf
->current_frame
&& (cf
->search_pos
|| cf
->search_len
)) {
3657 /* Use the current frame (this will perform the equivalent of
3658 * cf_read_current_record() in match_function).
3660 if (match_function(cf
, cf
->current_frame
, &cf
->rec
, &cf
->buf
, &info
)) {
3661 cf
->search_in_progress
= true;
3663 field_info
*fi
= NULL
;
3664 /* The regex match can match an empty string. */
3665 if (cf
->search_len
) {
3666 fi
= proto_find_field_from_offset(cf
->edt
->tree
, cf
->search_pos
+ cf
->search_len
- 1, cf
->edt
->tvb
);
3668 packet_list_select_finfo(fi
);
3670 packet_list_select_row_from_data(cf
->current_frame
);
3672 cf
->search_in_progress
= false;
3676 cf
->search_pos
= 0; /* Reset the position */
3677 cf
->search_len
= 0; /* Reset length */
3678 return find_packet(cf
, match_function
, &info
, dir
);
3682 match_narrow_and_wide(capture_file
*cf
, frame_data
*fdata
,
3683 wtap_rec
*rec
, Buffer
*buf
, void *criterion
)
3685 cbs_t
*info
= (cbs_t
*)criterion
;
3686 const uint8_t *ascii_text
= info
->data
;
3687 size_t textlen
= info
->data_len
;
3688 match_result result
;
3690 uint8_t *pd
, *buf_start
, *buf_end
;
3695 /* Load the frame's data. */
3696 if (!cf_read_record(cf
, fdata
, rec
, buf
)) {
3697 /* Attempt to get the packet failed. */
3701 result
= MR_NOTMATCHED
;
3702 buf_len
= fdata
->cap_len
;
3703 buf_start
= ws_buffer_start_ptr(buf
);
3704 buf_end
= buf_start
+ buf_len
;
3706 if (cf
->search_len
|| cf
->search_pos
) {
3707 /* we want to start searching one byte past the previous match start */
3708 pd
+= cf
->search_pos
+ 1;
3710 for (; pd
< buf_end
; pd
++) {
3711 pd
= (uint8_t *)memchr(pd
, ascii_text
[0], buf_end
- pd
);
3712 if (pd
== NULL
) break;
3713 /* Try narrow match at this start location */
3715 for (i
= 0; pd
+ i
< buf_end
; i
++) {
3717 if (c_char
== ascii_text
[c_match
]) {
3719 if (c_match
== textlen
) {
3720 result
= MR_MATCHED
;
3721 /* Save position and length for highlighting the field. */
3722 cf
->search_pos
= (uint32_t)(pd
- buf_start
);
3723 cf
->search_len
= (uint32_t)(i
+ 1);
3731 /* Now try wide match at the same start location. */
3733 for (i
= 0; pd
+ i
< buf_end
; i
++) {
3735 if (c_char
== ascii_text
[c_match
]) {
3737 if (c_match
== textlen
) {
3738 result
= MR_MATCHED
;
3739 /* Save position and length for highlighting the field. */
3740 cf
->search_pos
= (uint32_t)(pd
- buf_start
);
3741 cf
->search_len
= (uint32_t)(i
+ 1);
3745 if (pd
+ i
>= buf_end
|| pd
[i
] != '\0') break;
3757 match_narrow_and_wide_reverse(capture_file
*cf
, frame_data
*fdata
,
3758 wtap_rec
*rec
, Buffer
*buf
, void *criterion
)
3760 cbs_t
*info
= (cbs_t
*)criterion
;
3761 const uint8_t *ascii_text
= info
->data
;
3762 size_t textlen
= info
->data_len
;
3763 match_result result
;
3765 uint8_t *pd
, *buf_start
, *buf_end
;
3770 /* Load the frame's data. */
3771 if (!cf_read_record(cf
, fdata
, rec
, buf
)) {
3772 /* Attempt to get the packet failed. */
3776 result
= MR_NOTMATCHED
;
3777 /* Has to be room to hold the sought data. */
3778 if (textlen
> fdata
->cap_len
) {
3781 buf_len
= fdata
->cap_len
;
3782 buf_start
= ws_buffer_start_ptr(buf
);
3783 buf_end
= buf_start
+ buf_len
;
3784 pd
= buf_end
- textlen
;
3785 if (cf
->search_len
|| cf
->search_pos
) {
3786 /* we want to start searching one byte before the previous match start */
3787 pd
= buf_start
+ cf
->search_pos
- 1;
3789 for (; pd
< buf_end
; pd
++) {
3790 pd
= (uint8_t *)ws_memrchr(buf_start
, ascii_text
[0], pd
- buf_start
+ 1);
3791 if (pd
== NULL
) break;
3792 /* Try narrow match at this start location */
3794 for (i
= 0; pd
+ i
< buf_end
; i
++) {
3796 if (c_char
== ascii_text
[c_match
]) {
3798 if (c_match
== textlen
) {
3799 result
= MR_MATCHED
;
3800 /* Save position and length for highlighting the field. */
3801 cf
->search_pos
= (uint32_t)(pd
- buf_start
);
3802 cf
->search_len
= (uint32_t)(i
+ 1);
3810 /* Now try wide match at the same start location. */
3812 for (i
= 0; pd
+ i
< buf_end
; i
++) {
3814 if (c_char
== ascii_text
[c_match
]) {
3816 if (c_match
== textlen
) {
3817 result
= MR_MATCHED
;
3818 /* Save position and length for highlighting the field. */
3819 cf
->search_pos
= (uint32_t)(pd
- buf_start
);
3820 cf
->search_len
= (uint32_t)(i
+ 1);
3824 if (pd
+ i
>= buf_end
|| pd
[i
] != '\0') break;
3835 /* Case insensitive match */
3837 match_narrow_and_wide_case(capture_file
*cf
, frame_data
*fdata
,
3838 wtap_rec
*rec
, Buffer
*buf
, void *criterion
)
3840 cbs_t
*info
= (cbs_t
*)criterion
;
3841 const uint8_t *ascii_text
= info
->data
;
3842 size_t textlen
= info
->data_len
;
3843 ws_mempbrk_pattern
*pattern
= info
->pattern
;
3844 match_result result
;
3846 uint8_t *pd
, *buf_start
, *buf_end
;
3851 /* Load the frame's data. */
3852 if (!cf_read_record(cf
, fdata
, rec
, buf
)) {
3853 /* Attempt to get the packet failed. */
3857 ws_assert(pattern
!= NULL
);
3859 result
= MR_NOTMATCHED
;
3860 buf_len
= fdata
->cap_len
;
3861 buf_start
= ws_buffer_start_ptr(buf
);
3862 buf_end
= buf_start
+ buf_len
;
3864 if (cf
->search_len
|| cf
->search_pos
) {
3865 /* we want to start searching one byte past the previous match start */
3866 pd
+= cf
->search_pos
+ 1;
3868 for (; pd
< buf_end
; pd
++) {
3869 pd
= (uint8_t *)ws_mempbrk_exec(pd
, buf_end
- pd
, pattern
, &c_char
);
3870 if (pd
== NULL
) break;
3871 /* Try narrow match at this start location */
3873 for (i
= 0; pd
+ i
< buf_end
; i
++) {
3874 c_char
= g_ascii_toupper(pd
[i
]);
3875 if (c_char
== ascii_text
[c_match
]) {
3877 if (c_match
== textlen
) {
3878 result
= MR_MATCHED
;
3879 /* Save position and length for highlighting the field. */
3880 cf
->search_pos
= (uint32_t)(pd
- buf_start
);
3881 cf
->search_len
= (uint32_t)(i
+ 1);
3889 /* Now try wide match at the same start location. */
3891 for (i
= 0; pd
+ i
< buf_end
; i
++) {
3892 c_char
= g_ascii_toupper(pd
[i
]);
3893 if (c_char
== ascii_text
[c_match
]) {
3895 if (c_match
== textlen
) {
3896 result
= MR_MATCHED
;
3897 /* Save position and length for highlighting the field. */
3898 cf
->search_pos
= (uint32_t)(pd
- buf_start
);
3899 cf
->search_len
= (uint32_t)(i
+ 1);
3903 if (pd
+ i
>= buf_end
|| pd
[i
] != '\0') break;
3915 match_narrow_and_wide_case_reverse(capture_file
*cf
, frame_data
*fdata
,
3916 wtap_rec
*rec
, Buffer
*buf
, void *criterion
)
3918 cbs_t
*info
= (cbs_t
*)criterion
;
3919 const uint8_t *ascii_text
= info
->data
;
3920 size_t textlen
= info
->data_len
;
3921 ws_mempbrk_pattern
*pattern
= info
->pattern
;
3922 match_result result
;
3924 uint8_t *pd
, *buf_start
, *buf_end
;
3929 /* Load the frame's data. */
3930 if (!cf_read_record(cf
, fdata
, rec
, buf
)) {
3931 /* Attempt to get the packet failed. */
3935 ws_assert(pattern
!= NULL
);
3937 result
= MR_NOTMATCHED
;
3938 /* Has to be room to hold the sought data. */
3939 if (textlen
> fdata
->cap_len
) {
3942 buf_len
= fdata
->cap_len
;
3943 buf_start
= ws_buffer_start_ptr(buf
);
3944 buf_end
= buf_start
+ buf_len
;
3945 pd
= buf_end
- textlen
;
3946 if (cf
->search_len
|| cf
->search_pos
) {
3947 /* we want to start searching one byte before the previous match start */
3948 pd
= buf_start
+ cf
->search_pos
- 1;
3950 for (; pd
>= buf_start
; pd
--) {
3951 pd
= (uint8_t *)ws_memrpbrk_exec(buf_start
, pd
- buf_start
+ 1, pattern
, &c_char
);
3952 if (pd
== NULL
) break;
3953 /* Try narrow match at this start location */
3955 for (i
= 0; pd
+ i
< buf_end
; i
++) {
3956 c_char
= g_ascii_toupper(pd
[i
]);
3957 if (c_char
== ascii_text
[c_match
]) {
3959 if (c_match
== textlen
) {
3960 result
= MR_MATCHED
;
3961 /* Save position and length for highlighting the field. */
3962 cf
->search_pos
= (uint32_t)(pd
- buf_start
);
3963 cf
->search_len
= (uint32_t)(i
+ 1);
3971 /* Now try wide match at the same start location. */
3973 for (i
= 0; pd
+ i
< buf_end
; i
++) {
3974 c_char
= g_ascii_toupper(pd
[i
]);
3975 if (c_char
== ascii_text
[c_match
]) {
3977 if (c_match
== textlen
) {
3978 result
= MR_MATCHED
;
3979 /* Save position and length for highlighting the field. */
3980 cf
->search_pos
= (uint32_t)(pd
- buf_start
);
3981 cf
->search_len
= (uint32_t)(i
+ 1);
3985 if (pd
+ i
>= buf_end
|| pd
[i
] != '\0') break;
3996 /* Case insensitive match */
3998 match_narrow_case(capture_file
*cf
, frame_data
*fdata
,
3999 wtap_rec
*rec
, Buffer
*buf
, void *criterion
)
4001 cbs_t
*info
= (cbs_t
*)criterion
;
4002 const uint8_t *ascii_text
= info
->data
;
4003 size_t textlen
= info
->data_len
;
4004 ws_mempbrk_pattern
*pattern
= info
->pattern
;
4005 match_result result
;
4007 uint8_t *pd
, *buf_start
, *buf_end
;
4012 /* Load the frame's data. */
4013 if (!cf_read_record(cf
, fdata
, rec
, buf
)) {
4014 /* Attempt to get the packet failed. */
4018 ws_assert(pattern
!= NULL
);
4020 result
= MR_NOTMATCHED
;
4021 buf_len
= fdata
->cap_len
;
4022 buf_start
= ws_buffer_start_ptr(buf
);
4023 buf_end
= buf_start
+ buf_len
;
4025 if (cf
->search_len
|| cf
->search_pos
) {
4026 /* we want to start searching one byte past the previous match start */
4027 pd
+= cf
->search_pos
+ 1;
4029 for (; pd
< buf_end
; pd
++) {
4030 pd
= (uint8_t *)ws_mempbrk_exec(pd
, buf_end
- pd
, pattern
, &c_char
);
4031 if (pd
== NULL
) break;
4033 for (i
= 0; pd
+ i
< buf_end
; i
++) {
4034 c_char
= g_ascii_toupper(pd
[i
]);
4035 if (c_char
== ascii_text
[c_match
]) {
4037 if (c_match
== textlen
) {
4038 /* Save position and length for highlighting the field. */
4039 result
= MR_MATCHED
;
4040 cf
->search_pos
= (uint32_t)(pd
- buf_start
);
4041 cf
->search_len
= (uint32_t)(i
+ 1);
4055 match_narrow_case_reverse(capture_file
*cf
, frame_data
*fdata
,
4056 wtap_rec
*rec
, Buffer
*buf
, void *criterion
)
4058 cbs_t
*info
= (cbs_t
*)criterion
;
4059 const uint8_t *ascii_text
= info
->data
;
4060 size_t textlen
= info
->data_len
;
4061 ws_mempbrk_pattern
*pattern
= info
->pattern
;
4062 match_result result
;
4064 uint8_t *pd
, *buf_start
, *buf_end
;
4069 /* Load the frame's data. */
4070 if (!cf_read_record(cf
, fdata
, rec
, buf
)) {
4071 /* Attempt to get the packet failed. */
4075 ws_assert(pattern
!= NULL
);
4077 result
= MR_NOTMATCHED
;
4078 /* Has to be room to hold the sought data. */
4079 if (textlen
> fdata
->cap_len
) {
4082 buf_len
= fdata
->cap_len
;
4083 buf_start
= ws_buffer_start_ptr(buf
);
4084 buf_end
= buf_start
+ buf_len
;
4085 pd
= buf_end
- textlen
;
4086 if (cf
->search_len
|| cf
->search_pos
) {
4087 /* we want to start searching one byte before the previous match start */
4088 pd
= buf_start
+ cf
->search_pos
- 1;
4090 for (; pd
>= buf_start
; pd
--) {
4091 pd
= (uint8_t *)ws_memrpbrk_exec(buf_start
, pd
- buf_start
+ 1, pattern
, &c_char
);
4092 if (pd
== NULL
) break;
4094 for (i
= 0; pd
+ i
< buf_end
; i
++) {
4095 c_char
= g_ascii_toupper(pd
[i
]);
4096 if (c_char
== ascii_text
[c_match
]) {
4098 if (c_match
== textlen
) {
4099 /* Save position and length for highlighting the field. */
4100 result
= MR_MATCHED
;
4101 cf
->search_pos
= (uint32_t)(pd
- buf_start
);
4102 cf
->search_len
= (uint32_t)(i
+ 1);
4116 match_wide(capture_file
*cf
, frame_data
*fdata
,
4117 wtap_rec
*rec
, Buffer
*buf
, void *criterion
)
4119 cbs_t
*info
= (cbs_t
*)criterion
;
4120 const uint8_t *ascii_text
= info
->data
;
4121 size_t textlen
= info
->data_len
;
4122 match_result result
;
4124 uint8_t *pd
, *buf_start
, *buf_end
;
4129 /* Load the frame's data. */
4130 if (!cf_read_record(cf
, fdata
, rec
, buf
)) {
4131 /* Attempt to get the packet failed. */
4135 result
= MR_NOTMATCHED
;
4136 buf_len
= fdata
->cap_len
;
4137 buf_start
= ws_buffer_start_ptr(buf
);
4138 buf_end
= buf_start
+ buf_len
;
4140 if (cf
->search_len
|| cf
->search_pos
) {
4141 /* we want to start searching one byte past the previous match start */
4142 pd
+= cf
->search_pos
+ 1;
4144 for (; pd
< buf_end
; pd
++) {
4145 pd
= (uint8_t *)memchr(pd
, ascii_text
[0], buf_end
- pd
);
4146 if (pd
== NULL
) break;
4148 for (i
= 0; pd
+ i
< buf_end
; i
++) {
4150 if (c_char
== ascii_text
[c_match
]) {
4152 if (c_match
== textlen
) {
4153 result
= MR_MATCHED
;
4154 /* Save position and length for highlighting the field. */
4155 cf
->search_pos
= (uint32_t)(pd
- buf_start
);
4156 cf
->search_len
= (uint32_t)(i
+ 1);
4160 if (pd
+ i
>= buf_end
|| pd
[i
] != '\0') break;
4172 match_wide_reverse(capture_file
*cf
, frame_data
*fdata
,
4173 wtap_rec
*rec
, Buffer
*buf
, void *criterion
)
4175 cbs_t
*info
= (cbs_t
*)criterion
;
4176 const uint8_t *ascii_text
= info
->data
;
4177 size_t textlen
= info
->data_len
;
4178 match_result result
;
4180 uint8_t *pd
, *buf_start
, *buf_end
;
4185 /* Load the frame's data. */
4186 if (!cf_read_record(cf
, fdata
, rec
, buf
)) {
4187 /* Attempt to get the packet failed. */
4191 result
= MR_NOTMATCHED
;
4192 /* Has to be room to hold the sought data. */
4193 if (textlen
> fdata
->cap_len
) {
4196 buf_len
= fdata
->cap_len
;
4197 buf_start
= ws_buffer_start_ptr(buf
);
4198 buf_end
= buf_start
+ buf_len
;
4199 pd
= buf_end
- textlen
;
4200 if (cf
->search_len
|| cf
->search_pos
) {
4201 /* we want to start searching one byte before the previous match start */
4202 pd
= buf_start
+ cf
->search_pos
- 1;
4204 for (; pd
< buf_end
; pd
++) {
4205 pd
= (uint8_t *)ws_memrchr(buf_start
, ascii_text
[0], pd
- buf_start
+ 1);
4206 if (pd
== NULL
) break;
4208 for (i
= 0; pd
+ i
< buf_end
; i
++) {
4210 if (c_char
== ascii_text
[c_match
]) {
4212 if (c_match
== textlen
) {
4213 result
= MR_MATCHED
;
4214 /* Save position and length for highlighting the field. */
4215 cf
->search_pos
= (uint32_t)(pd
- buf_start
);
4216 cf
->search_len
= (uint32_t)(i
+ 1);
4220 if (pd
+ i
>= buf_end
|| pd
[i
] != '\0') break;
4231 /* Case insensitive match */
4233 match_wide_case(capture_file
*cf
, frame_data
*fdata
,
4234 wtap_rec
*rec
, Buffer
*buf
, void *criterion
)
4236 cbs_t
*info
= (cbs_t
*)criterion
;
4237 const uint8_t *ascii_text
= info
->data
;
4238 size_t textlen
= info
->data_len
;
4239 ws_mempbrk_pattern
*pattern
= info
->pattern
;
4240 match_result result
;
4242 uint8_t *pd
, *buf_start
, *buf_end
;
4247 /* Load the frame's data. */
4248 if (!cf_read_record(cf
, fdata
, rec
, buf
)) {
4249 /* Attempt to get the packet failed. */
4253 ws_assert(pattern
!= NULL
);
4255 result
= MR_NOTMATCHED
;
4256 buf_len
= fdata
->cap_len
;
4257 buf_start
= ws_buffer_start_ptr(buf
);
4258 buf_end
= buf_start
+ buf_len
;
4260 if (cf
->search_len
|| cf
->search_pos
) {
4261 /* we want to start searching one byte past the previous match start */
4262 pd
+= cf
->search_pos
+ 1;
4264 for (; pd
< buf_end
; pd
++) {
4265 pd
= (uint8_t *)ws_mempbrk_exec(pd
, buf_end
- pd
, pattern
, &c_char
);
4266 if (pd
== NULL
) break;
4268 for (i
= 0; pd
+ i
< buf_end
; i
++) {
4269 c_char
= g_ascii_toupper(pd
[i
]);
4270 if (c_char
== ascii_text
[c_match
]) {
4272 if (c_match
== textlen
) {
4273 result
= MR_MATCHED
;
4274 /* Save position and length for highlighting the field. */
4275 cf
->search_pos
= (uint32_t)(pd
- buf_start
);
4276 cf
->search_len
= (uint32_t)(i
+ 1);
4280 if (pd
+ i
>= buf_end
|| pd
[i
] != '\0') break;
4291 /* Case insensitive match */
4293 match_wide_case_reverse(capture_file
*cf
, frame_data
*fdata
,
4294 wtap_rec
*rec
, Buffer
*buf
, void *criterion
)
4296 cbs_t
*info
= (cbs_t
*)criterion
;
4297 const uint8_t *ascii_text
= info
->data
;
4298 size_t textlen
= info
->data_len
;
4299 ws_mempbrk_pattern
*pattern
= info
->pattern
;
4300 match_result result
;
4302 uint8_t *pd
, *buf_start
, *buf_end
;
4307 /* Load the frame's data. */
4308 if (!cf_read_record(cf
, fdata
, rec
, buf
)) {
4309 /* Attempt to get the packet failed. */
4313 ws_assert(pattern
!= NULL
);
4315 result
= MR_NOTMATCHED
;
4316 /* Has to be room to hold the sought data. */
4317 if (textlen
> fdata
->cap_len
) {
4320 buf_len
= fdata
->cap_len
;
4321 buf_start
= ws_buffer_start_ptr(buf
);
4322 buf_end
= buf_start
+ buf_len
;
4323 pd
= buf_end
- textlen
;
4324 if (cf
->search_len
|| cf
->search_pos
) {
4325 /* we want to start searching one byte before the previous match start */
4326 pd
= buf_start
+ cf
->search_pos
- 1;
4328 for (; pd
>= buf_start
; pd
--) {
4329 pd
= (uint8_t *)ws_memrpbrk_exec(buf_start
, pd
- buf_start
+ 1, pattern
, &c_char
);
4330 if (pd
== NULL
) break;
4332 for (i
= 0; pd
+ i
< buf_end
; i
++) {
4333 c_char
= g_ascii_toupper(pd
[i
]);
4334 if (c_char
== ascii_text
[c_match
]) {
4336 if (c_match
== textlen
) {
4337 result
= MR_MATCHED
;
4338 /* Save position and length for highlighting the field. */
4339 cf
->search_pos
= (uint32_t)(pd
- buf_start
);
4340 cf
->search_len
= (uint32_t)(i
+ 1);
4344 if (pd
+ i
>= buf_end
|| pd
[i
] != '\0') break;
4356 match_binary(capture_file
*cf
, frame_data
*fdata
,
4357 wtap_rec
*rec
, Buffer
*buf
, void *criterion
)
4359 cbs_t
*info
= (cbs_t
*)criterion
;
4360 size_t datalen
= info
->data_len
;
4361 match_result result
;
4362 const uint8_t *pd
= NULL
, *buf_start
;
4364 /* Load the frame's data. */
4365 if (!cf_read_record(cf
, fdata
, rec
, buf
)) {
4366 /* Attempt to get the packet failed. */
4370 result
= MR_NOTMATCHED
;
4371 buf_start
= ws_buffer_start_ptr(buf
);
4373 if (cf
->search_len
|| cf
->search_pos
) {
4374 /* we want to start searching one byte past the previous match start */
4375 offset
= cf
->search_pos
+ 1;
4377 if (offset
< fdata
->cap_len
) {
4378 pd
= ws_memmem(buf_start
+ offset
, fdata
->cap_len
- offset
, info
->data
, datalen
);
4381 result
= MR_MATCHED
;
4382 /* Save position and length for highlighting the field. */
4383 cf
->search_pos
= (uint32_t)(pd
- buf_start
);
4384 cf
->search_len
= (uint32_t)datalen
;
4391 match_binary_reverse(capture_file
*cf
, frame_data
*fdata
,
4392 wtap_rec
*rec
, Buffer
*buf
, void *criterion
)
4394 cbs_t
*info
= (cbs_t
*)criterion
;
4395 size_t datalen
= info
->data_len
;
4396 match_result result
;
4397 const uint8_t *pd
= NULL
, *buf_start
;
4399 /* Load the frame's data. */
4400 if (!cf_read_record(cf
, fdata
, rec
, buf
)) {
4401 /* Attempt to get the packet failed. */
4405 result
= MR_NOTMATCHED
;
4406 buf_start
= ws_buffer_start_ptr(buf
);
4407 /* Has to be room to hold the sought data. */
4408 if (datalen
> fdata
->cap_len
) {
4411 pd
= buf_start
+ fdata
->cap_len
- datalen
;
4412 if (cf
->search_len
|| cf
->search_pos
) {
4413 /* we want to start searching one byte before the previous match start */
4414 pd
= buf_start
+ cf
->search_pos
- 1;
4416 for (; pd
>= buf_start
; pd
--) {
4417 pd
= (uint8_t *)ws_memrchr(buf_start
, info
->data
[0], pd
- buf_start
+ 1);
4418 if (pd
== NULL
) break;
4419 if (memcmp(pd
, info
->data
, datalen
) == 0) {
4420 result
= MR_MATCHED
;
4421 /* Save position and length for highlighting the field. */
4422 cf
->search_pos
= (uint32_t)(pd
- buf_start
);
4423 cf
->search_len
= (uint32_t)datalen
;
4432 match_regex(capture_file
*cf
, frame_data
*fdata
,
4433 wtap_rec
*rec
, Buffer
*buf
, void *criterion _U_
)
4435 match_result result
= MR_NOTMATCHED
;
4436 size_t result_pos
[2] = {0, 0};
4438 /* Load the frame's data. */
4439 if (!cf_read_record(cf
, fdata
, rec
, buf
)) {
4440 /* Attempt to get the packet failed. */
4445 if (cf
->search_len
|| cf
->search_pos
) {
4446 /* we want to start searching one byte past the previous match start */
4447 offset
= cf
->search_pos
+ 1;
4449 if (offset
< fdata
->cap_len
) {
4450 if (ws_regex_matches_pos(cf
->regex
,
4451 (const char *)ws_buffer_start_ptr(buf
),
4452 fdata
->cap_len
, offset
,
4454 //TODO: A chosen regex can match the empty string (zero length)
4455 // which doesn't make a lot of sense for searching the packet bytes.
4456 // Should we search with the PCRE2_NOTEMPTY option?
4458 /* Save position and length for highlighting the field. */
4459 cf
->search_pos
= (uint32_t)(result_pos
[0]);
4460 cf
->search_len
= (uint32_t)(result_pos
[1] - result_pos
[0]);
4461 result
= MR_MATCHED
;
4468 match_regex_reverse(capture_file
*cf
, frame_data
*fdata
,
4469 wtap_rec
*rec
, Buffer
*buf
, void *criterion _U_
)
4471 match_result result
= MR_NOTMATCHED
;
4472 size_t result_pos
[2] = {0, 0};
4474 /* Load the frame's data. */
4475 if (!cf_read_record(cf
, fdata
, rec
, buf
)) {
4476 /* Attempt to get the packet failed. */
4480 size_t offset
= fdata
->cap_len
- 1;
4481 if (cf
->search_pos
) {
4482 /* we want to start searching one byte before the previous match */
4483 offset
= cf
->search_pos
- 1;
4485 for (; offset
> 0; offset
--) {
4486 if (ws_regex_matches_pos(cf
->regex
,
4487 (const char *)ws_buffer_start_ptr(buf
),
4488 fdata
->cap_len
, offset
,
4490 //TODO: A chosen regex can match the empty string (zero length)
4491 // which doesn't make a lot of sense for searching the packet bytes.
4492 // Should we search with the PCRE2_NOTEMPTY option?
4494 /* Save position and length for highlighting the field. */
4495 cf
->search_pos
= (uint32_t)(result_pos
[0]);
4496 cf
->search_len
= (uint32_t)(result_pos
[1] - result_pos
[0]);
4497 result
= MR_MATCHED
;
4505 cf_find_packet_dfilter(capture_file
*cf
, dfilter_t
*sfcode
,
4506 search_direction dir
)
4508 return find_packet(cf
, match_dfilter
, sfcode
, dir
);
4512 cf_find_packet_dfilter_string(capture_file
*cf
, const char *filter
,
4513 search_direction dir
)
4518 if (!dfilter_compile(filter
, &sfcode
, NULL
)) {
4520 * XXX - this shouldn't happen, as the filter string is machine
4525 if (sfcode
== NULL
) {
4527 * XXX - this shouldn't happen, as the filter string is machine
4532 result
= find_packet(cf
, match_dfilter
, sfcode
, dir
);
4533 dfilter_free(sfcode
);
4538 match_dfilter(capture_file
*cf
, frame_data
*fdata
,
4539 wtap_rec
*rec
, Buffer
*buf
, void *criterion
)
4541 dfilter_t
*sfcode
= (dfilter_t
*)criterion
;
4543 match_result result
;
4545 /* Load the frame's data. */
4546 if (!cf_read_record(cf
, fdata
, rec
, buf
)) {
4547 /* Attempt to get the packet failed. */
4551 epan_dissect_init(&edt
, cf
->epan
, true, false);
4552 epan_dissect_prime_with_dfilter(&edt
, sfcode
);
4553 epan_dissect_run(&edt
, cf
->cd_t
, rec
,
4554 frame_tvbuff_new_buffer(&cf
->provider
, fdata
, buf
),
4556 result
= dfilter_apply_edt(sfcode
, &edt
) ? MR_MATCHED
: MR_NOTMATCHED
;
4557 epan_dissect_cleanup(&edt
);
4562 cf_find_packet_marked(capture_file
*cf
, search_direction dir
)
4564 return find_packet(cf
, match_marked
, NULL
, dir
);
4568 match_marked(capture_file
*cf _U_
, frame_data
*fdata
, wtap_rec
*rec _U_
,
4569 Buffer
*buf _U_
, void *criterion _U_
)
4571 return fdata
->marked
? MR_MATCHED
: MR_NOTMATCHED
;
4575 cf_find_packet_time_reference(capture_file
*cf
, search_direction dir
)
4577 return find_packet(cf
, match_time_reference
, NULL
, dir
);
4581 match_time_reference(capture_file
*cf _U_
, frame_data
*fdata
, wtap_rec
*rec _U_
,
4582 Buffer
*buf _U_
, void *criterion _U_
)
4584 return fdata
->ref_time
? MR_MATCHED
: MR_NOTMATCHED
;
4588 find_packet(capture_file
*cf
, ws_match_function match_function
,
4589 void *criterion
, search_direction dir
)
4591 frame_data
*start_fd
;
4593 uint32_t prev_framenum
;
4597 frame_data
*new_fd
= NULL
;
4598 progdlg_t
*progbar
= NULL
;
4599 GTimer
*prog_timer
= g_timer_new();
4601 bool wrap
= prefs
.gui_find_wrap
;
4604 char status_str
[100];
4605 match_result result
;
4607 wtap_rec_init(&rec
);
4608 ws_buffer_init(&buf
, 1514);
4610 start_fd
= cf
->current_frame
;
4611 if (start_fd
!= NULL
) {
4612 prev_framenum
= start_fd
->num
;
4614 prev_framenum
= 0; /* No start packet selected. */
4618 /* Iterate through the list of packets, starting at the packet we've
4619 picked, calling a routine to run the filter on the packet, see if
4620 it matches, and stop if so. */
4622 framenum
= prev_framenum
;
4623 if (framenum
== 0 && dir
== SD_BACKWARD
) {
4624 /* If we have no start packet selected, and we're going backwards,
4625 * start at the end (even if wrap is off.)
4627 framenum
= cf
->count
+ 1;
4630 g_timer_start(prog_timer
);
4631 /* Progress so far. */
4634 cf
->stop_flag
= false;
4637 /* Create the progress bar if necessary.
4638 We check on every iteration of the loop, so that it takes no
4639 longer than the standard time to create it (otherwise, for a
4640 large file, we might take considerably longer than that standard
4641 time in order to get to the next progress bar step). */
4642 if (progbar
== NULL
)
4643 progbar
= delayed_create_progress_dlg(cf
->window
, NULL
, NULL
,
4644 false, &cf
->stop_flag
, progbar_val
);
4647 * Update the progress bar, but do it only after PROGBAR_UPDATE_INTERVAL
4648 * has elapsed. Calling update_progress_dlg and packets_bar_update will
4649 * likely trigger UI paint events, which might take a while depending on
4650 * the platform and display. Reset our timer *after* painting.
4652 if (g_timer_elapsed(prog_timer
, NULL
) > PROGBAR_UPDATE_INTERVAL
) {
4653 /* let's not divide by zero. I should never be started
4654 * with count == 0, so let's assert that
4656 ws_assert(cf
->count
> 0);
4658 progbar_val
= (float) count
/ cf
->count
;
4660 snprintf(status_str
, sizeof(status_str
),
4661 "%4u of %u packets", count
, cf
->count
);
4662 update_progress_dlg(progbar
, progbar_val
, status_str
);
4664 g_timer_start(prog_timer
);
4667 if (cf
->stop_flag
) {
4668 /* Well, the user decided to abort the search. Go back to the
4669 frame where we started. */
4674 /* Go past the current frame. */
4675 if (dir
== SD_BACKWARD
) {
4676 /* Go on to the previous frame. */
4677 if (framenum
<= 1) {
4679 * XXX - other apps have a bit more of a detailed message
4680 * for this, and instead of offering "OK" and "Cancel",
4681 * they offer things such as "Continue" and "Cancel";
4682 * we need an API for popping up alert boxes with
4683 * {Verb} and "Cancel".
4687 statusbar_push_temporary_msg("Search reached the beginning. Continuing at end.");
4688 framenum
= cf
->count
; /* wrap around */
4691 statusbar_push_temporary_msg("Search reached the beginning.");
4692 framenum
= prev_framenum
; /* stay on previous packet */
4697 /* Go on to the next frame. */
4698 if (framenum
== cf
->count
) {
4700 statusbar_push_temporary_msg("Search reached the end. Continuing at beginning.");
4701 framenum
= 1; /* wrap around */
4704 statusbar_push_temporary_msg("Search reached the end.");
4705 framenum
= prev_framenum
; /* stay on previous packet */
4711 fdata
= frame_data_sequence_find(cf
->provider
.frames
, framenum
);
4714 /* Is this packet in the display? */
4715 if (fdata
&& fdata
->passed_dfilter
) {
4716 /* Yes. Does it match the search criterion? */
4717 result
= (*match_function
)(cf
, fdata
, &rec
, &buf
, criterion
);
4718 if (result
== MR_ERROR
) {
4719 /* Error; our caller has reported the error. Go back to the frame
4720 where we started. */
4723 } else if (result
== MR_MATCHED
) {
4724 /* Yes. Go to the new frame. */
4728 wtap_rec_reset(&rec
);
4731 if (fdata
== start_fd
) {
4732 /* We're back to the frame we were on originally, and that frame
4733 doesn't match the search filter. The search failed. */
4738 /* We're done scanning the packets; destroy the progress bar if it
4740 if (progbar
!= NULL
)
4741 destroy_progress_dlg(progbar
);
4742 g_timer_destroy(prog_timer
);
4744 if (new_fd
!= NULL
) {
4745 /* We found a frame that's displayed and that matches.
4746 Try to find and select the packet summary list row for that frame. */
4749 cf
->search_in_progress
= true;
4750 found_row
= packet_list_select_row_from_data(new_fd
);
4751 cf
->search_in_progress
= false;
4753 /* We didn't find a row corresponding to this frame.
4754 This means that the frame isn't being displayed currently,
4755 so we can't select it. */
4756 cf
->search_pos
= 0; /* Reset the position */
4757 cf
->search_len
= 0; /* Reset length */
4758 simple_message_box(ESD_TYPE_INFO
, NULL
,
4759 "The capture file is probably not fully dissected.",
4760 "End of capture exceeded.");
4761 succeeded
= false; /* The search succeeded but we didn't find the row */
4763 succeeded
= true; /* The search succeeded and we found the row */
4765 succeeded
= false; /* The search failed */
4766 wtap_rec_cleanup(&rec
);
4767 ws_buffer_free(&buf
);
4772 cf_goto_frame(capture_file
*cf
, unsigned fnumber
, bool exact
)
4776 if (cf
== NULL
|| cf
->provider
.frames
== NULL
) {
4777 /* we don't have a loaded capture file - fix for bugs 11810 & 11989 */
4778 statusbar_push_temporary_msg("There is no file loaded");
4779 return false; /* we failed to go to that packet */
4782 fdata
= frame_data_sequence_find(cf
->provider
.frames
, fnumber
);
4784 if (fdata
== NULL
) {
4785 /* we didn't find a packet with that packet number */
4786 statusbar_push_temporary_msg("There is no packet number %u.", fnumber
);
4787 return false; /* we failed to go to that packet */
4789 if (!fdata
->passed_dfilter
) {
4790 /* that packet currently isn't displayed */
4791 /* XXX - add it to the set of displayed packets? */
4792 if (cf
->first_displayed
== 0 || exact
) {
4793 /* We only want that exact frame, or no frames are displayed. */
4794 statusbar_push_temporary_msg("Packet number %u isn't displayed.", fnumber
);
4795 return false; /* we failed to go to that packet */
4797 if (fdata
->prev_dis_num
== 0) {
4798 /* There is no previous displayed frame, so this frame is
4799 * before the first displayed frame. Go to the first line,
4800 * which is the closest frame.
4802 fdata
= NULL
; /* This will select the first row. */
4803 statusbar_push_temporary_msg("Packet number %u isn't displayed, going to the first displayed packet, %u.", fnumber
, cf
->first_displayed
);
4805 uint32_t delta
= fnumber
- fdata
->prev_dis_num
;
4806 /* The next displayed frame might be closer, we can do an
4807 * O(log n) binary search for the earliest displayed frame
4808 * in the open interval (fnumber, fnumber + delta).
4810 * This is possibly overkill, we could just go to the previous
4814 uint32_t lower_bound
= fnumber
+ 1;
4815 uint32_t upper_bound
= fnumber
+ delta
- 1;
4817 while (lower_bound
<= upper_bound
) {
4818 uint32_t middle
= (lower_bound
+ upper_bound
) / 2;
4819 fdata2
= frame_data_sequence_find(cf
->provider
.frames
, middle
);
4820 if (fdata2
== NULL
) {
4821 /* We don't have a frame of that number, so search before it. */
4822 upper_bound
= middle
- 1;
4825 /* We have a frame of that number. What's the displayed
4826 * frame before it? */
4827 if (fdata2
->prev_dis_num
> fnumber
) {
4828 /* The previous frame that passed the filter is also after
4829 * our target, so our answer is no later than that.
4831 upper_bound
= fdata2
->prev_dis_num
;
4833 /* The previous displayed frame is before fnumber.
4834 * (We already know fnumber itself is not displayed.)
4835 * Is this frame itself displayed?
4837 if (fdata2
->passed_dfilter
) {
4838 /* Yes. So this is our answer. */
4842 /* No. So our answer, if any, is after this frame. */
4843 lower_bound
= middle
+ 1;
4848 statusbar_push_temporary_msg("Packet number %u isn't displayed, going to the next displayed packet, %u.", fnumber
, fdata
->num
);
4850 statusbar_push_temporary_msg("Packet number %u isn't displayed, going to the previous displayed packet, %u.", fnumber
, fdata
->prev_dis_num
);
4851 fdata
= frame_data_sequence_find(cf
->provider
.frames
, fdata
->prev_dis_num
);
4856 if (!packet_list_select_row_from_data(fdata
)) {
4857 /* We didn't find a row corresponding to this frame.
4858 This means that the frame isn't being displayed currently,
4859 so we can't select it. */
4860 simple_message_box(ESD_TYPE_INFO
, NULL
,
4861 "The capture file is probably not fully dissected.",
4862 "End of capture exceeded.");
4865 return true; /* we got to that packet */
4869 * Go to frame specified by currently selected protocol tree item.
4872 cf_goto_framenum(capture_file
*cf
)
4874 const header_field_info
*hfinfo
;
4877 if (cf
->finfo_selected
) {
4878 hfinfo
= cf
->finfo_selected
->hfinfo
;
4880 if (hfinfo
->type
== FT_FRAMENUM
) {
4881 framenum
= fvalue_get_uinteger(cf
->finfo_selected
->value
);
4882 if (framenum
!= 0) {
4883 /* We probably only want to go to the exact match,
4884 * even though "Go to Previous Packet in History" exists.
4886 return cf_goto_frame(cf
, framenum
, true);
4894 /* Select the packet on a given row. */
4896 cf_select_packet(capture_file
*cf
, frame_data
*fdata
)
4898 epan_dissect_t
*old_edt
;
4900 /* check the frame data struct pointer for this frame */
4901 if (fdata
== NULL
) {
4905 /* Get the data in that frame. */
4906 if (!cf_read_record(cf
, fdata
, &cf
->rec
, &cf
->buf
)) {
4910 /* Record that this frame is the current frame. */
4911 cf
->current_frame
= fdata
;
4914 * The change to defer freeing the current epan_dissect_t was in
4915 * commit a2bb94c3b33d53f42534aceb7cc67aab1d1fb1f9; to quote
4916 * that commit's comment:
4918 * Clear GtkTreeStore before freeing edt
4920 * When building current data for packet details treeview we store two
4922 * - Generated string with item label
4923 * - Pointer to node field_info structure
4925 * After epan_dissect_{free, cleanup} pointer to field_info node is no
4926 * longer valid so we should clear GtkTreeStore before freeing.
4928 * XXX - we're no longer using GTK+; is there a way to ensure that
4929 * *nothing* refers to any of the current frame information before
4933 /* Create the logical protocol tree. */
4934 /* We don't need the columns here. */
4935 cf
->edt
= epan_dissect_new(cf
->epan
, true, true);
4937 tap_build_interesting(cf
->edt
);
4938 epan_dissect_run(cf
->edt
, cf
->cd_t
, &cf
->rec
,
4939 frame_tvbuff_new_buffer(&cf
->provider
, cf
->current_frame
, &cf
->buf
),
4940 cf
->current_frame
, NULL
);
4942 if (old_edt
!= NULL
)
4943 epan_dissect_free(old_edt
);
4946 /* Unselect the selected packet, if any. */
4948 cf_unselect_packet(capture_file
*cf
)
4950 epan_dissect_t
*old_edt
= cf
->edt
;
4953 * See the comment in cf_select_packet() about deferring the freeing
4954 * of the old cf->edt.
4958 /* No packet is selected. */
4959 cf
->current_frame
= NULL
;
4961 /* Destroy the epan_dissect_t for the unselected packet. */
4962 if (old_edt
!= NULL
)
4963 epan_dissect_free(old_edt
);
4967 * Mark a particular frame.
4970 cf_mark_frame(capture_file
*cf
, frame_data
*frame
)
4972 if (! frame
->marked
) {
4973 frame
->marked
= true;
4974 if (cf
->count
> cf
->marked_count
)
4980 * Unmark a particular frame.
4983 cf_unmark_frame(capture_file
*cf
, frame_data
*frame
)
4985 if (frame
->marked
) {
4986 frame
->marked
= false;
4987 if (cf
->marked_count
> 0)
4993 * Ignore a particular frame.
4996 cf_ignore_frame(capture_file
*cf
, frame_data
*frame
)
4998 if (! frame
->ignored
) {
4999 frame
->ignored
= true;
5000 if (cf
->count
> cf
->ignored_count
)
5001 cf
->ignored_count
++;
5006 * Un-ignore a particular frame.
5009 cf_unignore_frame(capture_file
*cf
, frame_data
*frame
)
5011 if (frame
->ignored
) {
5012 frame
->ignored
= false;
5013 if (cf
->ignored_count
> 0)
5014 cf
->ignored_count
--;
5019 * Modify the section comment.
5022 cf_update_section_comment(capture_file
*cf
, char *comment
)
5024 wtap_block_t shb_inf
;
5027 /* Get the first SHB. */
5028 /* XXX - support multiple SHBs */
5029 shb_inf
= wtap_file_get_shb(cf
->provider
.wth
, 0);
5031 /* Get the first comment from the SHB. */
5032 /* XXX - support multiple comments */
5033 if (wtap_block_get_nth_string_option_value(shb_inf
, OPT_COMMENT
, 0, &shb_comment
) != WTAP_OPTTYPE_SUCCESS
) {
5034 /* There's no comment - add one. */
5035 wtap_block_add_string_option(shb_inf
, OPT_COMMENT
, comment
, strlen(comment
));
5037 /* See if the comment has changed or not */
5038 if (strcmp(shb_comment
, comment
) == 0) {
5043 /* The comment has changed, let's update it */
5044 wtap_block_set_nth_string_option_value(shb_inf
, OPT_COMMENT
, 0, comment
, strlen(comment
));
5046 /* Mark the file as having unsaved changes */
5047 cf
->unsaved_changes
= true;
5051 * Modify the section comments for a given section.
5054 cf_update_section_comments(capture_file
*cf
, unsigned shb_idx
, char **comments
)
5056 wtap_block_t shb_inf
;
5059 shb_inf
= wtap_file_get_shb(cf
->provider
.wth
, shb_idx
);
5060 if (shb_inf
== NULL
) {
5061 /* Shouldn't happen. XXX: Report it if it does? */
5065 unsigned n_comments
= g_strv_length(comments
);
5069 for (i
= 0; i
< n_comments
; i
++) {
5070 comment
= comments
[i
];
5071 if (wtap_block_get_nth_string_option_value(shb_inf
, OPT_COMMENT
, i
, &shb_comment
) != WTAP_OPTTYPE_SUCCESS
) {
5072 /* There's no comment - add one. */
5073 wtap_block_add_string_option_owned(shb_inf
, OPT_COMMENT
, comment
);
5074 cf
->unsaved_changes
= true;
5076 /* See if the comment has changed or not */
5077 if (strcmp(shb_comment
, comment
) != 0) {
5078 /* The comment has changed, let's update it */
5079 wtap_block_set_nth_string_option_value(shb_inf
, OPT_COMMENT
, 0, comment
, strlen(comment
));
5080 cf
->unsaved_changes
= true;
5085 /* We either transferred ownership of the comments or freed them
5086 * above, so free the array of strings but not the strings themselves. */
5089 /* If there are extra old comments, remove them. Start at the end. */
5090 for (i
= wtap_block_count_option(shb_inf
, OPT_COMMENT
); i
> n_comments
; i
--) {
5091 wtap_block_remove_nth_option_instance(shb_inf
, OPT_COMMENT
, i
- 1);
5092 cf
->unsaved_changes
= true;
5097 * Get the packet block for a packet (record).
5098 * If the block has been edited, it returns the result of the edit,
5099 * otherwise it returns the block from the file.
5100 * NB. Caller must wtap_block_unref() the result when done.
5103 cf_get_packet_block(capture_file
*cf
, const frame_data
*fd
)
5105 /* If this block has been modified, fetch the modified version */
5106 if (fd
->has_modified_block
)
5107 return wtap_block_ref(cap_file_provider_get_modified_block(&cf
->provider
, fd
));
5109 wtap_rec rec
; /* Record metadata */
5110 Buffer buf
; /* Record data */
5113 /* fetch record block */
5114 wtap_rec_init(&rec
);
5115 ws_buffer_init(&buf
, 1514);
5117 if (!cf_read_record(cf
, fd
, &rec
, &buf
))
5118 { /* XXX, what we can do here? */ }
5120 /* rec.block is owned by the record, steal it before it is gone. */
5121 block
= wtap_block_ref(rec
.block
);
5123 wtap_rec_cleanup(&rec
);
5124 ws_buffer_free(&buf
);
5130 * Update(replace) the block on a capture from a frame
5133 cf_set_modified_block(capture_file
*cf
, frame_data
*fd
, const wtap_block_t new_block
)
5135 wtap_block_t pkt_block
= cf_get_packet_block(cf
, fd
);
5137 /* It's possible to further modify the modified block "in place" by doing
5138 * a call to cf_get_packet_block() that returns an already created modified
5139 * block, modifying that, and calling this function.
5140 * If the caller did that, then the block pointers will be equal.
5142 if (pkt_block
== new_block
) {
5143 /* No need to save anything here, the caller changes went right
5145 * Unfortunately we don't have a way to know how many comments were
5146 * in the block before the caller modified it, so tell the caller
5147 * it is its responsibility to update the comment count.
5153 cf
->packet_comment_count
-= wtap_block_count_option(pkt_block
, OPT_COMMENT
);
5156 cf
->packet_comment_count
+= wtap_block_count_option(new_block
, OPT_COMMENT
);
5158 cap_file_provider_set_modified_block(&cf
->provider
, fd
, new_block
);
5160 expert_update_comment_count(cf
->packet_comment_count
);
5163 /* Either way, we have unsaved changes. */
5164 wtap_block_unref(pkt_block
);
5165 cf
->unsaved_changes
= true;
5170 * What types of comments does this capture file have?
5173 cf_comment_types(capture_file
*cf
)
5175 uint32_t comment_types
= 0;
5178 * Does this file have any sections with at least one comment?
5180 for (unsigned section_number
= 0;
5181 section_number
< wtap_file_get_num_shbs(cf
->provider
.wth
);
5183 wtap_block_t shb_inf
;
5186 shb_inf
= wtap_file_get_shb(cf
->provider
.wth
, section_number
);
5188 /* Try to get the first comment from that SHB. */
5189 if (wtap_block_get_nth_string_option_value(shb_inf
, OPT_COMMENT
, 0,
5190 &shb_comment
) == WTAP_OPTTYPE_SUCCESS
) {
5191 /* We succeeded, so this file has at least one section comment. */
5192 comment_types
|= WTAP_COMMENT_PER_SECTION
;
5194 /* We don't need to search any more. */
5198 if (cf
->packet_comment_count
!= 0)
5199 comment_types
|= WTAP_COMMENT_PER_PACKET
;
5200 return comment_types
;
5204 * Add a resolved address to this file's list of resolved addresses.
5207 cf_add_ip_name_from_string(capture_file
*cf
, const char *addr
, const char *name
)
5210 * XXX - support multiple resolved address lists, and add to the one
5211 * attached to this file?
5213 if (!add_ip_name_from_string(addr
, name
))
5216 /* OK, we have unsaved changes. */
5217 cf
->unsaved_changes
= true;
5226 } save_callback_args_t
;
5229 * Save a capture to a file, in a particular format, saving either
5230 * all packets, all currently-displayed packets, or all marked packets.
5232 * Returns true if it succeeds, false otherwise; if it fails, it pops
5233 * up a message box for the failure.
5236 save_record(capture_file
*cf
, frame_data
*fdata
, wtap_rec
*rec
,
5237 Buffer
*buf
, void *argsp
)
5239 save_callback_args_t
*args
= (save_callback_args_t
*)argsp
;
5243 wtap_block_t pkt_block
;
5245 /* Copy the record information from what was read in from the file. */
5248 /* Make changes based on anything that the user has done but that
5249 hasn't been saved yet. */
5250 if (fdata
->has_modified_block
)
5251 pkt_block
= cap_file_provider_get_modified_block(&cf
->provider
, fdata
);
5253 pkt_block
= rec
->block
;
5254 new_rec
.block
= pkt_block
;
5255 new_rec
.block_was_modified
= fdata
->has_modified_block
? true : false;
5257 if (!nstime_is_zero(&fdata
->shift_offset
)) {
5258 if (new_rec
.presence_flags
& WTAP_HAS_TS
) {
5259 nstime_add(&new_rec
.ts
, &fdata
->shift_offset
);
5263 /* and save the packet */
5264 if (!wtap_dump(args
->pdh
, &new_rec
, ws_buffer_start_ptr(buf
), &err
, &err_info
)) {
5265 report_cfile_write_failure(NULL
, args
->fname
, err
, err_info
, fdata
->num
,
5270 /* If we are saving (i.e., replacing the current file with the one we're
5271 * writing), then update the frame data to clear the shift offset.
5272 * This keeps us from having to re-read the entire file.
5273 * We could do this in rescan_file(), but
5274 * 1) Ideally we shouldn't have to call rescan_file if all we're doing
5275 * is changing the timestamps, since that shouldn't change the offsets.
5276 * 2) The long term goal is to try to do the offset adjustment here
5277 * instead of using rescan_file, which should be faster (#1257).
5279 * If we're exporting to a different file, then don't do that.
5281 if (!args
->export
&& new_rec
.presence_flags
& WTAP_HAS_TS
) {
5282 nstime_set_zero(&fdata
->shift_offset
);
5289 * Can this capture file be written out in any format using Wiretap
5290 * rather than by copying the raw data?
5293 cf_can_write_with_wiretap(capture_file
*cf
)
5295 /* We don't care whether we support the comments in this file or not;
5296 if we can't, we'll offer the user the option of discarding the
5298 return wtap_dump_can_write(cf
->linktypes
, 0);
5302 * Should we let the user do a save?
5306 * the file has unsaved changes, and we can save it in some
5307 * format through Wiretap
5311 * the file is a temporary file and has no unsaved changes (so
5312 * that "saving" it just means copying it).
5314 * XXX - we shouldn't allow files to be edited if they can't be saved,
5315 * so cf->unsaved_changes should be true only if the file can be saved.
5317 * We don't care whether we support the comments in this file or not;
5318 * if we can't, we'll offer the user the option of discarding the
5322 cf_can_save(capture_file
*cf
)
5324 if (cf
->unsaved_changes
&& wtap_dump_can_write(cf
->linktypes
, 0)) {
5325 /* Saved changes, and we can write it out with Wiretap. */
5329 if (cf
->is_tempfile
&& !cf
->unsaved_changes
) {
5331 * Temporary file with no unsaved changes, so we can just do a
5337 /* Nothing to save. */
5342 * Should we let the user do a "save as"?
5346 * we can save it in some format through Wiretap
5350 * the file is a temporary file and has no unsaved changes (so
5351 * that "saving" it just means copying it).
5353 * XXX - we shouldn't allow files to be edited if they can't be saved,
5354 * so cf->unsaved_changes should be true only if the file can be saved.
5356 * We don't care whether we support the comments in this file or not;
5357 * if we can't, we'll offer the user the option of discarding the
5361 cf_can_save_as(capture_file
*cf
)
5363 if (wtap_dump_can_write(cf
->linktypes
, 0)) {
5364 /* We can write it out with Wiretap. */
5368 if (cf
->is_tempfile
&& !cf
->unsaved_changes
) {
5370 * Temporary file with no unsaved changes, so we can just do a
5376 /* Nothing to save. */
5381 * Does this file have unsaved data?
5384 cf_has_unsaved_data(capture_file
*cf
)
5387 * If this is a temporary file, or a file with unsaved changes, it
5390 return (cf
->is_tempfile
&& cf
->count
>0) || cf
->unsaved_changes
;
5394 * Quick scan to find packet offsets.
5396 static cf_read_status_t
5397 rescan_file(capture_file
*cf
, const char *fname
, bool is_tempfile
)
5404 int64_t data_offset
;
5405 progdlg_t
*progbar
= NULL
;
5406 GTimer
*prog_timer
= g_timer_new();
5410 char status_str
[100];
5414 /* Close the old handle. */
5415 wtap_close(cf
->provider
.wth
);
5417 /* Open the new file. */
5418 /* XXX: this will go through all open_routines for a matching one. But right
5419 now rescan_file() is only used when a file is being saved to a different
5420 format than the original, and the user is not given a choice of which
5421 reader to use (only which format to save it in), so doing this makes
5422 sense for now. (XXX: Now it is also used when saving a changed file,
5423 e.g. comments or time-shifted frames.) */
5424 cf
->provider
.wth
= wtap_open_offline(fname
, WTAP_TYPE_AUTO
, &err
, &err_info
, true);
5425 if (cf
->provider
.wth
== NULL
) {
5426 report_cfile_open_failure(fname
, err
, err_info
);
5427 return CF_READ_ERROR
;
5430 /* We're scanning a file whose contents should be the same as what
5431 we had before, so we don't discard dissection state etc.. */
5434 /* Set the file name because we need it to set the follow stream filter.
5435 XXX - is that still true? We need it for other reasons, though,
5437 if (cf
->filename
!= NULL
) {
5438 g_free(cf
->filename
);
5440 cf
->filename
= g_strdup(fname
);
5442 /* Indicate whether it's a permanent or temporary file. */
5443 cf
->is_tempfile
= is_tempfile
;
5445 /* No user changes yet. */
5446 cf
->unsaved_changes
= false;
5448 cf
->cd_t
= wtap_file_type_subtype(cf
->provider
.wth
);
5449 if (cf
->linktypes
!= NULL
) {
5450 g_array_free(cf
->linktypes
, TRUE
);
5452 cf
->linktypes
= g_array_sized_new(FALSE
, FALSE
, (unsigned) sizeof(int), 1);
5454 cf
->snap
= wtap_snapshot_length(cf
->provider
.wth
);
5456 name_ptr
= g_filename_display_basename(cf
->filename
);
5458 cf_callback_invoke(cf_cb_file_rescan_started
, cf
);
5460 /* Record the file's compression type.
5461 XXX - do we know this at open time? */
5462 cf
->compression_type
= wtap_get_compression_type(cf
->provider
.wth
);
5464 /* Find the size of the file. */
5465 size
= wtap_file_size(cf
->provider
.wth
, NULL
);
5467 g_timer_start(prog_timer
);
5469 cf
->stop_flag
= false;
5470 start_time
= g_get_monotonic_time();
5473 wtap_rec_init(&rec
);
5474 ws_buffer_init(&buf
, 1514);
5475 while ((wtap_read(cf
->provider
.wth
, &rec
, &buf
, &err
, &err_info
,
5478 fdata
= frame_data_sequence_find(cf
->provider
.frames
, framenum
);
5479 if (G_LIKELY(fdata
!= NULL
)) {
5480 fdata
->file_off
= data_offset
;
5483 cf
->f_datalen
= wtap_read_so_far(cf
->provider
.wth
);
5485 /* Create the progress bar if necessary. */
5486 if (progress_is_slow(progbar
, prog_timer
, size
, cf
->f_datalen
)) {
5487 progbar_val
= calc_progbar_val(cf
, size
, cf
->f_datalen
, status_str
, sizeof(status_str
));
5488 progbar
= delayed_create_progress_dlg(cf
->window
, NULL
, NULL
,
5489 true, &cf
->stop_flag
, progbar_val
);
5493 * Update the progress bar, but do it only after PROGBAR_UPDATE_INTERVAL
5494 * has elapsed. Calling update_progress_dlg and packets_bar_update will
5495 * likely trigger UI paint events, which might take a while depending on
5496 * the platform and display. Reset our timer *after* painting.
5498 if (progbar
&& g_timer_elapsed(prog_timer
, NULL
) > PROGBAR_UPDATE_INTERVAL
) {
5499 progbar_val
= calc_progbar_val(cf
, size
, cf
->f_datalen
, status_str
, sizeof(status_str
));
5500 /* update the packet bar content on the first run or frequently on very large files */
5501 update_progress_dlg(progbar
, progbar_val
, status_str
);
5502 compute_elapsed(cf
, start_time
);
5503 packets_bar_update();
5504 g_timer_start(prog_timer
);
5508 if (cf
->stop_flag
) {
5509 /* Well, the user decided to abort the rescan. Sadly, as this
5510 isn't a reread, recovering is difficult, so we'll just
5511 close the current capture. */
5515 /* Add this packet's link-layer encapsulation type to cf->linktypes, if
5516 it's not already there.
5517 XXX - yes, this is O(N), so if every packet had a different
5518 link-layer encapsulation type, it'd be O(N^2) to read the file, but
5519 there are probably going to be a small number of encapsulation types
5521 if (rec
.rec_type
== REC_TYPE_PACKET
) {
5522 cf_add_encapsulation_type(cf
, rec
.rec_header
.packet_header
.pkt_encap
);
5524 wtap_rec_reset(&rec
);
5526 wtap_rec_cleanup(&rec
);
5527 ws_buffer_free(&buf
);
5529 /* Free the display name */
5532 /* We're done reading the file; destroy the progress bar if it was created. */
5533 if (progbar
!= NULL
)
5534 destroy_progress_dlg(progbar
);
5535 g_timer_destroy(prog_timer
);
5537 /* We're done reading sequentially through the file. */
5538 cf
->state
= FILE_READ_DONE
;
5540 /* Close the sequential I/O side, to free up memory it requires. */
5541 wtap_sequential_close(cf
->provider
.wth
);
5543 /* compute the time it took to load the file */
5544 compute_elapsed(cf
, start_time
);
5546 /* Set the file encapsulation type now; we don't know what it is until
5547 we've looked at all the packets, as we don't know until then whether
5548 there's more than one type (and thus whether it's
5549 WTAP_ENCAP_PER_PACKET). */
5550 cf
->lnk_t
= wtap_file_encap(cf
->provider
.wth
);
5552 cf_callback_invoke(cf_cb_file_rescan_finished
, cf
);
5554 if (cf
->stop_flag
) {
5555 /* Our caller will give up at this point. */
5556 return CF_READ_ABORTED
;
5560 /* Put up a message box noting that the read failed somewhere along
5561 the line. Don't throw out the stuff we managed to read, though,
5563 report_cfile_read_failure(NULL
, err
, err_info
);
5564 return CF_READ_ERROR
;
5570 cf_save_records(capture_file
*cf
, const char *fname
, unsigned save_format
,
5571 wtap_compression_type compression_type
,
5572 bool discard_comments
, bool dont_reopen
)
5574 char *err_info
= "Unknown error";
5575 char *fname_new
= NULL
;
5578 addrinfo_lists_t
*addr_lists
;
5586 save_callback_args_t callback_args
;
5587 callback_args
.export
= false;
5588 bool needs_reload
= false;
5590 /* XXX caller should avoid saving the file while a read is pending
5591 * (e.g. by delaying the save action) */
5592 if (cf
->read_lock
) {
5593 ws_warning("cf_save_records(\"%s\") while the file is being read, potential crash ahead", fname
);
5596 cf_callback_invoke(cf_cb_file_save_started
, (void *)fname
);
5598 addr_lists
= get_addrinfo_list();
5600 if (save_format
== cf
->cd_t
&& compression_type
== cf
->compression_type
5601 && !discard_comments
&& !cf
->unsaved_changes
5602 && (wtap_addrinfo_list_empty(addr_lists
) || wtap_file_type_subtype_supports_block(save_format
, WTAP_BLOCK_NAME_RESOLUTION
) == BLOCK_NOT_SUPPORTED
)) {
5603 /* We're saving in the format it's already in, and we're not discarding
5604 comments, and there are no changes we have in memory that aren't saved
5605 to the file, and we have no name resolution information to write or
5606 the file format we're saving in doesn't support writing name
5607 resolution information, so we can just move or copy the raw data. */
5609 if (cf
->is_tempfile
) {
5610 /* The file being saved is a temporary file from a live
5611 capture, so it doesn't need to stay around under that name;
5612 first, try renaming the capture buffer file to the new name.
5613 This acts as a "safe save", in that, if the file already
5614 exists, the existing file will be removed only if the rename
5617 Sadly, on Windows, as we have the current capture file
5618 open, even MoveFileEx() with MOVEFILE_REPLACE_EXISTING
5619 (to cause the rename to remove an existing target), as
5620 done by ws_stdio_rename() (ws_rename() is #defined to
5621 be ws_stdio_rename() on Windows) will fail.
5623 According to the MSDN documentation for CreateFile(), if,
5624 when we open a capture file, we were to directly do a CreateFile(),
5625 opening with FILE_SHARE_DELETE|FILE_SHARE_READ, and then
5626 convert it to a file descriptor with _open_osfhandle(),
5627 that would allow the file to be renamed out from under us.
5629 However, that doesn't work in practice. Perhaps the problem
5630 is that the process doing the rename is the process that
5631 has the file open. */
5633 if (ws_rename(cf
->filename
, fname
) == 0) {
5634 /* That succeeded - there's no need to copy the source file. */
5635 how_to_save
= SAVE_WITH_MOVE
;
5637 if (errno
== EXDEV
) {
5638 /* They're on different file systems, so we have to copy the
5640 how_to_save
= SAVE_WITH_COPY
;
5642 /* The rename failed, but not because they're on different
5643 file systems - put up an error message. (Or should we
5644 just punt and try to copy? The only reason why I'd
5645 expect the rename to fail and the copy to succeed would
5646 be if we didn't have permission to remove the file from
5647 the temporary directory, and that might be fixable - but
5648 is it worth requiring the user to go off and fix it?) */
5649 report_rename_failure(cf
->filename
, fname
, errno
);
5654 /* Windows - copy the file to its new location. */
5655 how_to_save
= SAVE_WITH_COPY
;
5658 /* It's a permanent file, so we should copy it, and not remove the
5660 how_to_save
= SAVE_WITH_COPY
;
5663 if (how_to_save
== SAVE_WITH_COPY
) {
5664 /* Copy the file, if we haven't moved it. If we're overwriting
5665 an existing file, we do it with a "safe save", by writing
5666 to a new file and, if the write succeeds, renaming the
5667 new file on top of the old file. */
5668 if (file_exists(fname
)) {
5669 fname_new
= ws_strdup_printf("%s~", fname
);
5670 if (!copy_file_binary_mode(cf
->filename
, fname_new
))
5673 if (!copy_file_binary_mode(cf
->filename
, fname
))
5678 /* Either we're saving in a different format or we're saving changes,
5679 such as added, modified, or removed comments, that haven't yet
5680 been written to the underlying file; we can't do that by copying
5681 or moving the capture file, we have to do it by writing the packets
5684 wtap_dump_params params
;
5687 how_to_save
= SAVE_WITH_WTAP
;
5688 wtap_dump_params_init(¶ms
, cf
->provider
.wth
);
5690 /* Determine what file encapsulation type we should use. */
5691 encap
= wtap_dump_required_file_encap_type(cf
->linktypes
);
5692 params
.encap
= encap
;
5694 /* Use the snaplen from cf (XXX - does wtap_dump_params_init handle that?) */
5695 params
.snaplen
= cf
->snap
;
5697 if (file_exists(fname
)) {
5698 /* We're overwriting an existing file; write out to a new file,
5699 and, if that succeeds, rename the new file on top of the
5700 old file. That makes this a "safe save", so that we don't
5701 lose the old file if we have a problem writing out the new
5702 file. (If the existing file is the current capture file,
5703 we *HAVE* to do that, otherwise we're overwriting the file
5704 from which we're reading the packets that we're writing!) */
5705 fname_new
= ws_strdup_printf("%s~", fname
);
5706 pdh
= wtap_dump_open(fname_new
, save_format
, compression_type
, ¶ms
,
5709 pdh
= wtap_dump_open(fname
, save_format
, compression_type
, ¶ms
,
5712 /* XXX idb_inf is documented to be used until wtap_dump_close. */
5713 g_free(params
.idb_inf
);
5714 params
.idb_inf
= NULL
;
5717 report_cfile_dump_open_failure(fname
, err
, err_info
, save_format
);
5721 /* Add address resolution */
5722 wtap_dump_set_addrinfo_list(pdh
, addr_lists
);
5724 /* Iterate through the list of packets, processing all the packets. */
5725 callback_args
.pdh
= pdh
;
5726 callback_args
.fname
= fname
;
5727 callback_args
.file_type
= save_format
;
5728 switch (process_specified_records(cf
, NULL
, "Saving", "packets",
5729 true, save_record
, &callback_args
, true)) {
5732 /* Completed successfully. */
5736 /* The user decided to abort the saving.
5737 If we're writing to a temporary file, remove it.
5738 XXX - should we do so even if we're not writing to a
5740 wtap_dump_close(pdh
, NULL
, &err
, &err_info
);
5741 if (fname_new
!= NULL
)
5742 ws_unlink(fname_new
);
5743 cf_callback_invoke(cf_cb_file_save_stopped
, NULL
);
5744 wtap_dump_params_cleanup(¶ms
);
5745 return CF_WRITE_ABORTED
;
5748 /* Error while saving.
5749 If we're writing to a temporary file, remove it. */
5750 if (fname_new
!= NULL
)
5751 ws_unlink(fname_new
);
5752 wtap_dump_close(pdh
, NULL
, &err
, &err_info
);
5753 wtap_dump_params_cleanup(¶ms
);
5757 if (!wtap_dump_close(pdh
, &needs_reload
, &err
, &err_info
)) {
5758 report_cfile_close_failure(fname
, err
, err_info
);
5759 wtap_dump_params_cleanup(¶ms
);
5763 wtap_dump_params_cleanup(¶ms
);
5766 if (fname_new
!= NULL
) {
5767 /* We wrote out to fname_new, and should rename it on top of
5768 fname. fname_new is now closed, so that should be possible even
5769 on Windows. However, on Windows, we first need to close whatever
5770 file descriptors we have open for fname. */
5772 wtap_fdclose(cf
->provider
.wth
);
5774 /* Now do the rename. */
5775 if (ws_rename(fname_new
, fname
) == -1) {
5776 /* Well, the rename failed. */
5777 report_rename_failure(fname_new
, fname
, errno
);
5779 /* Attempt to reopen the random file descriptor using the
5780 current file's filename. (At this point, the sequential
5781 file descriptor is closed.) */
5782 if (!wtap_fdreopen(cf
->provider
.wth
, cf
->filename
, &err
)) {
5783 /* Oh, well, we're screwed. */
5784 report_cfile_open_failure(cf
->filename
, err
, NULL
);
5792 /* If this was a temporary file, and we didn't do the save by doing
5793 a move, so the tempoary file is still around under its old name,
5795 if (cf
->is_tempfile
&& how_to_save
!= SAVE_WITH_MOVE
) {
5796 /* If this fails, there's not much we can do, so just ignore errors. */
5797 ws_unlink(cf
->filename
);
5800 cf_callback_invoke(cf_cb_file_save_finished
, NULL
);
5801 cf
->unsaved_changes
= false;
5804 switch (how_to_save
) {
5806 case SAVE_WITH_MOVE
:
5807 /* We just moved the file, so the wtap structure refers to the
5808 new file, and all the information other than the filename
5809 and the "is temporary" status applies to the new file; just
5811 g_free(cf
->filename
);
5812 cf
->filename
= g_strdup(fname
);
5813 cf
->is_tempfile
= false;
5814 cf_callback_invoke(cf_cb_file_fast_save_finished
, cf
);
5817 case SAVE_WITH_COPY
:
5818 /* We just copied the file, so all the information other than
5819 the file descriptors, the filename, and the "is temporary"
5820 status applies to the new file; just update that. */
5821 wtap_fdclose(cf
->provider
.wth
);
5822 /* Attempt to reopen the random file descriptor using the
5823 new file's filename. (At this point, the sequential
5824 file descriptor is closed.) */
5825 if (!wtap_fdreopen(cf
->provider
.wth
, fname
, &err
)) {
5826 report_cfile_open_failure(fname
, err
, err_info
);
5829 g_free(cf
->filename
);
5830 cf
->filename
= g_strdup(fname
);
5831 cf
->is_tempfile
= false;
5833 cf_callback_invoke(cf_cb_file_fast_save_finished
, cf
);
5836 case SAVE_WITH_WTAP
:
5837 /* Open and read the file we saved to.
5839 XXX - this is somewhat of a waste; we already have the
5840 packets, all this gets us is updated file type information
5841 (which we could just stuff into "cf"), and having the new
5842 file be the one we have opened and from which we're reading
5843 the data, and it means we have to spend time opening and
5844 reading the file, which could be a significant amount of
5845 time if the file is large.
5847 If the capture-file-writing code were to return the
5848 seek offset of each packet it writes, we could save that
5849 in the frame_data structure for the frame, and just open
5850 the file without reading it again...
5852 ...as long as, for gzipped files, the process of writing
5853 out the file *also* generates the information needed to
5854 support fast random access to the compressed file. */
5855 /* rescan_file will cause us to try all open_routines, so
5856 reset cfile's open_type */
5857 cf
->open_type
= WTAP_TYPE_AUTO
;
5858 /* There are cases when SAVE_WITH_WTAP can result in new packets
5859 being written to the file, e.g ERF records
5860 In that case, we need to reload the whole file */
5862 if (cf_open(cf
, fname
, WTAP_TYPE_AUTO
, false, &err
) == CF_OK
) {
5863 if (cf_read(cf
, /*reloading=*/true) != CF_READ_OK
) {
5864 /* The rescan failed; just close the file. Either
5865 a dialog was popped up for the failure, so the
5866 user knows what happened, or they stopped the
5867 rescan, in which case they know what happened. */
5868 /* XXX: This is inconsistent with normal open/reload behaviour. */
5874 if (rescan_file(cf
, fname
, false) != CF_READ_OK
) {
5875 /* The rescan failed; just close the file. Either
5876 a dialog was popped up for the failure, so the
5877 user knows what happened, or they stopped the
5878 rescan, in which case they know what happened. */
5885 /* If we were told to discard the comments, do so. */
5886 if (discard_comments
) {
5887 /* Remove SHB comment, if any. */
5888 wtap_write_shb_comment(cf
->provider
.wth
, NULL
);
5890 /* remove all user comments */
5891 for (framenum
= 1; framenum
<= cf
->count
; framenum
++) {
5892 fdata
= frame_data_sequence_find(cf
->provider
.frames
, framenum
);
5894 // XXX: This also ignores non-comment options like verdict
5895 fdata
->has_modified_block
= false;
5898 if (cf
->provider
.frames_modified_blocks
) {
5899 g_tree_destroy(cf
->provider
.frames_modified_blocks
);
5900 cf
->provider
.frames_modified_blocks
= NULL
;
5903 cf
->packet_comment_count
= 0;
5909 if (fname_new
!= NULL
) {
5910 /* We were trying to write to a temporary file; get rid of it if it
5911 exists. (We don't care whether this fails, as, if it fails,
5912 there's not much we can do about it. I guess if it failed for
5913 a reason other than "it doesn't exist", we could report an
5914 error, so the user knows there's a junk file that they might
5915 want to clean up.) */
5916 ws_unlink(fname_new
);
5919 cf_callback_invoke(cf_cb_file_save_failed
, NULL
);
5920 return CF_WRITE_ERROR
;
5924 cf_export_specified_packets(capture_file
*cf
, const char *fname
,
5925 packet_range_t
*range
, unsigned save_format
,
5926 wtap_compression_type compression_type
)
5928 char *fname_new
= NULL
;
5932 save_callback_args_t callback_args
;
5933 wtap_dump_params params
;
5936 callback_args
.export
= true;
5937 packet_range_process_init(range
);
5939 /* We're writing out specified packets from the specified capture
5940 file to another file. Even if all captured packets are to be
5941 written, don't special-case the operation - read each packet
5942 and then write it out if it's one of the specified ones. */
5944 wtap_dump_params_init(¶ms
, cf
->provider
.wth
);
5946 /* Determine what file encapsulation type we should use. */
5947 encap
= wtap_dump_required_file_encap_type(cf
->linktypes
);
5948 params
.encap
= encap
;
5950 /* Use the snaplen from cf (XXX - does wtap_dump_params_init handle that?) */
5951 params
.snaplen
= cf
->snap
;
5953 if (file_exists(fname
)) {
5954 /* We're overwriting an existing file; write out to a new file,
5955 and, if that succeeds, rename the new file on top of the
5956 old file. That makes this a "safe save", so that we don't
5957 lose the old file if we have a problem writing out the new
5958 file. (If the existing file is the current capture file,
5959 we *HAVE* to do that, otherwise we're overwriting the file
5960 from which we're reading the packets that we're writing!) */
5961 fname_new
= ws_strdup_printf("%s~", fname
);
5962 pdh
= wtap_dump_open(fname_new
, save_format
, compression_type
, ¶ms
,
5965 pdh
= wtap_dump_open(fname
, save_format
, compression_type
, ¶ms
,
5968 /* XXX idb_inf is documented to be used until wtap_dump_close. */
5969 g_free(params
.idb_inf
);
5970 params
.idb_inf
= NULL
;
5973 report_cfile_dump_open_failure(fname
, err
, err_info
, save_format
);
5977 /* Add address resolution */
5978 wtap_dump_set_addrinfo_list(pdh
, get_addrinfo_list());
5980 /* Iterate through the list of packets, processing the packets we were
5983 XXX - we've already called "packet_range_process_init(range)", but
5984 "process_specified_records()" will do it again. Fortunately,
5985 that's harmless in this case, as we haven't done anything to
5986 "range" since we initialized it. */
5987 callback_args
.pdh
= pdh
;
5988 callback_args
.fname
= fname
;
5989 callback_args
.file_type
= save_format
;
5990 switch (process_specified_records(cf
, range
, "Writing", "specified records",
5991 true, save_record
, &callback_args
, true)) {
5994 /* Completed successfully. */
5998 /* The user decided to abort the saving.
5999 If we're writing to a temporary file, remove it.
6000 XXX - should we do so even if we're not writing to a
6002 wtap_dump_close(pdh
, NULL
, &err
, &err_info
);
6003 if (fname_new
!= NULL
) {
6004 ws_unlink(fname_new
);
6007 wtap_dump_params_cleanup(¶ms
);
6009 return CF_WRITE_ABORTED
;
6012 /* Error while saving. */
6013 wtap_dump_close(pdh
, NULL
, &err
, &err_info
);
6015 * We don't report any error from closing; the error that caused
6016 * process_specified_records() to fail has already been reported.
6021 if (!wtap_dump_close(pdh
, NULL
, &err
, &err_info
)) {
6022 report_cfile_close_failure(fname
, err
, err_info
);
6026 if (fname_new
!= NULL
) {
6027 /* We wrote out to fname_new, and should rename it on top of
6028 fname; fname is now closed, so that should be possible even
6029 on Windows. Do the rename. */
6030 if (ws_rename(fname_new
, fname
) == -1) {
6031 /* Well, the rename failed. */
6032 report_rename_failure(fname_new
, fname
, errno
);
6037 wtap_dump_params_cleanup(¶ms
);
6042 if (fname_new
!= NULL
) {
6043 /* We were trying to write to a temporary file; get rid of it if it
6044 exists. (We don't care whether this fails, as, if it fails,
6045 there's not much we can do about it. I guess if it failed for
6046 a reason other than "it doesn't exist", we could report an
6047 error, so the user knows there's a junk file that they might
6048 want to clean up.) */
6049 ws_unlink(fname_new
);
6052 wtap_dump_params_cleanup(¶ms
);
6054 return CF_WRITE_ERROR
;
6057 /* Reload the current capture file. */
6059 cf_reload(capture_file
*cf
)
6063 cf_status_t cf_status
= CF_OK
;
6066 if (cf
->read_lock
) {
6067 ws_warning("Failing cf_reload(\"%s\") since a read is in progress", cf
->filename
);
6071 /* If the file could be opened, "cf_open()" calls "cf_close()"
6072 to get rid of state for the old capture file before filling in state
6073 for the new capture file. "cf_close()" will remove the file if
6074 it's a temporary file; we don't want that to happen (for one thing,
6075 it'd prevent subsequent reopens from working). Remember whether it's
6076 a temporary file, mark it as not being a temporary file, and then
6077 reopen it as the type of file it was.
6079 Also, "cf_close()" will free "cf->filename", so we must make
6080 a copy of it first. */
6081 filename
= g_strdup(cf
->filename
);
6082 is_tempfile
= cf
->is_tempfile
;
6083 cf
->is_tempfile
= false;
6084 if (cf_open(cf
, filename
, cf
->open_type
, is_tempfile
, &err
) == CF_OK
) {
6085 switch (cf_read(cf
, /*reloading=*/true)) {
6089 /* Just because we got an error, that doesn't mean we were unable
6090 to read any of the file; we handle what we could get from the
6094 case CF_READ_ABORTED
:
6095 /* The user bailed out of re-reading the capture file; the
6096 capture file has been closed. */
6100 /* The open failed, so "cf->is_tempfile" wasn't set to "is_tempfile".
6101 Instead, the file was left open, so we should restore "cf->is_tempfile"
6104 XXX - change the menu? Presumably "cf_open()" will do that;
6105 make sure it does! */
6106 cf
->is_tempfile
= is_tempfile
;
6107 cf_status
= CF_ERROR
;
6109 /* "cf_open()" made a copy of the file name we handed it, so
6110 we should free up our copy. */