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 XXX - pop up a dialog box instead? */
921 if (err_info
!= NULL
) {
922 ws_warning("Error \"%s\" while reading \"%s\" (\"%s\")",
923 wtap_strerror(*err
), cf
->filename
, err_info
);
926 ws_warning("Error \"%s\" while reading \"%s\"",
927 wtap_strerror(*err
), cf
->filename
);
929 return CF_READ_ERROR
;
935 cf_fake_continue_tail(capture_file
*cf
)
937 if (cf
->state
== FILE_CLOSED
) {
938 cf
->state
= FILE_READ_PENDING
;
943 cf_finish_tail(capture_file
*cf
, wtap_rec
*rec
, int *err
,
944 fifo_string_cache_t
*frame_dup_cache
, GChecksum
*frame_cksum
)
950 bool create_proto_tree
;
953 /* All the comments above in cf_continue_tail apply regarding the
954 * current display filter.
957 /* Get the union of the flags for all tap listeners. */
958 tap_flags
= union_of_tap_listener_flags();
960 /* If the display filter or any tap listeners require the columns,
962 cinfo
= (tap_listeners_require_columns() ||
963 dfilter_requires_columns(cf
->dfcode
)) ? &cf
->cinfo
: NULL
;
966 * Determine whether we need to create a protocol tree.
969 * we're going to apply a display filter;
971 * one of the tap listeners is going to apply a filter;
973 * one of the tap listeners requires a protocol tree;
975 * a postdissector wants field values or protocols on
979 (cf
->dfcode
!= NULL
|| have_filtering_tap_listeners() ||
980 (tap_flags
& TL_REQUIRES_PROTO_TREE
) || postdissectors_want_hfids());
982 if (cf
->provider
.wth
== NULL
) {
984 return CF_READ_ERROR
;
987 /* Don't freeze/thaw the list when doing live capture */
988 /*packet_list_freeze();*/
990 epan_dissect_init(&edt
, cf
->epan
, create_proto_tree
, false);
992 while ((wtap_read(cf
->provider
.wth
, rec
, err
, &err_info
, &data_offset
))) {
993 if (cf
->state
== FILE_READ_ABORTED
) {
994 /* Well, the user decided to abort the read. Break out of the
995 loop, and let the code below (which is called even if there
996 aren't any packets left to read) exit. */
999 read_record(cf
, rec
, cf
->dfcode
, &edt
, cinfo
, data_offset
, frame_dup_cache
, frame_cksum
);
1000 wtap_rec_reset(rec
);
1003 epan_dissect_cleanup(&edt
);
1005 /* Don't freeze/thaw the list when doing live capture */
1006 /*packet_list_thaw();*/
1008 if (cf
->state
== FILE_READ_ABORTED
) {
1009 /* Well, the user decided to abort the read. We're only called
1010 when the child capture process closes the pipe to us (meaning
1011 it's probably exited), so we can just close the capture
1012 file; we return CF_READ_ABORTED so our caller can do whatever
1013 is appropriate when that happens. */
1015 return CF_READ_ABORTED
;
1018 /* We're done reading sequentially through the file. */
1019 cf
->state
= FILE_READ_DONE
;
1021 /* We're done reading sequentially through the file; close the
1022 sequential I/O side, to free up memory it requires. */
1023 wtap_sequential_close(cf
->provider
.wth
);
1025 /* Allow the protocol dissectors to free up memory that they
1026 * don't need after the sequential run-through of the packets. */
1027 postseq_cleanup_all_protocols();
1029 /* Update the file encapsulation; it might have changed based on the
1030 packets we've read. */
1031 cf
->lnk_t
= wtap_file_encap(cf
->provider
.wth
);
1033 /* Update the details in the file-set dialog, as the capture file
1034 * has likely grown since we first stat-ed it */
1035 fileset_update_file(cf
->filename
);
1038 /* We got an error reading the capture file.
1039 XXX - pop up a dialog box? */
1040 if (err_info
!= NULL
) {
1041 ws_warning("Error \"%s\" while reading \"%s\" (\"%s\")",
1042 wtap_strerror(*err
), cf
->filename
, err_info
);
1045 ws_warning("Error \"%s\" while reading \"%s\"",
1046 wtap_strerror(*err
), cf
->filename
);
1048 return CF_READ_ERROR
;
1053 #endif /* HAVE_LIBPCAP */
1056 cf_get_display_name(capture_file
*cf
)
1060 /* Return a name to use in displays */
1061 if (!cf
->is_tempfile
) {
1062 /* Get the last component of the file name, and use that. */
1064 displayname
= g_filename_display_basename(cf
->filename
);
1066 displayname
=g_strdup("(No file)");
1069 /* The file we read is a temporary file from a live capture or
1070 a merge operation; we don't mention its name, but, if it's
1071 from a capture, give the source of the capture. */
1073 displayname
= g_strdup(cf
->source
);
1075 displayname
= g_strdup("(Untitled)");
1082 cf_get_basename(capture_file
*cf
)
1086 /* Return a name to use in the GUI for the basename for files to
1087 which we save statistics */
1088 if (!cf
->is_tempfile
) {
1089 /* Get the last component of the file name, and use that. */
1091 displayname
= g_filename_display_basename(cf
->filename
);
1093 /* If the file name ends with any extension that corresponds
1094 to a file type we support - including compressed versions
1095 of those files - strip it off. */
1096 size_t displayname_len
= strlen(displayname
);
1097 GSList
*extensions
= wtap_get_all_file_extensions_list();
1099 for (suffix
= extensions
; suffix
!= NULL
; suffix
= g_slist_next(suffix
)) {
1100 /* Does the file name end with that extension? */
1101 const char *extension
= (char *)suffix
->data
;
1102 size_t extension_len
= strlen(extension
);
1103 if (displayname_len
> extension_len
&&
1104 displayname
[displayname_len
- extension_len
- 1] == '.' &&
1105 strcmp(&displayname
[displayname_len
- extension_len
], extension
) == 0) {
1106 /* Yes. Strip the extension off, and return the result. */
1107 displayname
[displayname_len
- extension_len
- 1] = '\0';
1111 wtap_free_extensions_list(extensions
);
1113 displayname
=g_strdup("");
1116 /* The file we read is a temporary file from a live capture or
1117 a merge operation; we don't mention its name, but, if it's
1118 from a capture, give the source of the capture. */
1120 displayname
= g_strdup(cf
->source
);
1122 displayname
= g_strdup("");
1129 cf_set_tempfile_source(capture_file
*cf
, char *source
)
1136 cf
->source
= g_strdup(source
);
1138 cf
->source
= g_strdup("");
1143 cf_get_tempfile_source(capture_file
*cf
)
1152 /* XXX - use a macro instead? */
1154 cf_get_packet_count(capture_file
*cf
)
1159 /* XXX - use a macro instead? */
1161 cf_is_tempfile(capture_file
*cf
)
1163 return cf
->is_tempfile
;
1167 cf_set_tempfile(capture_file
*cf
, bool is_tempfile
)
1169 cf
->is_tempfile
= is_tempfile
;
1173 /* XXX - use a macro instead? */
1175 cf_set_drops_known(capture_file
*cf
, bool drops_known
)
1177 cf
->drops_known
= drops_known
;
1180 /* XXX - use a macro instead? */
1182 cf_set_drops(capture_file
*cf
, uint32_t drops
)
1187 /* XXX - use a macro instead? */
1189 cf_get_drops_known(capture_file
*cf
)
1191 return cf
->drops_known
;
1194 /* XXX - use a macro instead? */
1196 cf_get_drops(capture_file
*cf
)
1202 cf_set_rfcode(capture_file
*cf
, dfilter_t
*rfcode
)
1204 cf
->rfcode
= rfcode
;
1208 add_packet_to_packet_list(frame_data
*fdata
, capture_file
*cf
,
1209 epan_dissect_t
*edt
, dfilter_t
*dfcode
, column_info
*cinfo
,
1210 wtap_rec
*rec
, bool add_to_packet_list
)
1212 frame_data_set_before_dissect(fdata
, &cf
->elapsed_time
,
1213 &cf
->provider
.ref
, cf
->provider
.prev_dis
);
1214 cf
->provider
.prev_cap
= fdata
;
1216 if (dfcode
!= NULL
) {
1217 epan_dissect_prime_with_dfilter(edt
, dfcode
);
1220 /* Prepare coloring rules, this ensures that display filter rules containing
1221 * frame.color_rule references are still processed.
1222 * TODO: actually detect that situation or maybe apply other optimizations? */
1223 if (edt
->tree
&& color_filters_used()) {
1224 color_filters_prime_edt(edt
);
1225 fdata
->need_colorize
= 1;
1229 if (!fdata
->visited
) {
1230 /* This is the first pass, so prime the epan_dissect_t with the
1231 hfids postdissectors want on the first pass. */
1232 prime_epan_dissect_with_postdissector_wanted_hfids(edt
);
1235 /* Initialize passed_dfilter here so that dissectors can hide packets. */
1236 /* XXX We might want to add a separate "visible" bit to frame_data instead. */
1237 fdata
->passed_dfilter
= 1;
1239 /* Dissect the frame. */
1240 epan_dissect_run_with_taps(edt
, cf
->cd_t
, rec
, fdata
, cinfo
);
1242 if (fdata
->passed_dfilter
&& dfcode
!= NULL
) {
1243 fdata
->passed_dfilter
= dfilter_apply_edt(dfcode
, edt
) ? 1 : 0;
1245 if (fdata
->passed_dfilter
&& edt
->pi
.fd
->dependent_frames
) {
1246 /* This frame passed the display filter but it may depend on other
1247 * (potentially not displayed) frames. Find those frames and mark them
1250 g_hash_table_foreach(edt
->pi
.fd
->dependent_frames
, find_and_mark_frame_depended_upon
, cf
->provider
.frames
);
1254 if (fdata
->passed_dfilter
|| fdata
->ref_time
) {
1255 cf
->displayed_count
++;
1256 fdata
->dis_num
= cf
->displayed_count
;
1259 if (add_to_packet_list
) {
1260 /* We fill the needed columns from new_packet_list */
1261 packet_list_append(cinfo
, fdata
);
1264 if (fdata
->passed_dfilter
|| fdata
->ref_time
)
1266 frame_data_set_after_dissect(fdata
, &cf
->cum_bytes
);
1267 /* The only way we use prev_dis is to get the time stamp of
1268 * the previous displayed frame, so ignore it if it doesn't
1269 * have a time stamp, because we're presumably interested in
1270 * the timestamp of the previously displayed frame with a
1271 * time. XXX: What if in the future we want to use the previously
1272 * displayed frame for something else, too?
1274 if (fdata
->has_ts
) {
1275 cf
->provider
.prev_dis
= fdata
;
1278 /* If we haven't yet seen the first frame, this is it. */
1279 if (cf
->first_displayed
== 0)
1280 cf
->first_displayed
= fdata
->num
;
1282 /* This is the last frame we've seen so far. */
1283 cf
->last_displayed
= fdata
->num
;
1286 epan_dissect_reset(edt
);
1290 * Read in a new record.
1291 * Returns true if the packet was added to the packet (record) list,
1295 read_record(capture_file
*cf
, wtap_rec
*rec
, dfilter_t
*dfcode
,
1296 epan_dissect_t
*edt
, column_info
*cinfo
, int64_t offset
,
1297 fifo_string_cache_t
*frame_dup_cache
, GChecksum
*frame_cksum
)
1303 const char *cksum_string
;
1306 /* Add this packet's link-layer encapsulation type to cf->linktypes, if
1307 it's not already there.
1308 XXX - yes, this is O(N), so if every packet had a different
1309 link-layer encapsulation type, it'd be O(N^2) to read the file, but
1310 there are probably going to be a small number of encapsulation types
1312 if (rec
->rec_type
== REC_TYPE_PACKET
) {
1313 cf_add_encapsulation_type(cf
, rec
->rec_header
.packet_header
.pkt_encap
);
1316 /* The frame number of this packet, if we add it to the set of frames,
1317 would be one more than the count of frames in the file so far. */
1318 frame_data_init(&fdlocal
, cf
->count
+ 1, rec
, offset
, cf
->cum_bytes
);
1321 epan_dissect_t rf_edt
;
1322 column_info
*rf_cinfo
= NULL
;
1324 epan_dissect_init(&rf_edt
, cf
->epan
, true, false);
1325 epan_dissect_prime_with_dfilter(&rf_edt
, cf
->rfcode
);
1326 if (dfilter_requires_columns(cf
->rfcode
)) {
1327 rf_cinfo
= &cf
->cinfo
;
1329 epan_dissect_run(&rf_edt
, cf
->cd_t
, rec
, &fdlocal
, rf_cinfo
);
1330 passed
= dfilter_apply_edt(cf
->rfcode
, &rf_edt
);
1331 epan_dissect_cleanup(&rf_edt
);
1337 /* This does a shallow copy of fdlocal, which is good enough. */
1338 fdata
= frame_data_sequence_add(cf
->provider
.frames
, &fdlocal
);
1341 if (rec
->block
!= NULL
)
1342 cf
->packet_comment_count
+= wtap_block_count_option(rec
->block
, OPT_COMMENT
);
1343 cf
->f_datalen
= offset
+ fdlocal
.cap_len
;
1345 // Should we check if the frame data is a duplicate, and thus, ignore
1347 if (frame_cksum
!= NULL
&& rec
->rec_type
== REC_TYPE_PACKET
) {
1348 g_checksum_reset(frame_cksum
);
1349 g_checksum_update(frame_cksum
, ws_buffer_start_ptr(&rec
->data
), ws_buffer_length(&rec
->data
));
1350 cksum_string
= g_strdup(g_checksum_get_string(frame_cksum
));
1351 was_in_cache
= fifo_string_cache_insert(frame_dup_cache
, cksum_string
);
1353 g_free((void *)cksum_string
);
1354 fdata
->ignored
= true;
1355 cf
->ignored_count
++;
1359 /* When a redissection is in progress (or queued), do not process packets.
1360 * This will be done once all (new) packets have been scanned. */
1361 if (!cf
->redissecting
&& cf
->redissection_queued
== RESCAN_NONE
) {
1362 add_packet_to_packet_list(fdata
, cf
, edt
, dfcode
, cinfo
, rec
, true);
1370 typedef struct _callback_data_t
{
1380 merge_callback(merge_event event
, int num _U_
,
1381 const merge_in_file_t in_files
[], const unsigned in_file_count
,
1385 callback_data_t
*cb_data
= (callback_data_t
*) data
;
1387 ws_assert(cb_data
!= NULL
);
1391 case MERGE_EVENT_INPUT_FILES_OPENED
:
1395 case MERGE_EVENT_FRAME_TYPE_SELECTED
:
1399 case MERGE_EVENT_READY_TO_MERGE
:
1400 /* Get the sum of the sizes of all the files. */
1401 for (i
= 0; i
< in_file_count
; i
++)
1402 cb_data
->f_len
+= in_files
[i
].size
;
1404 cb_data
->prog_timer
= g_timer_new();
1405 g_timer_start(cb_data
->prog_timer
);
1408 case MERGE_EVENT_RECORD_WAS_READ
:
1410 /* Create the progress bar if necessary.
1411 We check on every iteration of the loop, so that it takes no
1412 longer than the standard time to create it (otherwise, for a
1413 large file, we might take considerably longer than that standard
1414 time in order to get to the next progress bar step). */
1415 if (cb_data
->progbar
== NULL
) {
1416 cb_data
->progbar
= delayed_create_progress_dlg(cb_data
->pd_window
, NULL
, NULL
,
1417 false, &cb_data
->stop_flag
, 0.0f
);
1421 * Update the progress bar, but do it only after
1422 * PROGBAR_UPDATE_INTERVAL has elapsed. Calling update_progress_dlg
1423 * and packets_bar_update will likely trigger UI paint events, which
1424 * might take a while depending on the platform and display. Reset
1425 * our timer *after* painting.
1427 if (g_timer_elapsed(cb_data
->prog_timer
, NULL
) > PROGBAR_UPDATE_INTERVAL
) {
1429 int64_t file_pos
= 0;
1430 /* Get the sum of the seek positions in all of the files. */
1431 for (i
= 0; i
< in_file_count
; i
++)
1432 file_pos
+= wtap_read_so_far(in_files
[i
].wth
);
1434 progbar_val
= (float) file_pos
/ (float) cb_data
->f_len
;
1435 if (progbar_val
> 1.0f
) {
1436 /* Some file probably grew while we were reading it.
1437 That "shouldn't happen", so we'll just clip the progress
1442 if (cb_data
->progbar
!= NULL
) {
1443 char status_str
[100];
1444 snprintf(status_str
, sizeof(status_str
),
1445 "%" PRId64
"KB of %" PRId64
"KB",
1446 file_pos
/ 1024, cb_data
->f_len
/ 1024);
1447 update_progress_dlg(cb_data
->progbar
, progbar_val
, status_str
);
1449 g_timer_start(cb_data
->prog_timer
);
1454 case MERGE_EVENT_DONE
:
1455 /* We're done merging the files; destroy the progress bar if it was created. */
1456 if (cb_data
->progbar
!= NULL
)
1457 destroy_progress_dlg(cb_data
->progbar
);
1458 g_timer_destroy(cb_data
->prog_timer
);
1462 return cb_data
->stop_flag
;
1468 cf_merge_files_to_tempfile(void *pd_window
, const char *temp_dir
, char **out_filenamep
,
1469 int in_file_count
, const char *const *in_filenames
,
1470 int file_type
, bool do_append
)
1473 merge_progress_callback_t cb
;
1474 callback_data_t
*cb_data
= g_new0(callback_data_t
, 1);
1476 /* prepare our callback routine */
1477 cb_data
->pd_window
= pd_window
;
1478 cb
.callback_func
= merge_callback
;
1481 cf_callback_invoke(cf_cb_file_merge_started
, NULL
);
1483 /* merge the files */
1484 status
= merge_files_to_tempfile(temp_dir
, out_filenamep
, "wireshark", file_type
,
1486 in_file_count
, do_append
,
1487 IDB_MERGE_MODE_ALL_SAME
, 0 /* snaplen */,
1492 cf_callback_invoke(cf_cb_file_merge_finished
, NULL
);
1495 /* Callers aren't expected to treat an error or an explicit abort
1496 differently - the merge code puts up error dialogs itself, so
1497 they don't have to. */
1504 cf_filter_packets(capture_file
*cf
, char *dftext
, bool force
)
1506 const char *filter_new
= dftext
? dftext
: "";
1507 const char *filter_old
= cf
->dfilter
? cf
->dfilter
: "";
1511 /* if new filter equals old one, do nothing unless told to do so */
1512 /* XXX - The text can be the same without compiling to the same code.
1513 * (Macros, field references, etc.)
1515 if (!force
&& strcmp(filter_new
, filter_old
) == 0) {
1521 if (dftext
== NULL
) {
1522 /* The new filter is an empty filter (i.e., display all packets).
1523 * so leave dfcode==NULL
1527 * We have a filter; make a copy of it (as we'll be saving it),
1528 * and try to compile it.
1530 dftext
= g_strdup(dftext
);
1531 if (!dfilter_compile(dftext
, &dfcode
, &df_err
)) {
1532 /* The attempt failed; report an error. */
1533 simple_message_box(ESD_TYPE_ERROR
, NULL
,
1534 "See the help for a description of the display filter syntax.",
1535 "\"%s\" isn't a valid display filter: %s",
1536 dftext
, df_err
->msg
);
1537 df_error_free(&df_err
);
1543 if (dfcode
== NULL
) {
1544 /* Yes - free the filter text, and set it to null. */
1550 /* We have a valid filter. Replace the current filter. */
1551 g_free(cf
->dfilter
);
1552 cf
->dfilter
= dftext
;
1554 /* We'll recompile this when the rescan starts, or in cf_read()
1555 * if no file is open currently. However, if no file is open and
1556 * we start a new capture, we want to use this rather than
1557 * recompiling in cf_continue_tail() */
1558 dfilter_free(cf
->dfcode
);
1559 cf
->dfcode
= dfcode
;
1561 /* Now rescan the packet list, applying the new filter, but not
1562 * throwing away information constructed on a previous pass.
1563 * If a dissection is already in progress, queue it.
1565 if (cf
->redissection_queued
== RESCAN_NONE
) {
1566 if (cf
->read_lock
) {
1567 cf
->redissection_queued
= RESCAN_SCAN
;
1568 } else if (cf
->state
!= FILE_CLOSED
) {
1569 if (dftext
== NULL
) {
1570 rescan_packets(cf
, "Resetting", "filter", false);
1572 rescan_packets(cf
, "Filtering", dftext
, false);
1581 cf_redissect_packets(capture_file
*cf
)
1583 if (cf
->read_lock
|| cf
->redissection_queued
== RESCAN_SCAN
) {
1584 /* Dissection in progress, signal redissection rather than rescanning. That
1585 * would destroy the current (in-progress) dissection in "cf_read" which
1586 * will cause issues when "cf_read" tries to add packets to the list.
1587 * If a previous rescan was requested, "upgrade" it to a full redissection.
1589 cf
->redissection_queued
= RESCAN_REDISSECT
;
1591 if (cf
->redissection_queued
!= RESCAN_NONE
) {
1592 /* Redissection is (already) queued, wait for "cf_read" to finish. */
1593 /* XXX - what if whatever set and later clears read_lock is *not*
1594 * cf_read, e.g. process_specified_records ? We need to handle a
1595 * queued redissection there too like we do in cf_read.
1600 if (cf
->state
!= FILE_CLOSED
) {
1601 /* Restart dissection in case no cf_read is pending. */
1602 rescan_packets(cf
, "Reprocessing", "all packets", true);
1607 cf_read_record(capture_file
*cf
, const frame_data
*fdata
, wtap_rec
*rec
)
1612 if (!wtap_seek_read(cf
->provider
.wth
, fdata
->file_off
, rec
, &err
, &err_info
)) {
1613 report_cfile_read_failure(cf
->filename
, err
, err_info
);
1620 cf_read_record_no_alert(capture_file
*cf
, const frame_data
*fdata
,
1626 if (!wtap_seek_read(cf
->provider
.wth
, fdata
->file_off
, rec
, &err
, &err_info
)) {
1634 cf_read_current_record(capture_file
*cf
)
1636 return cf_read_record(cf
, cf
->current_frame
, &cf
->rec
);
1639 /* Rescan the list of packets, reconstructing the CList.
1641 "action" describes why we're doing this; it's used in the progress
1644 "action_item" describes what we're doing; it's used in the progress
1647 "redissect" is true if we need to make the dissectors reconstruct
1648 any state information they have (because a preference that affects
1649 some dissector has changed, meaning some dissector might construct
1650 its state differently from the way it was constructed the last time). */
1652 rescan_packets(capture_file
*cf
, const char *action
, const char *action_item
, bool redissect
)
1654 /* Rescan packets new packet list */
1658 progdlg_t
*progbar
= NULL
;
1659 GTimer
*prog_timer
= g_timer_new();
1661 frame_data
*selected_frame
, *preceding_frame
, *following_frame
, *prev_frame
;
1662 int selected_frame_num
, preceding_frame_num
, following_frame_num
, prev_frame_num
;
1663 bool selected_frame_seen
;
1666 char status_str
[100];
1668 dfilter_t
*dfcode
= NULL
;
1670 bool create_proto_tree
;
1671 bool filtering_tap_listeners
= false;
1673 bool add_to_packet_list
= false;
1675 uint32_t frames_count
;
1676 rescan_type queued_rescan_type
= RESCAN_NONE
;
1678 if (cf
->state
== FILE_CLOSED
|| cf
->state
== FILE_READ_PENDING
) {
1682 /* Rescan in progress, clear pending actions. */
1683 cf
->redissection_queued
= RESCAN_NONE
;
1684 ws_assert(!cf
->read_lock
);
1685 cf
->read_lock
= true;
1687 wtap_rec_init(&rec
, 1514);
1689 /* Compile the current display filter.
1690 * The code it compiles to might have changed, e.g. if a display
1691 * filter macro used has changed.
1693 * We assume this will not fail since cf->dfilter is only set in
1694 * cf_filter IFF the filter was valid.
1695 * XXX - This is not necessarily true, if the filter has a FT_IPv4
1696 * or FT_IPv6 field compared to a resolved hostname in it, because
1697 * we do a new host lookup, and that *could* timeout this time
1698 * (though with the read lock above we shouldn't have many lookups at
1699 * once, reducing the chances of that)... (#19612)
1702 compiled
= dfilter_compile(cf
->dfilter
, &dfcode
, NULL
);
1703 ws_assert(compiled
&& dfcode
);
1706 dfilter_free(cf
->dfcode
);
1707 cf
->dfcode
= dfcode
;
1709 /* Do we have any tap listeners with filters? */
1710 filtering_tap_listeners
= have_filtering_tap_listeners();
1712 /* Update references in filters (if any) for the protocol
1713 * tree corresponding to the currently selected frame in the GUI. */
1714 if (cf
->edt
!= NULL
&& cf
->edt
->tree
!= NULL
) {
1716 dfilter_load_field_references(cf
->dfcode
, cf
->edt
->tree
);
1717 if (filtering_tap_listeners
)
1718 tap_listeners_load_field_references(cf
->edt
);
1721 if (cf
->dfcode
!= NULL
) {
1722 dfilter_log_full(LOG_DOMAIN_DFILTER
, LOG_LEVEL_NOISY
, NULL
, -1, NULL
,
1723 cf
->dfcode
, "Rescanning packets with display filter");
1726 /* Get the union of the flags for all tap listeners. */
1727 tap_flags
= union_of_tap_listener_flags();
1729 /* If the display filter or any tap listeners require the columns,
1730 * construct them. */
1731 cinfo
= (tap_listeners_require_columns() ||
1732 dfilter_requires_columns(cf
->dfcode
)) ? &cf
->cinfo
: NULL
;
1735 * Determine whether we need to create a protocol tree.
1738 * we're going to apply a display filter;
1740 * one of the tap listeners is going to apply a filter;
1742 * one of the tap listeners requires a protocol tree;
1744 * we're redissecting and a postdissector wants field
1745 * values or protocols on the first pass.
1748 (cf
->dfcode
!= NULL
|| filtering_tap_listeners
||
1749 (tap_flags
& TL_REQUIRES_PROTO_TREE
) ||
1750 (redissect
&& postdissectors_want_hfids()));
1752 reset_tap_listeners();
1753 /* Which frame, if any, is the currently selected frame?
1754 XXX - should the selected frame or the focus frame be the "current"
1755 frame, that frame being the one from which "Find Frame" searches
1757 selected_frame
= cf
->current_frame
;
1759 /* Mark frame num as not found */
1760 selected_frame_num
= -1;
1762 /* Freeze the packet list while we redo it, so we don't get any
1763 screen updates while it happens. */
1764 packet_list_freeze();
1767 /* We need to re-initialize all the state information that protocols
1768 keep, because some preference that controls a dissector has changed,
1769 which might cause the state information to be constructed differently
1770 by that dissector. */
1772 /* We might receive new packets while redissecting, and we don't
1773 want to dissect those before their time. */
1774 cf
->redissecting
= true;
1776 /* 'reset' dissection session */
1777 epan_free(cf
->epan
);
1778 if (cf
->edt
&& cf
->edt
->pi
.fd
) {
1779 /* All pointers in "per frame proto data" for the currently selected
1780 packet are allocated in wmem_file_scope() and deallocated in epan_free().
1781 Free them here to avoid unintended usage in packet_list_clear(). */
1782 frame_data_destroy(cf
->edt
->pi
.fd
);
1784 cf
->epan
= ws_epan_new(cf
);
1785 cf
->cinfo
.epan
= cf
->epan
;
1787 /* A new Lua tap listener may be registered in lua_prime_all_fields()
1788 called via epan_new() / init_dissection() when reloading Lua plugins. */
1789 if (!create_proto_tree
&& have_filtering_tap_listeners()) {
1790 create_proto_tree
= true;
1792 if (!cinfo
&& tap_listeners_require_columns()) {
1796 /* We need to redissect the packets so we have to discard our old
1797 * packet list store. */
1798 packet_list_clear();
1799 add_to_packet_list
= true;
1802 /* We don't yet know which will be the first and last frames displayed. */
1803 cf
->first_displayed
= 0;
1804 cf
->last_displayed
= 0;
1806 /* We currently don't display any packets */
1807 cf
->displayed_count
= 0;
1809 /* Iterate through the list of frames. Call a routine for each frame
1810 to check whether it should be displayed and, if so, add it to
1811 the display list. */
1812 cf
->provider
.ref
= NULL
;
1813 cf
->provider
.prev_dis
= NULL
;
1814 cf
->provider
.prev_cap
= NULL
;
1817 cf_callback_invoke(cf_cb_file_rescan_started
, cf
);
1819 g_timer_start(prog_timer
);
1820 /* Count of packets at which we've looked. */
1822 /* Progress so far. */
1825 cf
->stop_flag
= false;
1826 start_time
= g_get_monotonic_time();
1828 /* no previous row yet */
1829 prev_frame_num
= -1;
1832 preceding_frame_num
= -1;
1833 preceding_frame
= NULL
;
1834 following_frame_num
= -1;
1835 following_frame
= NULL
;
1837 selected_frame_seen
= false;
1839 frames_count
= cf
->count
;
1841 epan_dissect_init(&edt
, cf
->epan
, create_proto_tree
, false);
1845 * Decryption secrets and name resolution blocks are read while
1846 * sequentially processing records and then passed to the dissector.
1847 * During redissection, the previous information is lost (see epan_free
1848 * above), but they are not read again from the file as only packet
1849 * records are re-read. Therefore reset the wtap secrets and name
1850 * resolution callbacks such that wtap resupplies the callbacks with
1851 * previously read information.
1853 wtap_set_cb_new_ipv4(cf
->provider
.wth
, add_ipv4_name
);
1854 wtap_set_cb_new_ipv6(cf
->provider
.wth
, (wtap_new_ipv6_callback_t
) add_ipv6_name
);
1855 wtap_set_cb_new_secrets(cf
->provider
.wth
, secrets_wtap_callback
);
1858 for (framenum
= 1; framenum
<= frames_count
; framenum
++) {
1859 fdata
= frame_data_sequence_find(cf
->provider
.frames
, framenum
);
1861 /* Create the progress bar if necessary.
1862 We check on every iteration of the loop, so that it takes no
1863 longer than the standard time to create it (otherwise, for a
1864 large file, we might take considerably longer than that standard
1865 time in order to get to the next progress bar step). */
1866 if (progbar
== NULL
)
1867 progbar
= delayed_create_progress_dlg(cf
->window
, action
, action_item
, true,
1872 * Update the progress bar, but do it only after PROGBAR_UPDATE_INTERVAL
1873 * has elapsed. Calling update_progress_dlg and packets_bar_update will
1874 * likely trigger UI paint events, which might take a while depending on
1875 * the platform and display. Reset our timer *after* painting.
1877 if (g_timer_elapsed(prog_timer
, NULL
) > PROGBAR_UPDATE_INTERVAL
) {
1878 /* let's not divide by zero. I should never be started
1879 * with count == 0, so let's assert that
1881 ws_assert(cf
->count
> 0);
1882 progbar_val
= (float) count
/ frames_count
;
1884 if (progbar
!= NULL
) {
1885 snprintf(status_str
, sizeof(status_str
),
1886 "%4u of %u frames", count
, frames_count
);
1887 update_progress_dlg(progbar
, progbar_val
, status_str
);
1890 g_timer_start(prog_timer
);
1893 queued_rescan_type
= cf
->redissection_queued
;
1894 if (queued_rescan_type
!= RESCAN_NONE
) {
1895 /* A redissection was requested while an existing redissection was
1900 if (cf
->stop_flag
) {
1901 /* Well, the user decided to abort the filtering. Just stop.
1903 XXX - go back to the previous filter? Users probably just
1904 want not to wait for a filtering operation to finish;
1905 unless we cancel by having no filter, reverting to the
1906 previous filter will probably be even more expensive than
1907 continuing the filtering, as it involves going back to the
1908 beginning and filtering, and even with no filter we currently
1909 have to re-generate the entire clist, which is also expensive.
1911 I'm not sure what Network Monitor does, but it doesn't appear
1912 to give you an unfiltered display if you cancel. */
1919 /* Since all state for the frame was destroyed, mark the frame
1920 * as not visited, free the GSList referring to the state
1921 * data (the per-frame data itself was freed by
1922 * "init_dissection()"), and null out the GSList pointer. */
1923 frame_data_reset(fdata
);
1924 frames_count
= cf
->count
;
1927 /* Frame dependencies from the previous dissection/filtering are no longer valid. */
1928 fdata
->dependent_of_displayed
= 0;
1930 if (!cf_read_record(cf
, fdata
, &rec
))
1931 break; /* error reading the frame */
1933 /* If the previous frame is displayed, and we haven't yet seen the
1934 selected frame, remember that frame - it's the closest one we've
1935 yet seen before the selected frame. */
1936 if (prev_frame_num
!= -1 && !selected_frame_seen
&& prev_frame
->passed_dfilter
) {
1937 preceding_frame_num
= prev_frame_num
;
1938 preceding_frame
= prev_frame
;
1941 add_packet_to_packet_list(fdata
, cf
, &edt
, cf
->dfcode
, cinfo
, &rec
,
1942 add_to_packet_list
);
1944 /* If this frame is displayed, and this is the first frame we've
1945 seen displayed after the selected frame, remember this frame -
1946 it's the closest one we've yet seen at or after the selected
1948 if (fdata
->passed_dfilter
&& selected_frame_seen
&& following_frame_num
== -1) {
1949 following_frame_num
= fdata
->num
;
1950 following_frame
= fdata
;
1952 if (fdata
== selected_frame
) {
1953 selected_frame_seen
= true;
1954 if (fdata
->passed_dfilter
)
1955 selected_frame_num
= fdata
->num
;
1958 /* Remember this frame - it'll be the previous frame
1959 on the next pass through the loop. */
1960 prev_frame_num
= fdata
->num
;
1962 wtap_rec_reset(&rec
);
1965 epan_dissect_cleanup(&edt
);
1966 wtap_rec_cleanup(&rec
);
1968 /* We are done redissecting the packet list. */
1969 cf
->redissecting
= false;
1972 frames_count
= cf
->count
;
1973 /* Clear out what remains of the visited flags and per-frame data
1976 XXX - that may cause various forms of bogosity when dissecting
1977 these frames, as they won't have been seen by this sequential
1978 pass, but the only alternative I see is to keep scanning them
1979 even though the user requested that the scan stop, and that
1980 would leave the user stuck with an Wireshark grinding on
1981 until it finishes. Should we just stick them with that? */
1982 for (; framenum
<= frames_count
; framenum
++) {
1983 fdata
= frame_data_sequence_find(cf
->provider
.frames
, framenum
);
1984 frame_data_reset(fdata
);
1988 /* We're done filtering the packets; destroy the progress bar if it
1990 if (progbar
!= NULL
)
1991 destroy_progress_dlg(progbar
);
1992 g_timer_destroy(prog_timer
);
1994 /* Unfreeze the packet list. */
1995 if (!add_to_packet_list
)
1996 packet_list_recreate_visible_rows();
1998 /* Compute the time it took to filter the file */
1999 compute_elapsed(cf
, start_time
);
2003 /* It is safe again to execute redissections or sort. */
2004 ws_assert(cf
->read_lock
);
2005 cf
->read_lock
= false;
2007 cf_callback_invoke(cf_cb_file_rescan_finished
, cf
);
2009 if (selected_frame_num
== -1) {
2010 /* The selected frame didn't pass the filter. */
2011 if (selected_frame
== NULL
) {
2012 /* That's because there *was* no selected frame. Make the first
2013 displayed frame the current frame. */
2014 selected_frame_num
= 0;
2016 /* Find the nearest displayed frame to the selected frame (whether
2017 it's before or after that frame) and make that the current frame.
2018 If the next and previous displayed frames are equidistant from the
2019 selected frame, choose the next one. */
2020 ws_assert(following_frame
== NULL
||
2021 following_frame
->num
>= selected_frame
->num
);
2022 ws_assert(preceding_frame
== NULL
||
2023 preceding_frame
->num
<= selected_frame
->num
);
2024 if (following_frame
== NULL
) {
2025 /* No frame after the selected frame passed the filter, so we
2026 have to select the last displayed frame before the selected
2028 selected_frame_num
= preceding_frame_num
;
2029 selected_frame
= preceding_frame
;
2030 } else if (preceding_frame
== NULL
) {
2031 /* No frame before the selected frame passed the filter, so we
2032 have to select the first displayed frame after the selected
2034 selected_frame_num
= following_frame_num
;
2035 selected_frame
= following_frame
;
2037 /* Frames before and after the selected frame passed the filter, so
2038 we'll select the previous frame */
2039 selected_frame_num
= preceding_frame_num
;
2040 selected_frame
= preceding_frame
;
2045 if (selected_frame_num
== -1) {
2046 /* There are no frames displayed at all. */
2047 cf_unselect_packet(cf
);
2049 /* Either the frame that was selected passed the filter, or we've
2050 found the nearest displayed frame to that frame. Select it, make
2051 it the focus row, and make it visible. */
2052 /* Set to invalid to force update of packet list and packet details */
2053 if (selected_frame_num
== 0) {
2054 packet_list_select_row_from_data(NULL
);
2056 if (!packet_list_select_row_from_data(selected_frame
)) {
2057 /* We didn't find a row corresponding to this frame.
2058 This means that the frame isn't being displayed currently,
2059 so we can't select it. */
2060 simple_message_box(ESD_TYPE_INFO
, NULL
,
2061 "The capture file is probably not fully dissected.",
2062 "End of capture exceeded.");
2067 /* If another rescan (due to dfilter change) or redissection (due to profile
2068 * change) was requested, the rescan above is aborted and restarted here. */
2069 if (queued_rescan_type
!= RESCAN_NONE
) {
2070 redissect
= redissect
|| queued_rescan_type
== RESCAN_REDISSECT
;
2071 rescan_packets(cf
, "Reprocessing", "all packets", redissect
);
2077 * Scan through all frame data and recalculate the ref time
2078 * without rereading the file.
2079 * XXX - do we need a progress bar or is this fast enough?
2082 cf_reftime_packets(capture_file
* cf
)
2088 cf
->provider
.ref
= NULL
;
2089 cf
->provider
.prev_dis
= NULL
;
2092 for (framenum
= 1; framenum
<= cf
->count
; framenum
++) {
2093 fdata
= frame_data_sequence_find(cf
->provider
.frames
, framenum
);
2095 /* just add some value here until we know if it is being displayed or not */
2096 fdata
->cum_bytes
= cf
->cum_bytes
+ fdata
->pkt_len
;
2102 if (fdata
->has_ts
) {
2103 /* If we don't have the time stamp of the first packet in the
2104 capture, it's because this is the first packet. Save the time
2105 stamp of this packet as the time stamp of the first packet. */
2106 if (cf
->provider
.ref
== NULL
)
2107 cf
->provider
.ref
= fdata
;
2108 /* if this frames is marked as a reference time frame, reset
2109 firstsec and firstusec to this frame */
2110 if (fdata
->ref_time
)
2111 cf
->provider
.ref
= fdata
;
2113 /* Get the time elapsed between the first packet and this one. */
2114 fdata
->frame_ref_num
= (fdata
!= cf
->provider
.ref
) ? cf
->provider
.ref
->num
: 0;
2115 nstime_delta(&rel_ts
, &fdata
->abs_ts
, &cf
->provider
.ref
->abs_ts
);
2117 /* If it's greater than the current elapsed time, set the elapsed
2118 time to it (we check for "greater than" so as not to be
2119 confused by time moving backwards). */
2120 if ((int32_t)cf
->elapsed_time
.secs
< rel_ts
.secs
2121 || ((int32_t)cf
->elapsed_time
.secs
== rel_ts
.secs
&& (int32_t)cf
->elapsed_time
.nsecs
< rel_ts
.nsecs
)) {
2122 cf
->elapsed_time
= rel_ts
;
2125 /* If this frame is displayed, get the time elapsed between the
2126 previous displayed packet and this packet. */
2127 /* XXX: What if in the future we want to use the previously
2128 * displayed frame for something else, too? Then we'd want
2129 * to store this frame as prev_dis even if it doesn't have a
2131 if ( fdata
->passed_dfilter
) {
2132 /* If we don't have the time stamp of the previous displayed
2133 packet, it's because this is the first displayed packet.
2134 Save the time stamp of this packet as the time stamp of
2135 the previous displayed packet. */
2136 if (cf
->provider
.prev_dis
== NULL
) {
2137 cf
->provider
.prev_dis
= fdata
;
2140 fdata
->prev_dis_num
= cf
->provider
.prev_dis
->num
;
2141 cf
->provider
.prev_dis
= fdata
;
2144 /* If this frame doesn't have a timestamp, don't calculate
2145 anything with relative times. */
2146 /* However, if this frame is marked as a reference time frame,
2147 clear the reference frame so that the next frame with a
2148 timestamp becomes the reference frame. */
2149 if (fdata
->ref_time
) {
2150 cf
->provider
.ref
= NULL
;
2157 if ( (fdata
->passed_dfilter
) || (fdata
->ref_time
) ) {
2158 /* This frame either passed the display filter list or is marked as
2159 a time reference frame. All time reference frames are displayed
2160 even if they don't pass the display filter */
2161 if (fdata
->ref_time
) {
2162 /* if this was a TIME REF frame we should reset the cum_bytes field */
2163 cf
->cum_bytes
= fdata
->pkt_len
;
2164 fdata
->cum_bytes
= cf
->cum_bytes
;
2166 /* increase cum_bytes with this packets length */
2167 cf
->cum_bytes
+= fdata
->pkt_len
;
2180 process_specified_records(capture_file
*cf
, packet_range_t
*range
,
2181 const char *string1
, const char *string2
, bool terminate_is_stop
,
2182 bool (*callback
)(capture_file
*, frame_data
*,
2183 wtap_rec
*, void *),
2184 void *callback_args
,
2185 bool show_progress_bar
)
2190 psp_return_t ret
= PSP_FINISHED
;
2192 progdlg_t
*progbar
= NULL
;
2193 GTimer
*prog_timer
= g_timer_new();
2196 char progbar_status_str
[100];
2197 range_process_e process_this
;
2199 wtap_rec_init(&rec
, 1514);
2201 g_timer_start(prog_timer
);
2202 /* Count of packets at which we've looked. */
2204 /* Progress so far. */
2207 /* XXX - It should be ok to have multiple readers, so long as nothing
2208 * frees the epan context, e.g. rescan_packets with redissect true,
2209 * or anything that closes the file (including reload and certain forms
2210 * of saving.) This is mostly to stop cf_save_records but should probably
2211 * be handled by callers in order to allow multiple readers (e.g.,
2212 * restarting taps after adding or changing one.) We should probably
2213 * make this a real reader-writer lock.
2215 if (cf
->read_lock
) {
2216 ws_warning("Failing due to nested process_specified_records(\"%s\") call!", cf
->filename
);
2219 cf
->read_lock
= true;
2221 cf
->stop_flag
= false;
2224 packet_range_process_init(range
);
2226 /* Iterate through all the packets, printing the packets that
2227 were selected by the current display filter. */
2228 for (framenum
= 1; framenum
<= cf
->count
; framenum
++) {
2229 fdata
= frame_data_sequence_find(cf
->provider
.frames
, framenum
);
2231 /* Create the progress bar if necessary.
2232 We check on every iteration of the loop, so that it takes no
2233 longer than the standard time to create it (otherwise, for a
2234 large file, we might take considerably longer than that standard
2235 time in order to get to the next progress bar step). */
2236 if (show_progress_bar
&& progbar
== NULL
)
2237 progbar
= delayed_create_progress_dlg(cf
->window
, string1
, string2
,
2243 * Update the progress bar, but do it only after PROGBAR_UPDATE_INTERVAL
2244 * has elapsed. Calling update_progress_dlg and packets_bar_update will
2245 * likely trigger UI paint events, which might take a while depending on
2246 * the platform and display. Reset our timer *after* painting.
2248 if (progbar
&& g_timer_elapsed(prog_timer
, NULL
) > PROGBAR_UPDATE_INTERVAL
) {
2249 /* let's not divide by zero. I should never be started
2250 * with count == 0, so let's assert that
2252 ws_assert(cf
->count
> 0);
2253 progbar_val
= (float) progbar_count
/ cf
->count
;
2255 snprintf(progbar_status_str
, sizeof(progbar_status_str
),
2256 "%4u of %u packets", progbar_count
, cf
->count
);
2257 update_progress_dlg(progbar
, progbar_val
, progbar_status_str
);
2259 g_timer_start(prog_timer
);
2262 if (cf
->stop_flag
) {
2263 /* Well, the user decided to abort the operation. Just stop,
2264 and arrange to return PSP_STOPPED to our caller, so they know
2265 it was stopped explicitly. */
2272 if (range
!= NULL
) {
2273 /* do we have to process this packet? */
2274 process_this
= packet_range_process_packet(range
, fdata
);
2275 if (process_this
== range_process_next
) {
2276 /* this packet uninteresting, continue with next one */
2278 } else if (process_this
== range_processing_finished
) {
2279 /* all interesting packets processed, stop the loop */
2284 /* Get the packet */
2285 if (!cf_read_record(cf
, fdata
, &rec
)) {
2286 /* Attempt to get the packet failed. */
2290 /* Process the packet */
2291 if (!callback(cf
, fdata
, &rec
, callback_args
)) {
2292 /* Callback failed. We assume it reported the error appropriately. */
2296 wtap_rec_reset(&rec
);
2299 /* We're done printing the packets; destroy the progress bar if
2301 if (progbar
!= NULL
)
2302 destroy_progress_dlg(progbar
);
2303 g_timer_destroy(prog_timer
);
2305 ws_assert(cf
->read_lock
);
2306 cf
->read_lock
= false;
2308 wtap_rec_cleanup(&rec
);
2316 } retap_callback_args_t
;
2319 retap_packet(capture_file
*cf
, frame_data
*fdata
, wtap_rec
*rec
, void *argsp
)
2321 retap_callback_args_t
*args
= (retap_callback_args_t
*)argsp
;
2323 epan_dissect_run_with_taps(&args
->edt
, cf
->cd_t
, rec
, fdata
, args
->cinfo
);
2324 epan_dissect_reset(&args
->edt
);
2330 cf_retap_packets(capture_file
*cf
)
2332 packet_range_t range
;
2333 retap_callback_args_t callback_args
;
2334 bool create_proto_tree
;
2335 bool filtering_tap_listeners
;
2339 /* Presumably the user closed the capture file. */
2341 return CF_READ_ABORTED
;
2344 /* XXX - If cf->read_lock is true, process_specified_records will fail
2345 * due to a nested call. We fail here so that we don't reset the tap
2346 * listeners if this tap isn't going to succeed.
2348 if (cf
->read_lock
) {
2349 ws_warning("Failing due to nested process_specified_records(\"%s\") call!", cf
->filename
);
2350 return CF_READ_ERROR
;
2353 cf_callback_invoke(cf_cb_file_retap_started
, cf
);
2355 /* Do we have any tap listeners with filters? */
2356 filtering_tap_listeners
= have_filtering_tap_listeners();
2358 /* Update references in filters (if any) for the protocol
2359 * tree corresponding to the currently selected frame in the GUI. */
2360 /* XXX - What if we *don't* have a currently selected frame in the GUI,
2361 * but we did the last time we loaded field references? Then they'll
2362 * match something instead of nothing (unless they've been recompiled).
2363 * Should we have a way to clear the field references even with a NULL tree?
2365 if (cf
->edt
!= NULL
&& cf
->edt
->tree
!= NULL
) {
2366 if (filtering_tap_listeners
)
2367 tap_listeners_load_field_references(cf
->edt
);
2370 /* Get the union of the flags for all tap listeners. */
2371 tap_flags
= union_of_tap_listener_flags();
2373 /* If any tap listeners require the columns, construct them. */
2374 callback_args
.cinfo
= (tap_listeners_require_columns()) ? &cf
->cinfo
: NULL
;
2377 * Determine whether we need to create a protocol tree.
2380 * one of the tap listeners is going to apply a filter;
2382 * one of the tap listeners requires a protocol tree.
2385 (filtering_tap_listeners
|| (tap_flags
& TL_REQUIRES_PROTO_TREE
));
2387 /* Reset the tap listeners. */
2388 reset_tap_listeners();
2389 uint32_t count
= cf
->count
;
2391 epan_dissect_init(&callback_args
.edt
, cf
->epan
, create_proto_tree
, false);
2393 /* Iterate through the list of packets, dissecting all packets and
2394 re-running the taps. */
2395 packet_range_init(&range
, cf
);
2396 packet_range_process_init(&range
);
2398 if (cf
->state
== FILE_READ_IN_PROGRESS
) {
2399 /* We're not done with the sequential read of the file and might
2400 * add more frames while process_specified_records is going. We
2401 * don't want to tap new frames twice, so limit the range to the
2402 * frames already here.
2404 * cf_read sets read_lock so we don't tap in case of an offline
2405 * file, but cf_continue_tail and cf_finish_tail don't, and we
2406 * don't want them to, because tapping new packets in a live
2407 * capture is a common use case.
2409 * Note that most other users of process_specified_records (saving,
2410 * printing) do want to process new packets, unlike taps.
2413 char* range_str
= g_strdup_printf("-%u", count
);
2414 packet_range_convert_str(&range
, range_str
);
2417 /* range_t treats a missing number as meaning 1, not 0, and
2418 * reverses the order if backwards; thus the syntax -0 means
2419 * 0-1, so to only take zero packets we do this.
2421 packet_range_convert_str(&range
, "0");
2423 range
.process
= range_process_user_range
;
2426 ret
= process_specified_records(cf
, &range
, "Recalculating statistics on",
2427 "all packets", true, retap_packet
,
2428 &callback_args
, true);
2430 packet_range_cleanup(&range
);
2431 epan_dissect_cleanup(&callback_args
.edt
);
2433 cf_callback_invoke(cf_cb_file_retap_finished
, cf
);
2437 /* Completed successfully. */
2441 /* Well, the user decided to abort the refiltering.
2442 Return CF_READ_ABORTED so our caller knows they did that. */
2443 return CF_READ_ABORTED
;
2446 /* Error while retapping. */
2447 return CF_READ_ERROR
;
2450 ws_assert_not_reached();
2455 print_args_t
*print_args
;
2456 bool print_header_line
;
2457 char *header_line_buf
;
2458 int header_line_buf_len
;
2459 bool print_formfeed
;
2460 bool print_separator
;
2464 int num_visible_cols
;
2467 } print_callback_args_t
;
2470 print_packet(capture_file
*cf
, frame_data
*fdata
, wtap_rec
*rec
, void *argsp
)
2472 print_callback_args_t
*args
= (print_callback_args_t
*)argsp
;
2478 char bookmark_name
[9+10+1]; /* "__frameNNNNNNNNNN__\0" */
2479 char bookmark_title
[6+10+1]; /* "Frame NNNNNNNNNN__\0" */
2480 col_item_t
* col_item
;
2481 const char* col_text
;
2483 /* Fill in the column information if we're printing the summary
2485 if (args
->print_args
->print_summary
) {
2486 col_custom_prime_edt(&args
->edt
, &cf
->cinfo
);
2487 epan_dissect_run(&args
->edt
, cf
->cd_t
, rec
, fdata
, &cf
->cinfo
);
2488 epan_dissect_fill_in_columns(&args
->edt
, false, true);
2490 epan_dissect_run(&args
->edt
, cf
->cd_t
, rec
, fdata
, NULL
);
2492 if (args
->print_formfeed
) {
2493 if (!new_page(args
->print_args
->stream
))
2497 * Print another header line if we print a packet summary on the
2500 if (args
->print_args
->print_col_headings
)
2501 args
->print_header_line
= true;
2503 if (args
->print_separator
) {
2504 if (!print_line(args
->print_args
->stream
, 0, ""))
2510 * We generate bookmarks, if the output format supports them.
2511 * The name is "__frameN__".
2513 snprintf(bookmark_name
, sizeof bookmark_name
, "__frame%u__", fdata
->num
);
2515 if (args
->print_args
->print_summary
) {
2516 if (!args
->print_args
->print_col_headings
)
2517 args
->print_header_line
= false;
2518 if (args
->print_header_line
) {
2519 if (!print_line(args
->print_args
->stream
, 0, args
->header_line_buf
))
2521 args
->print_header_line
= false; /* we might not need to print any more */
2523 cp
= &args
->line_buf
[0];
2525 for (i
= 0; i
< args
->num_visible_cols
; i
++) {
2526 col_item
= &cf
->cinfo
.columns
[args
->visible_cols
[i
]];
2527 col_text
= get_column_text(&cf
->cinfo
, args
->visible_cols
[i
]);
2528 /* Find the length of the string for this column. */
2529 column_len
= (int) strlen(col_text
);
2530 if (args
->col_widths
[i
] > column_len
)
2531 column_len
= args
->col_widths
[i
];
2533 /* Make sure there's room in the line buffer for the column; if not,
2534 double its length. */
2535 line_len
+= column_len
+ 1; /* "+1" for space */
2536 if (line_len
> args
->line_buf_len
) {
2537 cp_off
= (int) (cp
- args
->line_buf
);
2538 args
->line_buf_len
= 2 * line_len
;
2539 args
->line_buf
= (char *)g_realloc(args
->line_buf
, args
->line_buf_len
+ 1);
2540 cp
= args
->line_buf
+ cp_off
;
2543 /* Right-justify the packet number column. */
2544 if (col_item
->col_fmt
== COL_NUMBER
|| col_item
->col_fmt
== COL_NUMBER_DIS
)
2545 snprintf(cp
, column_len
+1, "%*s", args
->col_widths
[i
], col_text
);
2547 snprintf(cp
, column_len
+1, "%-*s", args
->col_widths
[i
], col_text
);
2549 if (i
!= args
->num_visible_cols
- 1)
2555 * Generate a bookmark, using the summary line as the title.
2557 if (!print_bookmark(args
->print_args
->stream
, bookmark_name
,
2561 if (!print_line(args
->print_args
->stream
, 0, args
->line_buf
))
2565 * Generate a bookmark, using "Frame N" as the title, as we're not
2566 * printing the summary line.
2568 snprintf(bookmark_title
, sizeof bookmark_title
, "Frame %u", fdata
->num
);
2569 if (!print_bookmark(args
->print_args
->stream
, bookmark_name
,
2572 } /* if (print_summary) */
2574 if (args
->print_args
->print_dissections
!= print_dissections_none
) {
2575 if (args
->print_args
->print_summary
) {
2576 /* Separate the summary line from the tree with a blank line. */
2577 if (!print_line(args
->print_args
->stream
, 0, ""))
2581 /* Print the information in that tree. */
2582 if (!proto_tree_print(args
->print_args
->print_dissections
,
2583 args
->print_args
->print_hex
, &args
->edt
, NULL
,
2584 args
->print_args
->stream
))
2587 /* Print a blank line if we print anything after this (aka more than one packet). */
2588 args
->print_separator
= true;
2590 /* Print a header line if we print any more packet summaries */
2591 if (args
->print_args
->print_col_headings
)
2592 args
->print_header_line
= true;
2595 if (args
->print_args
->print_hex
) {
2596 if (args
->print_args
->print_summary
|| (args
->print_args
->print_dissections
!= print_dissections_none
)) {
2597 if (!print_line(args
->print_args
->stream
, 0, ""))
2600 /* Print the full packet data as hex. */
2601 if (!print_hex_data(args
->print_args
->stream
, &args
->edt
, args
->print_args
->hexdump_options
))
2604 /* Print a blank line if we print anything after this (aka more than one packet). */
2605 args
->print_separator
= true;
2607 /* Print a header line if we print any more packet summaries */
2608 if (args
->print_args
->print_col_headings
)
2609 args
->print_header_line
= true;
2610 } /* if (args->print_args->print_dissections != print_dissections_none) */
2612 epan_dissect_reset(&args
->edt
);
2614 /* do we want to have a formfeed between each packet from now on? */
2615 if (args
->print_args
->print_formfeed
) {
2616 args
->print_formfeed
= true;
2622 epan_dissect_reset(&args
->edt
);
2627 cf_print_packets(capture_file
*cf
, print_args_t
*print_args
,
2628 bool show_progress_bar
)
2630 print_callback_args_t callback_args
;
2633 int i
, cp_off
, column_len
, line_len
;
2634 int num_visible_col
= 0, last_visible_col
= 0, visible_col_count
;
2638 bool proto_tree_needed
;
2640 callback_args
.print_args
= print_args
;
2641 callback_args
.print_header_line
= print_args
->print_col_headings
;
2642 callback_args
.header_line_buf
= NULL
;
2643 callback_args
.header_line_buf_len
= 256;
2644 callback_args
.print_formfeed
= false;
2645 callback_args
.print_separator
= false;
2646 callback_args
.line_buf
= NULL
;
2647 callback_args
.line_buf_len
= 256;
2648 callback_args
.col_widths
= NULL
;
2649 callback_args
.num_visible_cols
= 0;
2650 callback_args
.visible_cols
= NULL
;
2652 if (!print_preamble(print_args
->stream
, cf
->filename
, get_ws_vcs_version_info())) {
2653 destroy_print_stream(print_args
->stream
);
2654 return CF_PRINT_WRITE_ERROR
;
2657 if (print_args
->print_summary
) {
2658 /* We're printing packet summaries. Allocate the header line buffer
2659 and get the column widths. */
2660 callback_args
.header_line_buf
= (char *)g_malloc(callback_args
.header_line_buf_len
+ 1);
2662 /* Find the number of visible columns and the last visible column */
2663 for (i
= 0; i
< prefs
.num_cols
; i
++) {
2665 clp
= g_list_nth(prefs
.col_list
, i
);
2666 if (clp
== NULL
) /* Sanity check, Invalid column requested */
2669 cfmt
= (fmt_data
*) clp
->data
;
2670 if (cfmt
->visible
) {
2672 last_visible_col
= i
;
2676 /* if num_visible_col is 0, we are done */
2677 if (num_visible_col
== 0) {
2678 g_free(callback_args
.header_line_buf
);
2682 /* Find the widths for each of the columns - maximum of the
2683 width of the title and the width of the data - and construct
2684 a buffer with a line containing the column titles. */
2685 callback_args
.num_visible_cols
= num_visible_col
;
2686 callback_args
.col_widths
= g_new(int, num_visible_col
);
2687 callback_args
.visible_cols
= g_new(int, num_visible_col
);
2688 cp
= &callback_args
.header_line_buf
[0];
2690 visible_col_count
= 0;
2691 for (i
= 0; i
< cf
->cinfo
.num_cols
; i
++) {
2693 clp
= g_list_nth(prefs
.col_list
, i
);
2694 if (clp
== NULL
) /* Sanity check, Invalid column requested */
2697 cfmt
= (fmt_data
*) clp
->data
;
2698 if (cfmt
->visible
== false)
2701 /* Save the order of visible columns */
2702 callback_args
.visible_cols
[visible_col_count
] = i
;
2704 /* Don't pad the last column. */
2705 if (i
== last_visible_col
)
2706 callback_args
.col_widths
[visible_col_count
] = 0;
2708 callback_args
.col_widths
[visible_col_count
] = (int) strlen(cf
->cinfo
.columns
[i
].col_title
);
2709 data_width
= get_column_char_width(get_column_format(i
));
2710 if (data_width
> callback_args
.col_widths
[visible_col_count
])
2711 callback_args
.col_widths
[visible_col_count
] = data_width
;
2714 /* Find the length of the string for this column. */
2715 column_len
= (int) strlen(cf
->cinfo
.columns
[i
].col_title
);
2716 if (callback_args
.col_widths
[visible_col_count
] > column_len
)
2717 column_len
= callback_args
.col_widths
[visible_col_count
];
2719 /* Make sure there's room in the line buffer for the column; if not,
2720 double its length. */
2721 line_len
+= column_len
+ 1; /* "+1" for space */
2722 if (line_len
> callback_args
.header_line_buf_len
) {
2723 cp_off
= (int) (cp
- callback_args
.header_line_buf
);
2724 callback_args
.header_line_buf_len
= 2 * line_len
;
2725 callback_args
.header_line_buf
= (char *)g_realloc(callback_args
.header_line_buf
,
2726 callback_args
.header_line_buf_len
+ 1);
2727 cp
= callback_args
.header_line_buf
+ cp_off
;
2730 /* Right-justify the packet number column. */
2731 /* if (cf->cinfo.col_fmt[i] == COL_NUMBER || cf->cinfo.col_fmt[i] == COL_NUMBER_DIS)
2732 snprintf(cp, column_len+1, "%*s", callback_args.col_widths[visible_col_count], cf->cinfo.columns[i].col_title);
2734 snprintf(cp
, column_len
+1, "%-*s", callback_args
.col_widths
[visible_col_count
], cf
->cinfo
.columns
[i
].col_title
);
2736 if (i
!= cf
->cinfo
.num_cols
- 1)
2739 visible_col_count
++;
2743 /* Now start out the main line buffer with the same length as the
2744 header line buffer. */
2745 callback_args
.line_buf_len
= callback_args
.header_line_buf_len
;
2746 callback_args
.line_buf
= (char *)g_malloc(callback_args
.line_buf_len
+ 1);
2747 } /* if (print_summary) */
2749 /* Create the protocol tree, and make it visible, if we're printing
2750 the dissection or the hex data.
2751 XXX - do we need it if we're just printing the hex data? */
2753 callback_args
.print_args
->print_dissections
!= print_dissections_none
||
2754 callback_args
.print_args
->print_hex
||
2755 have_custom_cols(&cf
->cinfo
) || have_field_extractors();
2756 epan_dissect_init(&callback_args
.edt
, cf
->epan
, proto_tree_needed
, proto_tree_needed
);
2758 /* Iterate through the list of packets, printing the packets we were
2760 ret
= process_specified_records(cf
, &print_args
->range
, "Printing",
2761 "selected packets", true, print_packet
,
2762 &callback_args
, show_progress_bar
);
2763 epan_dissect_cleanup(&callback_args
.edt
);
2764 g_free(callback_args
.header_line_buf
);
2765 g_free(callback_args
.line_buf
);
2766 g_free(callback_args
.col_widths
);
2767 g_free(callback_args
.visible_cols
);
2772 /* Completed successfully. */
2776 /* Well, the user decided to abort the printing.
2778 XXX - note that what got generated before they did that
2779 will get printed if we're piping to a print program; we'd
2780 have to write to a file and then hand that to the print
2781 program to make it actually not print anything. */
2785 /* Error while printing.
2787 XXX - note that what got generated before they did that
2788 will get printed if we're piping to a print program; we'd
2789 have to write to a file and then hand that to the print
2790 program to make it actually not print anything. */
2791 destroy_print_stream(print_args
->stream
);
2792 return CF_PRINT_WRITE_ERROR
;
2795 if (!print_finale(print_args
->stream
)) {
2796 destroy_print_stream(print_args
->stream
);
2797 return CF_PRINT_WRITE_ERROR
;
2800 if (!destroy_print_stream(print_args
->stream
))
2801 return CF_PRINT_WRITE_ERROR
;
2809 print_args_t
*print_args
;
2810 json_dumper jdumper
;
2811 } write_packet_callback_args_t
;
2814 write_pdml_packet(capture_file
*cf
, frame_data
*fdata
, wtap_rec
*rec
,
2817 write_packet_callback_args_t
*args
= (write_packet_callback_args_t
*)argsp
;
2819 /* Create the protocol tree, but don't fill in the column information. */
2820 epan_dissect_run(&args
->edt
, cf
->cd_t
, rec
, fdata
, NULL
);
2822 /* Write out the information in that tree. */
2823 write_pdml_proto_tree(NULL
, &args
->edt
, &cf
->cinfo
, args
->fh
, false);
2825 epan_dissect_reset(&args
->edt
);
2827 return !ferror(args
->fh
);
2831 cf_write_pdml_packets(capture_file
*cf
, print_args_t
*print_args
)
2833 write_packet_callback_args_t callback_args
;
2837 fh
= ws_fopen(print_args
->file
, "w");
2839 return CF_PRINT_OPEN_ERROR
; /* attempt to open destination failed */
2841 write_pdml_preamble(fh
, cf
->filename
);
2844 return CF_PRINT_WRITE_ERROR
;
2847 callback_args
.fh
= fh
;
2848 callback_args
.print_args
= print_args
;
2849 epan_dissect_init(&callback_args
.edt
, cf
->epan
, true, true);
2851 /* Iterate through the list of packets, printing the packets we were
2853 ret
= process_specified_records(cf
, &print_args
->range
, "Writing PDML",
2854 "selected packets", true,
2855 write_pdml_packet
, &callback_args
, true);
2857 epan_dissect_cleanup(&callback_args
.edt
);
2862 /* Completed successfully. */
2866 /* Well, the user decided to abort the printing. */
2870 /* Error while printing. */
2872 return CF_PRINT_WRITE_ERROR
;
2875 write_pdml_finale(fh
);
2878 return CF_PRINT_WRITE_ERROR
;
2881 /* XXX - check for an error */
2888 write_psml_packet(capture_file
*cf
, frame_data
*fdata
, wtap_rec
*rec
,
2891 write_packet_callback_args_t
*args
= (write_packet_callback_args_t
*)argsp
;
2893 /* Fill in the column information */
2894 col_custom_prime_edt(&args
->edt
, &cf
->cinfo
);
2895 epan_dissect_run(&args
->edt
, cf
->cd_t
, rec
, fdata
, &cf
->cinfo
);
2896 epan_dissect_fill_in_columns(&args
->edt
, false, true);
2898 /* Write out the column information. */
2899 write_psml_columns(&args
->edt
, args
->fh
, false);
2901 epan_dissect_reset(&args
->edt
);
2903 return !ferror(args
->fh
);
2907 cf_write_psml_packets(capture_file
*cf
, print_args_t
*print_args
)
2909 write_packet_callback_args_t callback_args
;
2913 bool proto_tree_needed
;
2915 fh
= ws_fopen(print_args
->file
, "w");
2917 return CF_PRINT_OPEN_ERROR
; /* attempt to open destination failed */
2919 write_psml_preamble(&cf
->cinfo
, fh
);
2922 return CF_PRINT_WRITE_ERROR
;
2925 callback_args
.fh
= fh
;
2926 callback_args
.print_args
= print_args
;
2928 /* Fill in the column information, only create the protocol tree
2929 if having custom columns or field extractors. */
2930 proto_tree_needed
= have_custom_cols(&cf
->cinfo
) || have_field_extractors();
2931 epan_dissect_init(&callback_args
.edt
, cf
->epan
, proto_tree_needed
, proto_tree_needed
);
2933 /* Iterate through the list of packets, printing the packets we were
2935 ret
= process_specified_records(cf
, &print_args
->range
, "Writing PSML",
2936 "selected packets", true,
2937 write_psml_packet
, &callback_args
, true);
2939 epan_dissect_cleanup(&callback_args
.edt
);
2944 /* Completed successfully. */
2948 /* Well, the user decided to abort the printing. */
2952 /* Error while printing. */
2954 return CF_PRINT_WRITE_ERROR
;
2957 write_psml_finale(fh
);
2960 return CF_PRINT_WRITE_ERROR
;
2963 /* XXX - check for an error */
2970 write_csv_packet(capture_file
*cf
, frame_data
*fdata
, wtap_rec
*rec
,
2973 write_packet_callback_args_t
*args
= (write_packet_callback_args_t
*)argsp
;
2975 col_custom_prime_edt(&args
->edt
, &cf
->cinfo
);
2976 epan_dissect_run(&args
->edt
, cf
->cd_t
, rec
, fdata
, &cf
->cinfo
);
2977 epan_dissect_fill_in_columns(&args
->edt
, false, true);
2979 /* Write out the column information. */
2980 write_csv_columns(&args
->edt
, args
->fh
);
2982 epan_dissect_reset(&args
->edt
);
2984 return !ferror(args
->fh
);
2988 cf_write_csv_packets(capture_file
*cf
, print_args_t
*print_args
)
2990 write_packet_callback_args_t callback_args
;
2991 bool proto_tree_needed
;
2995 fh
= ws_fopen(print_args
->file
, "w");
2997 return CF_PRINT_OPEN_ERROR
; /* attempt to open destination failed */
2999 write_csv_column_titles(&cf
->cinfo
, fh
);
3002 return CF_PRINT_WRITE_ERROR
;
3005 callback_args
.fh
= fh
;
3006 callback_args
.print_args
= print_args
;
3008 /* only create the protocol tree if having custom columns or field extractors. */
3009 proto_tree_needed
= have_custom_cols(&cf
->cinfo
) || have_field_extractors();
3010 epan_dissect_init(&callback_args
.edt
, cf
->epan
, proto_tree_needed
, proto_tree_needed
);
3012 /* Iterate through the list of packets, printing the packets we were
3014 ret
= process_specified_records(cf
, &print_args
->range
, "Writing CSV",
3015 "selected packets", true,
3016 write_csv_packet
, &callback_args
, true);
3018 epan_dissect_cleanup(&callback_args
.edt
);
3023 /* Completed successfully. */
3027 /* Well, the user decided to abort the printing. */
3031 /* Error while printing. */
3033 return CF_PRINT_WRITE_ERROR
;
3036 /* XXX - check for an error */
3043 carrays_write_packet(capture_file
*cf
, frame_data
*fdata
, wtap_rec
*rec
,
3046 write_packet_callback_args_t
*args
= (write_packet_callback_args_t
*)argsp
;
3048 epan_dissect_run(&args
->edt
, cf
->cd_t
, rec
, fdata
, NULL
);
3049 write_carrays_hex_data(fdata
->num
, args
->fh
, &args
->edt
);
3050 epan_dissect_reset(&args
->edt
);
3052 return !ferror(args
->fh
);
3056 cf_write_carrays_packets(capture_file
*cf
, print_args_t
*print_args
)
3058 write_packet_callback_args_t callback_args
;
3062 fh
= ws_fopen(print_args
->file
, "w");
3065 return CF_PRINT_OPEN_ERROR
; /* attempt to open destination failed */
3069 return CF_PRINT_WRITE_ERROR
;
3072 callback_args
.fh
= fh
;
3073 callback_args
.print_args
= print_args
;
3074 epan_dissect_init(&callback_args
.edt
, cf
->epan
, true, true);
3076 /* Iterate through the list of packets, printing the packets we were
3078 ret
= process_specified_records(cf
, &print_args
->range
,
3080 "selected packets", true,
3081 carrays_write_packet
, &callback_args
, true);
3083 epan_dissect_cleanup(&callback_args
.edt
);
3087 /* Completed successfully. */
3090 /* Well, the user decided to abort the printing. */
3093 /* Error while printing. */
3095 return CF_PRINT_WRITE_ERROR
;
3103 write_json_packet(capture_file
*cf
, frame_data
*fdata
, wtap_rec
*rec
,
3106 write_packet_callback_args_t
*args
= (write_packet_callback_args_t
*)argsp
;
3108 /* Create the protocol tree, but don't fill in the column information. */
3109 epan_dissect_run(&args
->edt
, cf
->cd_t
, rec
, fdata
, NULL
);
3111 /* Write out the information in that tree. */
3112 write_json_proto_tree(NULL
, args
->print_args
->print_dissections
,
3113 args
->print_args
->print_hex
,
3114 &args
->edt
, &cf
->cinfo
, proto_node_group_children_by_unique
,
3117 epan_dissect_reset(&args
->edt
);
3119 return !ferror(args
->fh
);
3123 cf_write_json_packets(capture_file
*cf
, print_args_t
*print_args
)
3125 write_packet_callback_args_t callback_args
;
3129 fh
= ws_fopen(print_args
->file
, "w");
3131 return CF_PRINT_OPEN_ERROR
; /* attempt to open destination failed */
3133 callback_args
.jdumper
= write_json_preamble(fh
);
3136 return CF_PRINT_WRITE_ERROR
;
3139 callback_args
.fh
= fh
;
3140 callback_args
.print_args
= print_args
;
3141 epan_dissect_init(&callback_args
.edt
, cf
->epan
, true, true);
3143 /* Iterate through the list of packets, printing the packets we were
3145 ret
= process_specified_records(cf
, &print_args
->range
, "Writing JSON",
3146 "selected packets", true,
3147 write_json_packet
, &callback_args
, true);
3149 epan_dissect_cleanup(&callback_args
.edt
);
3154 /* Completed successfully. */
3158 /* Well, the user decided to abort the printing. */
3162 /* Error while printing. */
3164 return CF_PRINT_WRITE_ERROR
;
3167 write_json_finale(&callback_args
.jdumper
);
3170 return CF_PRINT_WRITE_ERROR
;
3173 /* XXX - check for an error */
3180 cf_find_packet_protocol_tree(capture_file
*cf
, const char *string
,
3181 search_direction dir
, bool multiple
)
3185 mdata
.frame_matched
= false;
3187 mdata
.string
= string
;
3188 mdata
.string_len
= strlen(string
);
3190 mdata
.prev_finfo
= cf
->finfo_selected
;
3191 if (multiple
&& cf
->finfo_selected
&& cf
->edt
) {
3192 if (dir
== SD_FORWARD
) {
3193 proto_tree_children_foreach(cf
->edt
->tree
, match_subtree_text
, &mdata
);
3195 proto_tree_children_foreach(cf
->edt
->tree
, match_subtree_text_reverse
, &mdata
);
3197 if (mdata
.frame_matched
) {
3198 packet_list_select_finfo(mdata
.finfo
);
3202 return find_packet(cf
, match_protocol_tree
, &mdata
, dir
, true);
3206 cf_find_string_protocol_tree(capture_file
*cf
, proto_tree
*tree
)
3209 mdata
.frame_matched
= false;
3211 mdata
.string
= convert_string_case(cf
->sfilter
, cf
->case_type
);
3212 mdata
.string_len
= strlen(mdata
.string
);
3214 mdata
.prev_finfo
= NULL
;
3215 /* Iterate through all the nodes looking for matching text */
3216 if (cf
->dir
== SD_FORWARD
) {
3217 proto_tree_children_foreach(tree
, match_subtree_text
, &mdata
);
3219 proto_tree_children_foreach(tree
, match_subtree_text_reverse
, &mdata
);
3221 g_free((char *)mdata
.string
);
3222 return mdata
.frame_matched
? mdata
.finfo
: NULL
;
3226 match_protocol_tree(capture_file
*cf
, frame_data
*fdata
,
3227 wtap_rec
*rec
, void *criterion
)
3229 match_data
*mdata
= (match_data
*)criterion
;
3232 /* Load the frame's data. */
3233 if (!cf_read_record(cf
, fdata
, rec
)) {
3234 /* Attempt to get the packet failed. */
3238 /* Construct the protocol tree, including the displayed text */
3239 epan_dissect_init(&edt
, cf
->epan
, true, true);
3240 /* We don't need the column information */
3241 epan_dissect_run(&edt
, cf
->cd_t
, rec
, fdata
, NULL
);
3243 /* Iterate through all the nodes, seeing if they have text that matches. */
3245 mdata
->frame_matched
= false;
3246 mdata
->halt
= false;
3247 mdata
->prev_finfo
= NULL
;
3248 /* We don't care about the direction here, because we're just looking
3249 * for one match and we'll destroy this tree anyway. (We find the actual
3250 * field later in PacketList::selectionChanged().) Forwards is faster.
3252 proto_tree_children_foreach(edt
.tree
, match_subtree_text
, mdata
);
3253 epan_dissect_cleanup(&edt
);
3254 return mdata
->frame_matched
? MR_MATCHED
: MR_NOTMATCHED
;
3258 match_subtree_text(proto_node
*node
, void *data
)
3260 match_data
*mdata
= (match_data
*) data
;
3261 const char *string
= mdata
->string
;
3262 size_t string_len
= mdata
->string_len
;
3263 capture_file
*cf
= mdata
->cf
;
3264 field_info
*fi
= PNODE_FINFO(node
);
3265 char label_str
[ITEM_LABEL_LENGTH
];
3268 uint32_t i
, i_restart
;
3272 /* dissection with an invisible proto tree? */
3275 if (mdata
->frame_matched
) {
3276 /* We already had a match; don't bother doing any more work. */
3280 /* Don't match invisible entries. */
3281 if (proto_item_is_hidden(node
))
3284 if (mdata
->prev_finfo
) {
3285 /* Haven't found the old match, so don't match this node. */
3286 if (fi
== mdata
->prev_finfo
) {
3287 /* Found the old match, look for the next one after this. */
3288 mdata
->prev_finfo
= NULL
;
3291 /* was a free format label produced? */
3293 label_ptr
= fi
->rep
->representation
;
3295 /* no, make a generic label */
3296 label_ptr
= label_str
;
3297 proto_item_fill_label(fi
, label_str
, NULL
);
3301 if (ws_regex_matches(cf
->regex
, label_ptr
)) {
3302 mdata
->frame_matched
= true;
3306 } else if (cf
->case_type
) {
3307 /* Case insensitive match */
3308 label_len
= strlen(label_ptr
);
3310 for (i
= 0; i
< label_len
; i
++) {
3311 if (i_restart
== 0 && c_match
== 0 && (label_len
- i
< string_len
))
3313 c_char
= label_ptr
[i
];
3314 c_char
= g_ascii_toupper(c_char
);
3315 /* If c_match is non-zero, save candidate for retrying full match. */
3316 if (c_match
> 0 && i_restart
== 0 && c_char
== string
[0])
3318 if (c_char
== string
[c_match
]) {
3320 if (c_match
== string_len
) {
3321 mdata
->frame_matched
= true;
3323 /* No need to look further; we have a match */
3326 } else if (i_restart
) {
3333 } else if (strstr(label_ptr
, string
) != NULL
) {
3334 /* Case sensitive match */
3335 mdata
->frame_matched
= true;
3341 /* Recurse into the subtree, if it exists */
3342 if (node
->first_child
!= NULL
)
3343 proto_tree_children_foreach(node
, match_subtree_text
, mdata
);
3347 match_subtree_text_reverse(proto_node
*node
, void *data
)
3349 match_data
*mdata
= (match_data
*) data
;
3350 const char *string
= mdata
->string
;
3351 size_t string_len
= mdata
->string_len
;
3352 capture_file
*cf
= mdata
->cf
;
3353 field_info
*fi
= PNODE_FINFO(node
);
3354 char label_str
[ITEM_LABEL_LENGTH
];
3357 uint32_t i
, i_restart
;
3361 /* dissection with an invisible proto tree? */
3364 /* We don't have an easy way to search backwards in the tree
3365 * (see also, proto_find_field_from_offset()) because we don't
3366 * have a previous node pointer, so we search backwards by
3367 * searching forwards, only stopping if we see the old match
3375 /* Don't match invisible entries. */
3376 if (proto_item_is_hidden(node
))
3379 if (mdata
->prev_finfo
&& fi
== mdata
->prev_finfo
) {
3380 /* Found the old match, use the previous match. */
3385 /* was a free format label produced? */
3387 label_ptr
= fi
->rep
->representation
;
3389 /* no, make a generic label */
3390 label_ptr
= label_str
;
3391 proto_item_fill_label(fi
, label_str
, NULL
);
3395 if (ws_regex_matches(cf
->regex
, label_ptr
)) {
3396 mdata
->frame_matched
= true;
3399 } else if (cf
->case_type
) {
3400 /* Case insensitive match */
3401 label_len
= strlen(label_ptr
);
3403 for (i
= 0; i
< label_len
; i
++) {
3404 if (i_restart
== 0 && c_match
== 0 && (label_len
- i
< string_len
))
3406 c_char
= label_ptr
[i
];
3407 c_char
= g_ascii_toupper(c_char
);
3408 /* If c_match is non-zero, save candidate for retrying full match. */
3409 if (c_match
> 0 && i_restart
== 0 && c_char
== string
[0])
3411 if (c_char
== string
[c_match
]) {
3413 if (c_match
== string_len
) {
3414 mdata
->frame_matched
= true;
3418 } else if (i_restart
) {
3425 } else if (strstr(label_ptr
, string
) != NULL
) {
3426 /* Case sensitive match */
3427 mdata
->frame_matched
= true;
3431 /* Recurse into the subtree, if it exists */
3432 if (node
->first_child
!= NULL
)
3433 proto_tree_children_foreach(node
, match_subtree_text_reverse
, mdata
);
3437 cf_find_packet_summary_line(capture_file
*cf
, const char *string
,
3438 search_direction dir
)
3442 mdata
.string
= string
;
3443 mdata
.string_len
= strlen(string
);
3444 return find_packet(cf
, match_summary_line
, &mdata
, dir
, true);
3448 match_summary_line(capture_file
*cf
, frame_data
*fdata
,
3449 wtap_rec
*rec
, void *criterion
)
3451 match_data
*mdata
= (match_data
*)criterion
;
3452 const char *string
= mdata
->string
;
3453 size_t string_len
= mdata
->string_len
;
3455 const char *info_column
;
3456 size_t info_column_len
;
3457 match_result result
= MR_NOTMATCHED
;
3459 uint32_t i
, i_restart
;
3463 /* Load the frame's data. */
3464 if (!cf_read_record(cf
, fdata
, rec
)) {
3465 /* Attempt to get the packet failed. */
3469 /* Don't bother constructing the protocol tree */
3470 epan_dissect_init(&edt
, cf
->epan
, false, false);
3471 /* Get the column information */
3472 epan_dissect_run(&edt
, cf
->cd_t
, rec
, fdata
, &cf
->cinfo
);
3474 /* Find the Info column */
3475 for (colx
= 0; colx
< cf
->cinfo
.num_cols
; colx
++) {
3476 if (cf
->cinfo
.columns
[colx
].fmt_matx
[COL_INFO
]) {
3477 /* Found it. See if we match. */
3478 info_column
= get_column_text(edt
.pi
.cinfo
, colx
);
3479 info_column_len
= strlen(info_column
);
3481 if (ws_regex_matches(cf
->regex
, info_column
)) {
3482 result
= MR_MATCHED
;
3485 } else if (cf
->case_type
) {
3486 /* Case insensitive match */
3488 for (i
= 0; i
< info_column_len
; i
++) {
3489 if (i_restart
== 0 && c_match
== 0 && (info_column_len
- i
< string_len
))
3491 c_char
= info_column
[i
];
3492 c_char
= g_ascii_toupper(c_char
);
3493 /* If c_match is non-zero, save candidate for retrying full match. */
3494 if (c_match
> 0 && i_restart
== 0 && c_char
== string
[0])
3496 if (c_char
== string
[c_match
]) {
3498 if (c_match
== string_len
) {
3499 result
= MR_MATCHED
;
3502 } else if (i_restart
) {
3509 } else if (strstr(info_column
, string
) != NULL
) {
3510 /* Case sensitive match */
3511 result
= MR_MATCHED
;
3516 epan_dissect_cleanup(&edt
);
3521 const uint8_t *data
;
3523 ws_mempbrk_pattern
*pattern
;
3524 } cbs_t
; /* "Counted byte string" */
3528 * The current match_* routines only support ASCII case insensitivity and don't
3529 * convert UTF-8 inputs to UTF-16 for matching. The UTF-16 support just
3530 * interleaves with \0 bytes, which works for 7 bit ASCII.
3532 * We could modify them to use the GLib Unicode routines or the International
3533 * Components for Unicode library but it's not apparent that we could do so
3534 * without consuming a lot more CPU and memory or that searching would be
3535 * significantly better.
3537 * XXX: We could test the search string to see if it's all ASCII, and if not
3538 * use Unicode aware routines for case insensitive searches or any UTF-16
3543 cf_find_packet_data(capture_file
*cf
, const uint8_t *string
, size_t string_size
,
3544 search_direction dir
, bool multiple
)
3548 ws_mempbrk_pattern pattern
= {0};
3549 ws_match_function match_function
;
3552 info
.data_len
= string_size
;
3554 /* Regex, String or hex search? */
3556 /* Regular Expression search */
3557 match_function
= (dir
== SD_FORWARD
) ? match_regex
: match_regex_reverse
;
3558 } else if (cf
->string
) {
3559 /* String search - what type of string? */
3560 if (cf
->case_type
) {
3561 needles
[0] = string
[0];
3562 needles
[1] = g_ascii_tolower(needles
[0]);
3564 ws_mempbrk_compile(&pattern
, needles
);
3565 info
.pattern
= &pattern
;
3566 switch (cf
->scs_type
) {
3568 case SCS_NARROW_AND_WIDE
:
3569 match_function
= (dir
== SD_FORWARD
) ? match_narrow_and_wide_case
: match_narrow_and_wide_case_reverse
;
3573 match_function
= (dir
== SD_FORWARD
) ? match_narrow_case
: match_narrow_case_reverse
;
3577 match_function
= (dir
== SD_FORWARD
) ? match_wide_case
: match_wide_case_reverse
;
3581 ws_assert_not_reached();
3586 switch (cf
->scs_type
) {
3588 case SCS_NARROW_AND_WIDE
:
3589 match_function
= (dir
== SD_FORWARD
) ? match_narrow_and_wide
: match_narrow_and_wide_reverse
;
3593 /* Narrow, case-sensitive match is the same as looking
3594 * for a converted hexstring. */
3595 match_function
= (dir
== SD_FORWARD
) ? match_binary
: match_binary_reverse
;
3599 match_function
= (dir
== SD_FORWARD
) ? match_wide
: match_wide_reverse
;
3603 ws_assert_not_reached();
3608 match_function
= (dir
== SD_FORWARD
) ? match_binary
: match_binary_reverse
;
3611 if (multiple
&& cf
->current_frame
&& (cf
->search_pos
|| cf
->search_len
)) {
3612 /* Use the current frame (this will perform the equivalent of
3613 * cf_read_current_record() in match_function).
3615 if (match_function(cf
, cf
->current_frame
, &cf
->rec
, &info
)) {
3616 cf
->search_in_progress
= true;
3618 field_info
*fi
= NULL
;
3619 /* The regex match can match an empty string. */
3620 if (cf
->search_len
) {
3621 fi
= proto_find_field_from_offset(cf
->edt
->tree
, cf
->search_pos
+ cf
->search_len
- 1, cf
->edt
->tvb
);
3623 packet_list_select_finfo(fi
);
3625 packet_list_select_row_from_data(cf
->current_frame
);
3627 cf
->search_in_progress
= false;
3631 cf
->search_pos
= 0; /* Reset the position */
3632 cf
->search_len
= 0; /* Reset length */
3633 return find_packet(cf
, match_function
, &info
, dir
, true);
3637 match_narrow_and_wide(capture_file
*cf
, frame_data
*fdata
,
3638 wtap_rec
*rec
, void *criterion
)
3640 cbs_t
*info
= (cbs_t
*)criterion
;
3641 const uint8_t *ascii_text
= info
->data
;
3642 size_t textlen
= info
->data_len
;
3643 match_result result
;
3645 const uint8_t *pd
, *buf_start
, *buf_end
;
3650 /* Load the frame's data. */
3651 if (!cf_read_record(cf
, fdata
, rec
)) {
3652 /* Attempt to get the packet failed. */
3656 result
= MR_NOTMATCHED
;
3657 buf_len
= fdata
->cap_len
;
3658 buf_start
= ws_buffer_start_ptr(&rec
->data
);
3659 buf_end
= buf_start
+ buf_len
;
3661 if (cf
->search_len
|| cf
->search_pos
) {
3662 /* we want to start searching one byte past the previous match start */
3663 pd
+= cf
->search_pos
+ 1;
3665 for (; pd
< buf_end
; pd
++) {
3666 pd
= (uint8_t *)memchr(pd
, ascii_text
[0], buf_end
- pd
);
3667 if (pd
== NULL
) break;
3668 /* Try narrow match at this start location */
3670 for (i
= 0; pd
+ i
< buf_end
; i
++) {
3672 if (c_char
== ascii_text
[c_match
]) {
3674 if (c_match
== textlen
) {
3675 result
= MR_MATCHED
;
3676 /* Save position and length for highlighting the field. */
3677 cf
->search_pos
= (uint32_t)(pd
- buf_start
);
3678 cf
->search_len
= (uint32_t)(i
+ 1);
3686 /* Now try wide match at the same start location. */
3688 for (i
= 0; pd
+ i
< buf_end
; i
++) {
3690 if (c_char
== ascii_text
[c_match
]) {
3692 if (c_match
== textlen
) {
3693 result
= MR_MATCHED
;
3694 /* Save position and length for highlighting the field. */
3695 cf
->search_pos
= (uint32_t)(pd
- buf_start
);
3696 cf
->search_len
= (uint32_t)(i
+ 1);
3700 if (pd
+ i
>= buf_end
|| pd
[i
] != '\0') break;
3712 match_narrow_and_wide_reverse(capture_file
*cf
, frame_data
*fdata
,
3713 wtap_rec
*rec
, void *criterion
)
3715 cbs_t
*info
= (cbs_t
*)criterion
;
3716 const uint8_t *ascii_text
= info
->data
;
3717 size_t textlen
= info
->data_len
;
3718 match_result result
;
3720 const uint8_t *pd
, *buf_start
, *buf_end
;
3725 /* Load the frame's data. */
3726 if (!cf_read_record(cf
, fdata
, rec
)) {
3727 /* Attempt to get the packet failed. */
3731 result
= MR_NOTMATCHED
;
3732 /* Has to be room to hold the sought data. */
3733 if (textlen
> fdata
->cap_len
) {
3736 buf_len
= fdata
->cap_len
;
3737 buf_start
= ws_buffer_start_ptr(&rec
->data
);
3738 buf_end
= buf_start
+ buf_len
;
3739 pd
= buf_end
- textlen
;
3740 if (cf
->search_len
|| cf
->search_pos
) {
3741 /* we want to start searching one byte before the previous match start */
3742 pd
= buf_start
+ cf
->search_pos
- 1;
3744 for (; pd
< buf_end
; pd
++) {
3745 pd
= (uint8_t *)ws_memrchr(buf_start
, ascii_text
[0], pd
- buf_start
+ 1);
3746 if (pd
== NULL
) break;
3747 /* Try narrow match at this start location */
3749 for (i
= 0; pd
+ i
< buf_end
; i
++) {
3751 if (c_char
== ascii_text
[c_match
]) {
3753 if (c_match
== textlen
) {
3754 result
= MR_MATCHED
;
3755 /* Save position and length for highlighting the field. */
3756 cf
->search_pos
= (uint32_t)(pd
- buf_start
);
3757 cf
->search_len
= (uint32_t)(i
+ 1);
3765 /* Now try wide match at the same start location. */
3767 for (i
= 0; pd
+ i
< buf_end
; i
++) {
3769 if (c_char
== ascii_text
[c_match
]) {
3771 if (c_match
== textlen
) {
3772 result
= MR_MATCHED
;
3773 /* Save position and length for highlighting the field. */
3774 cf
->search_pos
= (uint32_t)(pd
- buf_start
);
3775 cf
->search_len
= (uint32_t)(i
+ 1);
3779 if (pd
+ i
>= buf_end
|| pd
[i
] != '\0') break;
3790 /* Case insensitive match */
3792 match_narrow_and_wide_case(capture_file
*cf
, frame_data
*fdata
,
3793 wtap_rec
*rec
, void *criterion
)
3795 cbs_t
*info
= (cbs_t
*)criterion
;
3796 const uint8_t *ascii_text
= info
->data
;
3797 size_t textlen
= info
->data_len
;
3798 ws_mempbrk_pattern
*pattern
= info
->pattern
;
3799 match_result result
;
3801 const uint8_t *pd
, *buf_start
, *buf_end
;
3806 /* Load the frame's data. */
3807 if (!cf_read_record(cf
, fdata
, rec
)) {
3808 /* Attempt to get the packet failed. */
3812 ws_assert(pattern
!= NULL
);
3814 result
= MR_NOTMATCHED
;
3815 buf_len
= fdata
->cap_len
;
3816 buf_start
= ws_buffer_start_ptr(&rec
->data
);
3817 buf_end
= buf_start
+ buf_len
;
3819 if (cf
->search_len
|| cf
->search_pos
) {
3820 /* we want to start searching one byte past the previous match start */
3821 pd
+= cf
->search_pos
+ 1;
3823 for (; pd
< buf_end
; pd
++) {
3824 pd
= (uint8_t *)ws_mempbrk_exec(pd
, buf_end
- pd
, pattern
, &c_char
);
3825 if (pd
== NULL
) break;
3826 /* Try narrow match at this start location */
3828 for (i
= 0; pd
+ i
< buf_end
; i
++) {
3829 c_char
= g_ascii_toupper(pd
[i
]);
3830 if (c_char
== ascii_text
[c_match
]) {
3832 if (c_match
== textlen
) {
3833 result
= MR_MATCHED
;
3834 /* Save position and length for highlighting the field. */
3835 cf
->search_pos
= (uint32_t)(pd
- buf_start
);
3836 cf
->search_len
= (uint32_t)(i
+ 1);
3844 /* Now try wide match at the same start location. */
3846 for (i
= 0; pd
+ i
< buf_end
; i
++) {
3847 c_char
= g_ascii_toupper(pd
[i
]);
3848 if (c_char
== ascii_text
[c_match
]) {
3850 if (c_match
== textlen
) {
3851 result
= MR_MATCHED
;
3852 /* Save position and length for highlighting the field. */
3853 cf
->search_pos
= (uint32_t)(pd
- buf_start
);
3854 cf
->search_len
= (uint32_t)(i
+ 1);
3858 if (pd
+ i
>= buf_end
|| pd
[i
] != '\0') break;
3870 match_narrow_and_wide_case_reverse(capture_file
*cf
, frame_data
*fdata
,
3871 wtap_rec
*rec
, void *criterion
)
3873 cbs_t
*info
= (cbs_t
*)criterion
;
3874 const uint8_t *ascii_text
= info
->data
;
3875 size_t textlen
= info
->data_len
;
3876 ws_mempbrk_pattern
*pattern
= info
->pattern
;
3877 match_result result
;
3879 const uint8_t *pd
, *buf_start
, *buf_end
;
3884 /* Load the frame's data. */
3885 if (!cf_read_record(cf
, fdata
, rec
)) {
3886 /* Attempt to get the packet failed. */
3890 ws_assert(pattern
!= NULL
);
3892 result
= MR_NOTMATCHED
;
3893 /* Has to be room to hold the sought data. */
3894 if (textlen
> fdata
->cap_len
) {
3897 buf_len
= fdata
->cap_len
;
3898 buf_start
= ws_buffer_start_ptr(&rec
->data
);
3899 buf_end
= buf_start
+ buf_len
;
3900 pd
= buf_end
- textlen
;
3901 if (cf
->search_len
|| cf
->search_pos
) {
3902 /* we want to start searching one byte before the previous match start */
3903 pd
= buf_start
+ cf
->search_pos
- 1;
3905 for (; pd
>= buf_start
; pd
--) {
3906 pd
= (uint8_t *)ws_memrpbrk_exec(buf_start
, pd
- buf_start
+ 1, pattern
, &c_char
);
3907 if (pd
== NULL
) break;
3908 /* Try narrow match at this start location */
3910 for (i
= 0; pd
+ i
< buf_end
; i
++) {
3911 c_char
= g_ascii_toupper(pd
[i
]);
3912 if (c_char
== ascii_text
[c_match
]) {
3914 if (c_match
== textlen
) {
3915 result
= MR_MATCHED
;
3916 /* Save position and length for highlighting the field. */
3917 cf
->search_pos
= (uint32_t)(pd
- buf_start
);
3918 cf
->search_len
= (uint32_t)(i
+ 1);
3926 /* Now try wide match at the same start location. */
3928 for (i
= 0; pd
+ i
< buf_end
; i
++) {
3929 c_char
= g_ascii_toupper(pd
[i
]);
3930 if (c_char
== ascii_text
[c_match
]) {
3932 if (c_match
== textlen
) {
3933 result
= MR_MATCHED
;
3934 /* Save position and length for highlighting the field. */
3935 cf
->search_pos
= (uint32_t)(pd
- buf_start
);
3936 cf
->search_len
= (uint32_t)(i
+ 1);
3940 if (pd
+ i
>= buf_end
|| pd
[i
] != '\0') break;
3951 /* Case insensitive match */
3953 match_narrow_case(capture_file
*cf
, frame_data
*fdata
,
3954 wtap_rec
*rec
, void *criterion
)
3956 cbs_t
*info
= (cbs_t
*)criterion
;
3957 const uint8_t *ascii_text
= info
->data
;
3958 size_t textlen
= info
->data_len
;
3959 ws_mempbrk_pattern
*pattern
= info
->pattern
;
3960 match_result result
;
3962 const uint8_t *pd
, *buf_start
, *buf_end
;
3967 /* Load the frame's data. */
3968 if (!cf_read_record(cf
, fdata
, rec
)) {
3969 /* Attempt to get the packet failed. */
3973 ws_assert(pattern
!= NULL
);
3975 result
= MR_NOTMATCHED
;
3976 buf_len
= fdata
->cap_len
;
3977 buf_start
= ws_buffer_start_ptr(&rec
->data
);
3978 buf_end
= buf_start
+ buf_len
;
3980 if (cf
->search_len
|| cf
->search_pos
) {
3981 /* we want to start searching one byte past the previous match start */
3982 pd
+= cf
->search_pos
+ 1;
3984 for (; pd
< buf_end
; pd
++) {
3985 pd
= (uint8_t *)ws_mempbrk_exec(pd
, buf_end
- pd
, pattern
, &c_char
);
3986 if (pd
== NULL
) break;
3988 for (i
= 0; pd
+ i
< buf_end
; i
++) {
3989 c_char
= g_ascii_toupper(pd
[i
]);
3990 if (c_char
== ascii_text
[c_match
]) {
3992 if (c_match
== textlen
) {
3993 /* Save position and length for highlighting the field. */
3994 result
= MR_MATCHED
;
3995 cf
->search_pos
= (uint32_t)(pd
- buf_start
);
3996 cf
->search_len
= (uint32_t)(i
+ 1);
4010 match_narrow_case_reverse(capture_file
*cf
, frame_data
*fdata
,
4011 wtap_rec
*rec
, void *criterion
)
4013 cbs_t
*info
= (cbs_t
*)criterion
;
4014 const uint8_t *ascii_text
= info
->data
;
4015 size_t textlen
= info
->data_len
;
4016 ws_mempbrk_pattern
*pattern
= info
->pattern
;
4017 match_result result
;
4019 const uint8_t *pd
, *buf_start
, *buf_end
;
4024 /* Load the frame's data. */
4025 if (!cf_read_record(cf
, fdata
, rec
)) {
4026 /* Attempt to get the packet failed. */
4030 ws_assert(pattern
!= NULL
);
4032 result
= MR_NOTMATCHED
;
4033 /* Has to be room to hold the sought data. */
4034 if (textlen
> fdata
->cap_len
) {
4037 buf_len
= fdata
->cap_len
;
4038 buf_start
= ws_buffer_start_ptr(&rec
->data
);
4039 buf_end
= buf_start
+ buf_len
;
4040 pd
= buf_end
- textlen
;
4041 if (cf
->search_len
|| cf
->search_pos
) {
4042 /* we want to start searching one byte before the previous match start */
4043 pd
= buf_start
+ cf
->search_pos
- 1;
4045 for (; pd
>= buf_start
; pd
--) {
4046 pd
= (uint8_t *)ws_memrpbrk_exec(buf_start
, pd
- buf_start
+ 1, pattern
, &c_char
);
4047 if (pd
== NULL
) break;
4049 for (i
= 0; pd
+ i
< buf_end
; i
++) {
4050 c_char
= g_ascii_toupper(pd
[i
]);
4051 if (c_char
== ascii_text
[c_match
]) {
4053 if (c_match
== textlen
) {
4054 /* Save position and length for highlighting the field. */
4055 result
= MR_MATCHED
;
4056 cf
->search_pos
= (uint32_t)(pd
- buf_start
);
4057 cf
->search_len
= (uint32_t)(i
+ 1);
4071 match_wide(capture_file
*cf
, frame_data
*fdata
,
4072 wtap_rec
*rec
, void *criterion
)
4074 cbs_t
*info
= (cbs_t
*)criterion
;
4075 const uint8_t *ascii_text
= info
->data
;
4076 size_t textlen
= info
->data_len
;
4077 match_result result
;
4079 const uint8_t *pd
, *buf_start
, *buf_end
;
4084 /* Load the frame's data. */
4085 if (!cf_read_record(cf
, fdata
, rec
)) {
4086 /* Attempt to get the packet failed. */
4090 result
= MR_NOTMATCHED
;
4091 buf_len
= fdata
->cap_len
;
4092 buf_start
= ws_buffer_start_ptr(&rec
->data
);
4093 buf_end
= buf_start
+ buf_len
;
4095 if (cf
->search_len
|| cf
->search_pos
) {
4096 /* we want to start searching one byte past the previous match start */
4097 pd
+= cf
->search_pos
+ 1;
4099 for (; pd
< buf_end
; pd
++) {
4100 pd
= (uint8_t *)memchr(pd
, ascii_text
[0], buf_end
- pd
);
4101 if (pd
== NULL
) break;
4103 for (i
= 0; pd
+ i
< buf_end
; i
++) {
4105 if (c_char
== ascii_text
[c_match
]) {
4107 if (c_match
== textlen
) {
4108 result
= MR_MATCHED
;
4109 /* Save position and length for highlighting the field. */
4110 cf
->search_pos
= (uint32_t)(pd
- buf_start
);
4111 cf
->search_len
= (uint32_t)(i
+ 1);
4115 if (pd
+ i
>= buf_end
|| pd
[i
] != '\0') break;
4127 match_wide_reverse(capture_file
*cf
, frame_data
*fdata
,
4128 wtap_rec
*rec
, void *criterion
)
4130 cbs_t
*info
= (cbs_t
*)criterion
;
4131 const uint8_t *ascii_text
= info
->data
;
4132 size_t textlen
= info
->data_len
;
4133 match_result result
;
4135 const uint8_t *pd
, *buf_start
, *buf_end
;
4140 /* Load the frame's data. */
4141 if (!cf_read_record(cf
, fdata
, rec
)) {
4142 /* Attempt to get the packet failed. */
4146 result
= MR_NOTMATCHED
;
4147 /* Has to be room to hold the sought data. */
4148 if (textlen
> fdata
->cap_len
) {
4151 buf_len
= fdata
->cap_len
;
4152 buf_start
= ws_buffer_start_ptr(&rec
->data
);
4153 buf_end
= buf_start
+ buf_len
;
4154 pd
= buf_end
- textlen
;
4155 if (cf
->search_len
|| cf
->search_pos
) {
4156 /* we want to start searching one byte before the previous match start */
4157 pd
= buf_start
+ cf
->search_pos
- 1;
4159 for (; pd
< buf_end
; pd
++) {
4160 pd
= (uint8_t *)ws_memrchr(buf_start
, ascii_text
[0], pd
- buf_start
+ 1);
4161 if (pd
== NULL
) break;
4163 for (i
= 0; pd
+ i
< buf_end
; i
++) {
4165 if (c_char
== ascii_text
[c_match
]) {
4167 if (c_match
== textlen
) {
4168 result
= MR_MATCHED
;
4169 /* Save position and length for highlighting the field. */
4170 cf
->search_pos
= (uint32_t)(pd
- buf_start
);
4171 cf
->search_len
= (uint32_t)(i
+ 1);
4175 if (pd
+ i
>= buf_end
|| pd
[i
] != '\0') break;
4186 /* Case insensitive match */
4188 match_wide_case(capture_file
*cf
, frame_data
*fdata
,
4189 wtap_rec
*rec
, void *criterion
)
4191 cbs_t
*info
= (cbs_t
*)criterion
;
4192 const uint8_t *ascii_text
= info
->data
;
4193 size_t textlen
= info
->data_len
;
4194 ws_mempbrk_pattern
*pattern
= info
->pattern
;
4195 match_result result
;
4197 const uint8_t *pd
, *buf_start
, *buf_end
;
4202 /* Load the frame's data. */
4203 if (!cf_read_record(cf
, fdata
, rec
)) {
4204 /* Attempt to get the packet failed. */
4208 ws_assert(pattern
!= NULL
);
4210 result
= MR_NOTMATCHED
;
4211 buf_len
= fdata
->cap_len
;
4212 buf_start
= ws_buffer_start_ptr(&rec
->data
);
4213 buf_end
= buf_start
+ buf_len
;
4215 if (cf
->search_len
|| cf
->search_pos
) {
4216 /* we want to start searching one byte past the previous match start */
4217 pd
+= cf
->search_pos
+ 1;
4219 for (; pd
< buf_end
; pd
++) {
4220 pd
= (uint8_t *)ws_mempbrk_exec(pd
, buf_end
- pd
, pattern
, &c_char
);
4221 if (pd
== NULL
) break;
4223 for (i
= 0; pd
+ i
< buf_end
; i
++) {
4224 c_char
= g_ascii_toupper(pd
[i
]);
4225 if (c_char
== ascii_text
[c_match
]) {
4227 if (c_match
== textlen
) {
4228 result
= MR_MATCHED
;
4229 /* Save position and length for highlighting the field. */
4230 cf
->search_pos
= (uint32_t)(pd
- buf_start
);
4231 cf
->search_len
= (uint32_t)(i
+ 1);
4235 if (pd
+ i
>= buf_end
|| pd
[i
] != '\0') break;
4246 /* Case insensitive match */
4248 match_wide_case_reverse(capture_file
*cf
, frame_data
*fdata
,
4249 wtap_rec
*rec
, void *criterion
)
4251 cbs_t
*info
= (cbs_t
*)criterion
;
4252 const uint8_t *ascii_text
= info
->data
;
4253 size_t textlen
= info
->data_len
;
4254 ws_mempbrk_pattern
*pattern
= info
->pattern
;
4255 match_result result
;
4257 const uint8_t *pd
, *buf_start
, *buf_end
;
4262 /* Load the frame's data. */
4263 if (!cf_read_record(cf
, fdata
, rec
)) {
4264 /* Attempt to get the packet failed. */
4268 ws_assert(pattern
!= NULL
);
4270 result
= MR_NOTMATCHED
;
4271 /* Has to be room to hold the sought data. */
4272 if (textlen
> fdata
->cap_len
) {
4275 buf_len
= fdata
->cap_len
;
4276 buf_start
= ws_buffer_start_ptr(&rec
->data
);
4277 buf_end
= buf_start
+ buf_len
;
4278 pd
= buf_end
- textlen
;
4279 if (cf
->search_len
|| cf
->search_pos
) {
4280 /* we want to start searching one byte before the previous match start */
4281 pd
= buf_start
+ cf
->search_pos
- 1;
4283 for (; pd
>= buf_start
; pd
--) {
4284 pd
= (uint8_t *)ws_memrpbrk_exec(buf_start
, pd
- buf_start
+ 1, pattern
, &c_char
);
4285 if (pd
== NULL
) break;
4287 for (i
= 0; pd
+ i
< buf_end
; i
++) {
4288 c_char
= g_ascii_toupper(pd
[i
]);
4289 if (c_char
== ascii_text
[c_match
]) {
4291 if (c_match
== textlen
) {
4292 result
= MR_MATCHED
;
4293 /* Save position and length for highlighting the field. */
4294 cf
->search_pos
= (uint32_t)(pd
- buf_start
);
4295 cf
->search_len
= (uint32_t)(i
+ 1);
4299 if (pd
+ i
>= buf_end
|| pd
[i
] != '\0') break;
4311 match_binary(capture_file
*cf
, frame_data
*fdata
,
4312 wtap_rec
*rec
, void *criterion
)
4314 cbs_t
*info
= (cbs_t
*)criterion
;
4315 size_t datalen
= info
->data_len
;
4316 match_result result
;
4317 const uint8_t *pd
= NULL
, *buf_start
;
4319 /* Load the frame's data. */
4320 if (!cf_read_record(cf
, fdata
, rec
)) {
4321 /* Attempt to get the packet failed. */
4325 result
= MR_NOTMATCHED
;
4326 buf_start
= ws_buffer_start_ptr(&rec
->data
);
4328 if (cf
->search_len
|| cf
->search_pos
) {
4329 /* we want to start searching one byte past the previous match start */
4330 offset
= cf
->search_pos
+ 1;
4332 if (offset
< fdata
->cap_len
) {
4333 pd
= ws_memmem(buf_start
+ offset
, fdata
->cap_len
- offset
, info
->data
, datalen
);
4336 result
= MR_MATCHED
;
4337 /* Save position and length for highlighting the field. */
4338 cf
->search_pos
= (uint32_t)(pd
- buf_start
);
4339 cf
->search_len
= (uint32_t)datalen
;
4346 match_binary_reverse(capture_file
*cf
, frame_data
*fdata
,
4347 wtap_rec
*rec
, void *criterion
)
4349 cbs_t
*info
= (cbs_t
*)criterion
;
4350 size_t datalen
= info
->data_len
;
4351 match_result result
;
4352 const uint8_t *pd
= NULL
, *buf_start
;
4354 /* Load the frame's data. */
4355 if (!cf_read_record(cf
, fdata
, rec
)) {
4356 /* Attempt to get the packet failed. */
4360 result
= MR_NOTMATCHED
;
4361 buf_start
= ws_buffer_start_ptr(&rec
->data
);
4362 /* Has to be room to hold the sought data. */
4363 if (datalen
> fdata
->cap_len
) {
4366 pd
= buf_start
+ fdata
->cap_len
- datalen
;
4367 if (cf
->search_len
|| cf
->search_pos
) {
4368 /* we want to start searching one byte before the previous match start */
4369 pd
= buf_start
+ cf
->search_pos
- 1;
4371 for (; pd
>= buf_start
; pd
--) {
4372 pd
= (uint8_t *)ws_memrchr(buf_start
, info
->data
[0], pd
- buf_start
+ 1);
4373 if (pd
== NULL
) break;
4374 if (memcmp(pd
, info
->data
, datalen
) == 0) {
4375 result
= MR_MATCHED
;
4376 /* Save position and length for highlighting the field. */
4377 cf
->search_pos
= (uint32_t)(pd
- buf_start
);
4378 cf
->search_len
= (uint32_t)datalen
;
4387 match_regex(capture_file
*cf
, frame_data
*fdata
,
4388 wtap_rec
*rec
, void *criterion _U_
)
4390 match_result result
= MR_NOTMATCHED
;
4391 size_t result_pos
[2] = {0, 0};
4393 /* Load the frame's data. */
4394 if (!cf_read_record(cf
, fdata
, rec
)) {
4395 /* Attempt to get the packet failed. */
4400 if (cf
->search_len
|| cf
->search_pos
) {
4401 /* we want to start searching one byte past the previous match start */
4402 offset
= cf
->search_pos
+ 1;
4404 if (offset
< fdata
->cap_len
) {
4405 if (ws_regex_matches_pos(cf
->regex
,
4406 (const char *)ws_buffer_start_ptr(&rec
->data
),
4407 fdata
->cap_len
, offset
,
4409 //TODO: A chosen regex can match the empty string (zero length)
4410 // which doesn't make a lot of sense for searching the packet bytes.
4411 // Should we search with the PCRE2_NOTEMPTY option?
4413 /* Save position and length for highlighting the field. */
4414 cf
->search_pos
= (uint32_t)(result_pos
[0]);
4415 cf
->search_len
= (uint32_t)(result_pos
[1] - result_pos
[0]);
4416 result
= MR_MATCHED
;
4423 match_regex_reverse(capture_file
*cf
, frame_data
*fdata
,
4424 wtap_rec
*rec
, void *criterion _U_
)
4426 match_result result
= MR_NOTMATCHED
;
4427 size_t result_pos
[2] = {0, 0};
4429 /* Load the frame's data. */
4430 if (!cf_read_record(cf
, fdata
, rec
)) {
4431 /* Attempt to get the packet failed. */
4435 size_t offset
= fdata
->cap_len
- 1;
4436 if (cf
->search_pos
) {
4437 /* we want to start searching one byte before the previous match */
4438 offset
= cf
->search_pos
- 1;
4440 for (; offset
> 0; offset
--) {
4441 if (ws_regex_matches_pos(cf
->regex
,
4442 (const char *)ws_buffer_start_ptr(&rec
->data
),
4443 fdata
->cap_len
, offset
,
4445 //TODO: A chosen regex can match the empty string (zero length)
4446 // which doesn't make a lot of sense for searching the packet bytes.
4447 // Should we search with the PCRE2_NOTEMPTY option?
4449 /* Save position and length for highlighting the field. */
4450 cf
->search_pos
= (uint32_t)(result_pos
[0]);
4451 cf
->search_len
= (uint32_t)(result_pos
[1] - result_pos
[0]);
4452 result
= MR_MATCHED
;
4460 cf_find_packet_dfilter(capture_file
*cf
, dfilter_t
*sfcode
,
4461 search_direction dir
, bool start_current
)
4463 return find_packet(cf
, match_dfilter
, sfcode
, dir
, start_current
);
4467 cf_find_packet_dfilter_string(capture_file
*cf
, const char *filter
,
4468 search_direction dir
)
4473 if (!dfilter_compile(filter
, &sfcode
, NULL
)) {
4475 * XXX - this shouldn't happen, as the filter string is machine
4480 if (sfcode
== NULL
) {
4482 * XXX - this shouldn't happen, as the filter string is machine
4487 result
= find_packet(cf
, match_dfilter
, sfcode
, dir
, true);
4488 dfilter_free(sfcode
);
4493 match_dfilter(capture_file
*cf
, frame_data
*fdata
, wtap_rec
*rec
,
4496 dfilter_t
*sfcode
= (dfilter_t
*)criterion
;
4498 match_result result
;
4500 /* Load the frame's data. */
4501 if (!cf_read_record(cf
, fdata
, rec
)) {
4502 /* Attempt to get the packet failed. */
4506 epan_dissect_init(&edt
, cf
->epan
, true, false);
4507 epan_dissect_prime_with_dfilter(&edt
, sfcode
);
4508 epan_dissect_run(&edt
, cf
->cd_t
, rec
, fdata
, NULL
);
4509 result
= dfilter_apply_edt(sfcode
, &edt
) ? MR_MATCHED
: MR_NOTMATCHED
;
4510 epan_dissect_cleanup(&edt
);
4515 cf_find_packet_marked(capture_file
*cf
, search_direction dir
)
4517 return find_packet(cf
, match_marked
, NULL
, dir
, true);
4521 match_marked(capture_file
*cf _U_
, frame_data
*fdata
, wtap_rec
*rec _U_
,
4522 void *criterion _U_
)
4524 return fdata
->marked
? MR_MATCHED
: MR_NOTMATCHED
;
4528 cf_find_packet_time_reference(capture_file
*cf
, search_direction dir
)
4530 return find_packet(cf
, match_time_reference
, NULL
, dir
, true);
4534 match_time_reference(capture_file
*cf _U_
, frame_data
*fdata
, wtap_rec
*rec _U_
,
4535 void *criterion _U_
)
4537 return fdata
->ref_time
? MR_MATCHED
: MR_NOTMATCHED
;
4541 find_packet(capture_file
*cf
, ws_match_function match_function
,
4542 void *criterion
, search_direction dir
, bool start_current
)
4544 frame_data
*start_fd
;
4546 uint32_t prev_framenum
;
4549 frame_data
*new_fd
= NULL
;
4550 progdlg_t
*progbar
= NULL
;
4551 GTimer
*prog_timer
= g_timer_new();
4553 bool wrap
= prefs
.gui_find_wrap
;
4556 char status_str
[100];
4557 match_result result
;
4559 wtap_rec_init(&rec
, 1514);
4561 start_fd
= start_current
? cf
->current_frame
: NULL
;
4562 if (start_fd
!= NULL
) {
4563 prev_framenum
= start_fd
->num
;
4565 prev_framenum
= 0; /* No start packet selected. */
4569 /* Iterate through the list of packets, starting at the packet we've
4570 picked, calling a routine to run the filter on the packet, see if
4571 it matches, and stop if so. */
4573 framenum
= prev_framenum
;
4574 if (framenum
== 0 && dir
== SD_BACKWARD
) {
4575 /* If we have no start packet selected, and we're going backwards,
4576 * start at the end (even if wrap is off.)
4578 framenum
= cf
->count
+ 1;
4581 g_timer_start(prog_timer
);
4582 /* Progress so far. */
4585 cf
->stop_flag
= false;
4588 /* Create the progress bar if necessary.
4589 We check on every iteration of the loop, so that it takes no
4590 longer than the standard time to create it (otherwise, for a
4591 large file, we might take considerably longer than that standard
4592 time in order to get to the next progress bar step). */
4593 if (progbar
== NULL
)
4594 progbar
= delayed_create_progress_dlg(cf
->window
, NULL
, NULL
,
4595 false, &cf
->stop_flag
, progbar_val
);
4598 * Update the progress bar, but do it only after PROGBAR_UPDATE_INTERVAL
4599 * has elapsed. Calling update_progress_dlg and packets_bar_update will
4600 * likely trigger UI paint events, which might take a while depending on
4601 * the platform and display. Reset our timer *after* painting.
4603 if (g_timer_elapsed(prog_timer
, NULL
) > PROGBAR_UPDATE_INTERVAL
) {
4604 /* let's not divide by zero. I should never be started
4605 * with count == 0, so let's assert that
4607 ws_assert(cf
->count
> 0);
4609 progbar_val
= (float) count
/ cf
->count
;
4611 snprintf(status_str
, sizeof(status_str
),
4612 "%4u of %u packets", count
, cf
->count
);
4613 update_progress_dlg(progbar
, progbar_val
, status_str
);
4615 g_timer_start(prog_timer
);
4618 if (cf
->stop_flag
) {
4619 /* Well, the user decided to abort the search. Go back to the
4620 frame where we started.
4621 XXX - This ends up selecting the start packet and reporting
4622 "success". Perhaps new_fd should stay NULL? */
4627 /* Go past the current frame. */
4628 if (dir
== SD_BACKWARD
) {
4629 /* Go on to the previous frame. */
4630 if (framenum
<= 1) {
4632 * XXX - other apps have a bit more of a detailed message
4633 * for this, and instead of offering "OK" and "Cancel",
4634 * they offer things such as "Continue" and "Cancel";
4635 * we need an API for popping up alert boxes with
4636 * {Verb} and "Cancel".
4640 statusbar_push_temporary_msg("Search reached the beginning. Continuing at end.");
4641 framenum
= cf
->count
; /* wrap around */
4644 statusbar_push_temporary_msg("Search reached the beginning.");
4645 framenum
= prev_framenum
; /* stay on previous packet */
4650 /* Go on to the next frame. */
4651 if (framenum
== cf
->count
) {
4653 statusbar_push_temporary_msg("Search reached the end. Continuing at beginning.");
4654 framenum
= 1; /* wrap around */
4657 statusbar_push_temporary_msg("Search reached the end.");
4658 framenum
= prev_framenum
; /* stay on previous packet */
4664 fdata
= frame_data_sequence_find(cf
->provider
.frames
, framenum
);
4667 /* Is this packet in the display? */
4668 if (fdata
&& fdata
->passed_dfilter
) {
4669 /* Yes. Does it match the search criterion? */
4670 result
= (*match_function
)(cf
, fdata
, &rec
, criterion
);
4671 if (result
== MR_ERROR
) {
4672 /* Error; our caller has reported the error. Go back to the frame
4674 XXX - This ends up selecting the start packet and reporting
4675 "success." Perhaps new_fd should stay NULL? */
4678 } else if (result
== MR_MATCHED
) {
4679 /* Yes. Go to the new frame. */
4683 wtap_rec_reset(&rec
);
4686 if (fdata
== start_fd
) {
4687 /* We're back to the frame we were on originally, and that frame
4688 doesn't match the search filter. The search failed. */
4693 /* We're done scanning the packets; destroy the progress bar if it
4695 if (progbar
!= NULL
)
4696 destroy_progress_dlg(progbar
);
4697 g_timer_destroy(prog_timer
);
4699 if (new_fd
!= NULL
) {
4700 /* We found a frame that's displayed and that matches.
4701 Try to find and select the packet summary list row for that frame. */
4704 cf
->search_in_progress
= true;
4705 found_row
= packet_list_select_row_from_data(new_fd
);
4706 cf
->search_in_progress
= false;
4708 /* We didn't find a row corresponding to this frame.
4709 This means that the frame isn't being displayed currently,
4710 so we can't select it. */
4711 cf
->search_pos
= 0; /* Reset the position */
4712 cf
->search_len
= 0; /* Reset length */
4713 simple_message_box(ESD_TYPE_INFO
, NULL
,
4714 "The capture file is probably not fully dissected.",
4715 "End of capture exceeded.");
4716 succeeded
= false; /* The search succeeded but we didn't find the row */
4718 succeeded
= true; /* The search succeeded and we found the row */
4720 succeeded
= false; /* The search failed */
4721 wtap_rec_cleanup(&rec
);
4726 cf_goto_frame(capture_file
*cf
, unsigned fnumber
, bool exact
)
4730 if (cf
== NULL
|| cf
->provider
.frames
== NULL
) {
4731 /* we don't have a loaded capture file - fix for bugs 11810 & 11989 */
4732 statusbar_push_temporary_msg("There is no file loaded");
4733 return false; /* we failed to go to that packet */
4736 fdata
= frame_data_sequence_find(cf
->provider
.frames
, fnumber
);
4738 if (fdata
== NULL
) {
4739 /* we didn't find a packet with that packet number */
4740 statusbar_push_temporary_msg("There is no packet number %u.", fnumber
);
4741 return false; /* we failed to go to that packet */
4743 if (!fdata
->passed_dfilter
) {
4744 /* that packet currently isn't displayed */
4745 /* XXX - add it to the set of displayed packets? */
4746 if (cf
->first_displayed
== 0 || exact
) {
4747 /* We only want that exact frame, or no frames are displayed. */
4748 statusbar_push_temporary_msg("Packet number %u isn't displayed.", fnumber
);
4749 return false; /* we failed to go to that packet */
4751 if (fdata
->prev_dis_num
== 0) {
4752 /* There is no previous displayed frame, so this frame is
4753 * before the first displayed frame. Go to the first line,
4754 * which is the closest frame.
4756 fdata
= NULL
; /* This will select the first row. */
4757 statusbar_push_temporary_msg("Packet number %u isn't displayed, going to the first displayed packet, %u.", fnumber
, cf
->first_displayed
);
4759 uint32_t delta
= fnumber
- fdata
->prev_dis_num
;
4760 /* The next displayed frame might be closer, we can do an
4761 * O(log n) binary search for the earliest displayed frame
4762 * in the open interval (fnumber, fnumber + delta).
4764 * This is possibly overkill, we could just go to the previous
4768 uint32_t lower_bound
= fnumber
+ 1;
4769 uint32_t upper_bound
= fnumber
+ delta
- 1;
4771 while (lower_bound
<= upper_bound
) {
4772 uint32_t middle
= (lower_bound
+ upper_bound
) / 2;
4773 fdata2
= frame_data_sequence_find(cf
->provider
.frames
, middle
);
4774 if (fdata2
== NULL
) {
4775 /* We don't have a frame of that number, so search before it. */
4776 upper_bound
= middle
- 1;
4779 /* We have a frame of that number. What's the displayed
4780 * frame before it? */
4781 if (fdata2
->prev_dis_num
> fnumber
) {
4782 /* The previous frame that passed the filter is also after
4783 * our target, so our answer is no later than that.
4785 upper_bound
= fdata2
->prev_dis_num
;
4787 /* The previous displayed frame is before fnumber.
4788 * (We already know fnumber itself is not displayed.)
4789 * Is this frame itself displayed?
4791 if (fdata2
->passed_dfilter
) {
4792 /* Yes. So this is our answer. */
4796 /* No. So our answer, if any, is after this frame. */
4797 lower_bound
= middle
+ 1;
4802 statusbar_push_temporary_msg("Packet number %u isn't displayed, going to the next displayed packet, %u.", fnumber
, fdata
->num
);
4804 statusbar_push_temporary_msg("Packet number %u isn't displayed, going to the previous displayed packet, %u.", fnumber
, fdata
->prev_dis_num
);
4805 fdata
= frame_data_sequence_find(cf
->provider
.frames
, fdata
->prev_dis_num
);
4810 if (!packet_list_select_row_from_data(fdata
)) {
4811 /* We didn't find a row corresponding to this frame.
4812 This means that the frame isn't being displayed currently,
4813 so we can't select it. */
4814 simple_message_box(ESD_TYPE_INFO
, NULL
,
4815 "The capture file is probably not fully dissected.",
4816 "End of capture exceeded.");
4819 return true; /* we got to that packet */
4823 * Go to frame specified by currently selected protocol tree item.
4826 cf_goto_framenum(capture_file
*cf
)
4828 const header_field_info
*hfinfo
;
4831 if (cf
->finfo_selected
) {
4832 hfinfo
= cf
->finfo_selected
->hfinfo
;
4834 if (hfinfo
->type
== FT_FRAMENUM
) {
4835 framenum
= fvalue_get_uinteger(cf
->finfo_selected
->value
);
4836 if (framenum
!= 0) {
4837 /* We probably only want to go to the exact match,
4838 * even though "Go to Previous Packet in History" exists.
4840 return cf_goto_frame(cf
, framenum
, true);
4848 /* Select the packet on a given row. */
4850 cf_select_packet(capture_file
*cf
, frame_data
*fdata
)
4852 epan_dissect_t
*old_edt
;
4854 /* check the frame data struct pointer for this frame */
4855 if (fdata
== NULL
) {
4859 /* Get the data in that frame. */
4860 if (!cf_read_record(cf
, fdata
, &cf
->rec
)) {
4864 /* Record that this frame is the current frame. */
4865 cf
->current_frame
= fdata
;
4868 * The change to defer freeing the current epan_dissect_t was in
4869 * commit a2bb94c3b33d53f42534aceb7cc67aab1d1fb1f9; to quote
4870 * that commit's comment:
4872 * Clear GtkTreeStore before freeing edt
4874 * When building current data for packet details treeview we store two
4876 * - Generated string with item label
4877 * - Pointer to node field_info structure
4879 * After epan_dissect_{free, cleanup} pointer to field_info node is no
4880 * longer valid so we should clear GtkTreeStore before freeing.
4882 * XXX - we're no longer using GTK+; is there a way to ensure that
4883 * *nothing* refers to any of the current frame information before
4887 /* Create the logical protocol tree. */
4888 /* We don't need the columns here. */
4889 cf
->edt
= epan_dissect_new(cf
->epan
, true, true);
4891 tap_build_interesting(cf
->edt
);
4892 epan_dissect_run(cf
->edt
, cf
->cd_t
, &cf
->rec
, cf
->current_frame
, NULL
);
4894 if (old_edt
!= NULL
)
4895 epan_dissect_free(old_edt
);
4898 /* Unselect the selected packet, if any. */
4900 cf_unselect_packet(capture_file
*cf
)
4902 epan_dissect_t
*old_edt
= cf
->edt
;
4905 * See the comment in cf_select_packet() about deferring the freeing
4906 * of the old cf->edt.
4910 /* No packet is selected. */
4911 cf
->current_frame
= NULL
;
4913 /* Destroy the epan_dissect_t for the unselected packet. */
4914 if (old_edt
!= NULL
)
4915 epan_dissect_free(old_edt
);
4919 * Mark a particular frame.
4922 cf_mark_frame(capture_file
*cf
, frame_data
*frame
)
4924 if (! frame
->marked
) {
4925 frame
->marked
= true;
4926 if (cf
->count
> cf
->marked_count
)
4932 * Unmark a particular frame.
4935 cf_unmark_frame(capture_file
*cf
, frame_data
*frame
)
4937 if (frame
->marked
) {
4938 frame
->marked
= false;
4939 if (cf
->marked_count
> 0)
4945 * Ignore a particular frame.
4948 cf_ignore_frame(capture_file
*cf
, frame_data
*frame
)
4950 if (! frame
->ignored
) {
4951 frame
->ignored
= true;
4952 if (cf
->count
> cf
->ignored_count
)
4953 cf
->ignored_count
++;
4958 * Un-ignore a particular frame.
4961 cf_unignore_frame(capture_file
*cf
, frame_data
*frame
)
4963 if (frame
->ignored
) {
4964 frame
->ignored
= false;
4965 if (cf
->ignored_count
> 0)
4966 cf
->ignored_count
--;
4971 * Modify the section comment.
4974 cf_update_section_comment(capture_file
*cf
, char *comment
)
4976 wtap_block_t shb_inf
;
4979 /* Get the first SHB. */
4980 /* XXX - support multiple SHBs */
4981 shb_inf
= wtap_file_get_shb(cf
->provider
.wth
, 0);
4983 /* Get the first comment from the SHB. */
4984 /* XXX - support multiple comments */
4985 if (wtap_block_get_nth_string_option_value(shb_inf
, OPT_COMMENT
, 0, &shb_comment
) != WTAP_OPTTYPE_SUCCESS
) {
4986 /* There's no comment - add one. */
4987 wtap_block_add_string_option(shb_inf
, OPT_COMMENT
, comment
, strlen(comment
));
4989 /* See if the comment has changed or not */
4990 if (strcmp(shb_comment
, comment
) == 0) {
4995 /* The comment has changed, let's update it */
4996 wtap_block_set_nth_string_option_value(shb_inf
, OPT_COMMENT
, 0, comment
, strlen(comment
));
4998 /* Mark the file as having unsaved changes */
4999 cf
->unsaved_changes
= true;
5003 * Modify the section comments for a given section.
5006 cf_update_section_comments(capture_file
*cf
, unsigned shb_idx
, char **comments
)
5008 wtap_block_t shb_inf
;
5011 shb_inf
= wtap_file_get_shb(cf
->provider
.wth
, shb_idx
);
5012 if (shb_inf
== NULL
) {
5013 /* Shouldn't happen. XXX: Report it if it does? */
5017 unsigned n_comments
= g_strv_length(comments
);
5021 for (i
= 0; i
< n_comments
; i
++) {
5022 comment
= comments
[i
];
5023 if (wtap_block_get_nth_string_option_value(shb_inf
, OPT_COMMENT
, i
, &shb_comment
) != WTAP_OPTTYPE_SUCCESS
) {
5024 /* There's no comment - add one. */
5025 wtap_block_add_string_option_owned(shb_inf
, OPT_COMMENT
, comment
);
5026 cf
->unsaved_changes
= true;
5028 /* See if the comment has changed or not */
5029 if (strcmp(shb_comment
, comment
) != 0) {
5030 /* The comment has changed, let's update it */
5031 wtap_block_set_nth_string_option_value(shb_inf
, OPT_COMMENT
, 0, comment
, strlen(comment
));
5032 cf
->unsaved_changes
= true;
5037 /* We either transferred ownership of the comments or freed them
5038 * above, so free the array of strings but not the strings themselves. */
5041 /* If there are extra old comments, remove them. Start at the end. */
5042 for (i
= wtap_block_count_option(shb_inf
, OPT_COMMENT
); i
> n_comments
; i
--) {
5043 wtap_block_remove_nth_option_instance(shb_inf
, OPT_COMMENT
, i
- 1);
5044 cf
->unsaved_changes
= true;
5049 * Get the packet block for a packet (record).
5050 * If the block has been edited, it returns the result of the edit,
5051 * otherwise it returns the block from the file.
5052 * NB. Caller must wtap_block_unref() the result when done.
5055 cf_get_packet_block(capture_file
*cf
, const frame_data
*fd
)
5057 /* If this block has been modified, fetch the modified version */
5058 if (fd
->has_modified_block
)
5059 return wtap_block_ref(cap_file_provider_get_modified_block(&cf
->provider
, fd
));
5061 wtap_rec rec
; /* Record information */
5064 /* fetch record block */
5065 wtap_rec_init(&rec
, 1514);
5067 if (!cf_read_record(cf
, fd
, &rec
))
5068 { /* XXX, what we can do here? */ }
5070 /* rec.block is owned by the record, steal it before it is gone. */
5071 block
= wtap_block_ref(rec
.block
);
5073 wtap_rec_cleanup(&rec
);
5079 * Update(replace) the block on a capture from a frame
5082 cf_set_modified_block(capture_file
*cf
, frame_data
*fd
, const wtap_block_t new_block
)
5084 wtap_block_t pkt_block
= cf_get_packet_block(cf
, fd
);
5086 /* It's possible to further modify the modified block "in place" by doing
5087 * a call to cf_get_packet_block() that returns an already created modified
5088 * block, modifying that, and calling this function.
5089 * If the caller did that, then the block pointers will be equal.
5091 if (pkt_block
== new_block
) {
5092 /* No need to save anything here, the caller changes went right
5094 * Unfortunately we don't have a way to know how many comments were
5095 * in the block before the caller modified it, so tell the caller
5096 * it is its responsibility to update the comment count.
5102 cf
->packet_comment_count
-= wtap_block_count_option(pkt_block
, OPT_COMMENT
);
5105 cf
->packet_comment_count
+= wtap_block_count_option(new_block
, OPT_COMMENT
);
5107 cap_file_provider_set_modified_block(&cf
->provider
, fd
, new_block
);
5109 expert_update_comment_count(cf
->packet_comment_count
);
5112 /* Either way, we have unsaved changes. */
5113 wtap_block_unref(pkt_block
);
5114 cf
->unsaved_changes
= true;
5119 * What types of comments does this capture file have?
5122 cf_comment_types(capture_file
*cf
)
5124 uint32_t comment_types
= 0;
5127 * Does this file have any sections with at least one comment?
5129 for (unsigned section_number
= 0;
5130 section_number
< wtap_file_get_num_shbs(cf
->provider
.wth
);
5132 wtap_block_t shb_inf
;
5135 shb_inf
= wtap_file_get_shb(cf
->provider
.wth
, section_number
);
5137 /* Try to get the first comment from that SHB. */
5138 if (wtap_block_get_nth_string_option_value(shb_inf
, OPT_COMMENT
, 0,
5139 &shb_comment
) == WTAP_OPTTYPE_SUCCESS
) {
5140 /* We succeeded, so this file has at least one section comment. */
5141 comment_types
|= WTAP_COMMENT_PER_SECTION
;
5143 /* We don't need to search any more. */
5147 if (cf
->packet_comment_count
!= 0)
5148 comment_types
|= WTAP_COMMENT_PER_PACKET
;
5149 return comment_types
;
5153 * Add a resolved address to this file's list of resolved addresses.
5156 cf_add_ip_name_from_string(capture_file
*cf
, const char *addr
, const char *name
)
5159 * XXX - support multiple resolved address lists, and add to the one
5160 * attached to this file?
5162 if (!add_ip_name_from_string(addr
, name
))
5165 /* OK, we have unsaved changes. */
5166 cf
->unsaved_changes
= true;
5175 } save_callback_args_t
;
5178 * Save a capture to a file, in a particular format, saving either
5179 * all packets, all currently-displayed packets, or all marked packets.
5181 * Returns true if it succeeds, false otherwise; if it fails, it pops
5182 * up a message box for the failure.
5185 save_record(capture_file
*cf
, frame_data
*fdata
, wtap_rec
*rec
, void *argsp
)
5187 save_callback_args_t
*args
= (save_callback_args_t
*)argsp
;
5191 wtap_block_t pkt_block
;
5193 /* Copy the record information from what was read in from the file. */
5196 /* Make changes based on anything that the user has done but that
5197 hasn't been saved yet. */
5198 if (fdata
->has_modified_block
)
5199 pkt_block
= cap_file_provider_get_modified_block(&cf
->provider
, fdata
);
5201 pkt_block
= rec
->block
;
5202 new_rec
.block
= pkt_block
;
5203 new_rec
.block_was_modified
= fdata
->has_modified_block
? true : false;
5205 if (!nstime_is_zero(&fdata
->shift_offset
)) {
5206 if (new_rec
.presence_flags
& WTAP_HAS_TS
) {
5207 nstime_add(&new_rec
.ts
, &fdata
->shift_offset
);
5211 /* and save the packet */
5212 if (!wtap_dump(args
->pdh
, &new_rec
, ws_buffer_start_ptr(&rec
->data
), &err
, &err_info
)) {
5213 report_cfile_write_failure(NULL
, args
->fname
, err
, err_info
, fdata
->num
,
5218 /* If we are saving (i.e., replacing the current file with the one we're
5219 * writing), then update the frame data to clear the shift offset.
5220 * This keeps us from having to re-read the entire file.
5221 * We could do this in rescan_file(), but
5222 * 1) Ideally we shouldn't have to call rescan_file if all we're doing
5223 * is changing the timestamps, since that shouldn't change the offsets.
5224 * 2) The long term goal is to try to do the offset adjustment here
5225 * instead of using rescan_file, which should be faster (#1257).
5227 * If we're exporting to a different file, then don't do that.
5229 if (!args
->export
&& new_rec
.presence_flags
& WTAP_HAS_TS
) {
5230 nstime_set_zero(&fdata
->shift_offset
);
5237 * Can this capture file be written out in any format using Wiretap
5238 * rather than by copying the raw data?
5241 cf_can_write_with_wiretap(capture_file
*cf
)
5243 /* We don't care whether we support the comments in this file or not;
5244 if we can't, we'll offer the user the option of discarding the
5246 return wtap_dump_can_write(cf
->linktypes
, 0);
5250 * Should we let the user do a save?
5254 * the file has unsaved changes, and we can save it in some
5255 * format through Wiretap
5259 * the file is a temporary file and has no unsaved changes (so
5260 * that "saving" it just means copying it).
5262 * XXX - we shouldn't allow files to be edited if they can't be saved,
5263 * so cf->unsaved_changes should be true only if the file can be saved.
5265 * We don't care whether we support the comments in this file or not;
5266 * if we can't, we'll offer the user the option of discarding the
5270 cf_can_save(capture_file
*cf
)
5272 if (cf
->unsaved_changes
&& wtap_dump_can_write(cf
->linktypes
, 0)) {
5273 /* Saved changes, and we can write it out with Wiretap. */
5277 if (cf
->is_tempfile
&& !cf
->unsaved_changes
) {
5279 * Temporary file with no unsaved changes, so we can just do a
5285 /* Nothing to save. */
5290 * Should we let the user do a "save as"?
5294 * we can save it in some format through Wiretap
5298 * the file is a temporary file and has no unsaved changes (so
5299 * that "saving" it just means copying it).
5301 * XXX - we shouldn't allow files to be edited if they can't be saved,
5302 * so cf->unsaved_changes should be true only if the file can be saved.
5304 * We don't care whether we support the comments in this file or not;
5305 * if we can't, we'll offer the user the option of discarding the
5309 cf_can_save_as(capture_file
*cf
)
5311 if (wtap_dump_can_write(cf
->linktypes
, 0)) {
5312 /* We can write it out with Wiretap. */
5316 if (cf
->is_tempfile
&& !cf
->unsaved_changes
) {
5318 * Temporary file with no unsaved changes, so we can just do a
5324 /* Nothing to save. */
5329 * Does this file have unsaved data?
5332 cf_has_unsaved_data(capture_file
*cf
)
5335 * If this is a temporary file, or a file with unsaved changes, it
5338 return (cf
->is_tempfile
&& cf
->count
>0) || cf
->unsaved_changes
;
5342 * Quick scan to find packet offsets.
5344 static cf_read_status_t
5345 rescan_file(capture_file
*cf
, const char *fname
, bool is_tempfile
)
5351 int64_t data_offset
;
5352 progdlg_t
*progbar
= NULL
;
5353 GTimer
*prog_timer
= g_timer_new();
5357 char status_str
[100];
5361 /* Close the old handle. */
5362 wtap_close(cf
->provider
.wth
);
5364 /* Open the new file. */
5365 /* XXX: this will go through all open_routines for a matching one. But right
5366 now rescan_file() is only used when a file is being saved to a different
5367 format than the original, and the user is not given a choice of which
5368 reader to use (only which format to save it in), so doing this makes
5369 sense for now. (XXX: Now it is also used when saving a changed file,
5370 e.g. comments or time-shifted frames.) */
5371 cf
->provider
.wth
= wtap_open_offline(fname
, WTAP_TYPE_AUTO
, &err
, &err_info
, true);
5372 if (cf
->provider
.wth
== NULL
) {
5373 report_cfile_open_failure(fname
, err
, err_info
);
5374 return CF_READ_ERROR
;
5377 /* We're scanning a file whose contents should be the same as what
5378 we had before, so we don't discard dissection state etc.. */
5381 /* Set the file name because we need it to set the follow stream filter.
5382 XXX - is that still true? We need it for other reasons, though,
5384 if (cf
->filename
!= NULL
) {
5385 g_free(cf
->filename
);
5387 cf
->filename
= g_strdup(fname
);
5389 /* Indicate whether it's a permanent or temporary file. */
5390 cf
->is_tempfile
= is_tempfile
;
5392 /* No user changes yet. */
5393 cf
->unsaved_changes
= false;
5395 /* Record the file's type and compression type. */
5396 cf
->cd_t
= wtap_file_type_subtype(cf
->provider
.wth
);
5397 cf
->compression_type
= wtap_get_compression_type(cf
->provider
.wth
);
5398 if (cf
->linktypes
!= NULL
) {
5399 g_array_free(cf
->linktypes
, TRUE
);
5401 cf
->linktypes
= g_array_sized_new(FALSE
, FALSE
, (unsigned) sizeof(int), 1);
5403 cf
->snap
= wtap_snapshot_length(cf
->provider
.wth
);
5405 name_ptr
= g_filename_display_basename(cf
->filename
);
5407 cf_callback_invoke(cf_cb_file_rescan_started
, cf
);
5409 /* Find the size of the file. */
5410 size
= wtap_file_size(cf
->provider
.wth
, NULL
);
5412 g_timer_start(prog_timer
);
5414 cf
->stop_flag
= false;
5415 start_time
= g_get_monotonic_time();
5418 wtap_rec_init(&rec
, 1514);
5419 while ((wtap_read(cf
->provider
.wth
, &rec
, &err
, &err_info
,
5422 fdata
= frame_data_sequence_find(cf
->provider
.frames
, framenum
);
5423 if (G_LIKELY(fdata
!= NULL
)) {
5424 fdata
->file_off
= data_offset
;
5427 cf
->f_datalen
= wtap_read_so_far(cf
->provider
.wth
);
5429 /* Create the progress bar if necessary. */
5430 if (progress_is_slow(progbar
, prog_timer
, size
, cf
->f_datalen
)) {
5431 progbar_val
= calc_progbar_val(cf
, size
, cf
->f_datalen
, status_str
, sizeof(status_str
));
5432 progbar
= delayed_create_progress_dlg(cf
->window
, NULL
, NULL
,
5433 true, &cf
->stop_flag
, progbar_val
);
5437 * Update the progress bar, but do it only after PROGBAR_UPDATE_INTERVAL
5438 * has elapsed. Calling update_progress_dlg and packets_bar_update will
5439 * likely trigger UI paint events, which might take a while depending on
5440 * the platform and display. Reset our timer *after* painting.
5442 if (progbar
&& g_timer_elapsed(prog_timer
, NULL
) > PROGBAR_UPDATE_INTERVAL
) {
5443 progbar_val
= calc_progbar_val(cf
, size
, cf
->f_datalen
, status_str
, sizeof(status_str
));
5444 /* update the packet bar content on the first run or frequently on very large files */
5445 update_progress_dlg(progbar
, progbar_val
, status_str
);
5446 compute_elapsed(cf
, start_time
);
5447 packets_bar_update();
5448 g_timer_start(prog_timer
);
5452 if (cf
->stop_flag
) {
5453 /* Well, the user decided to abort the rescan. Sadly, as this
5454 isn't a reread, recovering is difficult, so we'll just
5455 close the current capture. */
5459 /* Add this packet's link-layer encapsulation type to cf->linktypes, if
5460 it's not already there.
5461 XXX - yes, this is O(N), so if every packet had a different
5462 link-layer encapsulation type, it'd be O(N^2) to read the file, but
5463 there are probably going to be a small number of encapsulation types
5465 if (rec
.rec_type
== REC_TYPE_PACKET
) {
5466 cf_add_encapsulation_type(cf
, rec
.rec_header
.packet_header
.pkt_encap
);
5468 wtap_rec_reset(&rec
);
5470 wtap_rec_cleanup(&rec
);
5472 /* Free the display name */
5475 /* We're done reading the file; destroy the progress bar if it was created. */
5476 if (progbar
!= NULL
)
5477 destroy_progress_dlg(progbar
);
5478 g_timer_destroy(prog_timer
);
5480 /* We're done reading sequentially through the file. */
5481 cf
->state
= FILE_READ_DONE
;
5483 /* Close the sequential I/O side, to free up memory it requires. */
5484 wtap_sequential_close(cf
->provider
.wth
);
5486 /* compute the time it took to load the file */
5487 compute_elapsed(cf
, start_time
);
5489 /* Set the file encapsulation type now; we don't know what it is until
5490 we've looked at all the packets, as we don't know until then whether
5491 there's more than one type (and thus whether it's
5492 WTAP_ENCAP_PER_PACKET). */
5493 cf
->lnk_t
= wtap_file_encap(cf
->provider
.wth
);
5495 cf_callback_invoke(cf_cb_file_rescan_finished
, cf
);
5497 if (cf
->stop_flag
) {
5498 /* Our caller will give up at this point. */
5499 return CF_READ_ABORTED
;
5503 /* Put up a message box noting that the read failed somewhere along
5504 the line. Don't throw out the stuff we managed to read, though,
5506 report_cfile_read_failure(NULL
, err
, err_info
);
5507 return CF_READ_ERROR
;
5513 cf_save_records(capture_file
*cf
, const char *fname
, unsigned save_format
,
5514 wtap_compression_type compression_type
,
5515 bool discard_comments
, bool dont_reopen
)
5517 char *err_info
= "Unknown error";
5518 char *fname_new
= NULL
;
5521 addrinfo_lists_t
*addr_lists
;
5529 save_callback_args_t callback_args
;
5530 callback_args
.export
= false;
5531 bool needs_reload
= false;
5533 /* XXX caller should avoid saving the file while a read is pending
5534 * (e.g. by delaying the save action) */
5535 if (cf
->read_lock
) {
5536 ws_warning("cf_save_records(\"%s\") while the file is being read, potential crash ahead", fname
);
5539 cf_callback_invoke(cf_cb_file_save_started
, (void *)fname
);
5541 addr_lists
= get_addrinfo_list();
5543 if (save_format
== cf
->cd_t
&& compression_type
== cf
->compression_type
5544 && !discard_comments
&& !cf
->unsaved_changes
5545 && (wtap_addrinfo_list_empty(addr_lists
) || wtap_file_type_subtype_supports_block(save_format
, WTAP_BLOCK_NAME_RESOLUTION
) == BLOCK_NOT_SUPPORTED
)) {
5546 /* We're saving in the format it's already in, and we're not discarding
5547 comments, and there are no changes we have in memory that aren't saved
5548 to the file, and we have no name resolution information to write or
5549 the file format we're saving in doesn't support writing name
5550 resolution information, so we can just move or copy the raw data. */
5552 if (cf
->is_tempfile
) {
5553 /* The file being saved is a temporary file from a live
5554 capture, so it doesn't need to stay around under that name;
5555 first, try renaming the capture buffer file to the new name.
5556 This acts as a "safe save", in that, if the file already
5557 exists, the existing file will be removed only if the rename
5560 Sadly, on Windows, as we have the current capture file
5561 open, even MoveFileEx() with MOVEFILE_REPLACE_EXISTING
5562 (to cause the rename to remove an existing target), as
5563 done by ws_stdio_rename() (ws_rename() is #defined to
5564 be ws_stdio_rename() on Windows) will fail.
5566 According to the MSDN documentation for CreateFile(), if,
5567 when we open a capture file, we were to directly do a CreateFile(),
5568 opening with FILE_SHARE_DELETE|FILE_SHARE_READ, and then
5569 convert it to a file descriptor with _open_osfhandle(),
5570 that would allow the file to be renamed out from under us.
5572 However, that doesn't work in practice. Perhaps the problem
5573 is that the process doing the rename is the process that
5574 has the file open. */
5576 if (ws_rename(cf
->filename
, fname
) == 0) {
5577 /* That succeeded - there's no need to copy the source file. */
5578 how_to_save
= SAVE_WITH_MOVE
;
5580 if (errno
== EXDEV
) {
5581 /* They're on different file systems, so we have to copy the
5583 how_to_save
= SAVE_WITH_COPY
;
5585 /* The rename failed, but not because they're on different
5586 file systems - put up an error message. (Or should we
5587 just punt and try to copy? The only reason why I'd
5588 expect the rename to fail and the copy to succeed would
5589 be if we didn't have permission to remove the file from
5590 the temporary directory, and that might be fixable - but
5591 is it worth requiring the user to go off and fix it?) */
5592 report_rename_failure(cf
->filename
, fname
, errno
);
5597 /* Windows - copy the file to its new location. */
5598 how_to_save
= SAVE_WITH_COPY
;
5601 /* It's a permanent file, so we should copy it, and not remove the
5603 how_to_save
= SAVE_WITH_COPY
;
5606 if (how_to_save
== SAVE_WITH_COPY
) {
5607 /* Copy the file, if we haven't moved it. If we're overwriting
5608 an existing file, we do it with a "safe save", by writing
5609 to a new file and, if the write succeeds, renaming the
5610 new file on top of the old file. */
5611 if (file_exists(fname
)) {
5612 fname_new
= ws_strdup_printf("%s~", fname
);
5613 if (!copy_file_binary_mode(cf
->filename
, fname_new
))
5616 if (!copy_file_binary_mode(cf
->filename
, fname
))
5621 /* Either we're saving in a different format or we're saving changes,
5622 such as added, modified, or removed comments, that haven't yet
5623 been written to the underlying file; we can't do that by copying
5624 or moving the capture file, we have to do it by writing the packets
5627 wtap_dump_params params
;
5630 how_to_save
= SAVE_WITH_WTAP
;
5631 wtap_dump_params_init(¶ms
, cf
->provider
.wth
);
5633 /* Determine what file encapsulation type we should use. */
5634 encap
= wtap_dump_required_file_encap_type(cf
->linktypes
);
5635 params
.encap
= encap
;
5637 /* Use the snaplen from cf (XXX - does wtap_dump_params_init handle that?) */
5638 params
.snaplen
= cf
->snap
;
5640 if (file_exists(fname
)) {
5641 /* We're overwriting an existing file; write out to a new file,
5642 and, if that succeeds, rename the new file on top of the
5643 old file. That makes this a "safe save", so that we don't
5644 lose the old file if we have a problem writing out the new
5645 file. (If the existing file is the current capture file,
5646 we *HAVE* to do that, otherwise we're overwriting the file
5647 from which we're reading the packets that we're writing!) */
5648 fname_new
= ws_strdup_printf("%s~", fname
);
5649 pdh
= wtap_dump_open(fname_new
, save_format
, compression_type
, ¶ms
,
5652 pdh
= wtap_dump_open(fname
, save_format
, compression_type
, ¶ms
,
5655 /* XXX idb_inf is documented to be used until wtap_dump_close. */
5656 g_free(params
.idb_inf
);
5657 params
.idb_inf
= NULL
;
5660 report_cfile_dump_open_failure(fname
, err
, err_info
, save_format
);
5664 /* Add address resolution */
5665 wtap_dump_set_addrinfo_list(pdh
, addr_lists
);
5667 /* Iterate through the list of packets, processing all the packets. */
5668 callback_args
.pdh
= pdh
;
5669 callback_args
.fname
= fname
;
5670 callback_args
.file_type
= save_format
;
5671 switch (process_specified_records(cf
, NULL
, "Saving", "packets",
5672 true, save_record
, &callback_args
, true)) {
5675 /* Completed successfully. */
5679 /* The user decided to abort the saving.
5680 If we're writing to a temporary file, remove it.
5681 XXX - should we do so even if we're not writing to a
5683 wtap_dump_close(pdh
, NULL
, &err
, &err_info
);
5684 if (fname_new
!= NULL
)
5685 ws_unlink(fname_new
);
5686 cf_callback_invoke(cf_cb_file_save_stopped
, NULL
);
5687 wtap_dump_params_cleanup(¶ms
);
5688 return CF_WRITE_ABORTED
;
5691 /* Error while saving.
5692 If we're writing to a temporary file, remove it. */
5693 if (fname_new
!= NULL
)
5694 ws_unlink(fname_new
);
5695 wtap_dump_close(pdh
, NULL
, &err
, &err_info
);
5696 wtap_dump_params_cleanup(¶ms
);
5700 if (!wtap_dump_close(pdh
, &needs_reload
, &err
, &err_info
)) {
5701 report_cfile_close_failure(fname
, err
, err_info
);
5702 wtap_dump_params_cleanup(¶ms
);
5706 wtap_dump_params_cleanup(¶ms
);
5709 if (fname_new
!= NULL
) {
5710 /* We wrote out to fname_new, and should rename it on top of
5711 fname. fname_new is now closed, so that should be possible even
5712 on Windows. However, on Windows, we first need to close whatever
5713 file descriptors we have open for fname. */
5715 wtap_fdclose(cf
->provider
.wth
);
5717 /* Now do the rename. */
5718 if (ws_rename(fname_new
, fname
) == -1) {
5719 /* Well, the rename failed. */
5720 report_rename_failure(fname_new
, fname
, errno
);
5722 /* Attempt to reopen the random file descriptor using the
5723 current file's filename. (At this point, the sequential
5724 file descriptor is closed.) */
5725 if (!wtap_fdreopen(cf
->provider
.wth
, cf
->filename
, &err
)) {
5726 /* Oh, well, we're screwed. */
5727 report_cfile_open_failure(cf
->filename
, err
, NULL
);
5735 /* If this was a temporary file, and we didn't do the save by doing
5736 a move, so the tempoary file is still around under its old name,
5738 if (cf
->is_tempfile
&& how_to_save
!= SAVE_WITH_MOVE
) {
5739 /* If this fails, there's not much we can do, so just ignore errors. */
5740 ws_unlink(cf
->filename
);
5743 cf_callback_invoke(cf_cb_file_save_finished
, NULL
);
5744 cf
->unsaved_changes
= false;
5747 switch (how_to_save
) {
5749 case SAVE_WITH_MOVE
:
5750 /* We just moved the file, so the wtap structure refers to the
5751 new file, and all the information other than the filename
5752 and the "is temporary" status applies to the new file; just
5754 g_free(cf
->filename
);
5755 cf
->filename
= g_strdup(fname
);
5756 cf
->is_tempfile
= false;
5757 cf_callback_invoke(cf_cb_file_fast_save_finished
, cf
);
5760 case SAVE_WITH_COPY
:
5761 /* We just copied the file, so all the information other than
5762 the file descriptors, the filename, and the "is temporary"
5763 status applies to the new file; just update that. */
5764 wtap_fdclose(cf
->provider
.wth
);
5765 /* Attempt to reopen the random file descriptor using the
5766 new file's filename. (At this point, the sequential
5767 file descriptor is closed.) */
5768 if (!wtap_fdreopen(cf
->provider
.wth
, fname
, &err
)) {
5769 report_cfile_open_failure(fname
, err
, err_info
);
5772 g_free(cf
->filename
);
5773 cf
->filename
= g_strdup(fname
);
5774 cf
->is_tempfile
= false;
5776 cf_callback_invoke(cf_cb_file_fast_save_finished
, cf
);
5779 case SAVE_WITH_WTAP
:
5780 /* Open and read the file we saved to.
5782 XXX - this is somewhat of a waste; we already have the
5783 packets, all this gets us is updated file type information
5784 (which we could just stuff into "cf"), and having the new
5785 file be the one we have opened and from which we're reading
5786 the data, and it means we have to spend time opening and
5787 reading the file, which could be a significant amount of
5788 time if the file is large.
5790 If the capture-file-writing code were to return the
5791 seek offset of each packet it writes, we could save that
5792 in the frame_data structure for the frame, and just open
5793 the file without reading it again...
5795 ...as long as, for gzipped files, the process of writing
5796 out the file *also* generates the information needed to
5797 support fast random access to the compressed file. */
5798 /* rescan_file will cause us to try all open_routines, so
5799 reset cfile's open_type */
5800 cf
->open_type
= WTAP_TYPE_AUTO
;
5801 /* There are cases when SAVE_WITH_WTAP can result in new packets
5802 being written to the file, e.g ERF records
5803 In that case, we need to reload the whole file */
5805 if (cf_open(cf
, fname
, WTAP_TYPE_AUTO
, false, &err
) == CF_OK
) {
5806 if (cf_read(cf
, /*reloading=*/true) != CF_READ_OK
) {
5807 /* The rescan failed; just close the file. Either
5808 a dialog was popped up for the failure, so the
5809 user knows what happened, or they stopped the
5810 rescan, in which case they know what happened. */
5811 /* XXX: This is inconsistent with normal open/reload behaviour. */
5817 if (rescan_file(cf
, fname
, false) != CF_READ_OK
) {
5818 /* The rescan failed; just close the file. Either
5819 a dialog was popped up for the failure, so the
5820 user knows what happened, or they stopped the
5821 rescan, in which case they know what happened. */
5828 /* If we were told to discard the comments, do so. */
5829 if (discard_comments
) {
5830 /* Remove SHB comment, if any. */
5831 wtap_write_shb_comment(cf
->provider
.wth
, NULL
);
5833 /* remove all user comments */
5834 for (framenum
= 1; framenum
<= cf
->count
; framenum
++) {
5835 fdata
= frame_data_sequence_find(cf
->provider
.frames
, framenum
);
5837 // XXX: This also ignores non-comment options like verdict
5838 fdata
->has_modified_block
= false;
5841 if (cf
->provider
.frames_modified_blocks
) {
5842 g_tree_destroy(cf
->provider
.frames_modified_blocks
);
5843 cf
->provider
.frames_modified_blocks
= NULL
;
5846 cf
->packet_comment_count
= 0;
5852 if (fname_new
!= NULL
) {
5853 /* We were trying to write to a temporary file; get rid of it if it
5854 exists. (We don't care whether this fails, as, if it fails,
5855 there's not much we can do about it. I guess if it failed for
5856 a reason other than "it doesn't exist", we could report an
5857 error, so the user knows there's a junk file that they might
5858 want to clean up.) */
5859 ws_unlink(fname_new
);
5862 cf_callback_invoke(cf_cb_file_save_failed
, NULL
);
5863 return CF_WRITE_ERROR
;
5867 cf_export_specified_packets(capture_file
*cf
, const char *fname
,
5868 packet_range_t
*range
, unsigned save_format
,
5869 wtap_compression_type compression_type
)
5871 char *fname_new
= NULL
;
5875 save_callback_args_t callback_args
;
5876 wtap_dump_params params
;
5879 callback_args
.export
= true;
5880 packet_range_process_init(range
);
5882 /* We're writing out specified packets from the specified capture
5883 file to another file. Even if all captured packets are to be
5884 written, don't special-case the operation - read each packet
5885 and then write it out if it's one of the specified ones. */
5887 wtap_dump_params_init(¶ms
, cf
->provider
.wth
);
5889 /* Determine what file encapsulation type we should use. */
5890 encap
= wtap_dump_required_file_encap_type(cf
->linktypes
);
5891 params
.encap
= encap
;
5893 /* Use the snaplen from cf (XXX - does wtap_dump_params_init handle that?) */
5894 params
.snaplen
= cf
->snap
;
5896 if (file_exists(fname
)) {
5897 /* We're overwriting an existing file; write out to a new file,
5898 and, if that succeeds, rename the new file on top of the
5899 old file. That makes this a "safe save", so that we don't
5900 lose the old file if we have a problem writing out the new
5901 file. (If the existing file is the current capture file,
5902 we *HAVE* to do that, otherwise we're overwriting the file
5903 from which we're reading the packets that we're writing!) */
5904 fname_new
= ws_strdup_printf("%s~", fname
);
5905 pdh
= wtap_dump_open(fname_new
, save_format
, compression_type
, ¶ms
,
5908 pdh
= wtap_dump_open(fname
, save_format
, compression_type
, ¶ms
,
5911 /* XXX idb_inf is documented to be used until wtap_dump_close. */
5912 g_free(params
.idb_inf
);
5913 params
.idb_inf
= NULL
;
5916 report_cfile_dump_open_failure(fname
, err
, err_info
, save_format
);
5920 /* Add address resolution */
5921 wtap_dump_set_addrinfo_list(pdh
, get_addrinfo_list());
5923 /* Iterate through the list of packets, processing the packets we were
5926 XXX - we've already called "packet_range_process_init(range)", but
5927 "process_specified_records()" will do it again. Fortunately,
5928 that's harmless in this case, as we haven't done anything to
5929 "range" since we initialized it. */
5930 callback_args
.pdh
= pdh
;
5931 callback_args
.fname
= fname
;
5932 callback_args
.file_type
= save_format
;
5933 switch (process_specified_records(cf
, range
, "Writing", "specified records",
5934 true, save_record
, &callback_args
, true)) {
5937 /* Completed successfully. */
5941 /* The user decided to abort the saving.
5942 If we're writing to a temporary file, remove it.
5943 XXX - should we do so even if we're not writing to a
5945 wtap_dump_close(pdh
, NULL
, &err
, &err_info
);
5946 if (fname_new
!= NULL
) {
5947 ws_unlink(fname_new
);
5950 wtap_dump_params_cleanup(¶ms
);
5952 return CF_WRITE_ABORTED
;
5955 /* Error while saving. */
5956 wtap_dump_close(pdh
, NULL
, &err
, &err_info
);
5958 * We don't report any error from closing; the error that caused
5959 * process_specified_records() to fail has already been reported.
5964 if (!wtap_dump_close(pdh
, NULL
, &err
, &err_info
)) {
5965 report_cfile_close_failure(fname
, err
, err_info
);
5969 if (fname_new
!= NULL
) {
5970 /* We wrote out to fname_new, and should rename it on top of
5971 fname; fname is now closed, so that should be possible even
5972 on Windows. Do the rename. */
5973 if (ws_rename(fname_new
, fname
) == -1) {
5974 /* Well, the rename failed. */
5975 report_rename_failure(fname_new
, fname
, errno
);
5980 wtap_dump_params_cleanup(¶ms
);
5985 if (fname_new
!= NULL
) {
5986 /* We were trying to write to a temporary file; get rid of it if it
5987 exists. (We don't care whether this fails, as, if it fails,
5988 there's not much we can do about it. I guess if it failed for
5989 a reason other than "it doesn't exist", we could report an
5990 error, so the user knows there's a junk file that they might
5991 want to clean up.) */
5992 ws_unlink(fname_new
);
5995 wtap_dump_params_cleanup(¶ms
);
5997 return CF_WRITE_ERROR
;
6000 /* Reload the current capture file. */
6002 cf_reload(capture_file
*cf
)
6006 cf_status_t cf_status
= CF_OK
;
6009 if (cf
->read_lock
) {
6010 ws_warning("Failing cf_reload(\"%s\") since a read is in progress", cf
->filename
);
6014 /* If the file could be opened, "cf_open()" calls "cf_close()"
6015 to get rid of state for the old capture file before filling in state
6016 for the new capture file. "cf_close()" will remove the file if
6017 it's a temporary file; we don't want that to happen (for one thing,
6018 it'd prevent subsequent reopens from working). Remember whether it's
6019 a temporary file, mark it as not being a temporary file, and then
6020 reopen it as the type of file it was.
6022 Also, "cf_close()" will free "cf->filename", so we must make
6023 a copy of it first. */
6024 filename
= g_strdup(cf
->filename
);
6025 is_tempfile
= cf
->is_tempfile
;
6026 cf
->is_tempfile
= false;
6027 if (cf_open(cf
, filename
, cf
->open_type
, is_tempfile
, &err
) == CF_OK
) {
6028 switch (cf_read(cf
, /*reloading=*/true)) {
6032 /* Just because we got an error, that doesn't mean we were unable
6033 to read any of the file; we handle what we could get from the
6037 case CF_READ_ABORTED
:
6038 /* The user bailed out of re-reading the capture file; the
6039 capture file has been closed. */
6043 /* The open failed, so "cf->is_tempfile" wasn't set to "is_tempfile".
6044 Instead, the file was left open, so we should restore "cf->is_tempfile"
6047 XXX - change the menu? Presumably "cf_open()" will do that;
6048 make sure it does! */
6049 cf
->is_tempfile
= is_tempfile
;
6050 cf_status
= CF_ERROR
;
6052 /* "cf_open()" made a copy of the file name we handed it, so
6053 we should free up our copy. */