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>
52 #include "ui/simple_dialog.h"
53 #include "ui/main_statusbar.h"
54 #include "ui/progress_dlg.h"
56 #include "ui/ws_ui_util.h"
57 #include "ui/packet_list_utils.h"
59 /* Needed for addrinfo */
60 #include <sys/types.h>
62 #ifdef HAVE_SYS_SOCKET_H
63 #include <sys/socket.h>
66 #ifdef HAVE_NETINET_IN_H
67 # include <netinet/in.h>
71 # include <winsock2.h>
72 # include <ws2tcpip.h>
75 static bool read_record(capture_file
*cf
, wtap_rec
*rec
, dfilter_t
*dfcode
,
76 epan_dissect_t
*edt
, column_info
*cinfo
, int64_t offset
,
77 fifo_string_cache_t
*frame_dup_cache
, GChecksum
*frame_cksum
);
79 static void rescan_packets(capture_file
*cf
, const char *action
, const char *action_item
, bool redissect
);
86 typedef match_result (*ws_match_function
)(capture_file
*, frame_data
*,
88 static match_result
match_protocol_tree(capture_file
*cf
, frame_data
*fdata
,
89 wtap_rec
*, void *criterion
);
90 static void match_subtree_text(proto_node
*node
, void *data
);
91 static void match_subtree_text_reverse(proto_node
*node
, void *data
);
92 static match_result
match_summary_line(capture_file
*cf
, frame_data
*fdata
,
93 wtap_rec
*, void *criterion
);
94 static match_result
match_narrow_and_wide(capture_file
*cf
, frame_data
*fdata
,
95 wtap_rec
*, void *criterion
);
96 static match_result
match_narrow_and_wide_reverse(capture_file
*cf
, frame_data
*fdata
,
97 wtap_rec
*, void *criterion
);
98 static match_result
match_narrow_and_wide_case(capture_file
*cf
, frame_data
*fdata
,
99 wtap_rec
*, void *criterion
);
100 static match_result
match_narrow_and_wide_case_reverse(capture_file
*cf
, frame_data
*fdata
,
101 wtap_rec
*, void *criterion
);
102 static match_result
match_narrow_case(capture_file
*cf
, frame_data
*fdata
,
103 wtap_rec
*, void *criterion
);
104 static match_result
match_narrow_case_reverse(capture_file
*cf
, frame_data
*fdata
,
105 wtap_rec
*, void *criterion
);
106 static match_result
match_wide(capture_file
*cf
, frame_data
*fdata
,
107 wtap_rec
*, void *criterion
);
108 static match_result
match_wide_reverse(capture_file
*cf
, frame_data
*fdata
,
109 wtap_rec
*, void *criterion
);
110 static match_result
match_wide_case(capture_file
*cf
, frame_data
*fdata
,
111 wtap_rec
*, void *criterion
);
112 static match_result
match_wide_case_reverse(capture_file
*cf
, frame_data
*fdata
,
113 wtap_rec
*, void *criterion
);
114 static match_result
match_binary(capture_file
*cf
, frame_data
*fdata
,
115 wtap_rec
*, void *criterion
);
116 static match_result
match_binary_reverse(capture_file
*cf
, frame_data
*fdata
,
117 wtap_rec
*, void *criterion
);
118 static match_result
match_regex(capture_file
*cf
, frame_data
*fdata
,
119 wtap_rec
*, void *criterion
);
120 static match_result
match_regex_reverse(capture_file
*cf
, frame_data
*fdata
,
121 wtap_rec
*, void *criterion
);
122 static match_result
match_dfilter(capture_file
*cf
, frame_data
*fdata
,
123 wtap_rec
*, void *criterion
);
124 static match_result
match_marked(capture_file
*cf
, frame_data
*fdata
,
125 wtap_rec
*, void *criterion
);
126 static match_result
match_time_reference(capture_file
*cf
, frame_data
*fdata
,
127 wtap_rec
*, void *criterion
);
128 static bool find_packet(capture_file
*cf
, ws_match_function match_function
,
129 void *criterion
, search_direction dir
, bool start_current
);
131 /* Seconds spent processing packets between pushing UI updates. */
132 #define PROGBAR_UPDATE_INTERVAL 0.150
134 /* Show the progress bar after this many seconds. */
135 #define PROGBAR_SHOW_DELAY 0.5
138 * Maximum number of records we support in a file.
140 * It is, at most, the maximum value of a uint32_t, as we use a uint32_t
141 * for the frame number.
143 * We allow it to be set to a lower value; see issue #16908 for why
144 * we're doing this. Thanks, Qt!
146 static uint32_t max_records
= UINT32_MAX
;
149 cf_set_max_records(unsigned max_records_arg
)
151 max_records
= max_records_arg
;
155 * We could probably use g_signal_...() instead of the callbacks below but that
156 * would require linking our CLI programs to libgobject and creating an object
157 * instance for the signals.
160 cf_callback_t cb_fct
;
162 } cf_callback_data_t
;
164 static GList
*cf_callbacks
;
167 cf_callback_invoke(int event
, void *data
)
169 cf_callback_data_t
*cb
;
170 GList
*cb_item
= cf_callbacks
;
172 /* there should be at least one interested */
173 ws_assert(cb_item
!= NULL
);
175 while (cb_item
!= NULL
) {
176 cb
= (cf_callback_data_t
*)cb_item
->data
;
177 cb
->cb_fct(event
, data
, cb
->user_data
);
178 cb_item
= g_list_next(cb_item
);
183 cf_callback_add(cf_callback_t func
, void *user_data
)
185 cf_callback_data_t
*cb
;
187 cb
= g_new(cf_callback_data_t
,1);
189 cb
->user_data
= user_data
;
191 cf_callbacks
= g_list_prepend(cf_callbacks
, cb
);
195 cf_callback_remove(cf_callback_t func
, void *user_data
)
197 cf_callback_data_t
*cb
;
198 GList
*cb_item
= cf_callbacks
;
200 while (cb_item
!= NULL
) {
201 cb
= (cf_callback_data_t
*)cb_item
->data
;
202 if (cb
->cb_fct
== func
&& cb
->user_data
== user_data
) {
203 cf_callbacks
= g_list_remove(cf_callbacks
, cb
);
207 cb_item
= g_list_next(cb_item
);
210 ws_assert_not_reached();
214 cf_get_computed_elapsed(capture_file
*cf
)
216 return cf
->computed_elapsed
;
220 compute_elapsed(capture_file
*cf
, int64_t start_time
)
222 int64_t delta_time
= g_get_monotonic_time() - start_time
;
224 cf
->computed_elapsed
= (unsigned long) (delta_time
/ 1000); /* ms */
228 ws_epan_new(capture_file
*cf
)
230 static const struct packet_provider_funcs funcs
= {
231 cap_file_provider_get_frame_ts
,
232 cap_file_provider_get_interface_name
,
233 cap_file_provider_get_interface_description
,
234 cap_file_provider_get_modified_block
237 return epan_new(&cf
->provider
, &funcs
);
241 cf_open(capture_file
*cf
, const char *fname
, unsigned int type
, bool is_tempfile
, int *err
)
246 wth
= wtap_open_offline(fname
, type
, err
, &err_info
, true);
250 /* The open succeeded. Close whatever capture file we had open,
251 and fill in the information for this file. */
254 /* Initialize the record information.
255 XXX - we really want to initialize this after we've read all
256 the packets, so we know how much we'll ultimately need. */
257 wtap_rec_init(&cf
->rec
, 1514);
259 /* We're about to start reading the file. */
260 cf
->state
= FILE_READ_IN_PROGRESS
;
262 /* If there was a pending redissection for the old file (there
263 * shouldn't be), clear it. cf_close() should have failed if the
264 * old file's read lock was held, but it doesn't hurt to clear it. */
265 cf
->read_lock
= false;
266 cf
->redissection_queued
= RESCAN_NONE
;
268 cf
->provider
.wth
= wth
;
271 /* Set the file name because we need it to set the follow stream filter.
272 XXX - is that still true? We need it for other reasons, though,
274 cf
->filename
= g_strdup(fname
);
276 /* Indicate whether it's a permanent or temporary file. */
277 cf
->is_tempfile
= is_tempfile
;
279 /* No user changes yet. */
280 cf
->unsaved_changes
= false;
282 cf
->computed_elapsed
= 0;
284 /* Record the file's type and compression type. */
285 cf
->cd_t
= wtap_file_type_subtype(cf
->provider
.wth
);
286 cf
->compression_type
= wtap_get_compression_type(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 information. */
380 wtap_rec_cleanup(&cf
->rec
);
382 /* Clear the packet list. */
383 packet_list_freeze();
387 dfilter_free(cf
->rfcode
);
389 if (cf
->provider
.frames
!= NULL
) {
390 free_frame_data_sequence(cf
->provider
.frames
);
391 cf
->provider
.frames
= NULL
;
393 if (cf
->provider
.frames_modified_blocks
) {
394 g_tree_destroy(cf
->provider
.frames_modified_blocks
);
395 cf
->provider
.frames_modified_blocks
= NULL
;
397 cf_unselect_packet(cf
); /* nothing to select */
398 cf
->first_displayed
= 0;
399 cf
->last_displayed
= 0;
401 /* No frames, no frame selected, no field in that frame selected. */
403 cf
->current_frame
= NULL
;
404 cf
->finfo_selected
= NULL
;
406 /* No frame link-layer types, either. */
407 if (cf
->linktypes
!= NULL
) {
408 g_array_free(cf
->linktypes
, TRUE
);
409 cf
->linktypes
= NULL
;
413 nstime_set_zero(&cf
->elapsed_time
);
415 reset_tap_listeners();
420 /* We have no file open. */
421 cf
->state
= FILE_CLOSED
;
423 cf_callback_invoke(cf_cb_file_closed
, cf
);
427 * true if the progress dialog doesn't exist and it looks like we'll
428 * take > PROGBAR_SHOW_DELAY (500ms) to load, false otherwise.
431 progress_is_slow(progdlg_t
*progdlg
, GTimer
*prog_timer
, int64_t size
, int64_t pos
)
435 if (progdlg
) return false;
436 elapsed
= g_timer_elapsed(prog_timer
, NULL
);
437 /* This only gets checked between reading records, which doesn't help if
438 * a single record takes a very long time, e.g., the first TLS packet if
439 * the SSLKEYLOGFILE is very large. (#17051) */
440 if ((elapsed
* 2 > PROGBAR_SHOW_DELAY
&& (size
/ pos
) >= 2) /* It looks like we're going to be slow. */
441 || elapsed
> PROGBAR_SHOW_DELAY
) { /* We are indeed slow. */
448 calc_progbar_val(capture_file
*cf
, int64_t size
, int64_t file_pos
, char *status_str
, unsigned long status_size
)
452 progbar_val
= (float) file_pos
/ (float) size
;
453 if (progbar_val
> 1.0) {
455 /* The file probably grew while we were reading it.
456 * Update file size, and try again.
458 size
= wtap_file_size(cf
->provider
.wth
, NULL
);
461 progbar_val
= (float) file_pos
/ (float) size
;
463 /* If it's still > 1, either "wtap_file_size()" failed (in which
464 * case there's not much we can do about it), or the file
465 * *shrank* (in which case there's not much we can do about
466 * it); just clip the progress value at 1.0.
468 if (progbar_val
> 1.0f
)
472 snprintf(status_str
, status_size
,
473 "%" PRId64
"KB of %" PRId64
"KB",
474 file_pos
/ 1024, size
/ 1024);
480 cf_read(capture_file
*cf
, bool reloading
)
483 char *err_info
= NULL
;
484 volatile bool too_many_records
= false;
486 progdlg_t
*volatile progbar
= NULL
;
487 GTimer
*prog_timer
= g_timer_new();
492 dfilter_t
*dfcode
= NULL
;
494 volatile bool create_proto_tree
;
497 volatile bool is_read_aborted
= false;
499 /* The update_progress_dlg call below might end up accepting a user request to
500 * trigger redissection/rescans which can modify/destroy the dissection
501 * context ("cf->epan"). That condition should be prevented by callers, but in
502 * case it occurs let's fail gracefully.
505 ws_warning("Failing due to recursive cf_read(\"%s\", %d) call!",
506 cf
->filename
, reloading
);
507 return CF_READ_ERROR
;
509 /* This is a full dissection, so clear any pending request for one. */
510 cf
->redissection_queued
= RESCAN_NONE
;
511 cf
->read_lock
= true;
513 /* Compile the current display filter.
514 * The code it compiles to might have changed, e.g. if a display
515 * filter macro used has changed.
517 * We assume this will not fail since cf->dfilter is only set in
518 * cf_filter IFF the filter was valid.
519 * XXX - This is not necessarily true, if the filter has a FT_IPv4
520 * or FT_IPv6 field compared to a resolved hostname in it, because
521 * we do a new host lookup, and that *could* timeout this time
522 * (though with the read lock above we shouldn't have many lookups at
523 * once, reducing the chances of that)... (#19612)
526 compiled
= dfilter_compile(cf
->dfilter
, &dfcode
, NULL
);
527 ws_assert(compiled
&& dfcode
);
530 dfilter_free(cf
->dfcode
);
533 /* The compiled dfilter might have a field reference; recompiling it
534 * means that the field references won't match anything. That's what
535 * we want since this is a new sequential read and we don't have
536 * a selected frame with a tree. (Will taps with filters with display
537 * references also have cleared display references?)
540 /* Get the union of the flags for all tap listeners. */
541 tap_flags
= union_of_tap_listener_flags();
544 * Determine whether we need to create a protocol tree.
547 * we're going to apply a display filter;
549 * one of the tap listeners is going to apply a filter;
551 * one of the tap listeners requires a protocol tree;
553 * a postdissector wants field values or protocols on
557 (cf
->dfcode
!= NULL
|| have_filtering_tap_listeners() ||
558 (tap_flags
& TL_REQUIRES_PROTO_TREE
) || postdissectors_want_hfids());
560 reset_tap_listeners();
562 name_ptr
= g_filename_display_basename(cf
->filename
);
565 cf_callback_invoke(cf_cb_file_reload_started
, cf
);
567 cf_callback_invoke(cf_cb_file_read_started
, cf
);
569 /* The packet list window will be empty until the file is completely loaded */
570 packet_list_freeze();
572 cf
->stop_flag
= false;
573 start_time
= g_get_monotonic_time();
575 epan_dissect_init(&edt
, cf
->epan
, create_proto_tree
, false);
577 /* If the display filter or any tap listeners require the columns,
579 cinfo
= (tap_listeners_require_columns() ||
580 dfilter_requires_columns(cf
->dfcode
)) ? &cf
->cinfo
: NULL
;
582 /* Find the size of the file. */
583 size
= wtap_file_size(cf
->provider
.wth
, NULL
);
585 /* If we are to ignore duplicate frames, we need a container to store
586 * hashes frame contents */
587 fifo_string_cache_t frame_dup_cache
;
588 GChecksum
*volatile cksum
= NULL
;
590 if (prefs
.ignore_dup_frames
) {
591 fifo_string_cache_init(&frame_dup_cache
, prefs
.ignore_dup_frames_cache_entries
, g_free
);
592 cksum
= g_checksum_new(G_CHECKSUM_SHA256
);
595 g_timer_start(prog_timer
);
597 wtap_rec_init(&rec
, 1514);
604 char status_str
[100];
606 while ((wtap_read(cf
->provider
.wth
, &rec
, &err
, &err_info
,
609 if (cf
->count
== max_records
) {
611 * Quit if we've already read the maximum number of
614 too_many_records
= true;
617 file_pos
= wtap_read_so_far(cf
->provider
.wth
);
619 /* Create the progress bar if necessary. */
620 if (progress_is_slow(progbar
, prog_timer
, size
, file_pos
)) {
621 progbar_val
= calc_progbar_val(cf
, size
, file_pos
, status_str
, sizeof(status_str
));
622 progbar
= delayed_create_progress_dlg(cf
->window
, NULL
, NULL
, true,
623 &cf
->stop_flag
, progbar_val
);
627 * Update the progress bar, but do it only after
628 * PROGBAR_UPDATE_INTERVAL has elapsed. Calling update_progress_dlg
629 * and packets_bar_update will likely trigger UI paint events, which
630 * might take a while depending on the platform and display. Reset
631 * our timer *after* painting.
633 if (progbar
&& g_timer_elapsed(prog_timer
, NULL
) > PROGBAR_UPDATE_INTERVAL
) {
634 progbar_val
= calc_progbar_val(cf
, size
, file_pos
, status_str
, sizeof(status_str
));
635 /* update the packet bar content on the first run or frequently on very large files */
636 update_progress_dlg(progbar
, progbar_val
, status_str
);
637 compute_elapsed(cf
, start_time
);
638 packets_bar_update();
639 g_timer_start(prog_timer
);
642 * The previous GUI triggers should not have destroyed the running
643 * session. If that did happen, it could blow up when read_record tries
644 * to use the destroyed edt.session, so detect it right here.
646 ws_assert(edt
.session
== cf
->epan
);
649 if (cf
->state
== FILE_READ_ABORTED
) {
650 /* Well, the user decided to exit Wireshark. Break out of the
651 loop, and let the code below (which is called even if there
652 aren't any packets left to read) exit. */
653 is_read_aborted
= true;
657 /* Well, the user decided to abort the read. He/She will be warned and
658 it might be enough for him/her to work with the already loaded
660 This is especially true for very large capture files, where you don't
661 want to wait loading the whole file (which may last minutes or even
662 hours even on fast machines) just to see that it was the wrong file. */
665 read_record(cf
, &rec
, cf
->dfcode
, &edt
, cinfo
, data_offset
, &frame_dup_cache
, cksum
);
666 wtap_rec_reset(&rec
);
669 CATCH(OutOfMemoryError
) {
670 simple_message_box(ESD_TYPE_ERROR
, NULL
,
671 "More information and workarounds can be found at\n"
672 WS_WIKI_URL("KnownBugs/OutOfMemory"),
673 "Sorry, but Wireshark has run out of memory and has to terminate now.");
675 /* Could we close the current capture and free up memory from that? */
677 /* we have to terminate, as we cannot recover from the memory error */
683 // If we're ignoring duplicate frames, clear the data structures.
684 // We really could look at prefs.ignore_dup_frames here, but it's even
685 // safer to check if we had allocated 'cksum'.
687 fifo_string_cache_free(&frame_dup_cache
);
688 g_checksum_free(cksum
);
691 /* We're done reading sequentially through the file. */
692 cf
->state
= FILE_READ_DONE
;
694 /* Destroy the progress bar if it was created. */
696 destroy_progress_dlg(progbar
);
697 g_timer_destroy(prog_timer
);
699 /* Free the display name */
702 epan_dissect_cleanup(&edt
);
703 wtap_rec_cleanup(&rec
);
705 /* Close the sequential I/O side, to free up memory it requires. */
706 wtap_sequential_close(cf
->provider
.wth
);
708 /* Allow the protocol dissectors to free up memory that they
709 * don't need after the sequential run-through of the packets. */
710 postseq_cleanup_all_protocols();
712 /* compute the time it took to load the file */
713 compute_elapsed(cf
, start_time
);
715 /* Set the file encapsulation type now; we don't know what it is until
716 we've looked at all the packets, as we don't know until then whether
717 there's more than one type (and thus whether it's
718 WTAP_ENCAP_PER_PACKET). */
719 cf
->lnk_t
= wtap_file_encap(cf
->provider
.wth
);
721 cf
->current_frame
= frame_data_sequence_find(cf
->provider
.frames
, cf
->first_displayed
);
725 /* It is safe again to execute redissections or sort. */
726 ws_assert(cf
->read_lock
);
727 cf
->read_lock
= false;
730 cf_callback_invoke(cf_cb_file_reload_finished
, cf
);
732 cf_callback_invoke(cf_cb_file_read_finished
, cf
);
734 /* If we have any displayed packets to select, select the first of those
735 packets by making the first row the selected row. */
736 if (cf
->first_displayed
!= 0) {
737 packet_list_select_row_from_data(NULL
);
740 if (is_read_aborted
) {
742 * Well, the user decided to exit Wireshark while reading this *offline*
743 * capture file (Live captures are handled by something like
744 * cf_continue_tail). Clean up accordingly.
747 cf
->redissection_queued
= RESCAN_NONE
;
748 return CF_READ_ABORTED
;
751 if (cf
->redissection_queued
!= RESCAN_NONE
) {
752 /* Redissection was queued up. Clear the request and perform it now. */
753 bool redissect
= cf
->redissection_queued
== RESCAN_REDISSECT
;
754 rescan_packets(cf
, NULL
, NULL
, redissect
);
758 simple_message_box(ESD_TYPE_WARN
, NULL
,
759 "The remaining packets in the file were discarded.\n"
761 "As a lot of packets from the original file will be missing,\n"
762 "remember to be careful when saving the current content to a file.\n",
763 "File loading was cancelled.");
764 return CF_READ_ERROR
;
768 /* Put up a message box noting that the read failed somewhere along
769 the line. Don't throw out the stuff we managed to read, though,
771 report_cfile_read_failure(NULL
, err
, err_info
);
772 return CF_READ_ERROR
;
773 } else if (too_many_records
) {
774 simple_message_box(ESD_TYPE_WARN
, NULL
,
775 "The remaining packets in the file were discarded.\n"
777 "As a lot of packets from the original file will be missing,\n"
778 "remember to be careful when saving the current content to a file.\n"
780 "The command-line utility editcap can be used to split "
781 "the file into multiple smaller files",
782 "The file contains more records than the maximum "
783 "supported number of records, %u.", max_records
);
784 return CF_READ_ERROR
;
791 cf_continue_tail(capture_file
*cf
, volatile int to_read
, wtap_rec
*rec
,
792 int *err
, fifo_string_cache_t
*frame_dup_cache
, GChecksum
*frame_cksum
)
795 volatile int newly_displayed_packets
= 0;
797 bool create_proto_tree
;
800 /* Don't compile the current display filter. The current display filter
801 * text might compile to different code than when the capture started:
803 * If it has a IP address resolved name, calling get_host_ipaddr every
804 * time new packets arrive can mean a *lot* of gethostbyname calls
805 * in flight at once, eventually leading to a timeout (#19612).
806 * addr_resolv.c says that ares_gethostbyname is "usually interactive",
807 * unlike ares_gethostbyaddr (used in dissection), and violating that
808 * expectation is bad.
810 * If it has a display filter macro, the definition might have changed.
812 * If it has a field reference, the selected frame / current proto tree
813 * might have changed, and we don't have the old one. If we recompile,
814 * we can't set the field references to the old values.
816 * For a rescan, redissection, reload, retap, or opening a new file, we
817 * want to compile. What about here, when new frames have arrived in a live
818 * capture? We might be able to cache the host lookup, and a user might want
819 * the new display filter macro definition, but the user almost surely wants
820 * the field references to refer to values from the proto tree when the
821 * filter was applied, not whatever it happens to be now if the user has
822 * clicked on a different packet.
824 * To get the new compiled filter, the user should refilter.
827 /* Get the union of the flags for all tap listeners. */
828 tap_flags
= union_of_tap_listener_flags();
831 * Determine whether we need to create a protocol tree.
834 * we're going to apply a display filter;
836 * one of the tap listeners is going to apply a filter;
838 * one of the tap listeners requires a protocol tree;
840 * a postdissector wants field values or protocols on
844 (cf
->dfcode
!= NULL
|| have_filtering_tap_listeners() ||
845 (tap_flags
& TL_REQUIRES_PROTO_TREE
) || postdissectors_want_hfids());
849 /* Don't freeze/thaw the list when doing live capture */
850 /*packet_list_freeze();*/
852 epan_dissect_init(&edt
, cf
->epan
, create_proto_tree
, false);
855 int64_t data_offset
= 0;
858 /* If the display filter or any tap listeners require the columns,
860 cinfo
= (tap_listeners_require_columns() ||
861 dfilter_requires_columns(cf
->dfcode
)) ? &cf
->cinfo
: NULL
;
863 while (to_read
!= 0) {
864 wtap_cleareof(cf
->provider
.wth
);
865 if (!wtap_read(cf
->provider
.wth
, rec
, err
, &err_info
,
869 if (cf
->state
== FILE_READ_ABORTED
) {
870 /* Well, the user decided to exit Wireshark. Break out of the
871 loop, and let the code below (which is called even if there
872 aren't any packets left to read) exit. */
875 if (read_record(cf
, rec
, cf
->dfcode
, &edt
, cinfo
, data_offset
, frame_dup_cache
, frame_cksum
)) {
876 newly_displayed_packets
++;
882 CATCH(OutOfMemoryError
) {
883 simple_message_box(ESD_TYPE_ERROR
, NULL
,
884 "More information and workarounds can be found at\n"
885 WS_WIKI_URL("KnownBugs/OutOfMemory"),
886 "Sorry, but Wireshark has run out of memory and has to terminate now.");
888 /* Could we close the current capture and free up memory from that? */
889 return CF_READ_ABORTED
;
891 /* we have to terminate, as we cannot recover from the memory error */
897 /* Update the file encapsulation; it might have changed based on the
898 packets we've read. */
899 cf
->lnk_t
= wtap_file_encap(cf
->provider
.wth
);
901 epan_dissect_cleanup(&edt
);
903 /* Don't freeze/thaw the list when doing live capture */
904 /*packet_list_thaw();*/
905 /* With the new packet list the first packet
906 * isn't automatically selected.
908 if (!cf
->current_frame
&& !packet_list_multi_select_active())
909 packet_list_select_row_from_data(NULL
);
911 if (cf
->state
== FILE_READ_ABORTED
) {
912 /* Well, the user decided to exit Wireshark. Return CF_READ_ABORTED
913 so that our caller can kill off the capture child process;
914 this will cause an EOF on the pipe from the child, so
915 "cf_finish_tail()" will be called, and it will clean up
917 return CF_READ_ABORTED
;
918 } else if (*err
!= 0) {
919 /* We got an error reading the capture file. */
920 report_cfile_read_failure(cf
->filename
, *err
, err_info
);
921 return CF_READ_ERROR
;
927 cf_fake_continue_tail(capture_file
*cf
)
929 if (cf
->state
== FILE_CLOSED
) {
930 cf
->state
= FILE_READ_PENDING
;
935 cf_finish_tail(capture_file
*cf
, wtap_rec
*rec
, int *err
,
936 fifo_string_cache_t
*frame_dup_cache
, GChecksum
*frame_cksum
)
942 bool create_proto_tree
;
945 /* All the comments above in cf_continue_tail apply regarding the
946 * current display filter.
949 /* Get the union of the flags for all tap listeners. */
950 tap_flags
= union_of_tap_listener_flags();
952 /* If the display filter or any tap listeners require the columns,
954 cinfo
= (tap_listeners_require_columns() ||
955 dfilter_requires_columns(cf
->dfcode
)) ? &cf
->cinfo
: NULL
;
958 * Determine whether we need to create a protocol tree.
961 * we're going to apply a display filter;
963 * one of the tap listeners is going to apply a filter;
965 * one of the tap listeners requires a protocol tree;
967 * a postdissector wants field values or protocols on
971 (cf
->dfcode
!= NULL
|| have_filtering_tap_listeners() ||
972 (tap_flags
& TL_REQUIRES_PROTO_TREE
) || postdissectors_want_hfids());
974 if (cf
->provider
.wth
== NULL
) {
976 return CF_READ_ERROR
;
979 /* Don't freeze/thaw the list when doing live capture */
980 /*packet_list_freeze();*/
982 epan_dissect_init(&edt
, cf
->epan
, create_proto_tree
, false);
984 wtap_cleareof(cf
->provider
.wth
);
985 while ((wtap_read(cf
->provider
.wth
, rec
, err
, &err_info
, &data_offset
))) {
986 if (cf
->state
== FILE_READ_ABORTED
) {
987 /* Well, the user decided to abort the read. Break out of the
988 loop, and let the code below (which is called even if there
989 aren't any packets left to read) exit. */
992 read_record(cf
, rec
, cf
->dfcode
, &edt
, cinfo
, data_offset
, frame_dup_cache
, frame_cksum
);
996 epan_dissect_cleanup(&edt
);
998 /* Don't freeze/thaw the list when doing live capture */
999 /*packet_list_thaw();*/
1001 if (cf
->state
== FILE_READ_ABORTED
) {
1002 /* Well, the user decided to abort the read. We're only called
1003 when the child capture process closes the pipe to us (meaning
1004 it's probably exited), so we can just close the capture
1005 file; we return CF_READ_ABORTED so our caller can do whatever
1006 is appropriate when that happens. */
1008 return CF_READ_ABORTED
;
1011 /* We're done reading sequentially through the file. */
1012 cf
->state
= FILE_READ_DONE
;
1014 /* We're done reading sequentially through the file; close the
1015 sequential I/O side, to free up memory it requires. */
1016 wtap_sequential_close(cf
->provider
.wth
);
1018 /* Allow the protocol dissectors to free up memory that they
1019 * don't need after the sequential run-through of the packets. */
1020 postseq_cleanup_all_protocols();
1022 /* Update the file encapsulation; it might have changed based on the
1023 packets we've read. */
1024 cf
->lnk_t
= wtap_file_encap(cf
->provider
.wth
);
1026 /* Update the details in the file-set dialog, as the capture file
1027 * has likely grown since we first stat-ed it */
1028 fileset_update_file(cf
->filename
);
1031 /* We got an error reading the capture file. */
1032 report_cfile_read_failure(cf
->filename
, *err
, err_info
);
1033 return CF_READ_ERROR
;
1038 #endif /* HAVE_LIBPCAP */
1041 cf_get_display_name(capture_file
*cf
)
1045 /* Return a name to use in displays */
1046 if (!cf
->is_tempfile
) {
1047 /* Get the last component of the file name, and use that. */
1049 displayname
= g_filename_display_basename(cf
->filename
);
1051 displayname
=g_strdup("(No file)");
1054 /* The file we read is a temporary file from a live capture or
1055 a merge operation; we don't mention its name, but, if it's
1056 from a capture, give the source of the capture. */
1058 displayname
= g_strdup(cf
->source
);
1060 displayname
= g_strdup("(Untitled)");
1067 cf_get_basename(capture_file
*cf
)
1071 /* Return a name to use in the GUI for the basename for files to
1072 which we save statistics */
1073 if (!cf
->is_tempfile
) {
1074 /* Get the last component of the file name, and use that. */
1076 displayname
= g_filename_display_basename(cf
->filename
);
1078 /* If the file name ends with any extension that corresponds
1079 to a file type we support - including compressed versions
1080 of those files - strip it off. */
1081 size_t displayname_len
= strlen(displayname
);
1082 GSList
*extensions
= wtap_get_all_file_extensions_list();
1084 for (suffix
= extensions
; suffix
!= NULL
; suffix
= g_slist_next(suffix
)) {
1085 /* Does the file name end with that extension? */
1086 const char *extension
= (char *)suffix
->data
;
1087 size_t extension_len
= strlen(extension
);
1088 if (displayname_len
> extension_len
&&
1089 displayname
[displayname_len
- extension_len
- 1] == '.' &&
1090 strcmp(&displayname
[displayname_len
- extension_len
], extension
) == 0) {
1091 /* Yes. Strip the extension off, and return the result. */
1092 displayname
[displayname_len
- extension_len
- 1] = '\0';
1096 wtap_free_extensions_list(extensions
);
1098 displayname
=g_strdup("");
1101 /* The file we read is a temporary file from a live capture or
1102 a merge operation; we don't mention its name, but, if it's
1103 from a capture, give the source of the capture. */
1105 displayname
= g_strdup(cf
->source
);
1107 displayname
= g_strdup("");
1114 cf_set_tempfile_source(capture_file
*cf
, char *source
)
1121 cf
->source
= g_strdup(source
);
1123 cf
->source
= g_strdup("");
1128 cf_get_tempfile_source(capture_file
*cf
)
1137 /* XXX - use a macro instead? */
1139 cf_get_packet_count(capture_file
*cf
)
1144 /* XXX - use a macro instead? */
1146 cf_is_tempfile(capture_file
*cf
)
1148 return cf
->is_tempfile
;
1152 cf_set_tempfile(capture_file
*cf
, bool is_tempfile
)
1154 cf
->is_tempfile
= is_tempfile
;
1158 /* XXX - use a macro instead? */
1160 cf_set_drops_known(capture_file
*cf
, bool drops_known
)
1162 cf
->drops_known
= drops_known
;
1165 /* XXX - use a macro instead? */
1167 cf_set_drops(capture_file
*cf
, uint32_t drops
)
1172 /* XXX - use a macro instead? */
1174 cf_get_drops_known(capture_file
*cf
)
1176 return cf
->drops_known
;
1179 /* XXX - use a macro instead? */
1181 cf_get_drops(capture_file
*cf
)
1187 cf_set_rfcode(capture_file
*cf
, dfilter_t
*rfcode
)
1189 cf
->rfcode
= rfcode
;
1193 add_packet_to_packet_list(frame_data
*fdata
, capture_file
*cf
,
1194 epan_dissect_t
*edt
, dfilter_t
*dfcode
, column_info
*cinfo
,
1195 wtap_rec
*rec
, bool add_to_packet_list
)
1197 frame_data_set_before_dissect(fdata
, &cf
->elapsed_time
,
1198 &cf
->provider
.ref
, cf
->provider
.prev_dis
);
1199 cf
->provider
.prev_cap
= fdata
;
1201 if (dfcode
!= NULL
) {
1202 epan_dissect_prime_with_dfilter(edt
, dfcode
);
1205 /* Prepare coloring rules, this ensures that display filter rules containing
1206 * frame.color_rule references are still processed.
1207 * TODO: actually detect that situation or maybe apply other optimizations? */
1208 if (edt
->tree
&& color_filters_used()) {
1209 color_filters_prime_edt(edt
);
1210 fdata
->need_colorize
= 1;
1214 if (!fdata
->visited
) {
1215 /* This is the first pass, so prime the epan_dissect_t with the
1216 hfids postdissectors want on the first pass. */
1217 prime_epan_dissect_with_postdissector_wanted_hfids(edt
);
1220 /* Initialize passed_dfilter here so that dissectors can hide packets. */
1221 /* XXX We might want to add a separate "visible" bit to frame_data instead. */
1222 fdata
->passed_dfilter
= 1;
1224 /* Dissect the frame. */
1225 epan_dissect_run_with_taps(edt
, cf
->cd_t
, rec
, fdata
, cinfo
);
1227 if (fdata
->passed_dfilter
&& dfcode
!= NULL
) {
1228 fdata
->passed_dfilter
= dfilter_apply_edt(dfcode
, edt
) ? 1 : 0;
1230 if (fdata
->passed_dfilter
&& edt
->pi
.fd
->dependent_frames
) {
1231 /* This frame passed the display filter but it may depend on other
1232 * (potentially not displayed) frames. Find those frames and mark them
1235 g_hash_table_foreach(edt
->pi
.fd
->dependent_frames
, find_and_mark_frame_depended_upon
, cf
->provider
.frames
);
1239 if (fdata
->passed_dfilter
|| fdata
->ref_time
) {
1240 cf
->displayed_count
++;
1241 fdata
->dis_num
= cf
->displayed_count
;
1244 if (add_to_packet_list
) {
1245 /* We fill the needed columns from new_packet_list */
1246 packet_list_append(cinfo
, fdata
);
1249 if (fdata
->passed_dfilter
|| fdata
->ref_time
)
1251 frame_data_set_after_dissect(fdata
, &cf
->cum_bytes
);
1252 /* The only way we use prev_dis is to get the time stamp of
1253 * the previous displayed frame, so ignore it if it doesn't
1254 * have a time stamp, because we're presumably interested in
1255 * the timestamp of the previously displayed frame with a
1256 * time. XXX: What if in the future we want to use the previously
1257 * displayed frame for something else, too?
1259 if (fdata
->has_ts
) {
1260 cf
->provider
.prev_dis
= fdata
;
1263 /* If we haven't yet seen the first frame, this is it. */
1264 if (cf
->first_displayed
== 0)
1265 cf
->first_displayed
= fdata
->num
;
1267 /* This is the last frame we've seen so far. */
1268 cf
->last_displayed
= fdata
->num
;
1271 epan_dissect_reset(edt
);
1275 * Read in a new record.
1276 * Returns true if the packet was added to the packet (record) list,
1280 read_record(capture_file
*cf
, wtap_rec
*rec
, dfilter_t
*dfcode
,
1281 epan_dissect_t
*edt
, column_info
*cinfo
, int64_t offset
,
1282 fifo_string_cache_t
*frame_dup_cache
, GChecksum
*frame_cksum
)
1288 const char *cksum_string
;
1291 /* Add this packet's link-layer encapsulation type to cf->linktypes, if
1292 it's not already there.
1293 XXX - yes, this is O(N), so if every packet had a different
1294 link-layer encapsulation type, it'd be O(N^2) to read the file, but
1295 there are probably going to be a small number of encapsulation types
1297 if (rec
->rec_type
== REC_TYPE_PACKET
) {
1298 cf_add_encapsulation_type(cf
, rec
->rec_header
.packet_header
.pkt_encap
);
1301 /* The frame number of this packet, if we add it to the set of frames,
1302 would be one more than the count of frames in the file so far. */
1303 frame_data_init(&fdlocal
, cf
->count
+ 1, rec
, offset
, cf
->cum_bytes
);
1306 epan_dissect_t rf_edt
;
1307 column_info
*rf_cinfo
= NULL
;
1309 epan_dissect_init(&rf_edt
, cf
->epan
, true, false);
1310 epan_dissect_prime_with_dfilter(&rf_edt
, cf
->rfcode
);
1311 if (dfilter_requires_columns(cf
->rfcode
)) {
1312 rf_cinfo
= &cf
->cinfo
;
1314 epan_dissect_run(&rf_edt
, cf
->cd_t
, rec
, &fdlocal
, rf_cinfo
);
1315 passed
= dfilter_apply_edt(cf
->rfcode
, &rf_edt
);
1316 epan_dissect_cleanup(&rf_edt
);
1322 /* This does a shallow copy of fdlocal, which is good enough. */
1323 fdata
= frame_data_sequence_add(cf
->provider
.frames
, &fdlocal
);
1326 if (rec
->block
!= NULL
)
1327 cf
->packet_comment_count
+= wtap_block_count_option(rec
->block
, OPT_COMMENT
);
1328 cf
->f_datalen
= offset
+ fdlocal
.cap_len
;
1330 // Should we check if the frame data is a duplicate, and thus, ignore
1332 if (frame_cksum
!= NULL
&& rec
->rec_type
== REC_TYPE_PACKET
) {
1333 g_checksum_reset(frame_cksum
);
1334 g_checksum_update(frame_cksum
, ws_buffer_start_ptr(&rec
->data
), ws_buffer_length(&rec
->data
));
1335 cksum_string
= g_strdup(g_checksum_get_string(frame_cksum
));
1336 was_in_cache
= fifo_string_cache_insert(frame_dup_cache
, cksum_string
);
1338 g_free((void *)cksum_string
);
1339 fdata
->ignored
= true;
1340 cf
->ignored_count
++;
1344 /* When a redissection is in progress (or queued), do not process packets.
1345 * This will be done once all (new) packets have been scanned. */
1346 if (!cf
->redissecting
&& cf
->redissection_queued
== RESCAN_NONE
) {
1347 add_packet_to_packet_list(fdata
, cf
, edt
, dfcode
, cinfo
, rec
, true);
1355 typedef struct _callback_data_t
{
1365 merge_callback(merge_event event
, int num _U_
,
1366 const merge_in_file_t in_files
[], const unsigned in_file_count
,
1370 callback_data_t
*cb_data
= (callback_data_t
*) data
;
1372 ws_assert(cb_data
!= NULL
);
1376 case MERGE_EVENT_INPUT_FILES_OPENED
:
1380 case MERGE_EVENT_FRAME_TYPE_SELECTED
:
1384 case MERGE_EVENT_READY_TO_MERGE
:
1385 /* Get the sum of the sizes of all the files. */
1386 for (i
= 0; i
< in_file_count
; i
++)
1387 cb_data
->f_len
+= in_files
[i
].size
;
1389 cb_data
->prog_timer
= g_timer_new();
1390 g_timer_start(cb_data
->prog_timer
);
1393 case MERGE_EVENT_RECORD_WAS_READ
:
1395 /* Create the progress bar if necessary.
1396 We check on every iteration of the loop, so that it takes no
1397 longer than the standard time to create it (otherwise, for a
1398 large file, we might take considerably longer than that standard
1399 time in order to get to the next progress bar step). */
1400 if (cb_data
->progbar
== NULL
) {
1401 cb_data
->progbar
= delayed_create_progress_dlg(cb_data
->pd_window
, NULL
, NULL
,
1402 false, &cb_data
->stop_flag
, 0.0f
);
1406 * Update the progress bar, but do it only after
1407 * PROGBAR_UPDATE_INTERVAL has elapsed. Calling update_progress_dlg
1408 * and packets_bar_update will likely trigger UI paint events, which
1409 * might take a while depending on the platform and display. Reset
1410 * our timer *after* painting.
1412 if (g_timer_elapsed(cb_data
->prog_timer
, NULL
) > PROGBAR_UPDATE_INTERVAL
) {
1414 int64_t file_pos
= 0;
1415 /* Get the sum of the seek positions in all of the files. */
1416 for (i
= 0; i
< in_file_count
; i
++)
1417 file_pos
+= wtap_read_so_far(in_files
[i
].wth
);
1419 progbar_val
= (float) file_pos
/ (float) cb_data
->f_len
;
1420 if (progbar_val
> 1.0f
) {
1421 /* Some file probably grew while we were reading it.
1422 That "shouldn't happen", so we'll just clip the progress
1427 if (cb_data
->progbar
!= NULL
) {
1428 char status_str
[100];
1429 snprintf(status_str
, sizeof(status_str
),
1430 "%" PRId64
"KB of %" PRId64
"KB",
1431 file_pos
/ 1024, cb_data
->f_len
/ 1024);
1432 update_progress_dlg(cb_data
->progbar
, progbar_val
, status_str
);
1434 g_timer_start(cb_data
->prog_timer
);
1439 case MERGE_EVENT_DONE
:
1440 /* We're done merging the files; destroy the progress bar if it was created. */
1441 if (cb_data
->progbar
!= NULL
)
1442 destroy_progress_dlg(cb_data
->progbar
);
1443 g_timer_destroy(cb_data
->prog_timer
);
1447 return cb_data
->stop_flag
;
1453 cf_merge_files_to_tempfile(void *pd_window
, const char *temp_dir
, char **out_filenamep
,
1454 int in_file_count
, const char *const *in_filenames
,
1455 int file_type
, bool do_append
)
1458 merge_progress_callback_t cb
;
1459 callback_data_t
*cb_data
= g_new0(callback_data_t
, 1);
1461 /* prepare our callback routine */
1462 cb_data
->pd_window
= pd_window
;
1463 cb
.callback_func
= merge_callback
;
1466 cf_callback_invoke(cf_cb_file_merge_started
, NULL
);
1468 /* merge the files */
1469 status
= merge_files_to_tempfile(temp_dir
, out_filenamep
, "wireshark", file_type
,
1471 in_file_count
, do_append
,
1472 IDB_MERGE_MODE_ALL_SAME
, 0 /* snaplen */,
1477 cf_callback_invoke(cf_cb_file_merge_finished
, NULL
);
1480 /* Callers aren't expected to treat an error or an explicit abort
1481 differently - the merge code puts up error dialogs itself, so
1482 they don't have to. */
1489 cf_filter_packets(capture_file
*cf
, char *dftext
, bool force
)
1491 const char *filter_new
= dftext
? dftext
: "";
1492 const char *filter_old
= cf
->dfilter
? cf
->dfilter
: "";
1496 /* if new filter equals old one, do nothing unless told to do so */
1497 /* XXX - The text can be the same without compiling to the same code.
1498 * (Macros, field references, etc.)
1500 if (!force
&& strcmp(filter_new
, filter_old
) == 0) {
1506 if (dftext
== NULL
) {
1507 /* The new filter is an empty filter (i.e., display all packets).
1508 * so leave dfcode==NULL
1512 * We have a filter; make a copy of it (as we'll be saving it),
1513 * and try to compile it.
1515 dftext
= g_strdup(dftext
);
1516 if (!dfilter_compile(dftext
, &dfcode
, &df_err
)) {
1517 /* The attempt failed; report an error. */
1518 simple_message_box(ESD_TYPE_ERROR
, NULL
,
1519 "See the help for a description of the display filter syntax.",
1520 "\"%s\" isn't a valid display filter: %s",
1521 dftext
, df_err
->msg
);
1522 df_error_free(&df_err
);
1528 if (dfcode
== NULL
) {
1529 /* Yes - free the filter text, and set it to null. */
1535 /* We have a valid filter. Replace the current filter. */
1536 g_free(cf
->dfilter
);
1537 cf
->dfilter
= dftext
;
1539 /* We'll recompile this when the rescan starts, or in cf_read()
1540 * if no file is open currently. However, if no file is open and
1541 * we start a new capture, we want to use this rather than
1542 * recompiling in cf_continue_tail() */
1543 dfilter_free(cf
->dfcode
);
1544 cf
->dfcode
= dfcode
;
1546 /* Now rescan the packet list, applying the new filter, but not
1547 * throwing away information constructed on a previous pass.
1548 * If a dissection is already in progress, queue it.
1550 if (cf
->redissection_queued
== RESCAN_NONE
) {
1551 if (cf
->read_lock
) {
1552 cf
->redissection_queued
= RESCAN_SCAN
;
1553 } else if (cf
->state
!= FILE_CLOSED
) {
1554 if (dftext
== NULL
) {
1555 rescan_packets(cf
, "Resetting", "filter", false);
1557 rescan_packets(cf
, "Filtering", dftext
, false);
1566 cf_redissect_packets(capture_file
*cf
)
1568 if (cf
->read_lock
|| cf
->redissection_queued
== RESCAN_SCAN
) {
1569 /* Dissection in progress, signal redissection rather than rescanning. That
1570 * would destroy the current (in-progress) dissection in "cf_read" which
1571 * will cause issues when "cf_read" tries to add packets to the list.
1572 * If a previous rescan was requested, "upgrade" it to a full redissection.
1574 cf
->redissection_queued
= RESCAN_REDISSECT
;
1576 if (cf
->redissection_queued
!= RESCAN_NONE
) {
1577 /* Redissection is (already) queued, wait for "cf_read" to finish. */
1578 /* XXX - what if whatever set and later clears read_lock is *not*
1579 * cf_read, e.g. process_specified_records ? We need to handle a
1580 * queued redissection there too like we do in cf_read.
1585 if (cf
->state
!= FILE_CLOSED
) {
1586 /* Restart dissection in case no cf_read is pending. */
1587 rescan_packets(cf
, "Reprocessing", "all packets", true);
1592 cf_read_record(capture_file
*cf
, const frame_data
*fdata
, wtap_rec
*rec
)
1597 if (!wtap_seek_read(cf
->provider
.wth
, fdata
->file_off
, rec
, &err
, &err_info
)) {
1598 report_cfile_read_failure(cf
->filename
, err
, err_info
);
1605 cf_read_record_no_alert(capture_file
*cf
, const frame_data
*fdata
,
1611 if (!wtap_seek_read(cf
->provider
.wth
, fdata
->file_off
, rec
, &err
, &err_info
)) {
1619 cf_read_current_record(capture_file
*cf
)
1621 return cf_read_record(cf
, cf
->current_frame
, &cf
->rec
);
1624 /* Rescan the list of packets, reconstructing the CList.
1626 "action" describes why we're doing this; it's used in the progress
1629 "action_item" describes what we're doing; it's used in the progress
1632 "redissect" is true if we need to make the dissectors reconstruct
1633 any state information they have (because a preference that affects
1634 some dissector has changed, meaning some dissector might construct
1635 its state differently from the way it was constructed the last time). */
1637 rescan_packets(capture_file
*cf
, const char *action
, const char *action_item
, bool redissect
)
1639 /* Rescan packets new packet list */
1643 progdlg_t
*progbar
= NULL
;
1644 GTimer
*prog_timer
= g_timer_new();
1646 frame_data
*selected_frame
, *preceding_frame
, *following_frame
, *prev_frame
;
1647 int selected_frame_num
, preceding_frame_num
, following_frame_num
, prev_frame_num
;
1648 bool selected_frame_seen
;
1651 char status_str
[100];
1653 dfilter_t
*dfcode
= NULL
;
1655 bool create_proto_tree
;
1656 bool filtering_tap_listeners
= false;
1658 bool add_to_packet_list
= false;
1660 uint32_t frames_count
;
1661 rescan_type queued_rescan_type
= RESCAN_NONE
;
1663 if (cf
->state
== FILE_CLOSED
|| cf
->state
== FILE_READ_PENDING
) {
1667 /* Rescan in progress, clear pending actions. */
1668 cf
->redissection_queued
= RESCAN_NONE
;
1669 ws_assert(!cf
->read_lock
);
1670 cf
->read_lock
= true;
1672 wtap_rec_init(&rec
, 1514);
1674 /* Compile the current display filter.
1675 * The code it compiles to might have changed, e.g. if a display
1676 * filter macro used has changed.
1678 * We assume this will not fail since cf->dfilter is only set in
1679 * cf_filter IFF the filter was valid.
1680 * XXX - This is not necessarily true, if the filter has a FT_IPv4
1681 * or FT_IPv6 field compared to a resolved hostname in it, because
1682 * we do a new host lookup, and that *could* timeout this time
1683 * (though with the read lock above we shouldn't have many lookups at
1684 * once, reducing the chances of that)... (#19612)
1687 compiled
= dfilter_compile(cf
->dfilter
, &dfcode
, NULL
);
1688 ws_assert(compiled
&& dfcode
);
1691 dfilter_free(cf
->dfcode
);
1692 cf
->dfcode
= dfcode
;
1694 /* Do we have any tap listeners with filters? */
1695 filtering_tap_listeners
= have_filtering_tap_listeners();
1697 /* Update references in filters (if any) for the protocol
1698 * tree corresponding to the currently selected frame in the GUI. */
1699 if (cf
->edt
!= NULL
&& cf
->edt
->tree
!= NULL
) {
1701 dfilter_load_field_references(cf
->dfcode
, cf
->edt
->tree
);
1702 if (filtering_tap_listeners
)
1703 tap_listeners_load_field_references(cf
->edt
);
1706 if (cf
->dfcode
!= NULL
) {
1707 dfilter_log_full(LOG_DOMAIN_DFILTER
, LOG_LEVEL_NOISY
, NULL
, -1, NULL
,
1708 cf
->dfcode
, "Rescanning packets with display filter");
1711 /* Get the union of the flags for all tap listeners. */
1712 tap_flags
= union_of_tap_listener_flags();
1714 /* If the display filter or any tap listeners require the columns,
1715 * construct them. */
1716 cinfo
= (tap_listeners_require_columns() ||
1717 dfilter_requires_columns(cf
->dfcode
)) ? &cf
->cinfo
: NULL
;
1720 * Determine whether we need to create a protocol tree.
1723 * we're going to apply a display filter;
1725 * one of the tap listeners is going to apply a filter;
1727 * one of the tap listeners requires a protocol tree;
1729 * we're redissecting and a postdissector wants field
1730 * values or protocols on the first pass.
1733 (cf
->dfcode
!= NULL
|| filtering_tap_listeners
||
1734 (tap_flags
& TL_REQUIRES_PROTO_TREE
) ||
1735 (redissect
&& postdissectors_want_hfids()));
1737 reset_tap_listeners();
1738 /* Which frame, if any, is the currently selected frame?
1739 XXX - should the selected frame or the focus frame be the "current"
1740 frame, that frame being the one from which "Find Frame" searches
1742 selected_frame
= cf
->current_frame
;
1744 /* Mark frame num as not found */
1745 selected_frame_num
= -1;
1747 /* Freeze the packet list while we redo it, so we don't get any
1748 screen updates while it happens. */
1749 packet_list_freeze();
1752 /* We need to re-initialize all the state information that protocols
1753 keep, because some preference that controls a dissector has changed,
1754 which might cause the state information to be constructed differently
1755 by that dissector. */
1757 /* We might receive new packets while redissecting, and we don't
1758 want to dissect those before their time. */
1759 cf
->redissecting
= true;
1761 /* 'reset' dissection session */
1762 epan_free(cf
->epan
);
1763 if (cf
->edt
&& cf
->edt
->pi
.fd
) {
1764 /* All pointers in "per frame proto data" for the currently selected
1765 packet are allocated in wmem_file_scope() and deallocated in epan_free().
1766 Free them here to avoid unintended usage in packet_list_clear(). */
1767 frame_data_destroy(cf
->edt
->pi
.fd
);
1769 cf
->epan
= ws_epan_new(cf
);
1770 cf
->cinfo
.epan
= cf
->epan
;
1772 /* A new Lua tap listener may be registered in lua_prime_all_fields()
1773 called via epan_new() / init_dissection() when reloading Lua plugins. */
1774 if (!create_proto_tree
&& have_filtering_tap_listeners()) {
1775 create_proto_tree
= true;
1777 if (!cinfo
&& tap_listeners_require_columns()) {
1781 /* We need to redissect the packets so we have to discard our old
1782 * packet list store. */
1783 packet_list_clear();
1784 add_to_packet_list
= true;
1787 /* We don't yet know which will be the first and last frames displayed. */
1788 cf
->first_displayed
= 0;
1789 cf
->last_displayed
= 0;
1791 /* We currently don't display any packets */
1792 cf
->displayed_count
= 0;
1794 /* Iterate through the list of frames. Call a routine for each frame
1795 to check whether it should be displayed and, if so, add it to
1796 the display list. */
1797 cf
->provider
.ref
= NULL
;
1798 cf
->provider
.prev_dis
= NULL
;
1799 cf
->provider
.prev_cap
= NULL
;
1802 cf_callback_invoke(cf_cb_file_rescan_started
, cf
);
1804 g_timer_start(prog_timer
);
1805 /* Count of packets at which we've looked. */
1807 /* Progress so far. */
1810 cf
->stop_flag
= false;
1811 start_time
= g_get_monotonic_time();
1813 /* no previous row yet */
1814 prev_frame_num
= -1;
1817 preceding_frame_num
= -1;
1818 preceding_frame
= NULL
;
1819 following_frame_num
= -1;
1820 following_frame
= NULL
;
1822 selected_frame_seen
= false;
1824 frames_count
= cf
->count
;
1826 epan_dissect_init(&edt
, cf
->epan
, create_proto_tree
, false);
1830 * Decryption secrets and name resolution blocks are read while
1831 * sequentially processing records and then passed to the dissector.
1832 * During redissection, the previous information is lost (see epan_free
1833 * above), but they are not read again from the file as only packet
1834 * records are re-read. Therefore reset the wtap secrets and name
1835 * resolution callbacks such that wtap resupplies the callbacks with
1836 * previously read information.
1838 wtap_set_cb_new_ipv4(cf
->provider
.wth
, add_ipv4_name
);
1839 wtap_set_cb_new_ipv6(cf
->provider
.wth
, (wtap_new_ipv6_callback_t
) add_ipv6_name
);
1840 wtap_set_cb_new_secrets(cf
->provider
.wth
, secrets_wtap_callback
);
1843 for (framenum
= 1; framenum
<= frames_count
; framenum
++) {
1844 fdata
= frame_data_sequence_find(cf
->provider
.frames
, framenum
);
1846 /* Create the progress bar if necessary.
1847 We check on every iteration of the loop, so that it takes no
1848 longer than the standard time to create it (otherwise, for a
1849 large file, we might take considerably longer than that standard
1850 time in order to get to the next progress bar step). */
1851 if (progbar
== NULL
)
1852 progbar
= delayed_create_progress_dlg(cf
->window
, action
, action_item
, true,
1857 * Update the progress bar, but do it only after PROGBAR_UPDATE_INTERVAL
1858 * has elapsed. Calling update_progress_dlg and packets_bar_update will
1859 * likely trigger UI paint events, which might take a while depending on
1860 * the platform and display. Reset our timer *after* painting.
1862 if (g_timer_elapsed(prog_timer
, NULL
) > PROGBAR_UPDATE_INTERVAL
) {
1863 /* let's not divide by zero. I should never be started
1864 * with count == 0, so let's assert that
1866 ws_assert(cf
->count
> 0);
1867 progbar_val
= (float) count
/ frames_count
;
1869 if (progbar
!= NULL
) {
1870 snprintf(status_str
, sizeof(status_str
),
1871 "%4u of %u frames", count
, frames_count
);
1872 update_progress_dlg(progbar
, progbar_val
, status_str
);
1875 g_timer_start(prog_timer
);
1878 queued_rescan_type
= cf
->redissection_queued
;
1879 if (queued_rescan_type
!= RESCAN_NONE
) {
1880 /* A redissection was requested while an existing redissection was
1885 if (cf
->stop_flag
) {
1886 /* Well, the user decided to abort the filtering. Just stop.
1888 XXX - go back to the previous filter? Users probably just
1889 want not to wait for a filtering operation to finish;
1890 unless we cancel by having no filter, reverting to the
1891 previous filter will probably be even more expensive than
1892 continuing the filtering, as it involves going back to the
1893 beginning and filtering, and even with no filter we currently
1894 have to re-generate the entire clist, which is also expensive.
1896 I'm not sure what Network Monitor does, but it doesn't appear
1897 to give you an unfiltered display if you cancel. */
1904 /* Since all state for the frame was destroyed, mark the frame
1905 * as not visited, free the GSList referring to the state
1906 * data (the per-frame data itself was freed by
1907 * "init_dissection()"), and null out the GSList pointer. */
1908 frame_data_reset(fdata
);
1909 frames_count
= cf
->count
;
1912 /* Frame dependencies from the previous dissection/filtering are no longer valid. */
1913 fdata
->dependent_of_displayed
= 0;
1915 if (!cf_read_record(cf
, fdata
, &rec
))
1916 break; /* error reading the frame */
1918 /* If the previous frame is displayed, and we haven't yet seen the
1919 selected frame, remember that frame - it's the closest one we've
1920 yet seen before the selected frame. */
1921 if (prev_frame_num
!= -1 && !selected_frame_seen
&& prev_frame
->passed_dfilter
) {
1922 preceding_frame_num
= prev_frame_num
;
1923 preceding_frame
= prev_frame
;
1926 add_packet_to_packet_list(fdata
, cf
, &edt
, cf
->dfcode
, cinfo
, &rec
,
1927 add_to_packet_list
);
1929 /* If this frame is displayed, and this is the first frame we've
1930 seen displayed after the selected frame, remember this frame -
1931 it's the closest one we've yet seen at or after the selected
1933 if (fdata
->passed_dfilter
&& selected_frame_seen
&& following_frame_num
== -1) {
1934 following_frame_num
= fdata
->num
;
1935 following_frame
= fdata
;
1937 if (fdata
== selected_frame
) {
1938 selected_frame_seen
= true;
1939 if (fdata
->passed_dfilter
)
1940 selected_frame_num
= fdata
->num
;
1943 /* Remember this frame - it'll be the previous frame
1944 on the next pass through the loop. */
1945 prev_frame_num
= fdata
->num
;
1947 wtap_rec_reset(&rec
);
1950 epan_dissect_cleanup(&edt
);
1951 wtap_rec_cleanup(&rec
);
1953 /* We are done redissecting the packet list. */
1954 cf
->redissecting
= false;
1957 frames_count
= cf
->count
;
1958 /* Clear out what remains of the visited flags and per-frame data
1961 XXX - that may cause various forms of bogosity when dissecting
1962 these frames, as they won't have been seen by this sequential
1963 pass, but the only alternative I see is to keep scanning them
1964 even though the user requested that the scan stop, and that
1965 would leave the user stuck with an Wireshark grinding on
1966 until it finishes. Should we just stick them with that? */
1967 for (; framenum
<= frames_count
; framenum
++) {
1968 fdata
= frame_data_sequence_find(cf
->provider
.frames
, framenum
);
1969 frame_data_reset(fdata
);
1973 /* We're done filtering the packets; destroy the progress bar if it
1975 if (progbar
!= NULL
)
1976 destroy_progress_dlg(progbar
);
1977 g_timer_destroy(prog_timer
);
1979 /* Unfreeze the packet list. */
1980 if (!add_to_packet_list
)
1981 packet_list_recreate_visible_rows();
1983 /* Compute the time it took to filter the file */
1984 compute_elapsed(cf
, start_time
);
1988 /* It is safe again to execute redissections or sort. */
1989 ws_assert(cf
->read_lock
);
1990 cf
->read_lock
= false;
1992 cf_callback_invoke(cf_cb_file_rescan_finished
, cf
);
1994 if (selected_frame_num
== -1) {
1995 /* The selected frame didn't pass the filter. */
1996 if (selected_frame
== NULL
) {
1997 /* That's because there *was* no selected frame. Make the first
1998 displayed frame the current frame. */
1999 selected_frame_num
= 0;
2001 /* Find the nearest displayed frame to the selected frame (whether
2002 it's before or after that frame) and make that the current frame.
2003 If the next and previous displayed frames are equidistant from the
2004 selected frame, choose the next one. */
2005 ws_assert(following_frame
== NULL
||
2006 following_frame
->num
>= selected_frame
->num
);
2007 ws_assert(preceding_frame
== NULL
||
2008 preceding_frame
->num
<= selected_frame
->num
);
2009 if (following_frame
== NULL
) {
2010 /* No frame after the selected frame passed the filter, so we
2011 have to select the last displayed frame before the selected
2013 selected_frame_num
= preceding_frame_num
;
2014 selected_frame
= preceding_frame
;
2015 } else if (preceding_frame
== NULL
) {
2016 /* No frame before the selected frame passed the filter, so we
2017 have to select the first displayed frame after the selected
2019 selected_frame_num
= following_frame_num
;
2020 selected_frame
= following_frame
;
2022 /* Frames before and after the selected frame passed the filter, so
2023 we'll select the previous frame */
2024 selected_frame_num
= preceding_frame_num
;
2025 selected_frame
= preceding_frame
;
2030 if (selected_frame_num
== -1) {
2031 /* There are no frames displayed at all. */
2032 cf_unselect_packet(cf
);
2034 /* Either the frame that was selected passed the filter, or we've
2035 found the nearest displayed frame to that frame. Select it, make
2036 it the focus row, and make it visible. */
2037 /* Set to invalid to force update of packet list and packet details */
2038 if (selected_frame_num
== 0) {
2039 packet_list_select_row_from_data(NULL
);
2041 if (!packet_list_select_row_from_data(selected_frame
)) {
2042 /* We didn't find a row corresponding to this frame.
2043 This means that the frame isn't being displayed currently,
2044 so we can't select it. */
2045 simple_message_box(ESD_TYPE_INFO
, NULL
,
2046 "The capture file is probably not fully dissected.",
2047 "End of capture exceeded.");
2052 /* If another rescan (due to dfilter change) or redissection (due to profile
2053 * change) was requested, the rescan above is aborted and restarted here. */
2054 if (queued_rescan_type
!= RESCAN_NONE
) {
2055 redissect
= redissect
|| queued_rescan_type
== RESCAN_REDISSECT
;
2056 rescan_packets(cf
, "Reprocessing", "all packets", redissect
);
2062 * Scan through all frame data and recalculate the ref time
2063 * without rereading the file.
2064 * XXX - do we need a progress bar or is this fast enough?
2067 cf_reftime_packets(capture_file
* cf
)
2073 cf
->provider
.ref
= NULL
;
2074 cf
->provider
.prev_dis
= NULL
;
2077 for (framenum
= 1; framenum
<= cf
->count
; framenum
++) {
2078 fdata
= frame_data_sequence_find(cf
->provider
.frames
, framenum
);
2080 /* just add some value here until we know if it is being displayed or not */
2081 fdata
->cum_bytes
= cf
->cum_bytes
+ fdata
->pkt_len
;
2087 if (fdata
->has_ts
) {
2088 /* If we don't have the time stamp of the first packet in the
2089 capture, it's because this is the first packet. Save the time
2090 stamp of this packet as the time stamp of the first packet. */
2091 if (cf
->provider
.ref
== NULL
)
2092 cf
->provider
.ref
= fdata
;
2093 /* if this frames is marked as a reference time frame, reset
2094 firstsec and firstusec to this frame */
2095 if (fdata
->ref_time
)
2096 cf
->provider
.ref
= fdata
;
2098 /* Get the time elapsed between the first packet and this one. */
2099 fdata
->frame_ref_num
= (fdata
!= cf
->provider
.ref
) ? cf
->provider
.ref
->num
: 0;
2100 nstime_delta(&rel_ts
, &fdata
->abs_ts
, &cf
->provider
.ref
->abs_ts
);
2102 /* If it's greater than the current elapsed time, set the elapsed
2103 time to it (we check for "greater than" so as not to be
2104 confused by time moving backwards). */
2105 if (nstime_cmp(&cf
->elapsed_time
, &rel_ts
) < 0) {
2106 cf
->elapsed_time
= rel_ts
;
2109 /* If this frame is displayed, get the time elapsed between the
2110 previous displayed packet and this packet. */
2111 /* XXX: What if in the future we want to use the previously
2112 * displayed frame for something else, too? Then we'd want
2113 * to store this frame as prev_dis even if it doesn't have a
2115 if ( fdata
->passed_dfilter
) {
2116 /* If we don't have the time stamp of the previous displayed
2117 packet, it's because this is the first displayed packet.
2118 Save the time stamp of this packet as the time stamp of
2119 the previous displayed packet. */
2120 if (cf
->provider
.prev_dis
== NULL
) {
2121 cf
->provider
.prev_dis
= fdata
;
2124 fdata
->prev_dis_num
= cf
->provider
.prev_dis
->num
;
2125 cf
->provider
.prev_dis
= fdata
;
2128 /* If this frame doesn't have a timestamp, don't calculate
2129 anything with relative times. */
2130 /* However, if this frame is marked as a reference time frame,
2131 clear the reference frame so that the next frame with a
2132 timestamp becomes the reference frame. */
2133 if (fdata
->ref_time
) {
2134 cf
->provider
.ref
= NULL
;
2141 if ( (fdata
->passed_dfilter
) || (fdata
->ref_time
) ) {
2142 /* This frame either passed the display filter list or is marked as
2143 a time reference frame. All time reference frames are displayed
2144 even if they don't pass the display filter */
2145 if (fdata
->ref_time
) {
2146 /* if this was a TIME REF frame we should reset the cum_bytes field */
2147 cf
->cum_bytes
= fdata
->pkt_len
;
2148 fdata
->cum_bytes
= cf
->cum_bytes
;
2150 /* increase cum_bytes with this packets length */
2151 cf
->cum_bytes
+= fdata
->pkt_len
;
2164 process_specified_records(capture_file
*cf
, packet_range_t
*range
,
2165 const char *string1
, const char *string2
, bool terminate_is_stop
,
2166 bool (*callback
)(capture_file
*, frame_data
*,
2167 wtap_rec
*, void *),
2168 void *callback_args
,
2169 bool show_progress_bar
)
2174 psp_return_t ret
= PSP_FINISHED
;
2176 progdlg_t
*progbar
= NULL
;
2177 GTimer
*prog_timer
= g_timer_new();
2180 char progbar_status_str
[100];
2181 range_process_e process_this
;
2183 wtap_rec_init(&rec
, 1514);
2185 g_timer_start(prog_timer
);
2186 /* Count of packets at which we've looked. */
2188 /* Progress so far. */
2191 /* XXX - It should be ok to have multiple readers, so long as nothing
2192 * frees the epan context, e.g. rescan_packets with redissect true,
2193 * or anything that closes the file (including reload and certain forms
2194 * of saving.) This is mostly to stop cf_save_records but should probably
2195 * be handled by callers in order to allow multiple readers (e.g.,
2196 * restarting taps after adding or changing one.) We should probably
2197 * make this a real reader-writer lock.
2199 if (cf
->read_lock
) {
2200 ws_warning("Failing due to nested process_specified_records(\"%s\") call!", cf
->filename
);
2203 cf
->read_lock
= true;
2205 cf
->stop_flag
= false;
2208 packet_range_process_init(range
);
2210 /* Iterate through all the packets, printing the packets that
2211 were selected by the current display filter. */
2212 for (framenum
= 1; framenum
<= cf
->count
; framenum
++) {
2213 fdata
= frame_data_sequence_find(cf
->provider
.frames
, framenum
);
2215 /* Create the progress bar if necessary.
2216 We check on every iteration of the loop, so that it takes no
2217 longer than the standard time to create it (otherwise, for a
2218 large file, we might take considerably longer than that standard
2219 time in order to get to the next progress bar step). */
2220 if (show_progress_bar
&& progbar
== NULL
)
2221 progbar
= delayed_create_progress_dlg(cf
->window
, string1
, string2
,
2227 * Update the progress bar, but do it only after PROGBAR_UPDATE_INTERVAL
2228 * has elapsed. Calling update_progress_dlg and packets_bar_update will
2229 * likely trigger UI paint events, which might take a while depending on
2230 * the platform and display. Reset our timer *after* painting.
2232 if (progbar
&& g_timer_elapsed(prog_timer
, NULL
) > PROGBAR_UPDATE_INTERVAL
) {
2233 /* let's not divide by zero. I should never be started
2234 * with count == 0, so let's assert that
2236 ws_assert(cf
->count
> 0);
2237 progbar_val
= (float) progbar_count
/ cf
->count
;
2239 snprintf(progbar_status_str
, sizeof(progbar_status_str
),
2240 "%4u of %u packets", progbar_count
, cf
->count
);
2241 update_progress_dlg(progbar
, progbar_val
, progbar_status_str
);
2243 g_timer_start(prog_timer
);
2246 if (cf
->stop_flag
) {
2247 /* Well, the user decided to abort the operation. Just stop,
2248 and arrange to return PSP_STOPPED to our caller, so they know
2249 it was stopped explicitly. */
2256 if (range
!= NULL
) {
2257 /* do we have to process this packet? */
2258 process_this
= packet_range_process_packet(range
, fdata
);
2259 if (process_this
== range_process_next
) {
2260 /* this packet uninteresting, continue with next one */
2262 } else if (process_this
== range_processing_finished
) {
2263 /* all interesting packets processed, stop the loop */
2268 /* Get the packet */
2269 if (!cf_read_record(cf
, fdata
, &rec
)) {
2270 /* Attempt to get the packet failed. */
2274 /* Process the packet */
2275 if (!callback(cf
, fdata
, &rec
, callback_args
)) {
2276 /* Callback failed. We assume it reported the error appropriately. */
2280 wtap_rec_reset(&rec
);
2283 /* We're done printing the packets; destroy the progress bar if
2285 if (progbar
!= NULL
)
2286 destroy_progress_dlg(progbar
);
2287 g_timer_destroy(prog_timer
);
2289 ws_assert(cf
->read_lock
);
2290 cf
->read_lock
= false;
2292 wtap_rec_cleanup(&rec
);
2300 } retap_callback_args_t
;
2303 retap_packet(capture_file
*cf
, frame_data
*fdata
, wtap_rec
*rec
, void *argsp
)
2305 retap_callback_args_t
*args
= (retap_callback_args_t
*)argsp
;
2307 epan_dissect_run_with_taps(&args
->edt
, cf
->cd_t
, rec
, fdata
, args
->cinfo
);
2308 epan_dissect_reset(&args
->edt
);
2314 cf_retap_packets(capture_file
*cf
)
2316 packet_range_t range
;
2317 retap_callback_args_t callback_args
;
2318 bool create_proto_tree
;
2319 bool filtering_tap_listeners
;
2323 /* Presumably the user closed the capture file. */
2325 return CF_READ_ABORTED
;
2328 /* XXX - If cf->read_lock is true, process_specified_records will fail
2329 * due to a nested call. We fail here so that we don't reset the tap
2330 * listeners if this tap isn't going to succeed.
2332 if (cf
->read_lock
) {
2333 ws_warning("Failing due to nested process_specified_records(\"%s\") call!", cf
->filename
);
2334 return CF_READ_ERROR
;
2337 cf_callback_invoke(cf_cb_file_retap_started
, cf
);
2339 /* Do we have any tap listeners with filters? */
2340 filtering_tap_listeners
= have_filtering_tap_listeners();
2342 /* Update references in filters (if any) for the protocol
2343 * tree corresponding to the currently selected frame in the GUI. */
2344 /* XXX - What if we *don't* have a currently selected frame in the GUI,
2345 * but we did the last time we loaded field references? Then they'll
2346 * match something instead of nothing (unless they've been recompiled).
2347 * Should we have a way to clear the field references even with a NULL tree?
2349 if (cf
->edt
!= NULL
&& cf
->edt
->tree
!= NULL
) {
2350 if (filtering_tap_listeners
)
2351 tap_listeners_load_field_references(cf
->edt
);
2354 /* Get the union of the flags for all tap listeners. */
2355 tap_flags
= union_of_tap_listener_flags();
2357 /* If any tap listeners require the columns, construct them. */
2358 callback_args
.cinfo
= (tap_listeners_require_columns()) ? &cf
->cinfo
: NULL
;
2361 * Determine whether we need to create a protocol tree.
2364 * one of the tap listeners is going to apply a filter;
2366 * one of the tap listeners requires a protocol tree.
2369 (filtering_tap_listeners
|| (tap_flags
& TL_REQUIRES_PROTO_TREE
));
2371 /* Reset the tap listeners. */
2372 reset_tap_listeners();
2373 uint32_t count
= cf
->count
;
2375 epan_dissect_init(&callback_args
.edt
, cf
->epan
, create_proto_tree
, false);
2377 /* Iterate through the list of packets, dissecting all packets and
2378 re-running the taps. */
2379 packet_range_init(&range
, cf
);
2380 packet_range_process_init(&range
);
2382 if (cf
->state
== FILE_READ_IN_PROGRESS
) {
2383 /* We're not done with the sequential read of the file and might
2384 * add more frames while process_specified_records is going. We
2385 * don't want to tap new frames twice, so limit the range to the
2386 * frames already here.
2388 * cf_read sets read_lock so we don't tap in case of an offline
2389 * file, but cf_continue_tail and cf_finish_tail don't, and we
2390 * don't want them to, because tapping new packets in a live
2391 * capture is a common use case.
2393 * Note that most other users of process_specified_records (saving,
2394 * printing) do want to process new packets, unlike taps.
2397 char* range_str
= g_strdup_printf("-%u", count
);
2398 packet_range_convert_str(&range
, range_str
);
2401 /* range_t treats a missing number as meaning 1, not 0, and
2402 * reverses the order if backwards; thus the syntax -0 means
2403 * 0-1, so to only take zero packets we do this.
2405 packet_range_convert_str(&range
, "0");
2407 range
.process
= range_process_user_range
;
2410 ret
= process_specified_records(cf
, &range
, "Recalculating statistics on",
2411 "all packets", true, retap_packet
,
2412 &callback_args
, true);
2414 packet_range_cleanup(&range
);
2415 epan_dissect_cleanup(&callback_args
.edt
);
2417 cf_callback_invoke(cf_cb_file_retap_finished
, cf
);
2421 /* Completed successfully. */
2425 /* Well, the user decided to abort the refiltering.
2426 Return CF_READ_ABORTED so our caller knows they did that. */
2427 return CF_READ_ABORTED
;
2430 /* Error while retapping. */
2431 return CF_READ_ERROR
;
2434 ws_assert_not_reached();
2439 print_args_t
*print_args
;
2440 bool print_header_line
;
2441 char *header_line_buf
;
2442 int header_line_buf_len
;
2443 bool print_formfeed
;
2444 bool print_separator
;
2448 int num_visible_cols
;
2451 } print_callback_args_t
;
2454 print_packet(capture_file
*cf
, frame_data
*fdata
, wtap_rec
*rec
, void *argsp
)
2456 print_callback_args_t
*args
= (print_callback_args_t
*)argsp
;
2462 char bookmark_name
[9+10+1]; /* "__frameNNNNNNNNNN__\0" */
2463 char bookmark_title
[6+10+1]; /* "Frame NNNNNNNNNN__\0" */
2464 col_item_t
* col_item
;
2465 const char* col_text
;
2467 /* Fill in the column information if we're printing the summary
2469 if (args
->print_args
->print_summary
) {
2470 col_custom_prime_edt(&args
->edt
, &cf
->cinfo
);
2471 epan_dissect_run(&args
->edt
, cf
->cd_t
, rec
, fdata
, &cf
->cinfo
);
2472 epan_dissect_fill_in_columns(&args
->edt
, false, true);
2474 epan_dissect_run(&args
->edt
, cf
->cd_t
, rec
, fdata
, NULL
);
2476 if (args
->print_formfeed
) {
2477 if (!new_page(args
->print_args
->stream
))
2481 * Print another header line if we print a packet summary on the
2484 if (args
->print_args
->print_col_headings
)
2485 args
->print_header_line
= true;
2487 if (args
->print_separator
) {
2488 if (!print_line(args
->print_args
->stream
, 0, ""))
2494 * We generate bookmarks, if the output format supports them.
2495 * The name is "__frameN__".
2497 snprintf(bookmark_name
, sizeof bookmark_name
, "__frame%u__", fdata
->num
);
2499 if (args
->print_args
->print_summary
) {
2500 if (!args
->print_args
->print_col_headings
)
2501 args
->print_header_line
= false;
2502 if (args
->print_header_line
) {
2503 if (!print_line(args
->print_args
->stream
, 0, args
->header_line_buf
))
2505 args
->print_header_line
= false; /* we might not need to print any more */
2507 cp
= &args
->line_buf
[0];
2509 for (i
= 0; i
< args
->num_visible_cols
; i
++) {
2510 col_item
= &cf
->cinfo
.columns
[args
->visible_cols
[i
]];
2511 col_text
= get_column_text(&cf
->cinfo
, args
->visible_cols
[i
]);
2512 /* Find the length of the string for this column. */
2513 column_len
= (int) strlen(col_text
);
2514 if (args
->col_widths
[i
] > column_len
)
2515 column_len
= args
->col_widths
[i
];
2517 /* Make sure there's room in the line buffer for the column; if not,
2518 double its length. */
2519 line_len
+= column_len
+ 1; /* "+1" for space */
2520 if (line_len
> args
->line_buf_len
) {
2521 cp_off
= (int) (cp
- args
->line_buf
);
2522 args
->line_buf_len
= 2 * line_len
;
2523 args
->line_buf
= (char *)g_realloc(args
->line_buf
, args
->line_buf_len
+ 1);
2524 cp
= args
->line_buf
+ cp_off
;
2527 /* Right-justify the packet number column. */
2528 if (col_item
->col_fmt
== COL_NUMBER
|| col_item
->col_fmt
== COL_NUMBER_DIS
)
2529 snprintf(cp
, column_len
+1, "%*s", args
->col_widths
[i
], col_text
);
2531 snprintf(cp
, column_len
+1, "%-*s", args
->col_widths
[i
], col_text
);
2533 if (i
!= args
->num_visible_cols
- 1)
2539 * Generate a bookmark, using the summary line as the title.
2541 if (!print_bookmark(args
->print_args
->stream
, bookmark_name
,
2545 if (!print_line(args
->print_args
->stream
, 0, args
->line_buf
))
2549 * Generate a bookmark, using "Frame N" as the title, as we're not
2550 * printing the summary line.
2552 snprintf(bookmark_title
, sizeof bookmark_title
, "Frame %u", fdata
->num
);
2553 if (!print_bookmark(args
->print_args
->stream
, bookmark_name
,
2556 } /* if (print_summary) */
2558 if (args
->print_args
->print_dissections
!= print_dissections_none
) {
2559 if (args
->print_args
->print_summary
) {
2560 /* Separate the summary line from the tree with a blank line. */
2561 if (!print_line(args
->print_args
->stream
, 0, ""))
2565 /* Print the information in that tree. */
2566 if (!proto_tree_print(args
->print_args
->print_dissections
,
2567 args
->print_args
->print_hex
, &args
->edt
, NULL
,
2568 args
->print_args
->stream
))
2571 /* Print a blank line if we print anything after this (aka more than one packet). */
2572 args
->print_separator
= true;
2574 /* Print a header line if we print any more packet summaries */
2575 if (args
->print_args
->print_col_headings
)
2576 args
->print_header_line
= true;
2579 if (args
->print_args
->print_hex
) {
2580 if (args
->print_args
->print_summary
|| (args
->print_args
->print_dissections
!= print_dissections_none
)) {
2581 if (!print_line(args
->print_args
->stream
, 0, ""))
2584 /* Print the full packet data as hex. */
2585 if (!print_hex_data(args
->print_args
->stream
, &args
->edt
, args
->print_args
->hexdump_options
))
2588 /* Print a blank line if we print anything after this (aka more than one packet). */
2589 args
->print_separator
= true;
2591 /* Print a header line if we print any more packet summaries */
2592 if (args
->print_args
->print_col_headings
)
2593 args
->print_header_line
= true;
2594 } /* if (args->print_args->print_dissections != print_dissections_none) */
2596 epan_dissect_reset(&args
->edt
);
2598 /* do we want to have a formfeed between each packet from now on? */
2599 if (args
->print_args
->print_formfeed
) {
2600 args
->print_formfeed
= true;
2606 epan_dissect_reset(&args
->edt
);
2611 cf_print_packets(capture_file
*cf
, print_args_t
*print_args
,
2612 bool show_progress_bar
)
2614 print_callback_args_t callback_args
;
2617 int i
, cp_off
, column_len
, line_len
;
2618 int num_visible_col
= 0, last_visible_col
= 0, visible_col_count
;
2622 bool proto_tree_needed
;
2624 callback_args
.print_args
= print_args
;
2625 callback_args
.print_header_line
= print_args
->print_col_headings
;
2626 callback_args
.header_line_buf
= NULL
;
2627 callback_args
.header_line_buf_len
= 256;
2628 callback_args
.print_formfeed
= false;
2629 callback_args
.print_separator
= false;
2630 callback_args
.line_buf
= NULL
;
2631 callback_args
.line_buf_len
= 256;
2632 callback_args
.col_widths
= NULL
;
2633 callback_args
.num_visible_cols
= 0;
2634 callback_args
.visible_cols
= NULL
;
2636 if (!print_preamble(print_args
->stream
, cf
->filename
, get_ws_vcs_version_info())) {
2637 destroy_print_stream(print_args
->stream
);
2638 return CF_PRINT_WRITE_ERROR
;
2641 if (print_args
->print_summary
) {
2642 /* We're printing packet summaries. Allocate the header line buffer
2643 and get the column widths. */
2644 callback_args
.header_line_buf
= (char *)g_malloc(callback_args
.header_line_buf_len
+ 1);
2646 /* Find the number of visible columns and the last visible column */
2647 for (i
= 0; i
< prefs
.num_cols
; i
++) {
2649 clp
= g_list_nth(prefs
.col_list
, i
);
2650 if (clp
== NULL
) /* Sanity check, Invalid column requested */
2653 cfmt
= (fmt_data
*) clp
->data
;
2654 if (cfmt
->visible
) {
2656 last_visible_col
= i
;
2660 /* if num_visible_col is 0, we are done */
2661 if (num_visible_col
== 0) {
2662 g_free(callback_args
.header_line_buf
);
2666 /* Find the widths for each of the columns - maximum of the
2667 width of the title and the width of the data - and construct
2668 a buffer with a line containing the column titles. */
2669 callback_args
.num_visible_cols
= num_visible_col
;
2670 callback_args
.col_widths
= g_new(int, num_visible_col
);
2671 callback_args
.visible_cols
= g_new(int, num_visible_col
);
2672 cp
= &callback_args
.header_line_buf
[0];
2674 visible_col_count
= 0;
2675 for (i
= 0; i
< cf
->cinfo
.num_cols
; i
++) {
2677 clp
= g_list_nth(prefs
.col_list
, i
);
2678 if (clp
== NULL
) /* Sanity check, Invalid column requested */
2681 cfmt
= (fmt_data
*) clp
->data
;
2682 if (cfmt
->visible
== false)
2685 /* Save the order of visible columns */
2686 callback_args
.visible_cols
[visible_col_count
] = i
;
2688 /* Don't pad the last column. */
2689 if (i
== last_visible_col
)
2690 callback_args
.col_widths
[visible_col_count
] = 0;
2692 callback_args
.col_widths
[visible_col_count
] = (int) strlen(cf
->cinfo
.columns
[i
].col_title
);
2693 data_width
= get_column_char_width(get_column_format(i
));
2694 if (data_width
> callback_args
.col_widths
[visible_col_count
])
2695 callback_args
.col_widths
[visible_col_count
] = data_width
;
2698 /* Find the length of the string for this column. */
2699 column_len
= (int) strlen(cf
->cinfo
.columns
[i
].col_title
);
2700 if (callback_args
.col_widths
[visible_col_count
] > column_len
)
2701 column_len
= callback_args
.col_widths
[visible_col_count
];
2703 /* Make sure there's room in the line buffer for the column; if not,
2704 double its length. */
2705 line_len
+= column_len
+ 1; /* "+1" for space */
2706 if (line_len
> callback_args
.header_line_buf_len
) {
2707 cp_off
= (int) (cp
- callback_args
.header_line_buf
);
2708 callback_args
.header_line_buf_len
= 2 * line_len
;
2709 callback_args
.header_line_buf
= (char *)g_realloc(callback_args
.header_line_buf
,
2710 callback_args
.header_line_buf_len
+ 1);
2711 cp
= callback_args
.header_line_buf
+ cp_off
;
2714 /* Right-justify the packet number column. */
2715 /* if (cf->cinfo.col_fmt[i] == COL_NUMBER || cf->cinfo.col_fmt[i] == COL_NUMBER_DIS)
2716 snprintf(cp, column_len+1, "%*s", callback_args.col_widths[visible_col_count], cf->cinfo.columns[i].col_title);
2718 snprintf(cp
, column_len
+1, "%-*s", callback_args
.col_widths
[visible_col_count
], cf
->cinfo
.columns
[i
].col_title
);
2720 if (i
!= cf
->cinfo
.num_cols
- 1)
2723 visible_col_count
++;
2727 /* Now start out the main line buffer with the same length as the
2728 header line buffer. */
2729 callback_args
.line_buf_len
= callback_args
.header_line_buf_len
;
2730 callback_args
.line_buf
= (char *)g_malloc(callback_args
.line_buf_len
+ 1);
2731 } /* if (print_summary) */
2733 /* Create the protocol tree, and make it visible, if we're printing
2734 the dissection or the hex data.
2735 XXX - do we need it if we're just printing the hex data? */
2737 callback_args
.print_args
->print_dissections
!= print_dissections_none
||
2738 callback_args
.print_args
->print_hex
||
2739 have_custom_cols(&cf
->cinfo
) || have_field_extractors();
2740 epan_dissect_init(&callback_args
.edt
, cf
->epan
, proto_tree_needed
, proto_tree_needed
);
2742 /* Iterate through the list of packets, printing the packets we were
2744 ret
= process_specified_records(cf
, &print_args
->range
, "Printing",
2745 "selected packets", true, print_packet
,
2746 &callback_args
, show_progress_bar
);
2747 epan_dissect_cleanup(&callback_args
.edt
);
2748 g_free(callback_args
.header_line_buf
);
2749 g_free(callback_args
.line_buf
);
2750 g_free(callback_args
.col_widths
);
2751 g_free(callback_args
.visible_cols
);
2756 /* Completed successfully. */
2760 /* Well, the user decided to abort the printing.
2762 XXX - note that what got generated before they did that
2763 will get printed if we're piping to a print program; we'd
2764 have to write to a file and then hand that to the print
2765 program to make it actually not print anything. */
2769 /* Error while printing.
2771 XXX - note that what got generated before they did that
2772 will get printed if we're piping to a print program; we'd
2773 have to write to a file and then hand that to the print
2774 program to make it actually not print anything. */
2775 destroy_print_stream(print_args
->stream
);
2776 return CF_PRINT_WRITE_ERROR
;
2779 if (!print_finale(print_args
->stream
)) {
2780 destroy_print_stream(print_args
->stream
);
2781 return CF_PRINT_WRITE_ERROR
;
2784 if (!destroy_print_stream(print_args
->stream
))
2785 return CF_PRINT_WRITE_ERROR
;
2793 print_args_t
*print_args
;
2794 json_dumper jdumper
;
2795 } write_packet_callback_args_t
;
2798 write_pdml_packet(capture_file
*cf
, frame_data
*fdata
, wtap_rec
*rec
,
2801 write_packet_callback_args_t
*args
= (write_packet_callback_args_t
*)argsp
;
2803 /* Create the protocol tree, but don't fill in the column information. */
2804 epan_dissect_run(&args
->edt
, cf
->cd_t
, rec
, fdata
, NULL
);
2806 /* Write out the information in that tree. */
2807 write_pdml_proto_tree(NULL
, &args
->edt
, &cf
->cinfo
, args
->fh
, false);
2809 epan_dissect_reset(&args
->edt
);
2811 return !ferror(args
->fh
);
2815 cf_write_pdml_packets(capture_file
*cf
, print_args_t
*print_args
)
2817 write_packet_callback_args_t callback_args
;
2821 fh
= ws_fopen(print_args
->file
, "w");
2823 return CF_PRINT_OPEN_ERROR
; /* attempt to open destination failed */
2825 write_pdml_preamble(fh
, cf
->filename
);
2828 return CF_PRINT_WRITE_ERROR
;
2831 callback_args
.fh
= fh
;
2832 callback_args
.print_args
= print_args
;
2833 epan_dissect_init(&callback_args
.edt
, cf
->epan
, true, true);
2835 /* Iterate through the list of packets, printing the packets we were
2837 ret
= process_specified_records(cf
, &print_args
->range
, "Writing PDML",
2838 "selected packets", true,
2839 write_pdml_packet
, &callback_args
, true);
2841 epan_dissect_cleanup(&callback_args
.edt
);
2846 /* Completed successfully. */
2850 /* Well, the user decided to abort the printing. */
2854 /* Error while printing. */
2856 return CF_PRINT_WRITE_ERROR
;
2859 write_pdml_finale(fh
);
2862 return CF_PRINT_WRITE_ERROR
;
2865 /* XXX - check for an error */
2872 write_psml_packet(capture_file
*cf
, frame_data
*fdata
, wtap_rec
*rec
,
2875 write_packet_callback_args_t
*args
= (write_packet_callback_args_t
*)argsp
;
2877 /* Fill in the column information */
2878 col_custom_prime_edt(&args
->edt
, &cf
->cinfo
);
2879 epan_dissect_run(&args
->edt
, cf
->cd_t
, rec
, fdata
, &cf
->cinfo
);
2880 epan_dissect_fill_in_columns(&args
->edt
, false, true);
2882 /* Write out the column information. */
2883 write_psml_columns(&args
->edt
, args
->fh
, false);
2885 epan_dissect_reset(&args
->edt
);
2887 return !ferror(args
->fh
);
2891 cf_write_psml_packets(capture_file
*cf
, print_args_t
*print_args
)
2893 write_packet_callback_args_t callback_args
;
2897 bool proto_tree_needed
;
2899 fh
= ws_fopen(print_args
->file
, "w");
2901 return CF_PRINT_OPEN_ERROR
; /* attempt to open destination failed */
2903 write_psml_preamble(&cf
->cinfo
, fh
);
2906 return CF_PRINT_WRITE_ERROR
;
2909 callback_args
.fh
= fh
;
2910 callback_args
.print_args
= print_args
;
2912 /* Fill in the column information, only create the protocol tree
2913 if having custom columns or field extractors. */
2914 proto_tree_needed
= have_custom_cols(&cf
->cinfo
) || have_field_extractors();
2915 epan_dissect_init(&callback_args
.edt
, cf
->epan
, proto_tree_needed
, proto_tree_needed
);
2917 /* Iterate through the list of packets, printing the packets we were
2919 ret
= process_specified_records(cf
, &print_args
->range
, "Writing PSML",
2920 "selected packets", true,
2921 write_psml_packet
, &callback_args
, true);
2923 epan_dissect_cleanup(&callback_args
.edt
);
2928 /* Completed successfully. */
2932 /* Well, the user decided to abort the printing. */
2936 /* Error while printing. */
2938 return CF_PRINT_WRITE_ERROR
;
2941 write_psml_finale(fh
);
2944 return CF_PRINT_WRITE_ERROR
;
2947 /* XXX - check for an error */
2954 write_csv_packet(capture_file
*cf
, frame_data
*fdata
, wtap_rec
*rec
,
2957 write_packet_callback_args_t
*args
= (write_packet_callback_args_t
*)argsp
;
2959 col_custom_prime_edt(&args
->edt
, &cf
->cinfo
);
2960 epan_dissect_run(&args
->edt
, cf
->cd_t
, rec
, fdata
, &cf
->cinfo
);
2961 epan_dissect_fill_in_columns(&args
->edt
, false, true);
2963 /* Write out the column information. */
2964 write_csv_columns(&args
->edt
, args
->fh
);
2966 epan_dissect_reset(&args
->edt
);
2968 return !ferror(args
->fh
);
2972 cf_write_csv_packets(capture_file
*cf
, print_args_t
*print_args
)
2974 write_packet_callback_args_t callback_args
;
2975 bool proto_tree_needed
;
2979 fh
= ws_fopen(print_args
->file
, "w");
2981 return CF_PRINT_OPEN_ERROR
; /* attempt to open destination failed */
2983 write_csv_column_titles(&cf
->cinfo
, fh
);
2986 return CF_PRINT_WRITE_ERROR
;
2989 callback_args
.fh
= fh
;
2990 callback_args
.print_args
= print_args
;
2992 /* only create the protocol tree if having custom columns or field extractors. */
2993 proto_tree_needed
= have_custom_cols(&cf
->cinfo
) || have_field_extractors();
2994 epan_dissect_init(&callback_args
.edt
, cf
->epan
, proto_tree_needed
, proto_tree_needed
);
2996 /* Iterate through the list of packets, printing the packets we were
2998 ret
= process_specified_records(cf
, &print_args
->range
, "Writing CSV",
2999 "selected packets", true,
3000 write_csv_packet
, &callback_args
, true);
3002 epan_dissect_cleanup(&callback_args
.edt
);
3007 /* Completed successfully. */
3011 /* Well, the user decided to abort the printing. */
3015 /* Error while printing. */
3017 return CF_PRINT_WRITE_ERROR
;
3020 /* XXX - check for an error */
3027 carrays_write_packet(capture_file
*cf
, frame_data
*fdata
, wtap_rec
*rec
,
3030 write_packet_callback_args_t
*args
= (write_packet_callback_args_t
*)argsp
;
3032 epan_dissect_run(&args
->edt
, cf
->cd_t
, rec
, fdata
, NULL
);
3033 write_carrays_hex_data(fdata
->num
, args
->fh
, &args
->edt
);
3034 epan_dissect_reset(&args
->edt
);
3036 return !ferror(args
->fh
);
3040 cf_write_carrays_packets(capture_file
*cf
, print_args_t
*print_args
)
3042 write_packet_callback_args_t callback_args
;
3046 fh
= ws_fopen(print_args
->file
, "w");
3049 return CF_PRINT_OPEN_ERROR
; /* attempt to open destination failed */
3053 return CF_PRINT_WRITE_ERROR
;
3056 callback_args
.fh
= fh
;
3057 callback_args
.print_args
= print_args
;
3058 epan_dissect_init(&callback_args
.edt
, cf
->epan
, true, true);
3060 /* Iterate through the list of packets, printing the packets we were
3062 ret
= process_specified_records(cf
, &print_args
->range
,
3064 "selected packets", true,
3065 carrays_write_packet
, &callback_args
, true);
3067 epan_dissect_cleanup(&callback_args
.edt
);
3071 /* Completed successfully. */
3074 /* Well, the user decided to abort the printing. */
3077 /* Error while printing. */
3079 return CF_PRINT_WRITE_ERROR
;
3087 write_json_packet(capture_file
*cf
, frame_data
*fdata
, wtap_rec
*rec
,
3090 write_packet_callback_args_t
*args
= (write_packet_callback_args_t
*)argsp
;
3092 /* Create the protocol tree, but don't fill in the column information. */
3093 epan_dissect_run(&args
->edt
, cf
->cd_t
, rec
, fdata
, NULL
);
3095 /* Write out the information in that tree. */
3096 write_json_proto_tree(NULL
, args
->print_args
->print_dissections
,
3097 args
->print_args
->print_hex
,
3098 &args
->edt
, &cf
->cinfo
, proto_node_group_children_by_unique
,
3101 epan_dissect_reset(&args
->edt
);
3103 return !ferror(args
->fh
);
3107 cf_write_json_packets(capture_file
*cf
, print_args_t
*print_args
)
3109 write_packet_callback_args_t callback_args
;
3113 fh
= ws_fopen(print_args
->file
, "w");
3115 return CF_PRINT_OPEN_ERROR
; /* attempt to open destination failed */
3117 callback_args
.jdumper
= write_json_preamble(fh
);
3120 return CF_PRINT_WRITE_ERROR
;
3123 callback_args
.fh
= fh
;
3124 callback_args
.print_args
= print_args
;
3125 epan_dissect_init(&callback_args
.edt
, cf
->epan
, true, true);
3127 /* Iterate through the list of packets, printing the packets we were
3129 ret
= process_specified_records(cf
, &print_args
->range
, "Writing JSON",
3130 "selected packets", true,
3131 write_json_packet
, &callback_args
, true);
3133 epan_dissect_cleanup(&callback_args
.edt
);
3138 /* Completed successfully. */
3142 /* Well, the user decided to abort the printing. */
3146 /* Error while printing. */
3148 return CF_PRINT_WRITE_ERROR
;
3151 write_json_finale(&callback_args
.jdumper
);
3154 return CF_PRINT_WRITE_ERROR
;
3157 /* XXX - check for an error */
3164 cf_find_packet_protocol_tree(capture_file
*cf
, const char *string
,
3165 search_direction dir
, bool multiple
)
3169 mdata
.frame_matched
= false;
3171 mdata
.string
= string
;
3172 mdata
.string_len
= strlen(string
);
3174 mdata
.prev_finfo
= cf
->finfo_selected
;
3175 if (multiple
&& cf
->finfo_selected
&& cf
->edt
) {
3176 if (dir
== SD_FORWARD
) {
3177 proto_tree_children_foreach(cf
->edt
->tree
, match_subtree_text
, &mdata
);
3179 proto_tree_children_foreach(cf
->edt
->tree
, match_subtree_text_reverse
, &mdata
);
3181 if (mdata
.frame_matched
) {
3182 packet_list_select_finfo(mdata
.finfo
);
3186 return find_packet(cf
, match_protocol_tree
, &mdata
, dir
, true);
3190 cf_find_string_protocol_tree(capture_file
*cf
, proto_tree
*tree
)
3193 mdata
.frame_matched
= false;
3195 mdata
.string
= convert_string_case(cf
->sfilter
, cf
->case_type
);
3196 mdata
.string_len
= strlen(mdata
.string
);
3198 mdata
.prev_finfo
= NULL
;
3199 /* Iterate through all the nodes looking for matching text */
3200 if (cf
->dir
== SD_FORWARD
) {
3201 proto_tree_children_foreach(tree
, match_subtree_text
, &mdata
);
3203 proto_tree_children_foreach(tree
, match_subtree_text_reverse
, &mdata
);
3205 g_free((char *)mdata
.string
);
3206 return mdata
.frame_matched
? mdata
.finfo
: NULL
;
3210 match_protocol_tree(capture_file
*cf
, frame_data
*fdata
,
3211 wtap_rec
*rec
, void *criterion
)
3213 match_data
*mdata
= (match_data
*)criterion
;
3216 /* Load the frame's data. */
3217 if (!cf_read_record(cf
, fdata
, rec
)) {
3218 /* Attempt to get the packet failed. */
3222 /* Construct the protocol tree, including the displayed text */
3223 epan_dissect_init(&edt
, cf
->epan
, true, true);
3224 /* We don't need the column information */
3225 epan_dissect_run(&edt
, cf
->cd_t
, rec
, fdata
, NULL
);
3227 /* Iterate through all the nodes, seeing if they have text that matches. */
3229 mdata
->frame_matched
= false;
3230 mdata
->halt
= false;
3231 mdata
->prev_finfo
= NULL
;
3232 /* We don't care about the direction here, because we're just looking
3233 * for one match and we'll destroy this tree anyway. (We find the actual
3234 * field later in PacketList::selectionChanged().) Forwards is faster.
3236 proto_tree_children_foreach(edt
.tree
, match_subtree_text
, mdata
);
3237 epan_dissect_cleanup(&edt
);
3238 return mdata
->frame_matched
? MR_MATCHED
: MR_NOTMATCHED
;
3242 match_subtree_text(proto_node
*node
, void *data
)
3244 match_data
*mdata
= (match_data
*) data
;
3245 const char *string
= mdata
->string
;
3246 size_t string_len
= mdata
->string_len
;
3247 capture_file
*cf
= mdata
->cf
;
3248 field_info
*fi
= PNODE_FINFO(node
);
3249 char label_str
[ITEM_LABEL_LENGTH
];
3252 uint32_t i
, i_restart
;
3256 /* dissection with an invisible proto tree? */
3259 if (mdata
->frame_matched
) {
3260 /* We already had a match; don't bother doing any more work. */
3264 /* Don't match invisible entries. */
3265 if (proto_item_is_hidden(node
))
3268 if (mdata
->prev_finfo
) {
3269 /* Haven't found the old match, so don't match this node. */
3270 if (fi
== mdata
->prev_finfo
) {
3271 /* Found the old match, look for the next one after this. */
3272 mdata
->prev_finfo
= NULL
;
3275 /* was a free format label produced? */
3277 label_ptr
= fi
->rep
->representation
;
3279 /* no, make a generic label */
3280 label_ptr
= label_str
;
3281 proto_item_fill_label(fi
, label_str
, NULL
);
3285 if (ws_regex_matches(cf
->regex
, label_ptr
)) {
3286 mdata
->frame_matched
= true;
3290 } else if (cf
->case_type
) {
3291 /* Case insensitive match */
3292 label_len
= strlen(label_ptr
);
3294 for (i
= 0; i
< label_len
; i
++) {
3295 if (i_restart
== 0 && c_match
== 0 && (label_len
- i
< string_len
))
3297 c_char
= label_ptr
[i
];
3298 c_char
= g_ascii_toupper(c_char
);
3299 /* If c_match is non-zero, save candidate for retrying full match. */
3300 if (c_match
> 0 && i_restart
== 0 && c_char
== string
[0])
3302 if (c_char
== string
[c_match
]) {
3304 if (c_match
== string_len
) {
3305 mdata
->frame_matched
= true;
3307 /* No need to look further; we have a match */
3310 } else if (i_restart
) {
3317 } else if (strstr(label_ptr
, string
) != NULL
) {
3318 /* Case sensitive match */
3319 mdata
->frame_matched
= true;
3325 /* Recurse into the subtree, if it exists */
3326 if (node
->first_child
!= NULL
)
3327 proto_tree_children_foreach(node
, match_subtree_text
, mdata
);
3331 match_subtree_text_reverse(proto_node
*node
, void *data
)
3333 match_data
*mdata
= (match_data
*) data
;
3334 const char *string
= mdata
->string
;
3335 size_t string_len
= mdata
->string_len
;
3336 capture_file
*cf
= mdata
->cf
;
3337 field_info
*fi
= PNODE_FINFO(node
);
3338 char label_str
[ITEM_LABEL_LENGTH
];
3341 uint32_t i
, i_restart
;
3345 /* dissection with an invisible proto tree? */
3348 /* We don't have an easy way to search backwards in the tree
3349 * (see also, proto_find_field_from_offset()) because we don't
3350 * have a previous node pointer, so we search backwards by
3351 * searching forwards, only stopping if we see the old match
3359 /* Don't match invisible entries. */
3360 if (proto_item_is_hidden(node
))
3363 if (mdata
->prev_finfo
&& fi
== mdata
->prev_finfo
) {
3364 /* Found the old match, use the previous match. */
3369 /* was a free format label produced? */
3371 label_ptr
= fi
->rep
->representation
;
3373 /* no, make a generic label */
3374 label_ptr
= label_str
;
3375 proto_item_fill_label(fi
, label_str
, NULL
);
3379 if (ws_regex_matches(cf
->regex
, label_ptr
)) {
3380 mdata
->frame_matched
= true;
3383 } else if (cf
->case_type
) {
3384 /* Case insensitive match */
3385 label_len
= strlen(label_ptr
);
3387 for (i
= 0; i
< label_len
; i
++) {
3388 if (i_restart
== 0 && c_match
== 0 && (label_len
- i
< string_len
))
3390 c_char
= label_ptr
[i
];
3391 c_char
= g_ascii_toupper(c_char
);
3392 /* If c_match is non-zero, save candidate for retrying full match. */
3393 if (c_match
> 0 && i_restart
== 0 && c_char
== string
[0])
3395 if (c_char
== string
[c_match
]) {
3397 if (c_match
== string_len
) {
3398 mdata
->frame_matched
= true;
3402 } else if (i_restart
) {
3409 } else if (strstr(label_ptr
, string
) != NULL
) {
3410 /* Case sensitive match */
3411 mdata
->frame_matched
= true;
3415 /* Recurse into the subtree, if it exists */
3416 if (node
->first_child
!= NULL
)
3417 proto_tree_children_foreach(node
, match_subtree_text_reverse
, mdata
);
3421 cf_find_packet_summary_line(capture_file
*cf
, const char *string
,
3422 search_direction dir
)
3426 mdata
.string
= string
;
3427 mdata
.string_len
= strlen(string
);
3428 return find_packet(cf
, match_summary_line
, &mdata
, dir
, true);
3432 match_summary_line(capture_file
*cf
, frame_data
*fdata
,
3433 wtap_rec
*rec
, void *criterion
)
3435 match_data
*mdata
= (match_data
*)criterion
;
3436 const char *string
= mdata
->string
;
3437 size_t string_len
= mdata
->string_len
;
3439 const char *info_column
;
3440 size_t info_column_len
;
3441 match_result result
= MR_NOTMATCHED
;
3443 uint32_t i
, i_restart
;
3447 /* Load the frame's data. */
3448 if (!cf_read_record(cf
, fdata
, rec
)) {
3449 /* Attempt to get the packet failed. */
3453 /* Don't bother constructing the protocol tree */
3454 epan_dissect_init(&edt
, cf
->epan
, false, false);
3455 /* Get the column information */
3456 epan_dissect_run(&edt
, cf
->cd_t
, rec
, fdata
, &cf
->cinfo
);
3458 /* Find the Info column */
3459 for (colx
= 0; colx
< cf
->cinfo
.num_cols
; colx
++) {
3460 if (cf
->cinfo
.columns
[colx
].fmt_matx
[COL_INFO
]) {
3461 /* Found it. See if we match. */
3462 info_column
= get_column_text(edt
.pi
.cinfo
, colx
);
3463 info_column_len
= strlen(info_column
);
3465 if (ws_regex_matches(cf
->regex
, info_column
)) {
3466 result
= MR_MATCHED
;
3469 } else if (cf
->case_type
) {
3470 /* Case insensitive match */
3472 for (i
= 0; i
< info_column_len
; i
++) {
3473 if (i_restart
== 0 && c_match
== 0 && (info_column_len
- i
< string_len
))
3475 c_char
= info_column
[i
];
3476 c_char
= g_ascii_toupper(c_char
);
3477 /* If c_match is non-zero, save candidate for retrying full match. */
3478 if (c_match
> 0 && i_restart
== 0 && c_char
== string
[0])
3480 if (c_char
== string
[c_match
]) {
3482 if (c_match
== string_len
) {
3483 result
= MR_MATCHED
;
3486 } else if (i_restart
) {
3493 } else if (strstr(info_column
, string
) != NULL
) {
3494 /* Case sensitive match */
3495 result
= MR_MATCHED
;
3500 epan_dissect_cleanup(&edt
);
3505 const uint8_t *data
;
3507 ws_mempbrk_pattern
*pattern
;
3508 } cbs_t
; /* "Counted byte string" */
3512 * The current match_* routines only support ASCII case insensitivity and don't
3513 * convert UTF-8 inputs to UTF-16 for matching. The UTF-16 support just
3514 * interleaves with \0 bytes, which works for 7 bit ASCII.
3516 * We could modify them to use the GLib Unicode routines or the International
3517 * Components for Unicode library but it's not apparent that we could do so
3518 * without consuming a lot more CPU and memory or that searching would be
3519 * significantly better.
3521 * XXX: We could test the search string to see if it's all ASCII, and if not
3522 * use Unicode aware routines for case insensitive searches or any UTF-16
3527 cf_find_packet_data(capture_file
*cf
, const uint8_t *string
, size_t string_size
,
3528 search_direction dir
, bool multiple
)
3532 ws_mempbrk_pattern pattern
= {0};
3533 ws_match_function match_function
;
3536 info
.data_len
= string_size
;
3538 /* Regex, String or hex search? */
3540 /* Regular Expression search */
3541 match_function
= (dir
== SD_FORWARD
) ? match_regex
: match_regex_reverse
;
3542 } else if (cf
->string
) {
3543 /* String search - what type of string? */
3544 if (cf
->case_type
) {
3545 needles
[0] = string
[0];
3546 needles
[1] = g_ascii_tolower(needles
[0]);
3548 ws_mempbrk_compile(&pattern
, needles
);
3549 info
.pattern
= &pattern
;
3550 switch (cf
->scs_type
) {
3552 case SCS_NARROW_AND_WIDE
:
3553 match_function
= (dir
== SD_FORWARD
) ? match_narrow_and_wide_case
: match_narrow_and_wide_case_reverse
;
3557 match_function
= (dir
== SD_FORWARD
) ? match_narrow_case
: match_narrow_case_reverse
;
3561 match_function
= (dir
== SD_FORWARD
) ? match_wide_case
: match_wide_case_reverse
;
3565 ws_assert_not_reached();
3570 switch (cf
->scs_type
) {
3572 case SCS_NARROW_AND_WIDE
:
3573 match_function
= (dir
== SD_FORWARD
) ? match_narrow_and_wide
: match_narrow_and_wide_reverse
;
3577 /* Narrow, case-sensitive match is the same as looking
3578 * for a converted hexstring. */
3579 match_function
= (dir
== SD_FORWARD
) ? match_binary
: match_binary_reverse
;
3583 match_function
= (dir
== SD_FORWARD
) ? match_wide
: match_wide_reverse
;
3587 ws_assert_not_reached();
3592 match_function
= (dir
== SD_FORWARD
) ? match_binary
: match_binary_reverse
;
3595 if (multiple
&& cf
->current_frame
&& (cf
->search_pos
|| cf
->search_len
)) {
3596 /* Use the current frame (this will perform the equivalent of
3597 * cf_read_current_record() in match_function).
3599 if (match_function(cf
, cf
->current_frame
, &cf
->rec
, &info
)) {
3600 cf
->search_in_progress
= true;
3602 field_info
*fi
= NULL
;
3603 /* The regex match can match an empty string. */
3604 if (cf
->search_len
) {
3605 fi
= proto_find_field_from_offset(cf
->edt
->tree
, cf
->search_pos
+ cf
->search_len
- 1, cf
->edt
->tvb
);
3607 packet_list_select_finfo(fi
);
3609 packet_list_select_row_from_data(cf
->current_frame
);
3611 cf
->search_in_progress
= false;
3615 cf
->search_pos
= 0; /* Reset the position */
3616 cf
->search_len
= 0; /* Reset length */
3617 return find_packet(cf
, match_function
, &info
, dir
, true);
3621 match_narrow_and_wide(capture_file
*cf
, frame_data
*fdata
,
3622 wtap_rec
*rec
, void *criterion
)
3624 cbs_t
*info
= (cbs_t
*)criterion
;
3625 const uint8_t *ascii_text
= info
->data
;
3626 size_t textlen
= info
->data_len
;
3627 match_result result
;
3629 const uint8_t *pd
, *buf_start
, *buf_end
;
3634 /* Load the frame's data. */
3635 if (!cf_read_record(cf
, fdata
, rec
)) {
3636 /* Attempt to get the packet failed. */
3640 result
= MR_NOTMATCHED
;
3641 buf_len
= fdata
->cap_len
;
3642 buf_start
= ws_buffer_start_ptr(&rec
->data
);
3643 buf_end
= buf_start
+ buf_len
;
3645 if (cf
->search_len
|| cf
->search_pos
) {
3646 /* we want to start searching one byte past the previous match start */
3647 pd
+= cf
->search_pos
+ 1;
3649 for (; pd
< buf_end
; pd
++) {
3650 pd
= (uint8_t *)memchr(pd
, ascii_text
[0], buf_end
- pd
);
3651 if (pd
== NULL
) break;
3652 /* Try narrow match at this start location */
3654 for (i
= 0; pd
+ i
< buf_end
; i
++) {
3656 if (c_char
== ascii_text
[c_match
]) {
3658 if (c_match
== textlen
) {
3659 result
= MR_MATCHED
;
3660 /* Save position and length for highlighting the field. */
3661 cf
->search_pos
= (uint32_t)(pd
- buf_start
);
3662 cf
->search_len
= (uint32_t)(i
+ 1);
3670 /* Now try wide match at the same start location. */
3672 for (i
= 0; pd
+ i
< buf_end
; i
++) {
3674 if (c_char
== ascii_text
[c_match
]) {
3676 if (c_match
== textlen
) {
3677 result
= MR_MATCHED
;
3678 /* Save position and length for highlighting the field. */
3679 cf
->search_pos
= (uint32_t)(pd
- buf_start
);
3680 cf
->search_len
= (uint32_t)(i
+ 1);
3684 if (pd
+ i
>= buf_end
|| pd
[i
] != '\0') break;
3696 match_narrow_and_wide_reverse(capture_file
*cf
, frame_data
*fdata
,
3697 wtap_rec
*rec
, void *criterion
)
3699 cbs_t
*info
= (cbs_t
*)criterion
;
3700 const uint8_t *ascii_text
= info
->data
;
3701 size_t textlen
= info
->data_len
;
3702 match_result result
;
3704 const uint8_t *pd
, *buf_start
, *buf_end
;
3709 /* Load the frame's data. */
3710 if (!cf_read_record(cf
, fdata
, rec
)) {
3711 /* Attempt to get the packet failed. */
3715 result
= MR_NOTMATCHED
;
3716 /* Has to be room to hold the sought data. */
3717 if (textlen
> fdata
->cap_len
) {
3720 buf_len
= fdata
->cap_len
;
3721 buf_start
= ws_buffer_start_ptr(&rec
->data
);
3722 buf_end
= buf_start
+ buf_len
;
3723 pd
= buf_end
- textlen
;
3724 if (cf
->search_len
|| cf
->search_pos
) {
3725 /* we want to start searching one byte before the previous match start */
3726 pd
= buf_start
+ cf
->search_pos
- 1;
3728 for (; pd
< buf_end
; pd
++) {
3729 pd
= (uint8_t *)ws_memrchr(buf_start
, ascii_text
[0], pd
- buf_start
+ 1);
3730 if (pd
== NULL
) break;
3731 /* Try narrow match at this 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);
3749 /* Now try wide match at the same start location. */
3751 for (i
= 0; pd
+ i
< buf_end
; i
++) {
3753 if (c_char
== ascii_text
[c_match
]) {
3755 if (c_match
== textlen
) {
3756 result
= MR_MATCHED
;
3757 /* Save position and length for highlighting the field. */
3758 cf
->search_pos
= (uint32_t)(pd
- buf_start
);
3759 cf
->search_len
= (uint32_t)(i
+ 1);
3763 if (pd
+ i
>= buf_end
|| pd
[i
] != '\0') break;
3774 /* Case insensitive match */
3776 match_narrow_and_wide_case(capture_file
*cf
, frame_data
*fdata
,
3777 wtap_rec
*rec
, void *criterion
)
3779 cbs_t
*info
= (cbs_t
*)criterion
;
3780 const uint8_t *ascii_text
= info
->data
;
3781 size_t textlen
= info
->data_len
;
3782 ws_mempbrk_pattern
*pattern
= info
->pattern
;
3783 match_result result
;
3785 const uint8_t *pd
, *buf_start
, *buf_end
;
3790 /* Load the frame's data. */
3791 if (!cf_read_record(cf
, fdata
, rec
)) {
3792 /* Attempt to get the packet failed. */
3796 ws_assert(pattern
!= NULL
);
3798 result
= MR_NOTMATCHED
;
3799 buf_len
= fdata
->cap_len
;
3800 buf_start
= ws_buffer_start_ptr(&rec
->data
);
3801 buf_end
= buf_start
+ buf_len
;
3803 if (cf
->search_len
|| cf
->search_pos
) {
3804 /* we want to start searching one byte past the previous match start */
3805 pd
+= cf
->search_pos
+ 1;
3807 for (; pd
< buf_end
; pd
++) {
3808 pd
= (uint8_t *)ws_mempbrk_exec(pd
, buf_end
- pd
, pattern
, &c_char
);
3809 if (pd
== NULL
) break;
3810 /* Try narrow match at this start location */
3812 for (i
= 0; pd
+ i
< buf_end
; i
++) {
3813 c_char
= g_ascii_toupper(pd
[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);
3828 /* Now try wide match at the same start location. */
3830 for (i
= 0; pd
+ i
< buf_end
; i
++) {
3831 c_char
= g_ascii_toupper(pd
[i
]);
3832 if (c_char
== ascii_text
[c_match
]) {
3834 if (c_match
== textlen
) {
3835 result
= MR_MATCHED
;
3836 /* Save position and length for highlighting the field. */
3837 cf
->search_pos
= (uint32_t)(pd
- buf_start
);
3838 cf
->search_len
= (uint32_t)(i
+ 1);
3842 if (pd
+ i
>= buf_end
|| pd
[i
] != '\0') break;
3854 match_narrow_and_wide_case_reverse(capture_file
*cf
, frame_data
*fdata
,
3855 wtap_rec
*rec
, void *criterion
)
3857 cbs_t
*info
= (cbs_t
*)criterion
;
3858 const uint8_t *ascii_text
= info
->data
;
3859 size_t textlen
= info
->data_len
;
3860 ws_mempbrk_pattern
*pattern
= info
->pattern
;
3861 match_result result
;
3863 const uint8_t *pd
, *buf_start
, *buf_end
;
3868 /* Load the frame's data. */
3869 if (!cf_read_record(cf
, fdata
, rec
)) {
3870 /* Attempt to get the packet failed. */
3874 ws_assert(pattern
!= NULL
);
3876 result
= MR_NOTMATCHED
;
3877 /* Has to be room to hold the sought data. */
3878 if (textlen
> fdata
->cap_len
) {
3881 buf_len
= fdata
->cap_len
;
3882 buf_start
= ws_buffer_start_ptr(&rec
->data
);
3883 buf_end
= buf_start
+ buf_len
;
3884 pd
= buf_end
- textlen
;
3885 if (cf
->search_len
|| cf
->search_pos
) {
3886 /* we want to start searching one byte before the previous match start */
3887 pd
= buf_start
+ cf
->search_pos
- 1;
3889 for (; pd
>= buf_start
; pd
--) {
3890 pd
= (uint8_t *)ws_memrpbrk_exec(buf_start
, pd
- buf_start
+ 1, pattern
, &c_char
);
3891 if (pd
== NULL
) break;
3892 /* Try narrow match at this start location */
3894 for (i
= 0; pd
+ i
< buf_end
; i
++) {
3895 c_char
= g_ascii_toupper(pd
[i
]);
3896 if (c_char
== ascii_text
[c_match
]) {
3898 if (c_match
== textlen
) {
3899 result
= MR_MATCHED
;
3900 /* Save position and length for highlighting the field. */
3901 cf
->search_pos
= (uint32_t)(pd
- buf_start
);
3902 cf
->search_len
= (uint32_t)(i
+ 1);
3910 /* Now try wide match at the same start location. */
3912 for (i
= 0; pd
+ i
< buf_end
; i
++) {
3913 c_char
= g_ascii_toupper(pd
[i
]);
3914 if (c_char
== ascii_text
[c_match
]) {
3916 if (c_match
== textlen
) {
3917 result
= MR_MATCHED
;
3918 /* Save position and length for highlighting the field. */
3919 cf
->search_pos
= (uint32_t)(pd
- buf_start
);
3920 cf
->search_len
= (uint32_t)(i
+ 1);
3924 if (pd
+ i
>= buf_end
|| pd
[i
] != '\0') break;
3935 /* Case insensitive match */
3937 match_narrow_case(capture_file
*cf
, frame_data
*fdata
,
3938 wtap_rec
*rec
, void *criterion
)
3940 cbs_t
*info
= (cbs_t
*)criterion
;
3941 const uint8_t *ascii_text
= info
->data
;
3942 size_t textlen
= info
->data_len
;
3943 ws_mempbrk_pattern
*pattern
= info
->pattern
;
3944 match_result result
;
3946 const uint8_t *pd
, *buf_start
, *buf_end
;
3951 /* Load the frame's data. */
3952 if (!cf_read_record(cf
, fdata
, rec
)) {
3953 /* Attempt to get the packet failed. */
3957 ws_assert(pattern
!= NULL
);
3959 result
= MR_NOTMATCHED
;
3960 buf_len
= fdata
->cap_len
;
3961 buf_start
= ws_buffer_start_ptr(&rec
->data
);
3962 buf_end
= buf_start
+ buf_len
;
3964 if (cf
->search_len
|| cf
->search_pos
) {
3965 /* we want to start searching one byte past the previous match start */
3966 pd
+= cf
->search_pos
+ 1;
3968 for (; pd
< buf_end
; pd
++) {
3969 pd
= (uint8_t *)ws_mempbrk_exec(pd
, buf_end
- pd
, pattern
, &c_char
);
3970 if (pd
== NULL
) break;
3972 for (i
= 0; pd
+ i
< buf_end
; i
++) {
3973 c_char
= g_ascii_toupper(pd
[i
]);
3974 if (c_char
== ascii_text
[c_match
]) {
3976 if (c_match
== textlen
) {
3977 /* Save position and length for highlighting the field. */
3978 result
= MR_MATCHED
;
3979 cf
->search_pos
= (uint32_t)(pd
- buf_start
);
3980 cf
->search_len
= (uint32_t)(i
+ 1);
3994 match_narrow_case_reverse(capture_file
*cf
, frame_data
*fdata
,
3995 wtap_rec
*rec
, void *criterion
)
3997 cbs_t
*info
= (cbs_t
*)criterion
;
3998 const uint8_t *ascii_text
= info
->data
;
3999 size_t textlen
= info
->data_len
;
4000 ws_mempbrk_pattern
*pattern
= info
->pattern
;
4001 match_result result
;
4003 const uint8_t *pd
, *buf_start
, *buf_end
;
4008 /* Load the frame's data. */
4009 if (!cf_read_record(cf
, fdata
, rec
)) {
4010 /* Attempt to get the packet failed. */
4014 ws_assert(pattern
!= NULL
);
4016 result
= MR_NOTMATCHED
;
4017 /* Has to be room to hold the sought data. */
4018 if (textlen
> fdata
->cap_len
) {
4021 buf_len
= fdata
->cap_len
;
4022 buf_start
= ws_buffer_start_ptr(&rec
->data
);
4023 buf_end
= buf_start
+ buf_len
;
4024 pd
= buf_end
- textlen
;
4025 if (cf
->search_len
|| cf
->search_pos
) {
4026 /* we want to start searching one byte before the previous match start */
4027 pd
= buf_start
+ cf
->search_pos
- 1;
4029 for (; pd
>= buf_start
; pd
--) {
4030 pd
= (uint8_t *)ws_memrpbrk_exec(buf_start
, pd
- buf_start
+ 1, 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_wide(capture_file
*cf
, frame_data
*fdata
,
4056 wtap_rec
*rec
, 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 match_result result
;
4063 const uint8_t *pd
, *buf_start
, *buf_end
;
4068 /* Load the frame's data. */
4069 if (!cf_read_record(cf
, fdata
, rec
)) {
4070 /* Attempt to get the packet failed. */
4074 result
= MR_NOTMATCHED
;
4075 buf_len
= fdata
->cap_len
;
4076 buf_start
= ws_buffer_start_ptr(&rec
->data
);
4077 buf_end
= buf_start
+ buf_len
;
4079 if (cf
->search_len
|| cf
->search_pos
) {
4080 /* we want to start searching one byte past the previous match start */
4081 pd
+= cf
->search_pos
+ 1;
4083 for (; pd
< buf_end
; pd
++) {
4084 pd
= (uint8_t *)memchr(pd
, ascii_text
[0], buf_end
- pd
);
4085 if (pd
== NULL
) break;
4087 for (i
= 0; pd
+ i
< buf_end
; i
++) {
4089 if (c_char
== ascii_text
[c_match
]) {
4091 if (c_match
== textlen
) {
4092 result
= MR_MATCHED
;
4093 /* Save position and length for highlighting the field. */
4094 cf
->search_pos
= (uint32_t)(pd
- buf_start
);
4095 cf
->search_len
= (uint32_t)(i
+ 1);
4099 if (pd
+ i
>= buf_end
|| pd
[i
] != '\0') break;
4111 match_wide_reverse(capture_file
*cf
, frame_data
*fdata
,
4112 wtap_rec
*rec
, void *criterion
)
4114 cbs_t
*info
= (cbs_t
*)criterion
;
4115 const uint8_t *ascii_text
= info
->data
;
4116 size_t textlen
= info
->data_len
;
4117 match_result result
;
4119 const uint8_t *pd
, *buf_start
, *buf_end
;
4124 /* Load the frame's data. */
4125 if (!cf_read_record(cf
, fdata
, rec
)) {
4126 /* Attempt to get the packet failed. */
4130 result
= MR_NOTMATCHED
;
4131 /* Has to be room to hold the sought data. */
4132 if (textlen
> fdata
->cap_len
) {
4135 buf_len
= fdata
->cap_len
;
4136 buf_start
= ws_buffer_start_ptr(&rec
->data
);
4137 buf_end
= buf_start
+ buf_len
;
4138 pd
= buf_end
- textlen
;
4139 if (cf
->search_len
|| cf
->search_pos
) {
4140 /* we want to start searching one byte before the previous match start */
4141 pd
= buf_start
+ cf
->search_pos
- 1;
4143 for (; pd
< buf_end
; pd
++) {
4144 pd
= (uint8_t *)ws_memrchr(buf_start
, ascii_text
[0], pd
- buf_start
+ 1);
4145 if (pd
== NULL
) break;
4147 for (i
= 0; pd
+ i
< buf_end
; i
++) {
4149 if (c_char
== ascii_text
[c_match
]) {
4151 if (c_match
== textlen
) {
4152 result
= MR_MATCHED
;
4153 /* Save position and length for highlighting the field. */
4154 cf
->search_pos
= (uint32_t)(pd
- buf_start
);
4155 cf
->search_len
= (uint32_t)(i
+ 1);
4159 if (pd
+ i
>= buf_end
|| pd
[i
] != '\0') break;
4170 /* Case insensitive match */
4172 match_wide_case(capture_file
*cf
, frame_data
*fdata
,
4173 wtap_rec
*rec
, 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 ws_mempbrk_pattern
*pattern
= info
->pattern
;
4179 match_result result
;
4181 const uint8_t *pd
, *buf_start
, *buf_end
;
4186 /* Load the frame's data. */
4187 if (!cf_read_record(cf
, fdata
, rec
)) {
4188 /* Attempt to get the packet failed. */
4192 ws_assert(pattern
!= NULL
);
4194 result
= MR_NOTMATCHED
;
4195 buf_len
= fdata
->cap_len
;
4196 buf_start
= ws_buffer_start_ptr(&rec
->data
);
4197 buf_end
= buf_start
+ buf_len
;
4199 if (cf
->search_len
|| cf
->search_pos
) {
4200 /* we want to start searching one byte past the previous match start */
4201 pd
+= cf
->search_pos
+ 1;
4203 for (; pd
< buf_end
; pd
++) {
4204 pd
= (uint8_t *)ws_mempbrk_exec(pd
, buf_end
- pd
, pattern
, &c_char
);
4205 if (pd
== NULL
) break;
4207 for (i
= 0; pd
+ i
< buf_end
; i
++) {
4208 c_char
= g_ascii_toupper(pd
[i
]);
4209 if (c_char
== ascii_text
[c_match
]) {
4211 if (c_match
== textlen
) {
4212 result
= MR_MATCHED
;
4213 /* Save position and length for highlighting the field. */
4214 cf
->search_pos
= (uint32_t)(pd
- buf_start
);
4215 cf
->search_len
= (uint32_t)(i
+ 1);
4219 if (pd
+ i
>= buf_end
|| pd
[i
] != '\0') break;
4230 /* Case insensitive match */
4232 match_wide_case_reverse(capture_file
*cf
, frame_data
*fdata
,
4233 wtap_rec
*rec
, void *criterion
)
4235 cbs_t
*info
= (cbs_t
*)criterion
;
4236 const uint8_t *ascii_text
= info
->data
;
4237 size_t textlen
= info
->data_len
;
4238 ws_mempbrk_pattern
*pattern
= info
->pattern
;
4239 match_result result
;
4241 const uint8_t *pd
, *buf_start
, *buf_end
;
4246 /* Load the frame's data. */
4247 if (!cf_read_record(cf
, fdata
, rec
)) {
4248 /* Attempt to get the packet failed. */
4252 ws_assert(pattern
!= NULL
);
4254 result
= MR_NOTMATCHED
;
4255 /* Has to be room to hold the sought data. */
4256 if (textlen
> fdata
->cap_len
) {
4259 buf_len
= fdata
->cap_len
;
4260 buf_start
= ws_buffer_start_ptr(&rec
->data
);
4261 buf_end
= buf_start
+ buf_len
;
4262 pd
= buf_end
- textlen
;
4263 if (cf
->search_len
|| cf
->search_pos
) {
4264 /* we want to start searching one byte before the previous match start */
4265 pd
= buf_start
+ cf
->search_pos
- 1;
4267 for (; pd
>= buf_start
; pd
--) {
4268 pd
= (uint8_t *)ws_memrpbrk_exec(buf_start
, pd
- buf_start
+ 1, pattern
, &c_char
);
4269 if (pd
== NULL
) break;
4271 for (i
= 0; pd
+ i
< buf_end
; i
++) {
4272 c_char
= g_ascii_toupper(pd
[i
]);
4273 if (c_char
== ascii_text
[c_match
]) {
4275 if (c_match
== textlen
) {
4276 result
= MR_MATCHED
;
4277 /* Save position and length for highlighting the field. */
4278 cf
->search_pos
= (uint32_t)(pd
- buf_start
);
4279 cf
->search_len
= (uint32_t)(i
+ 1);
4283 if (pd
+ i
>= buf_end
|| pd
[i
] != '\0') break;
4295 match_binary(capture_file
*cf
, frame_data
*fdata
,
4296 wtap_rec
*rec
, void *criterion
)
4298 cbs_t
*info
= (cbs_t
*)criterion
;
4299 size_t datalen
= info
->data_len
;
4300 match_result result
;
4301 const uint8_t *pd
= NULL
, *buf_start
;
4303 /* Load the frame's data. */
4304 if (!cf_read_record(cf
, fdata
, rec
)) {
4305 /* Attempt to get the packet failed. */
4309 result
= MR_NOTMATCHED
;
4310 buf_start
= ws_buffer_start_ptr(&rec
->data
);
4312 if (cf
->search_len
|| cf
->search_pos
) {
4313 /* we want to start searching one byte past the previous match start */
4314 offset
= cf
->search_pos
+ 1;
4316 if (offset
< fdata
->cap_len
) {
4317 pd
= ws_memmem(buf_start
+ offset
, fdata
->cap_len
- offset
, info
->data
, datalen
);
4320 result
= MR_MATCHED
;
4321 /* Save position and length for highlighting the field. */
4322 cf
->search_pos
= (uint32_t)(pd
- buf_start
);
4323 cf
->search_len
= (uint32_t)datalen
;
4330 match_binary_reverse(capture_file
*cf
, frame_data
*fdata
,
4331 wtap_rec
*rec
, void *criterion
)
4333 cbs_t
*info
= (cbs_t
*)criterion
;
4334 size_t datalen
= info
->data_len
;
4335 match_result result
;
4336 const uint8_t *pd
= NULL
, *buf_start
;
4338 /* Load the frame's data. */
4339 if (!cf_read_record(cf
, fdata
, rec
)) {
4340 /* Attempt to get the packet failed. */
4344 result
= MR_NOTMATCHED
;
4345 buf_start
= ws_buffer_start_ptr(&rec
->data
);
4346 /* Has to be room to hold the sought data. */
4347 if (datalen
> fdata
->cap_len
) {
4350 pd
= buf_start
+ fdata
->cap_len
- datalen
;
4351 if (cf
->search_len
|| cf
->search_pos
) {
4352 /* we want to start searching one byte before the previous match start */
4353 pd
= buf_start
+ cf
->search_pos
- 1;
4355 for (; pd
>= buf_start
; pd
--) {
4356 pd
= (uint8_t *)ws_memrchr(buf_start
, info
->data
[0], pd
- buf_start
+ 1);
4357 if (pd
== NULL
) break;
4358 if (memcmp(pd
, info
->data
, datalen
) == 0) {
4359 result
= MR_MATCHED
;
4360 /* Save position and length for highlighting the field. */
4361 cf
->search_pos
= (uint32_t)(pd
- buf_start
);
4362 cf
->search_len
= (uint32_t)datalen
;
4371 match_regex(capture_file
*cf
, frame_data
*fdata
,
4372 wtap_rec
*rec
, void *criterion _U_
)
4374 match_result result
= MR_NOTMATCHED
;
4375 size_t result_pos
[2] = {0, 0};
4377 /* Load the frame's data. */
4378 if (!cf_read_record(cf
, fdata
, rec
)) {
4379 /* Attempt to get the packet failed. */
4384 if (cf
->search_len
|| cf
->search_pos
) {
4385 /* we want to start searching one byte past the previous match start */
4386 offset
= cf
->search_pos
+ 1;
4388 if (offset
< fdata
->cap_len
) {
4389 if (ws_regex_matches_pos(cf
->regex
,
4390 (const char *)ws_buffer_start_ptr(&rec
->data
),
4391 fdata
->cap_len
, offset
,
4393 //TODO: A chosen regex can match the empty string (zero length)
4394 // which doesn't make a lot of sense for searching the packet bytes.
4395 // Should we search with the PCRE2_NOTEMPTY option?
4397 /* Save position and length for highlighting the field. */
4398 cf
->search_pos
= (uint32_t)(result_pos
[0]);
4399 cf
->search_len
= (uint32_t)(result_pos
[1] - result_pos
[0]);
4400 result
= MR_MATCHED
;
4407 match_regex_reverse(capture_file
*cf
, frame_data
*fdata
,
4408 wtap_rec
*rec
, void *criterion _U_
)
4410 match_result result
= MR_NOTMATCHED
;
4411 size_t result_pos
[2] = {0, 0};
4413 /* Load the frame's data. */
4414 if (!cf_read_record(cf
, fdata
, rec
)) {
4415 /* Attempt to get the packet failed. */
4419 size_t offset
= fdata
->cap_len
- 1;
4420 if (cf
->search_pos
) {
4421 /* we want to start searching one byte before the previous match */
4422 offset
= cf
->search_pos
- 1;
4424 for (; offset
> 0; offset
--) {
4425 if (ws_regex_matches_pos(cf
->regex
,
4426 (const char *)ws_buffer_start_ptr(&rec
->data
),
4427 fdata
->cap_len
, offset
,
4429 //TODO: A chosen regex can match the empty string (zero length)
4430 // which doesn't make a lot of sense for searching the packet bytes.
4431 // Should we search with the PCRE2_NOTEMPTY option?
4433 /* Save position and length for highlighting the field. */
4434 cf
->search_pos
= (uint32_t)(result_pos
[0]);
4435 cf
->search_len
= (uint32_t)(result_pos
[1] - result_pos
[0]);
4436 result
= MR_MATCHED
;
4444 cf_find_packet_dfilter(capture_file
*cf
, dfilter_t
*sfcode
,
4445 search_direction dir
, bool start_current
)
4447 return find_packet(cf
, match_dfilter
, sfcode
, dir
, start_current
);
4451 cf_find_packet_dfilter_string(capture_file
*cf
, const char *filter
,
4452 search_direction dir
)
4457 if (!dfilter_compile(filter
, &sfcode
, NULL
)) {
4459 * XXX - this shouldn't happen, as the filter string is machine
4464 if (sfcode
== NULL
) {
4466 * XXX - this shouldn't happen, as the filter string is machine
4471 result
= find_packet(cf
, match_dfilter
, sfcode
, dir
, true);
4472 dfilter_free(sfcode
);
4477 match_dfilter(capture_file
*cf
, frame_data
*fdata
, wtap_rec
*rec
,
4480 dfilter_t
*sfcode
= (dfilter_t
*)criterion
;
4482 match_result result
;
4484 /* Load the frame's data. */
4485 if (!cf_read_record(cf
, fdata
, rec
)) {
4486 /* Attempt to get the packet failed. */
4490 epan_dissect_init(&edt
, cf
->epan
, true, false);
4491 epan_dissect_prime_with_dfilter(&edt
, sfcode
);
4492 epan_dissect_run(&edt
, cf
->cd_t
, rec
, fdata
, NULL
);
4493 result
= dfilter_apply_edt(sfcode
, &edt
) ? MR_MATCHED
: MR_NOTMATCHED
;
4494 epan_dissect_cleanup(&edt
);
4499 cf_find_packet_marked(capture_file
*cf
, search_direction dir
)
4501 return find_packet(cf
, match_marked
, NULL
, dir
, true);
4505 match_marked(capture_file
*cf _U_
, frame_data
*fdata
, wtap_rec
*rec _U_
,
4506 void *criterion _U_
)
4508 return fdata
->marked
? MR_MATCHED
: MR_NOTMATCHED
;
4512 cf_find_packet_time_reference(capture_file
*cf
, search_direction dir
)
4514 return find_packet(cf
, match_time_reference
, NULL
, dir
, true);
4518 match_time_reference(capture_file
*cf _U_
, frame_data
*fdata
, wtap_rec
*rec _U_
,
4519 void *criterion _U_
)
4521 return fdata
->ref_time
? MR_MATCHED
: MR_NOTMATCHED
;
4525 find_packet(capture_file
*cf
, ws_match_function match_function
,
4526 void *criterion
, search_direction dir
, bool start_current
)
4528 frame_data
*start_fd
;
4530 uint32_t prev_framenum
;
4533 frame_data
*new_fd
= NULL
;
4534 progdlg_t
*progbar
= NULL
;
4535 GTimer
*prog_timer
= g_timer_new();
4537 bool wrap
= prefs
.gui_find_wrap
;
4540 char status_str
[100];
4541 match_result result
;
4543 wtap_rec_init(&rec
, 1514);
4545 start_fd
= start_current
? cf
->current_frame
: NULL
;
4546 if (start_fd
!= NULL
) {
4547 prev_framenum
= start_fd
->num
;
4549 prev_framenum
= 0; /* No start packet selected. */
4553 /* Iterate through the list of packets, starting at the packet we've
4554 picked, calling a routine to run the filter on the packet, see if
4555 it matches, and stop if so. */
4557 framenum
= prev_framenum
;
4558 if (framenum
== 0 && dir
== SD_BACKWARD
) {
4559 /* If we have no start packet selected, and we're going backwards,
4560 * start at the end (even if wrap is off.)
4562 framenum
= cf
->count
+ 1;
4565 g_timer_start(prog_timer
);
4566 /* Progress so far. */
4569 cf
->stop_flag
= false;
4572 /* Create the progress bar if necessary.
4573 We check on every iteration of the loop, so that it takes no
4574 longer than the standard time to create it (otherwise, for a
4575 large file, we might take considerably longer than that standard
4576 time in order to get to the next progress bar step). */
4577 if (progbar
== NULL
)
4578 progbar
= delayed_create_progress_dlg(cf
->window
, NULL
, NULL
,
4579 false, &cf
->stop_flag
, progbar_val
);
4582 * Update the progress bar, but do it only after PROGBAR_UPDATE_INTERVAL
4583 * has elapsed. Calling update_progress_dlg and packets_bar_update will
4584 * likely trigger UI paint events, which might take a while depending on
4585 * the platform and display. Reset our timer *after* painting.
4587 if (g_timer_elapsed(prog_timer
, NULL
) > PROGBAR_UPDATE_INTERVAL
) {
4588 /* let's not divide by zero. I should never be started
4589 * with count == 0, so let's assert that
4591 ws_assert(cf
->count
> 0);
4593 progbar_val
= (float) count
/ cf
->count
;
4595 snprintf(status_str
, sizeof(status_str
),
4596 "%4u of %u packets", count
, cf
->count
);
4597 update_progress_dlg(progbar
, progbar_val
, status_str
);
4599 g_timer_start(prog_timer
);
4602 if (cf
->stop_flag
) {
4603 /* Well, the user decided to abort the search. Go back to the
4604 frame where we started.
4605 XXX - This ends up selecting the start packet and reporting
4606 "success". Perhaps new_fd should stay NULL? */
4611 /* Go past the current frame. */
4612 if (dir
== SD_BACKWARD
) {
4613 /* Go on to the previous frame. */
4614 if (framenum
<= 1) {
4616 * XXX - other apps have a bit more of a detailed message
4617 * for this, and instead of offering "OK" and "Cancel",
4618 * they offer things such as "Continue" and "Cancel";
4619 * we need an API for popping up alert boxes with
4620 * {Verb} and "Cancel".
4624 statusbar_push_temporary_msg("Search reached the beginning. Continuing at end.");
4625 framenum
= cf
->count
; /* wrap around */
4628 statusbar_push_temporary_msg("Search reached the beginning.");
4629 framenum
= prev_framenum
; /* stay on previous packet */
4634 /* Go on to the next frame. */
4635 if (framenum
== cf
->count
) {
4637 statusbar_push_temporary_msg("Search reached the end. Continuing at beginning.");
4638 framenum
= 1; /* wrap around */
4641 statusbar_push_temporary_msg("Search reached the end.");
4642 framenum
= prev_framenum
; /* stay on previous packet */
4648 fdata
= frame_data_sequence_find(cf
->provider
.frames
, framenum
);
4651 /* Is this packet in the display? */
4652 if (fdata
&& fdata
->passed_dfilter
) {
4653 /* Yes. Does it match the search criterion? */
4654 result
= (*match_function
)(cf
, fdata
, &rec
, criterion
);
4655 if (result
== MR_ERROR
) {
4656 /* Error; our caller has reported the error. Go back to the frame
4658 XXX - This ends up selecting the start packet and reporting
4659 "success." Perhaps new_fd should stay NULL? */
4662 } else if (result
== MR_MATCHED
) {
4663 /* Yes. Go to the new frame. */
4667 wtap_rec_reset(&rec
);
4670 if (fdata
== start_fd
) {
4671 /* We're back to the frame we were on originally, and that frame
4672 doesn't match the search filter. The search failed. */
4677 /* We're done scanning the packets; destroy the progress bar if it
4679 if (progbar
!= NULL
)
4680 destroy_progress_dlg(progbar
);
4681 g_timer_destroy(prog_timer
);
4683 if (new_fd
!= NULL
) {
4684 /* We found a frame that's displayed and that matches.
4685 Try to find and select the packet summary list row for that frame. */
4688 cf
->search_in_progress
= true;
4689 found_row
= packet_list_select_row_from_data(new_fd
);
4690 cf
->search_in_progress
= false;
4692 /* We didn't find a row corresponding to this frame.
4693 This means that the frame isn't being displayed currently,
4694 so we can't select it. */
4695 cf
->search_pos
= 0; /* Reset the position */
4696 cf
->search_len
= 0; /* Reset length */
4697 simple_message_box(ESD_TYPE_INFO
, NULL
,
4698 "The capture file is probably not fully dissected.",
4699 "End of capture exceeded.");
4700 succeeded
= false; /* The search succeeded but we didn't find the row */
4702 succeeded
= true; /* The search succeeded and we found the row */
4704 succeeded
= false; /* The search failed */
4705 wtap_rec_cleanup(&rec
);
4710 cf_goto_frame(capture_file
*cf
, unsigned fnumber
, bool exact
)
4714 if (cf
== NULL
|| cf
->provider
.frames
== NULL
) {
4715 /* we don't have a loaded capture file - fix for bugs 11810 & 11989 */
4716 statusbar_push_temporary_msg("There is no file loaded");
4717 return false; /* we failed to go to that packet */
4720 fdata
= frame_data_sequence_find(cf
->provider
.frames
, fnumber
);
4722 if (fdata
== NULL
) {
4723 /* we didn't find a packet with that packet number */
4724 statusbar_push_temporary_msg("There is no packet number %u.", fnumber
);
4725 return false; /* we failed to go to that packet */
4727 if (!fdata
->passed_dfilter
) {
4728 /* that packet currently isn't displayed */
4729 /* XXX - add it to the set of displayed packets? */
4730 if (cf
->first_displayed
== 0 || exact
) {
4731 /* We only want that exact frame, or no frames are displayed. */
4732 statusbar_push_temporary_msg("Packet number %u isn't displayed.", fnumber
);
4733 return false; /* we failed to go to that packet */
4735 if (fdata
->prev_dis_num
== 0) {
4736 /* There is no previous displayed frame, so this frame is
4737 * before the first displayed frame. Go to the first line,
4738 * which is the closest frame.
4740 fdata
= NULL
; /* This will select the first row. */
4741 statusbar_push_temporary_msg("Packet number %u isn't displayed, going to the first displayed packet, %u.", fnumber
, cf
->first_displayed
);
4743 uint32_t delta
= fnumber
- fdata
->prev_dis_num
;
4744 /* The next displayed frame might be closer, we can do an
4745 * O(log n) binary search for the earliest displayed frame
4746 * in the open interval (fnumber, fnumber + delta).
4748 * This is possibly overkill, we could just go to the previous
4752 uint32_t lower_bound
= fnumber
+ 1;
4753 uint32_t upper_bound
= fnumber
+ delta
- 1;
4755 while (lower_bound
<= upper_bound
) {
4756 uint32_t middle
= (lower_bound
+ upper_bound
) / 2;
4757 fdata2
= frame_data_sequence_find(cf
->provider
.frames
, middle
);
4758 if (fdata2
== NULL
) {
4759 /* We don't have a frame of that number, so search before it. */
4760 upper_bound
= middle
- 1;
4763 /* We have a frame of that number. What's the displayed
4764 * frame before it? */
4765 if (fdata2
->prev_dis_num
> fnumber
) {
4766 /* The previous frame that passed the filter is also after
4767 * our target, so our answer is no later than that.
4769 upper_bound
= fdata2
->prev_dis_num
;
4771 /* The previous displayed frame is before fnumber.
4772 * (We already know fnumber itself is not displayed.)
4773 * Is this frame itself displayed?
4775 if (fdata2
->passed_dfilter
) {
4776 /* Yes. So this is our answer. */
4780 /* No. So our answer, if any, is after this frame. */
4781 lower_bound
= middle
+ 1;
4786 statusbar_push_temporary_msg("Packet number %u isn't displayed, going to the next displayed packet, %u.", fnumber
, fdata
->num
);
4788 statusbar_push_temporary_msg("Packet number %u isn't displayed, going to the previous displayed packet, %u.", fnumber
, fdata
->prev_dis_num
);
4789 fdata
= frame_data_sequence_find(cf
->provider
.frames
, fdata
->prev_dis_num
);
4794 if (!packet_list_select_row_from_data(fdata
)) {
4795 /* We didn't find a row corresponding to this frame.
4796 This means that the frame isn't being displayed currently,
4797 so we can't select it. */
4798 simple_message_box(ESD_TYPE_INFO
, NULL
,
4799 "The capture file is probably not fully dissected.",
4800 "End of capture exceeded.");
4803 return true; /* we got to that packet */
4807 * Go to frame specified by currently selected protocol tree item.
4810 cf_goto_framenum(capture_file
*cf
)
4812 const header_field_info
*hfinfo
;
4815 if (cf
->finfo_selected
) {
4816 hfinfo
= cf
->finfo_selected
->hfinfo
;
4818 if (hfinfo
->type
== FT_FRAMENUM
) {
4819 framenum
= fvalue_get_uinteger(cf
->finfo_selected
->value
);
4820 if (framenum
!= 0) {
4821 /* We probably only want to go to the exact match,
4822 * even though "Go to Previous Packet in History" exists.
4824 return cf_goto_frame(cf
, framenum
, true);
4832 /* Select the packet on a given row. */
4834 cf_select_packet(capture_file
*cf
, frame_data
*fdata
)
4836 epan_dissect_t
*old_edt
;
4838 /* check the frame data struct pointer for this frame */
4839 if (fdata
== NULL
) {
4843 /* Get the data in that frame. */
4844 if (!cf_read_record(cf
, fdata
, &cf
->rec
)) {
4848 /* Record that this frame is the current frame. */
4849 cf
->current_frame
= fdata
;
4852 * The change to defer freeing the current epan_dissect_t was in
4853 * commit a2bb94c3b33d53f42534aceb7cc67aab1d1fb1f9; to quote
4854 * that commit's comment:
4856 * Clear GtkTreeStore before freeing edt
4858 * When building current data for packet details treeview we store two
4860 * - Generated string with item label
4861 * - Pointer to node field_info structure
4863 * After epan_dissect_{free, cleanup} pointer to field_info node is no
4864 * longer valid so we should clear GtkTreeStore before freeing.
4866 * XXX - we're no longer using GTK+; is there a way to ensure that
4867 * *nothing* refers to any of the current frame information before
4871 /* Create the logical protocol tree. */
4872 /* We don't need the columns here. */
4873 cf
->edt
= epan_dissect_new(cf
->epan
, true, true);
4875 tap_build_interesting(cf
->edt
);
4876 epan_dissect_run(cf
->edt
, cf
->cd_t
, &cf
->rec
, cf
->current_frame
, NULL
);
4878 if (old_edt
!= NULL
)
4879 epan_dissect_free(old_edt
);
4882 /* Unselect the selected packet, if any. */
4884 cf_unselect_packet(capture_file
*cf
)
4886 epan_dissect_t
*old_edt
= cf
->edt
;
4889 * See the comment in cf_select_packet() about deferring the freeing
4890 * of the old cf->edt.
4894 /* No packet is selected. */
4895 cf
->current_frame
= NULL
;
4897 /* Destroy the epan_dissect_t for the unselected packet. */
4898 if (old_edt
!= NULL
)
4899 epan_dissect_free(old_edt
);
4903 * Mark a particular frame.
4906 cf_mark_frame(capture_file
*cf
, frame_data
*frame
)
4908 if (! frame
->marked
) {
4909 frame
->marked
= true;
4910 if (cf
->count
> cf
->marked_count
)
4916 * Unmark a particular frame.
4919 cf_unmark_frame(capture_file
*cf
, frame_data
*frame
)
4921 if (frame
->marked
) {
4922 frame
->marked
= false;
4923 if (cf
->marked_count
> 0)
4929 * Ignore a particular frame.
4932 cf_ignore_frame(capture_file
*cf
, frame_data
*frame
)
4934 if (! frame
->ignored
) {
4935 frame
->ignored
= true;
4936 if (cf
->count
> cf
->ignored_count
)
4937 cf
->ignored_count
++;
4942 * Un-ignore a particular frame.
4945 cf_unignore_frame(capture_file
*cf
, frame_data
*frame
)
4947 if (frame
->ignored
) {
4948 frame
->ignored
= false;
4949 if (cf
->ignored_count
> 0)
4950 cf
->ignored_count
--;
4955 * Modify the section comment.
4958 cf_update_section_comment(capture_file
*cf
, char *comment
)
4960 wtap_block_t shb_inf
;
4963 /* Get the first SHB. */
4964 /* XXX - support multiple SHBs */
4965 shb_inf
= wtap_file_get_shb(cf
->provider
.wth
, 0);
4967 /* Get the first comment from the SHB. */
4968 /* XXX - support multiple comments */
4969 if (wtap_block_get_nth_string_option_value(shb_inf
, OPT_COMMENT
, 0, &shb_comment
) != WTAP_OPTTYPE_SUCCESS
) {
4970 /* There's no comment - add one. */
4971 wtap_block_add_string_option(shb_inf
, OPT_COMMENT
, comment
, strlen(comment
));
4973 /* See if the comment has changed or not */
4974 if (strcmp(shb_comment
, comment
) == 0) {
4979 /* The comment has changed, let's update it */
4980 wtap_block_set_nth_string_option_value(shb_inf
, OPT_COMMENT
, 0, comment
, strlen(comment
));
4982 /* Mark the file as having unsaved changes */
4983 cf
->unsaved_changes
= true;
4987 * Modify the section comments for a given section.
4990 cf_update_section_comments(capture_file
*cf
, unsigned shb_idx
, char **comments
)
4992 wtap_block_t shb_inf
;
4995 shb_inf
= wtap_file_get_shb(cf
->provider
.wth
, shb_idx
);
4996 if (shb_inf
== NULL
) {
4997 /* Shouldn't happen. XXX: Report it if it does? */
5001 unsigned n_comments
= g_strv_length(comments
);
5005 for (i
= 0; i
< n_comments
; i
++) {
5006 comment
= comments
[i
];
5007 if (wtap_block_get_nth_string_option_value(shb_inf
, OPT_COMMENT
, i
, &shb_comment
) != WTAP_OPTTYPE_SUCCESS
) {
5008 /* There's no comment - add one. */
5009 wtap_block_add_string_option_owned(shb_inf
, OPT_COMMENT
, comment
);
5010 cf
->unsaved_changes
= true;
5012 /* See if the comment has changed or not */
5013 if (strcmp(shb_comment
, comment
) != 0) {
5014 /* The comment has changed, let's update it */
5015 wtap_block_set_nth_string_option_value(shb_inf
, OPT_COMMENT
, 0, comment
, strlen(comment
));
5016 cf
->unsaved_changes
= true;
5021 /* We either transferred ownership of the comments or freed them
5022 * above, so free the array of strings but not the strings themselves. */
5025 /* If there are extra old comments, remove them. Start at the end. */
5026 for (i
= wtap_block_count_option(shb_inf
, OPT_COMMENT
); i
> n_comments
; i
--) {
5027 wtap_block_remove_nth_option_instance(shb_inf
, OPT_COMMENT
, i
- 1);
5028 cf
->unsaved_changes
= true;
5033 * Get the packet block for a packet (record).
5034 * If the block has been edited, it returns the result of the edit,
5035 * otherwise it returns the block from the file.
5036 * NB. Caller must wtap_block_unref() the result when done.
5039 cf_get_packet_block(capture_file
*cf
, const frame_data
*fd
)
5041 /* If this block has been modified, fetch the modified version */
5042 if (fd
->has_modified_block
)
5043 return wtap_block_ref(cap_file_provider_get_modified_block(&cf
->provider
, fd
));
5045 wtap_rec rec
; /* Record information */
5048 /* fetch record block */
5049 wtap_rec_init(&rec
, 1514);
5051 if (!cf_read_record(cf
, fd
, &rec
))
5052 { /* XXX, what we can do here? */ }
5054 /* rec.block is owned by the record, steal it before it is gone. */
5055 block
= wtap_block_ref(rec
.block
);
5057 wtap_rec_cleanup(&rec
);
5063 * Update(replace) the block on a capture from a frame
5066 cf_set_modified_block(capture_file
*cf
, frame_data
*fd
, const wtap_block_t new_block
)
5068 wtap_block_t pkt_block
= cf_get_packet_block(cf
, fd
);
5070 /* It's possible to further modify the modified block "in place" by doing
5071 * a call to cf_get_packet_block() that returns an already created modified
5072 * block, modifying that, and calling this function.
5073 * If the caller did that, then the block pointers will be equal.
5075 if (pkt_block
== new_block
) {
5076 /* No need to save anything here, the caller changes went right
5078 * Unfortunately we don't have a way to know how many comments were
5079 * in the block before the caller modified it, so tell the caller
5080 * it is its responsibility to update the comment count.
5086 cf
->packet_comment_count
-= wtap_block_count_option(pkt_block
, OPT_COMMENT
);
5089 cf
->packet_comment_count
+= wtap_block_count_option(new_block
, OPT_COMMENT
);
5091 cap_file_provider_set_modified_block(&cf
->provider
, fd
, new_block
);
5093 expert_update_comment_count(cf
->packet_comment_count
);
5096 /* Either way, we have unsaved changes. */
5097 wtap_block_unref(pkt_block
);
5098 cf
->unsaved_changes
= true;
5103 * What types of comments does this capture file have?
5106 cf_comment_types(capture_file
*cf
)
5108 uint32_t comment_types
= 0;
5111 * Does this file have any sections with at least one comment?
5113 for (unsigned section_number
= 0;
5114 section_number
< wtap_file_get_num_shbs(cf
->provider
.wth
);
5116 wtap_block_t shb_inf
;
5119 shb_inf
= wtap_file_get_shb(cf
->provider
.wth
, section_number
);
5121 /* Try to get the first comment from that SHB. */
5122 if (wtap_block_get_nth_string_option_value(shb_inf
, OPT_COMMENT
, 0,
5123 &shb_comment
) == WTAP_OPTTYPE_SUCCESS
) {
5124 /* We succeeded, so this file has at least one section comment. */
5125 comment_types
|= WTAP_COMMENT_PER_SECTION
;
5127 /* We don't need to search any more. */
5131 if (cf
->packet_comment_count
!= 0)
5132 comment_types
|= WTAP_COMMENT_PER_PACKET
;
5133 return comment_types
;
5137 * Add a resolved address to this file's list of resolved addresses.
5140 cf_add_ip_name_from_string(capture_file
*cf
, const char *addr
, const char *name
)
5143 * XXX - support multiple resolved address lists, and add to the one
5144 * attached to this file?
5146 if (!add_ip_name_from_string(addr
, name
))
5149 /* OK, we have unsaved changes. */
5150 cf
->unsaved_changes
= true;
5159 } save_callback_args_t
;
5162 * Save a capture to a file, in a particular format, saving either
5163 * all packets, all currently-displayed packets, or all marked packets.
5165 * Returns true if it succeeds, false otherwise; if it fails, it pops
5166 * up a message box for the failure.
5169 save_record(capture_file
*cf
, frame_data
*fdata
, wtap_rec
*rec
, void *argsp
)
5171 save_callback_args_t
*args
= (save_callback_args_t
*)argsp
;
5175 wtap_block_t pkt_block
;
5177 /* Copy the record information from what was read in from the file. */
5180 /* Make changes based on anything that the user has done but that
5181 hasn't been saved yet. */
5182 if (fdata
->has_modified_block
)
5183 pkt_block
= cap_file_provider_get_modified_block(&cf
->provider
, fdata
);
5185 pkt_block
= rec
->block
;
5186 new_rec
.block
= pkt_block
;
5187 new_rec
.block_was_modified
= fdata
->has_modified_block
? true : false;
5189 if (!nstime_is_zero(&fdata
->shift_offset
)) {
5190 if (new_rec
.presence_flags
& WTAP_HAS_TS
) {
5191 nstime_add(&new_rec
.ts
, &fdata
->shift_offset
);
5195 /* and save the packet */
5196 if (!wtap_dump(args
->pdh
, &new_rec
, ws_buffer_start_ptr(&rec
->data
), &err
, &err_info
)) {
5197 report_cfile_write_failure(NULL
, args
->fname
, err
, err_info
, fdata
->num
,
5202 /* If we are saving (i.e., replacing the current file with the one we're
5203 * writing), then update the frame data to clear the shift offset.
5204 * This keeps us from having to re-read the entire file.
5205 * We could do this in rescan_file(), but
5206 * 1) Ideally we shouldn't have to call rescan_file if all we're doing
5207 * is changing the timestamps, since that shouldn't change the offsets.
5208 * 2) The long term goal is to try to do the offset adjustment here
5209 * instead of using rescan_file, which should be faster (#1257).
5211 * If we're exporting to a different file, then don't do that.
5213 if (!args
->export
&& new_rec
.presence_flags
& WTAP_HAS_TS
) {
5214 nstime_set_zero(&fdata
->shift_offset
);
5221 * Can this capture file be written out in any format using Wiretap
5222 * rather than by copying the raw data?
5225 cf_can_write_with_wiretap(capture_file
*cf
)
5227 /* We don't care whether we support the comments in this file or not;
5228 if we can't, we'll offer the user the option of discarding the
5230 return wtap_dump_can_write(cf
->linktypes
, 0);
5234 * Should we let the user do a save?
5238 * the file has unsaved changes, and we can save it in some
5239 * format through Wiretap
5243 * the file is a temporary file and has no unsaved changes (so
5244 * that "saving" it just means copying it).
5246 * XXX - we shouldn't allow files to be edited if they can't be saved,
5247 * so cf->unsaved_changes should be true only if the file can be saved.
5249 * We don't care whether we support the comments in this file or not;
5250 * if we can't, we'll offer the user the option of discarding the
5254 cf_can_save(capture_file
*cf
)
5256 if (cf
->unsaved_changes
&& wtap_dump_can_write(cf
->linktypes
, 0)) {
5257 /* Saved changes, and we can write it out with Wiretap. */
5261 if (cf
->is_tempfile
&& !cf
->unsaved_changes
) {
5263 * Temporary file with no unsaved changes, so we can just do a
5269 /* Nothing to save. */
5274 * Should we let the user do a "save as"?
5278 * we can save it in some format through Wiretap
5282 * the file is a temporary file and has no unsaved changes (so
5283 * that "saving" it just means copying it).
5285 * XXX - we shouldn't allow files to be edited if they can't be saved,
5286 * so cf->unsaved_changes should be true only if the file can be saved.
5288 * We don't care whether we support the comments in this file or not;
5289 * if we can't, we'll offer the user the option of discarding the
5293 cf_can_save_as(capture_file
*cf
)
5295 if (wtap_dump_can_write(cf
->linktypes
, 0)) {
5296 /* We can write it out with Wiretap. */
5300 if (cf
->is_tempfile
&& !cf
->unsaved_changes
) {
5302 * Temporary file with no unsaved changes, so we can just do a
5308 /* Nothing to save. */
5313 * Does this file have unsaved data?
5316 cf_has_unsaved_data(capture_file
*cf
)
5319 * If this is a temporary file, or a file with unsaved changes, it
5322 return (cf
->is_tempfile
&& cf
->count
>0) || cf
->unsaved_changes
;
5326 * Quick scan to find packet offsets.
5328 static cf_read_status_t
5329 rescan_file(capture_file
*cf
, const char *fname
, bool is_tempfile
)
5335 int64_t data_offset
;
5336 progdlg_t
*progbar
= NULL
;
5337 GTimer
*prog_timer
= g_timer_new();
5341 char status_str
[100];
5345 /* Close the old handle. */
5346 wtap_close(cf
->provider
.wth
);
5348 /* Open the new file. */
5349 /* XXX: this will go through all open_routines for a matching one. But right
5350 now rescan_file() is only used when a file is being saved to a different
5351 format than the original, and the user is not given a choice of which
5352 reader to use (only which format to save it in), so doing this makes
5353 sense for now. (XXX: Now it is also used when saving a changed file,
5354 e.g. comments or time-shifted frames.) */
5355 cf
->provider
.wth
= wtap_open_offline(fname
, WTAP_TYPE_AUTO
, &err
, &err_info
, true);
5356 if (cf
->provider
.wth
== NULL
) {
5357 report_cfile_open_failure(fname
, err
, err_info
);
5358 return CF_READ_ERROR
;
5361 /* We're scanning a file whose contents should be the same as what
5362 we had before, so we don't discard dissection state etc.. */
5365 /* Set the file name because we need it to set the follow stream filter.
5366 XXX - is that still true? We need it for other reasons, though,
5368 if (cf
->filename
!= NULL
) {
5369 g_free(cf
->filename
);
5371 cf
->filename
= g_strdup(fname
);
5373 /* Indicate whether it's a permanent or temporary file. */
5374 cf
->is_tempfile
= is_tempfile
;
5376 /* No user changes yet. */
5377 cf
->unsaved_changes
= false;
5379 /* Record the file's type and compression type. */
5380 cf
->cd_t
= wtap_file_type_subtype(cf
->provider
.wth
);
5381 cf
->compression_type
= wtap_get_compression_type(cf
->provider
.wth
);
5382 if (cf
->linktypes
!= NULL
) {
5383 g_array_free(cf
->linktypes
, TRUE
);
5385 cf
->linktypes
= g_array_sized_new(FALSE
, FALSE
, (unsigned) sizeof(int), 1);
5387 cf
->snap
= wtap_snapshot_length(cf
->provider
.wth
);
5389 name_ptr
= g_filename_display_basename(cf
->filename
);
5391 cf_callback_invoke(cf_cb_file_rescan_started
, cf
);
5393 /* Find the size of the file. */
5394 size
= wtap_file_size(cf
->provider
.wth
, NULL
);
5396 g_timer_start(prog_timer
);
5398 cf
->stop_flag
= false;
5399 start_time
= g_get_monotonic_time();
5402 wtap_rec_init(&rec
, 1514);
5403 while ((wtap_read(cf
->provider
.wth
, &rec
, &err
, &err_info
,
5406 fdata
= frame_data_sequence_find(cf
->provider
.frames
, framenum
);
5407 if (G_LIKELY(fdata
!= NULL
)) {
5408 fdata
->file_off
= data_offset
;
5411 cf
->f_datalen
= wtap_read_so_far(cf
->provider
.wth
);
5413 /* Create the progress bar if necessary. */
5414 if (progress_is_slow(progbar
, prog_timer
, size
, cf
->f_datalen
)) {
5415 progbar_val
= calc_progbar_val(cf
, size
, cf
->f_datalen
, status_str
, sizeof(status_str
));
5416 progbar
= delayed_create_progress_dlg(cf
->window
, NULL
, NULL
,
5417 true, &cf
->stop_flag
, progbar_val
);
5421 * Update the progress bar, but do it only after PROGBAR_UPDATE_INTERVAL
5422 * has elapsed. Calling update_progress_dlg and packets_bar_update will
5423 * likely trigger UI paint events, which might take a while depending on
5424 * the platform and display. Reset our timer *after* painting.
5426 if (progbar
&& g_timer_elapsed(prog_timer
, NULL
) > PROGBAR_UPDATE_INTERVAL
) {
5427 progbar_val
= calc_progbar_val(cf
, size
, cf
->f_datalen
, status_str
, sizeof(status_str
));
5428 /* update the packet bar content on the first run or frequently on very large files */
5429 update_progress_dlg(progbar
, progbar_val
, status_str
);
5430 compute_elapsed(cf
, start_time
);
5431 packets_bar_update();
5432 g_timer_start(prog_timer
);
5436 if (cf
->stop_flag
) {
5437 /* Well, the user decided to abort the rescan. Sadly, as this
5438 isn't a reread, recovering is difficult, so we'll just
5439 close the current capture. */
5443 /* Add this packet's link-layer encapsulation type to cf->linktypes, if
5444 it's not already there.
5445 XXX - yes, this is O(N), so if every packet had a different
5446 link-layer encapsulation type, it'd be O(N^2) to read the file, but
5447 there are probably going to be a small number of encapsulation types
5449 if (rec
.rec_type
== REC_TYPE_PACKET
) {
5450 cf_add_encapsulation_type(cf
, rec
.rec_header
.packet_header
.pkt_encap
);
5452 wtap_rec_reset(&rec
);
5454 wtap_rec_cleanup(&rec
);
5456 /* Free the display name */
5459 /* We're done reading the file; destroy the progress bar if it was created. */
5460 if (progbar
!= NULL
)
5461 destroy_progress_dlg(progbar
);
5462 g_timer_destroy(prog_timer
);
5464 /* We're done reading sequentially through the file. */
5465 cf
->state
= FILE_READ_DONE
;
5467 /* Close the sequential I/O side, to free up memory it requires. */
5468 wtap_sequential_close(cf
->provider
.wth
);
5470 /* compute the time it took to load the file */
5471 compute_elapsed(cf
, start_time
);
5473 /* Set the file encapsulation type now; we don't know what it is until
5474 we've looked at all the packets, as we don't know until then whether
5475 there's more than one type (and thus whether it's
5476 WTAP_ENCAP_PER_PACKET). */
5477 cf
->lnk_t
= wtap_file_encap(cf
->provider
.wth
);
5479 cf_callback_invoke(cf_cb_file_rescan_finished
, cf
);
5481 if (cf
->stop_flag
) {
5482 /* Our caller will give up at this point. */
5483 return CF_READ_ABORTED
;
5487 /* Put up a message box noting that the read failed somewhere along
5488 the line. Don't throw out the stuff we managed to read, though,
5490 report_cfile_read_failure(NULL
, err
, err_info
);
5491 return CF_READ_ERROR
;
5497 cf_save_records(capture_file
*cf
, const char *fname
, unsigned save_format
,
5498 wtap_compression_type compression_type
,
5499 bool discard_comments
, bool dont_reopen
)
5501 char *err_info
= "Unknown error";
5502 char *fname_new
= NULL
;
5505 addrinfo_lists_t
*addr_lists
;
5513 save_callback_args_t callback_args
;
5514 callback_args
.export
= false;
5515 bool needs_reload
= false;
5517 /* XXX caller should avoid saving the file while a read is pending
5518 * (e.g. by delaying the save action) */
5519 if (cf
->read_lock
) {
5520 ws_warning("cf_save_records(\"%s\") while the file is being read, potential crash ahead", fname
);
5523 cf_callback_invoke(cf_cb_file_save_started
, (void *)fname
);
5525 addr_lists
= get_addrinfo_list();
5527 if (save_format
== cf
->cd_t
&& compression_type
== cf
->compression_type
5528 && !discard_comments
&& !cf
->unsaved_changes
5529 && (wtap_addrinfo_list_empty(addr_lists
) || wtap_file_type_subtype_supports_block(save_format
, WTAP_BLOCK_NAME_RESOLUTION
) == BLOCK_NOT_SUPPORTED
)) {
5530 /* We're saving in the format it's already in, and we're not discarding
5531 comments, and there are no changes we have in memory that aren't saved
5532 to the file, and we have no name resolution information to write or
5533 the file format we're saving in doesn't support writing name
5534 resolution information, so we can just move or copy the raw data. */
5536 if (cf
->is_tempfile
) {
5537 /* The file being saved is a temporary file from a live
5538 capture, so it doesn't need to stay around under that name;
5539 first, try renaming the capture buffer file to the new name.
5540 This acts as a "safe save", in that, if the file already
5541 exists, the existing file will be removed only if the rename
5544 Sadly, on Windows, as we have the current capture file
5545 open, even MoveFileEx() with MOVEFILE_REPLACE_EXISTING
5546 (to cause the rename to remove an existing target), as
5547 done by ws_stdio_rename() (ws_rename() is #defined to
5548 be ws_stdio_rename() on Windows) will fail.
5550 According to the MSDN documentation for CreateFile(), if,
5551 when we open a capture file, we were to directly do a CreateFile(),
5552 opening with FILE_SHARE_DELETE|FILE_SHARE_READ, and then
5553 convert it to a file descriptor with _open_osfhandle(),
5554 that would allow the file to be renamed out from under us.
5556 However, that doesn't work in practice. Perhaps the problem
5557 is that the process doing the rename is the process that
5558 has the file open. */
5560 if (ws_rename(cf
->filename
, fname
) == 0) {
5561 /* That succeeded - there's no need to copy the source file. */
5562 how_to_save
= SAVE_WITH_MOVE
;
5564 if (errno
== EXDEV
) {
5565 /* They're on different file systems, so we have to copy the
5567 how_to_save
= SAVE_WITH_COPY
;
5569 /* The rename failed, but not because they're on different
5570 file systems - put up an error message. (Or should we
5571 just punt and try to copy? The only reason why I'd
5572 expect the rename to fail and the copy to succeed would
5573 be if we didn't have permission to remove the file from
5574 the temporary directory, and that might be fixable - but
5575 is it worth requiring the user to go off and fix it?) */
5576 report_rename_failure(cf
->filename
, fname
, errno
);
5581 /* Windows - copy the file to its new location. */
5582 how_to_save
= SAVE_WITH_COPY
;
5585 /* It's a permanent file, so we should copy it, and not remove the
5587 how_to_save
= SAVE_WITH_COPY
;
5590 if (how_to_save
== SAVE_WITH_COPY
) {
5591 /* Copy the file, if we haven't moved it. If we're overwriting
5592 an existing file, we do it with a "safe save", by writing
5593 to a new file and, if the write succeeds, renaming the
5594 new file on top of the old file. */
5595 if (file_exists(fname
)) {
5596 fname_new
= ws_strdup_printf("%s~", fname
);
5597 if (!copy_file_binary_mode(cf
->filename
, fname_new
))
5600 if (!copy_file_binary_mode(cf
->filename
, fname
))
5605 /* Either we're saving in a different format or we're saving changes,
5606 such as added, modified, or removed comments, that haven't yet
5607 been written to the underlying file; we can't do that by copying
5608 or moving the capture file, we have to do it by writing the packets
5611 wtap_dump_params params
;
5614 how_to_save
= SAVE_WITH_WTAP
;
5615 wtap_dump_params_init(¶ms
, cf
->provider
.wth
);
5617 /* Determine what file encapsulation type we should use. */
5618 encap
= wtap_dump_required_file_encap_type(cf
->linktypes
);
5619 params
.encap
= encap
;
5621 /* Use the snaplen from cf (XXX - does wtap_dump_params_init handle that?) */
5622 params
.snaplen
= cf
->snap
;
5624 if (file_exists(fname
)) {
5625 /* We're overwriting an existing file; write out to a new file,
5626 and, if that succeeds, rename the new file on top of the
5627 old file. That makes this a "safe save", so that we don't
5628 lose the old file if we have a problem writing out the new
5629 file. (If the existing file is the current capture file,
5630 we *HAVE* to do that, otherwise we're overwriting the file
5631 from which we're reading the packets that we're writing!) */
5632 fname_new
= ws_strdup_printf("%s~", fname
);
5633 pdh
= wtap_dump_open(fname_new
, save_format
, compression_type
, ¶ms
,
5636 pdh
= wtap_dump_open(fname
, save_format
, compression_type
, ¶ms
,
5639 /* XXX idb_inf is documented to be used until wtap_dump_close. */
5640 g_free(params
.idb_inf
);
5641 params
.idb_inf
= NULL
;
5644 report_cfile_dump_open_failure(fname
, err
, err_info
, save_format
);
5648 /* Add address resolution */
5649 wtap_dump_set_addrinfo_list(pdh
, addr_lists
);
5651 /* Iterate through the list of packets, processing all the packets. */
5652 callback_args
.pdh
= pdh
;
5653 callback_args
.fname
= fname
;
5654 callback_args
.file_type
= save_format
;
5655 switch (process_specified_records(cf
, NULL
, "Saving", "packets",
5656 true, save_record
, &callback_args
, true)) {
5659 /* Completed successfully. */
5663 /* The user decided to abort the saving.
5664 If we're writing to a temporary file, remove it.
5665 XXX - should we do so even if we're not writing to a
5667 wtap_dump_close(pdh
, NULL
, &err
, &err_info
);
5668 if (fname_new
!= NULL
)
5669 ws_unlink(fname_new
);
5670 cf_callback_invoke(cf_cb_file_save_stopped
, NULL
);
5671 wtap_dump_params_cleanup(¶ms
);
5672 return CF_WRITE_ABORTED
;
5675 /* Error while saving.
5676 If we're writing to a temporary file, remove it. */
5677 if (fname_new
!= NULL
)
5678 ws_unlink(fname_new
);
5679 wtap_dump_close(pdh
, NULL
, &err
, &err_info
);
5680 wtap_dump_params_cleanup(¶ms
);
5684 if (!wtap_dump_close(pdh
, &needs_reload
, &err
, &err_info
)) {
5685 report_cfile_close_failure(fname
, err
, err_info
);
5686 wtap_dump_params_cleanup(¶ms
);
5690 wtap_dump_params_cleanup(¶ms
);
5693 if (fname_new
!= NULL
) {
5694 /* We wrote out to fname_new, and should rename it on top of
5695 fname. fname_new is now closed, so that should be possible even
5696 on Windows. However, on Windows, we first need to close whatever
5697 file descriptors we have open for fname. */
5699 wtap_fdclose(cf
->provider
.wth
);
5701 /* Now do the rename. */
5702 if (ws_rename(fname_new
, fname
) == -1) {
5703 /* Well, the rename failed. */
5704 report_rename_failure(fname_new
, fname
, errno
);
5706 /* Attempt to reopen the random file descriptor using the
5707 current file's filename. (At this point, the sequential
5708 file descriptor is closed.) */
5709 if (!wtap_fdreopen(cf
->provider
.wth
, cf
->filename
, &err
)) {
5710 /* Oh, well, we're screwed. */
5711 report_cfile_open_failure(cf
->filename
, err
, NULL
);
5719 /* If this was a temporary file, and we didn't do the save by doing
5720 a move, so the tempoary file is still around under its old name,
5722 if (cf
->is_tempfile
&& how_to_save
!= SAVE_WITH_MOVE
) {
5723 /* If this fails, there's not much we can do, so just ignore errors. */
5724 ws_unlink(cf
->filename
);
5727 cf_callback_invoke(cf_cb_file_save_finished
, NULL
);
5728 cf
->unsaved_changes
= false;
5731 switch (how_to_save
) {
5733 case SAVE_WITH_MOVE
:
5734 /* We just moved the file, so the wtap structure refers to the
5735 new file, and all the information other than the filename
5736 and the "is temporary" status applies to the new file; just
5738 g_free(cf
->filename
);
5739 cf
->filename
= g_strdup(fname
);
5740 cf
->is_tempfile
= false;
5741 cf_callback_invoke(cf_cb_file_fast_save_finished
, cf
);
5744 case SAVE_WITH_COPY
:
5745 /* We just copied the file, so all the information other than
5746 the file descriptors, the filename, and the "is temporary"
5747 status applies to the new file; just update that. */
5748 wtap_fdclose(cf
->provider
.wth
);
5749 /* Attempt to reopen the random file descriptor using the
5750 new file's filename. (At this point, the sequential
5751 file descriptor is closed.) */
5752 if (!wtap_fdreopen(cf
->provider
.wth
, fname
, &err
)) {
5753 report_cfile_open_failure(fname
, err
, err_info
);
5756 g_free(cf
->filename
);
5757 cf
->filename
= g_strdup(fname
);
5758 cf
->is_tempfile
= false;
5760 cf_callback_invoke(cf_cb_file_fast_save_finished
, cf
);
5763 case SAVE_WITH_WTAP
:
5764 /* Open and read the file we saved to.
5766 XXX - this is somewhat of a waste; we already have the
5767 packets, all this gets us is updated file type information
5768 (which we could just stuff into "cf"), and having the new
5769 file be the one we have opened and from which we're reading
5770 the data, and it means we have to spend time opening and
5771 reading the file, which could be a significant amount of
5772 time if the file is large.
5774 If the capture-file-writing code were to return the
5775 seek offset of each packet it writes, we could save that
5776 in the frame_data structure for the frame, and just open
5777 the file without reading it again...
5779 ...as long as, for gzipped files, the process of writing
5780 out the file *also* generates the information needed to
5781 support fast random access to the compressed file. */
5782 /* rescan_file will cause us to try all open_routines, so
5783 reset cfile's open_type */
5784 cf
->open_type
= WTAP_TYPE_AUTO
;
5785 /* There are cases when SAVE_WITH_WTAP can result in new packets
5786 being written to the file, e.g ERF records
5787 In that case, we need to reload the whole file */
5789 if (cf_open(cf
, fname
, WTAP_TYPE_AUTO
, false, &err
) == CF_OK
) {
5790 if (cf_read(cf
, /*reloading=*/true) != CF_READ_OK
) {
5791 /* The rescan failed; just close the file. Either
5792 a dialog was popped up for the failure, so the
5793 user knows what happened, or they stopped the
5794 rescan, in which case they know what happened. */
5795 /* XXX: This is inconsistent with normal open/reload behaviour. */
5801 if (rescan_file(cf
, fname
, false) != CF_READ_OK
) {
5802 /* The rescan failed; just close the file. Either
5803 a dialog was popped up for the failure, so the
5804 user knows what happened, or they stopped the
5805 rescan, in which case they know what happened. */
5812 /* If we were told to discard the comments, do so. */
5813 if (discard_comments
) {
5814 /* Remove SHB comment, if any. */
5815 wtap_write_shb_comment(cf
->provider
.wth
, NULL
);
5817 /* remove all user comments */
5818 for (framenum
= 1; framenum
<= cf
->count
; framenum
++) {
5819 fdata
= frame_data_sequence_find(cf
->provider
.frames
, framenum
);
5821 // XXX: This also ignores non-comment options like verdict
5822 fdata
->has_modified_block
= false;
5825 if (cf
->provider
.frames_modified_blocks
) {
5826 g_tree_destroy(cf
->provider
.frames_modified_blocks
);
5827 cf
->provider
.frames_modified_blocks
= NULL
;
5830 cf
->packet_comment_count
= 0;
5836 if (fname_new
!= NULL
) {
5837 /* We were trying to write to a temporary file; get rid of it if it
5838 exists. (We don't care whether this fails, as, if it fails,
5839 there's not much we can do about it. I guess if it failed for
5840 a reason other than "it doesn't exist", we could report an
5841 error, so the user knows there's a junk file that they might
5842 want to clean up.) */
5843 ws_unlink(fname_new
);
5846 cf_callback_invoke(cf_cb_file_save_failed
, NULL
);
5847 return CF_WRITE_ERROR
;
5851 cf_export_specified_packets(capture_file
*cf
, const char *fname
,
5852 packet_range_t
*range
, unsigned save_format
,
5853 wtap_compression_type compression_type
)
5855 char *fname_new
= NULL
;
5859 save_callback_args_t callback_args
;
5860 wtap_dump_params params
;
5863 callback_args
.export
= true;
5864 packet_range_process_init(range
);
5866 /* We're writing out specified packets from the specified capture
5867 file to another file. Even if all captured packets are to be
5868 written, don't special-case the operation - read each packet
5869 and then write it out if it's one of the specified ones. */
5871 wtap_dump_params_init(¶ms
, cf
->provider
.wth
);
5873 /* Determine what file encapsulation type we should use. */
5874 encap
= wtap_dump_required_file_encap_type(cf
->linktypes
);
5875 params
.encap
= encap
;
5877 /* Use the snaplen from cf (XXX - does wtap_dump_params_init handle that?) */
5878 params
.snaplen
= cf
->snap
;
5880 if (file_exists(fname
)) {
5881 /* We're overwriting an existing file; write out to a new file,
5882 and, if that succeeds, rename the new file on top of the
5883 old file. That makes this a "safe save", so that we don't
5884 lose the old file if we have a problem writing out the new
5885 file. (If the existing file is the current capture file,
5886 we *HAVE* to do that, otherwise we're overwriting the file
5887 from which we're reading the packets that we're writing!) */
5888 fname_new
= ws_strdup_printf("%s~", fname
);
5889 pdh
= wtap_dump_open(fname_new
, save_format
, compression_type
, ¶ms
,
5892 pdh
= wtap_dump_open(fname
, save_format
, compression_type
, ¶ms
,
5895 /* XXX idb_inf is documented to be used until wtap_dump_close. */
5896 g_free(params
.idb_inf
);
5897 params
.idb_inf
= NULL
;
5900 report_cfile_dump_open_failure(fname
, err
, err_info
, save_format
);
5904 /* Add address resolution */
5905 wtap_dump_set_addrinfo_list(pdh
, get_addrinfo_list());
5907 /* Iterate through the list of packets, processing the packets we were
5910 XXX - we've already called "packet_range_process_init(range)", but
5911 "process_specified_records()" will do it again. Fortunately,
5912 that's harmless in this case, as we haven't done anything to
5913 "range" since we initialized it. */
5914 callback_args
.pdh
= pdh
;
5915 callback_args
.fname
= fname
;
5916 callback_args
.file_type
= save_format
;
5917 switch (process_specified_records(cf
, range
, "Writing", "specified records",
5918 true, save_record
, &callback_args
, true)) {
5921 /* Completed successfully. */
5925 /* The user decided to abort the saving.
5926 If we're writing to a temporary file, remove it.
5927 XXX - should we do so even if we're not writing to a
5929 wtap_dump_close(pdh
, NULL
, &err
, &err_info
);
5930 if (fname_new
!= NULL
) {
5931 ws_unlink(fname_new
);
5934 wtap_dump_params_cleanup(¶ms
);
5936 return CF_WRITE_ABORTED
;
5939 /* Error while saving. */
5940 wtap_dump_close(pdh
, NULL
, &err
, &err_info
);
5942 * We don't report any error from closing; the error that caused
5943 * process_specified_records() to fail has already been reported.
5948 if (!wtap_dump_close(pdh
, NULL
, &err
, &err_info
)) {
5949 report_cfile_close_failure(fname
, err
, err_info
);
5953 if (fname_new
!= NULL
) {
5954 /* We wrote out to fname_new, and should rename it on top of
5955 fname; fname is now closed, so that should be possible even
5956 on Windows. Do the rename. */
5957 if (ws_rename(fname_new
, fname
) == -1) {
5958 /* Well, the rename failed. */
5959 report_rename_failure(fname_new
, fname
, errno
);
5964 wtap_dump_params_cleanup(¶ms
);
5969 if (fname_new
!= NULL
) {
5970 /* We were trying to write to a temporary file; get rid of it if it
5971 exists. (We don't care whether this fails, as, if it fails,
5972 there's not much we can do about it. I guess if it failed for
5973 a reason other than "it doesn't exist", we could report an
5974 error, so the user knows there's a junk file that they might
5975 want to clean up.) */
5976 ws_unlink(fname_new
);
5979 wtap_dump_params_cleanup(¶ms
);
5981 return CF_WRITE_ERROR
;
5984 /* Reload the current capture file. */
5986 cf_reload(capture_file
*cf
)
5990 cf_status_t cf_status
= CF_OK
;
5993 if (cf
->read_lock
) {
5994 ws_warning("Failing cf_reload(\"%s\") since a read is in progress", cf
->filename
);
5998 /* If the file could be opened, "cf_open()" calls "cf_close()"
5999 to get rid of state for the old capture file before filling in state
6000 for the new capture file. "cf_close()" will remove the file if
6001 it's a temporary file; we don't want that to happen (for one thing,
6002 it'd prevent subsequent reopens from working). Remember whether it's
6003 a temporary file, mark it as not being a temporary file, and then
6004 reopen it as the type of file it was.
6006 Also, "cf_close()" will free "cf->filename", so we must make
6007 a copy of it first. */
6008 filename
= g_strdup(cf
->filename
);
6009 is_tempfile
= cf
->is_tempfile
;
6010 cf
->is_tempfile
= false;
6011 if (cf_open(cf
, filename
, cf
->open_type
, is_tempfile
, &err
) == CF_OK
) {
6012 switch (cf_read(cf
, /*reloading=*/true)) {
6016 /* Just because we got an error, that doesn't mean we were unable
6017 to read any of the file; we handle what we could get from the
6021 case CF_READ_ABORTED
:
6022 /* The user bailed out of re-reading the capture file; the
6023 capture file has been closed. */
6027 /* The open failed, so "cf->is_tempfile" wasn't set to "is_tempfile".
6028 Instead, the file was left open, so we should restore "cf->is_tempfile"
6031 XXX - change the menu? Presumably "cf_open()" will do that;
6032 make sure it does! */
6033 cf
->is_tempfile
= is_tempfile
;
6034 cf_status
= CF_ERROR
;
6036 /* "cf_open()" made a copy of the file name we handed it, so
6037 we should free up our copy. */