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
, Buffer
*buf
,
76 dfilter_t
*dfcode
, 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
*,
87 wtap_rec
*, Buffer
*, void *);
88 static match_result
match_protocol_tree(capture_file
*cf
, frame_data
*fdata
,
89 wtap_rec
*, Buffer
*, 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
*, Buffer
*, void *criterion
);
94 static match_result
match_narrow_and_wide(capture_file
*cf
, frame_data
*fdata
,
95 wtap_rec
*, Buffer
*, void *criterion
);
96 static match_result
match_narrow_and_wide_reverse(capture_file
*cf
, frame_data
*fdata
,
97 wtap_rec
*, Buffer
*, void *criterion
);
98 static match_result
match_narrow_and_wide_case(capture_file
*cf
, frame_data
*fdata
,
99 wtap_rec
*, Buffer
*, void *criterion
);
100 static match_result
match_narrow_and_wide_case_reverse(capture_file
*cf
, frame_data
*fdata
,
101 wtap_rec
*, Buffer
*, void *criterion
);
102 static match_result
match_narrow_case(capture_file
*cf
, frame_data
*fdata
,
103 wtap_rec
*, Buffer
*, void *criterion
);
104 static match_result
match_narrow_case_reverse(capture_file
*cf
, frame_data
*fdata
,
105 wtap_rec
*, Buffer
*, void *criterion
);
106 static match_result
match_wide(capture_file
*cf
, frame_data
*fdata
,
107 wtap_rec
*, Buffer
*, void *criterion
);
108 static match_result
match_wide_reverse(capture_file
*cf
, frame_data
*fdata
,
109 wtap_rec
*, Buffer
*, void *criterion
);
110 static match_result
match_wide_case(capture_file
*cf
, frame_data
*fdata
,
111 wtap_rec
*, Buffer
*, void *criterion
);
112 static match_result
match_wide_case_reverse(capture_file
*cf
, frame_data
*fdata
,
113 wtap_rec
*, Buffer
*, void *criterion
);
114 static match_result
match_binary(capture_file
*cf
, frame_data
*fdata
,
115 wtap_rec
*, Buffer
*, void *criterion
);
116 static match_result
match_binary_reverse(capture_file
*cf
, frame_data
*fdata
,
117 wtap_rec
*, Buffer
*, void *criterion
);
118 static match_result
match_regex(capture_file
*cf
, frame_data
*fdata
,
119 wtap_rec
*, Buffer
*, void *criterion
);
120 static match_result
match_regex_reverse(capture_file
*cf
, frame_data
*fdata
,
121 wtap_rec
*, Buffer
*, void *criterion
);
122 static match_result
match_dfilter(capture_file
*cf
, frame_data
*fdata
,
123 wtap_rec
*, Buffer
*, void *criterion
);
124 static match_result
match_marked(capture_file
*cf
, frame_data
*fdata
,
125 wtap_rec
*, Buffer
*, void *criterion
);
126 static match_result
match_time_reference(capture_file
*cf
, frame_data
*fdata
,
127 wtap_rec
*, Buffer
*, 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 metadata. */
255 wtap_rec_init(&cf
->rec
);
257 /* XXX - we really want to initialize this after we've read all
258 the packets, so we know how much we'll ultimately need. */
259 ws_buffer_init(&cf
->buf
, 1514);
261 /* We're about to start reading the file. */
262 cf
->state
= FILE_READ_IN_PROGRESS
;
264 /* If there was a pending redissection for the old file (there
265 * shouldn't be), clear it. cf_close() should have failed if the
266 * old file's read lock was held, but it doesn't hurt to clear it. */
267 cf
->read_lock
= false;
268 cf
->redissection_queued
= RESCAN_NONE
;
270 cf
->provider
.wth
= wth
;
273 /* Set the file name because we need it to set the follow stream filter.
274 XXX - is that still true? We need it for other reasons, though,
276 cf
->filename
= g_strdup(fname
);
278 /* Indicate whether it's a permanent or temporary file. */
279 cf
->is_tempfile
= is_tempfile
;
281 /* No user changes yet. */
282 cf
->unsaved_changes
= false;
284 cf
->computed_elapsed
= 0;
286 cf
->cd_t
= wtap_file_type_subtype(cf
->provider
.wth
);
287 cf
->open_type
= type
;
288 cf
->linktypes
= g_array_sized_new(FALSE
, FALSE
, (unsigned) sizeof(int), 1);
290 cf
->packet_comment_count
= 0;
291 cf
->displayed_count
= 0;
292 cf
->marked_count
= 0;
293 cf
->ignored_count
= 0;
294 cf
->ref_time_count
= 0;
295 cf
->drops_known
= false;
297 cf
->snap
= wtap_snapshot_length(cf
->provider
.wth
);
299 /* Allocate a frame_data_sequence for the frames in this file */
300 cf
->provider
.frames
= new_frame_data_sequence();
302 nstime_set_zero(&cf
->elapsed_time
);
303 cf
->provider
.ref
= NULL
;
304 cf
->provider
.prev_dis
= NULL
;
305 cf
->provider
.prev_cap
= NULL
;
308 /* Create new epan session for dissection.
309 * (The old one was freed in cf_close().)
311 cf
->epan
= ws_epan_new(cf
);
313 packet_list_queue_draw();
314 cf_callback_invoke(cf_cb_file_opened
, cf
);
316 wtap_set_cb_new_ipv4(cf
->provider
.wth
, add_ipv4_name
);
317 wtap_set_cb_new_ipv6(cf
->provider
.wth
, (wtap_new_ipv6_callback_t
) add_ipv6_name
);
318 wtap_set_cb_new_secrets(cf
->provider
.wth
, secrets_wtap_callback
);
323 report_cfile_open_failure(fname
, *err
, err_info
);
328 * Add an encapsulation type to cf->linktypes.
331 cf_add_encapsulation_type(capture_file
*cf
, int encap
)
335 for (i
= 0; i
< cf
->linktypes
->len
; i
++) {
336 if (g_array_index(cf
->linktypes
, int, i
) == encap
)
337 return; /* it's already there */
339 /* It's not already there - add it. */
340 g_array_append_val(cf
->linktypes
, encap
);
343 /* Reset everything to a pristine state */
345 cf_close(capture_file
*cf
)
347 cf
->stop_flag
= false;
348 if (cf
->state
== FILE_CLOSED
|| cf
->state
== FILE_READ_PENDING
)
349 return; /* Nothing to do */
351 /* Die if we're in the middle of reading a file. */
352 ws_assert(cf
->state
!= FILE_READ_IN_PROGRESS
);
353 ws_assert(!cf
->read_lock
);
355 cf_callback_invoke(cf_cb_file_closing
, cf
);
357 /* close things, if not already closed before */
358 color_filters_cleanup();
360 if (cf
->provider
.wth
) {
361 wtap_close(cf
->provider
.wth
);
362 cf
->provider
.wth
= NULL
;
364 /* We have no file open... */
365 if (cf
->filename
!= NULL
) {
366 /* If it's a temporary file, remove it. */
368 ws_unlink(cf
->filename
);
369 g_free(cf
->filename
);
372 /* ...which means we have no changes to that file to save. */
373 cf
->unsaved_changes
= false;
375 /* no open_routine type */
376 cf
->open_type
= WTAP_TYPE_AUTO
;
378 /* Clean up the record metadata. */
379 wtap_rec_cleanup(&cf
->rec
);
381 /* Clear the packet list. */
382 packet_list_freeze();
386 /* Free up the packet buffer. */
387 ws_buffer_free(&cf
->buf
);
389 dfilter_free(cf
->rfcode
);
391 if (cf
->provider
.frames
!= NULL
) {
392 free_frame_data_sequence(cf
->provider
.frames
);
393 cf
->provider
.frames
= NULL
;
395 if (cf
->provider
.frames_modified_blocks
) {
396 g_tree_destroy(cf
->provider
.frames_modified_blocks
);
397 cf
->provider
.frames_modified_blocks
= NULL
;
399 cf_unselect_packet(cf
); /* nothing to select */
400 cf
->first_displayed
= 0;
401 cf
->last_displayed
= 0;
403 /* No frames, no frame selected, no field in that frame selected. */
405 cf
->current_frame
= NULL
;
406 cf
->finfo_selected
= NULL
;
408 /* No frame link-layer types, either. */
409 if (cf
->linktypes
!= NULL
) {
410 g_array_free(cf
->linktypes
, TRUE
);
411 cf
->linktypes
= NULL
;
415 nstime_set_zero(&cf
->elapsed_time
);
417 reset_tap_listeners();
422 /* We have no file open. */
423 cf
->state
= FILE_CLOSED
;
425 cf_callback_invoke(cf_cb_file_closed
, cf
);
429 * true if the progress dialog doesn't exist and it looks like we'll
430 * take > PROGBAR_SHOW_DELAY (500ms) to load, false otherwise.
433 progress_is_slow(progdlg_t
*progdlg
, GTimer
*prog_timer
, int64_t size
, int64_t pos
)
437 if (progdlg
) return false;
438 elapsed
= g_timer_elapsed(prog_timer
, NULL
);
439 /* This only gets checked between reading records, which doesn't help if
440 * a single record takes a very long time, e.g., the first TLS packet if
441 * the SSLKEYLOGFILE is very large. (#17051) */
442 if ((elapsed
* 2 > PROGBAR_SHOW_DELAY
&& (size
/ pos
) >= 2) /* It looks like we're going to be slow. */
443 || elapsed
> PROGBAR_SHOW_DELAY
) { /* We are indeed slow. */
450 calc_progbar_val(capture_file
*cf
, int64_t size
, int64_t file_pos
, char *status_str
, unsigned long status_size
)
454 progbar_val
= (float) file_pos
/ (float) size
;
455 if (progbar_val
> 1.0) {
457 /* The file probably grew while we were reading it.
458 * Update file size, and try again.
460 size
= wtap_file_size(cf
->provider
.wth
, NULL
);
463 progbar_val
= (float) file_pos
/ (float) size
;
465 /* If it's still > 1, either "wtap_file_size()" failed (in which
466 * case there's not much we can do about it), or the file
467 * *shrank* (in which case there's not much we can do about
468 * it); just clip the progress value at 1.0.
470 if (progbar_val
> 1.0f
)
474 snprintf(status_str
, status_size
,
475 "%" PRId64
"KB of %" PRId64
"KB",
476 file_pos
/ 1024, size
/ 1024);
482 cf_read(capture_file
*cf
, bool reloading
)
485 char *err_info
= NULL
;
486 volatile bool too_many_records
= false;
488 progdlg_t
*volatile progbar
= NULL
;
489 GTimer
*prog_timer
= g_timer_new();
495 dfilter_t
*dfcode
= NULL
;
497 volatile bool create_proto_tree
;
500 volatile bool is_read_aborted
= false;
502 /* The update_progress_dlg call below might end up accepting a user request to
503 * trigger redissection/rescans which can modify/destroy the dissection
504 * context ("cf->epan"). That condition should be prevented by callers, but in
505 * case it occurs let's fail gracefully.
508 ws_warning("Failing due to recursive cf_read(\"%s\", %d) call!",
509 cf
->filename
, reloading
);
510 return CF_READ_ERROR
;
512 /* This is a full dissection, so clear any pending request for one. */
513 cf
->redissection_queued
= RESCAN_NONE
;
514 cf
->read_lock
= true;
516 /* Compile the current display filter.
517 * The code it compiles to might have changed, e.g. if a display
518 * filter macro used has changed.
520 * We assume this will not fail since cf->dfilter is only set in
521 * cf_filter IFF the filter was valid.
522 * XXX - This is not necessarily true, if the filter has a FT_IPv4
523 * or FT_IPv6 field compared to a resolved hostname in it, because
524 * we do a new host lookup, and that *could* timeout this time
525 * (though with the read lock above we shouldn't have many lookups at
526 * once, reducing the chances of that)... (#19612)
529 compiled
= dfilter_compile(cf
->dfilter
, &dfcode
, NULL
);
530 ws_assert(compiled
&& dfcode
);
533 dfilter_free(cf
->dfcode
);
536 /* The compiled dfilter might have a field reference; recompiling it
537 * means that the field references won't match anything. That's what
538 * we want since this is a new sequential read and we don't have
539 * a selected frame with a tree. (Will taps with filters with display
540 * references also have cleared display references?)
543 /* Get the union of the flags for all tap listeners. */
544 tap_flags
= union_of_tap_listener_flags();
547 * Determine whether we need to create a protocol tree.
550 * we're going to apply a display filter;
552 * one of the tap listeners is going to apply a filter;
554 * one of the tap listeners requires a protocol tree;
556 * a postdissector wants field values or protocols on
560 (cf
->dfcode
!= NULL
|| have_filtering_tap_listeners() ||
561 (tap_flags
& TL_REQUIRES_PROTO_TREE
) || postdissectors_want_hfids());
563 reset_tap_listeners();
565 name_ptr
= g_filename_display_basename(cf
->filename
);
568 cf_callback_invoke(cf_cb_file_reload_started
, cf
);
570 cf_callback_invoke(cf_cb_file_read_started
, cf
);
572 /* Record the file's compression type.
573 XXX - do we know this at open time? */
574 cf
->compression_type
= wtap_get_compression_type(cf
->provider
.wth
);
576 /* The packet list window will be empty until the file is completely loaded */
577 packet_list_freeze();
579 cf
->stop_flag
= false;
580 start_time
= g_get_monotonic_time();
582 epan_dissect_init(&edt
, cf
->epan
, create_proto_tree
, false);
584 /* If the display filter or any tap listeners require the columns,
586 cinfo
= (tap_listeners_require_columns() ||
587 dfilter_requires_columns(cf
->dfcode
)) ? &cf
->cinfo
: NULL
;
589 /* Find the size of the file. */
590 size
= wtap_file_size(cf
->provider
.wth
, NULL
);
592 /* If we are to ignore duplicate frames, we need a container to store
593 * hashes frame contents */
594 fifo_string_cache_t frame_dup_cache
;
595 GChecksum
*volatile cksum
= NULL
;
597 if (prefs
.ignore_dup_frames
) {
598 fifo_string_cache_init(&frame_dup_cache
, prefs
.ignore_dup_frames_cache_entries
, g_free
);
599 cksum
= g_checksum_new(G_CHECKSUM_SHA256
);
602 g_timer_start(prog_timer
);
605 ws_buffer_init(&buf
, 1514);
612 char status_str
[100];
614 while ((wtap_read(cf
->provider
.wth
, &rec
, &buf
, &err
, &err_info
,
617 if (cf
->count
== max_records
) {
619 * Quit if we've already read the maximum number of
622 too_many_records
= true;
625 file_pos
= wtap_read_so_far(cf
->provider
.wth
);
627 /* Create the progress bar if necessary. */
628 if (progress_is_slow(progbar
, prog_timer
, size
, file_pos
)) {
629 progbar_val
= calc_progbar_val(cf
, size
, file_pos
, status_str
, sizeof(status_str
));
630 progbar
= delayed_create_progress_dlg(cf
->window
, NULL
, NULL
, true,
631 &cf
->stop_flag
, progbar_val
);
635 * Update the progress bar, but do it only after
636 * PROGBAR_UPDATE_INTERVAL has elapsed. Calling update_progress_dlg
637 * and packets_bar_update will likely trigger UI paint events, which
638 * might take a while depending on the platform and display. Reset
639 * our timer *after* painting.
641 if (progbar
&& g_timer_elapsed(prog_timer
, NULL
) > PROGBAR_UPDATE_INTERVAL
) {
642 progbar_val
= calc_progbar_val(cf
, size
, file_pos
, status_str
, sizeof(status_str
));
643 /* update the packet bar content on the first run or frequently on very large files */
644 update_progress_dlg(progbar
, progbar_val
, status_str
);
645 compute_elapsed(cf
, start_time
);
646 packets_bar_update();
647 g_timer_start(prog_timer
);
650 * The previous GUI triggers should not have destroyed the running
651 * session. If that did happen, it could blow up when read_record tries
652 * to use the destroyed edt.session, so detect it right here.
654 ws_assert(edt
.session
== cf
->epan
);
657 if (cf
->state
== FILE_READ_ABORTED
) {
658 /* Well, the user decided to exit Wireshark. Break out of the
659 loop, and let the code below (which is called even if there
660 aren't any packets left to read) exit. */
661 is_read_aborted
= true;
665 /* Well, the user decided to abort the read. He/She will be warned and
666 it might be enough for him/her to work with the already loaded
668 This is especially true for very large capture files, where you don't
669 want to wait loading the whole file (which may last minutes or even
670 hours even on fast machines) just to see that it was the wrong file. */
673 read_record(cf
, &rec
, &buf
, cf
->dfcode
, &edt
, cinfo
, data_offset
, &frame_dup_cache
, cksum
);
674 wtap_rec_reset(&rec
);
677 CATCH(OutOfMemoryError
) {
678 simple_message_box(ESD_TYPE_ERROR
, NULL
,
679 "More information and workarounds can be found at\n"
680 WS_WIKI_URL("KnownBugs/OutOfMemory"),
681 "Sorry, but Wireshark has run out of memory and has to terminate now.");
683 /* Could we close the current capture and free up memory from that? */
685 /* we have to terminate, as we cannot recover from the memory error */
691 // If we're ignoring duplicate frames, clear the data structures.
692 // We really could look at prefs.ignore_dup_frames here, but it's even
693 // safer to check if we had allocated 'cksum'.
695 fifo_string_cache_free(&frame_dup_cache
);
696 g_checksum_free(cksum
);
699 /* We're done reading sequentially through the file. */
700 cf
->state
= FILE_READ_DONE
;
702 /* Destroy the progress bar if it was created. */
704 destroy_progress_dlg(progbar
);
705 g_timer_destroy(prog_timer
);
707 /* Free the display name */
710 epan_dissect_cleanup(&edt
);
711 wtap_rec_cleanup(&rec
);
712 ws_buffer_free(&buf
);
714 /* Close the sequential I/O side, to free up memory it requires. */
715 wtap_sequential_close(cf
->provider
.wth
);
717 /* Allow the protocol dissectors to free up memory that they
718 * don't need after the sequential run-through of the packets. */
719 postseq_cleanup_all_protocols();
721 /* compute the time it took to load the file */
722 compute_elapsed(cf
, start_time
);
724 /* Set the file encapsulation type now; we don't know what it is until
725 we've looked at all the packets, as we don't know until then whether
726 there's more than one type (and thus whether it's
727 WTAP_ENCAP_PER_PACKET). */
728 cf
->lnk_t
= wtap_file_encap(cf
->provider
.wth
);
730 cf
->current_frame
= frame_data_sequence_find(cf
->provider
.frames
, cf
->first_displayed
);
734 /* It is safe again to execute redissections or sort. */
735 ws_assert(cf
->read_lock
);
736 cf
->read_lock
= false;
739 cf_callback_invoke(cf_cb_file_reload_finished
, cf
);
741 cf_callback_invoke(cf_cb_file_read_finished
, cf
);
743 /* If we have any displayed packets to select, select the first of those
744 packets by making the first row the selected row. */
745 if (cf
->first_displayed
!= 0) {
746 packet_list_select_row_from_data(NULL
);
749 if (is_read_aborted
) {
751 * Well, the user decided to exit Wireshark while reading this *offline*
752 * capture file (Live captures are handled by something like
753 * cf_continue_tail). Clean up accordingly.
756 cf
->redissection_queued
= RESCAN_NONE
;
757 return CF_READ_ABORTED
;
760 if (cf
->redissection_queued
!= RESCAN_NONE
) {
761 /* Redissection was queued up. Clear the request and perform it now. */
762 bool redissect
= cf
->redissection_queued
== RESCAN_REDISSECT
;
763 rescan_packets(cf
, NULL
, NULL
, redissect
);
767 simple_message_box(ESD_TYPE_WARN
, NULL
,
768 "The remaining packets in the file were discarded.\n"
770 "As a lot of packets from the original file will be missing,\n"
771 "remember to be careful when saving the current content to a file.\n",
772 "File loading was cancelled.");
773 return CF_READ_ERROR
;
777 /* Put up a message box noting that the read failed somewhere along
778 the line. Don't throw out the stuff we managed to read, though,
780 report_cfile_read_failure(NULL
, err
, err_info
);
781 return CF_READ_ERROR
;
782 } else if (too_many_records
) {
783 simple_message_box(ESD_TYPE_WARN
, NULL
,
784 "The remaining packets in the file were discarded.\n"
786 "As a lot of packets from the original file will be missing,\n"
787 "remember to be careful when saving the current content to a file.\n"
789 "The command-line utility editcap can be used to split "
790 "the file into multiple smaller files",
791 "The file contains more records than the maximum "
792 "supported number of records, %u.", max_records
);
793 return CF_READ_ERROR
;
800 cf_continue_tail(capture_file
*cf
, volatile int to_read
, wtap_rec
*rec
,
801 Buffer
*buf
, int *err
, fifo_string_cache_t
*frame_dup_cache
, GChecksum
*frame_cksum
)
804 volatile int newly_displayed_packets
= 0;
806 bool create_proto_tree
;
809 /* Don't compile the current display filter. The current display filter
810 * text might compile to different code than when the capture started:
812 * If it has a IP address resolved name, calling get_host_ipaddr every
813 * time new packets arrive can mean a *lot* of gethostbyname calls
814 * in flight at once, eventually leading to a timeout (#19612).
815 * addr_resolv.c says that ares_gethostbyname is "usually interactive",
816 * unlike ares_gethostbyaddr (used in dissection), and violating that
817 * expectation is bad.
819 * If it has a display filter macro, the definition might have changed.
821 * If it has a field reference, the selected frame / current proto tree
822 * might have changed, and we don't have the old one. If we recompile,
823 * we can't set the field references to the old values.
825 * For a rescan, redissection, reload, retap, or opening a new file, we
826 * want to compile. What about here, when new frames have arrived in a live
827 * capture? We might be able to cache the host lookup, and a user might want
828 * the new display filter macro definition, but the user almost surely wants
829 * the field references to refer to values from the proto tree when the
830 * filter was applied, not whatever it happens to be now if the user has
831 * clicked on a different packet.
833 * To get the new compiled filter, the user should refilter.
836 /* Get the union of the flags for all tap listeners. */
837 tap_flags
= union_of_tap_listener_flags();
840 * Determine whether we need to create a protocol tree.
843 * we're going to apply a display filter;
845 * one of the tap listeners is going to apply a filter;
847 * one of the tap listeners requires a protocol tree;
849 * a postdissector wants field values or protocols on
853 (cf
->dfcode
!= NULL
|| have_filtering_tap_listeners() ||
854 (tap_flags
& TL_REQUIRES_PROTO_TREE
) || postdissectors_want_hfids());
858 /* Don't freeze/thaw the list when doing live capture */
859 /*packet_list_freeze();*/
861 epan_dissect_init(&edt
, cf
->epan
, create_proto_tree
, false);
864 int64_t data_offset
= 0;
867 /* If the display filter or any tap listeners require the columns,
869 cinfo
= (tap_listeners_require_columns() ||
870 dfilter_requires_columns(cf
->dfcode
)) ? &cf
->cinfo
: NULL
;
872 while (to_read
!= 0) {
873 wtap_cleareof(cf
->provider
.wth
);
874 if (!wtap_read(cf
->provider
.wth
, rec
, buf
, err
, &err_info
,
878 if (cf
->state
== FILE_READ_ABORTED
) {
879 /* Well, the user decided to exit Wireshark. Break out of the
880 loop, and let the code below (which is called even if there
881 aren't any packets left to read) exit. */
884 if (read_record(cf
, rec
, buf
, cf
->dfcode
, &edt
, cinfo
, data_offset
, frame_dup_cache
, frame_cksum
)) {
885 newly_displayed_packets
++;
891 CATCH(OutOfMemoryError
) {
892 simple_message_box(ESD_TYPE_ERROR
, NULL
,
893 "More information and workarounds can be found at\n"
894 WS_WIKI_URL("KnownBugs/OutOfMemory"),
895 "Sorry, but Wireshark has run out of memory and has to terminate now.");
897 /* Could we close the current capture and free up memory from that? */
898 return CF_READ_ABORTED
;
900 /* we have to terminate, as we cannot recover from the memory error */
906 /* Update the file encapsulation; it might have changed based on the
907 packets we've read. */
908 cf
->lnk_t
= wtap_file_encap(cf
->provider
.wth
);
910 epan_dissect_cleanup(&edt
);
912 /* Don't freeze/thaw the list when doing live capture */
913 /*packet_list_thaw();*/
914 /* With the new packet list the first packet
915 * isn't automatically selected.
917 if (!cf
->current_frame
&& !packet_list_multi_select_active())
918 packet_list_select_row_from_data(NULL
);
920 if (cf
->state
== FILE_READ_ABORTED
) {
921 /* Well, the user decided to exit Wireshark. Return CF_READ_ABORTED
922 so that our caller can kill off the capture child process;
923 this will cause an EOF on the pipe from the child, so
924 "cf_finish_tail()" will be called, and it will clean up
926 return CF_READ_ABORTED
;
927 } else if (*err
!= 0) {
928 /* We got an error reading the capture file.
929 XXX - pop up a dialog box instead? */
930 if (err_info
!= NULL
) {
931 ws_warning("Error \"%s\" while reading \"%s\" (\"%s\")",
932 wtap_strerror(*err
), cf
->filename
, err_info
);
935 ws_warning("Error \"%s\" while reading \"%s\"",
936 wtap_strerror(*err
), cf
->filename
);
938 return CF_READ_ERROR
;
944 cf_fake_continue_tail(capture_file
*cf
)
946 if (cf
->state
== FILE_CLOSED
) {
947 cf
->state
= FILE_READ_PENDING
;
952 cf_finish_tail(capture_file
*cf
, wtap_rec
*rec
, Buffer
*buf
, int *err
,
953 fifo_string_cache_t
*frame_dup_cache
, GChecksum
*frame_cksum
)
959 bool create_proto_tree
;
962 /* All the comments above in cf_continue_tail apply regarding the
963 * current display filter.
966 /* Get the union of the flags for all tap listeners. */
967 tap_flags
= union_of_tap_listener_flags();
969 /* If the display filter or any tap listeners require the columns,
971 cinfo
= (tap_listeners_require_columns() ||
972 dfilter_requires_columns(cf
->dfcode
)) ? &cf
->cinfo
: NULL
;
975 * Determine whether we need to create a protocol tree.
978 * we're going to apply a display filter;
980 * one of the tap listeners is going to apply a filter;
982 * one of the tap listeners requires a protocol tree;
984 * a postdissector wants field values or protocols on
988 (cf
->dfcode
!= NULL
|| have_filtering_tap_listeners() ||
989 (tap_flags
& TL_REQUIRES_PROTO_TREE
) || postdissectors_want_hfids());
991 if (cf
->provider
.wth
== NULL
) {
993 return CF_READ_ERROR
;
996 /* Don't freeze/thaw the list when doing live capture */
997 /*packet_list_freeze();*/
999 epan_dissect_init(&edt
, cf
->epan
, create_proto_tree
, false);
1001 while ((wtap_read(cf
->provider
.wth
, rec
, buf
, err
, &err_info
, &data_offset
))) {
1002 if (cf
->state
== FILE_READ_ABORTED
) {
1003 /* Well, the user decided to abort the read. Break out of the
1004 loop, and let the code below (which is called even if there
1005 aren't any packets left to read) exit. */
1008 read_record(cf
, rec
, buf
, cf
->dfcode
, &edt
, cinfo
, data_offset
, frame_dup_cache
, frame_cksum
);
1009 wtap_rec_reset(rec
);
1012 epan_dissect_cleanup(&edt
);
1014 /* Don't freeze/thaw the list when doing live capture */
1015 /*packet_list_thaw();*/
1017 if (cf
->state
== FILE_READ_ABORTED
) {
1018 /* Well, the user decided to abort the read. We're only called
1019 when the child capture process closes the pipe to us (meaning
1020 it's probably exited), so we can just close the capture
1021 file; we return CF_READ_ABORTED so our caller can do whatever
1022 is appropriate when that happens. */
1024 return CF_READ_ABORTED
;
1027 /* We're done reading sequentially through the file. */
1028 cf
->state
= FILE_READ_DONE
;
1030 /* We're done reading sequentially through the file; close the
1031 sequential I/O side, to free up memory it requires. */
1032 wtap_sequential_close(cf
->provider
.wth
);
1034 /* Allow the protocol dissectors to free up memory that they
1035 * don't need after the sequential run-through of the packets. */
1036 postseq_cleanup_all_protocols();
1038 /* Update the file encapsulation; it might have changed based on the
1039 packets we've read. */
1040 cf
->lnk_t
= wtap_file_encap(cf
->provider
.wth
);
1042 /* Update the details in the file-set dialog, as the capture file
1043 * has likely grown since we first stat-ed it */
1044 fileset_update_file(cf
->filename
);
1047 /* We got an error reading the capture file.
1048 XXX - pop up a dialog box? */
1049 if (err_info
!= NULL
) {
1050 ws_warning("Error \"%s\" while reading \"%s\" (\"%s\")",
1051 wtap_strerror(*err
), cf
->filename
, err_info
);
1054 ws_warning("Error \"%s\" while reading \"%s\"",
1055 wtap_strerror(*err
), cf
->filename
);
1057 return CF_READ_ERROR
;
1062 #endif /* HAVE_LIBPCAP */
1065 cf_get_display_name(capture_file
*cf
)
1069 /* Return a name to use in displays */
1070 if (!cf
->is_tempfile
) {
1071 /* Get the last component of the file name, and use that. */
1073 displayname
= g_filename_display_basename(cf
->filename
);
1075 displayname
=g_strdup("(No file)");
1078 /* The file we read is a temporary file from a live capture or
1079 a merge operation; we don't mention its name, but, if it's
1080 from a capture, give the source of the capture. */
1082 displayname
= g_strdup(cf
->source
);
1084 displayname
= g_strdup("(Untitled)");
1091 cf_get_basename(capture_file
*cf
)
1095 /* Return a name to use in the GUI for the basename for files to
1096 which we save statistics */
1097 if (!cf
->is_tempfile
) {
1098 /* Get the last component of the file name, and use that. */
1100 displayname
= g_filename_display_basename(cf
->filename
);
1102 /* If the file name ends with any extension that corresponds
1103 to a file type we support - including compressed versions
1104 of those files - strip it off. */
1105 size_t displayname_len
= strlen(displayname
);
1106 GSList
*extensions
= wtap_get_all_file_extensions_list();
1108 for (suffix
= extensions
; suffix
!= NULL
; suffix
= g_slist_next(suffix
)) {
1109 /* Does the file name end with that extension? */
1110 const char *extension
= (char *)suffix
->data
;
1111 size_t extension_len
= strlen(extension
);
1112 if (displayname_len
> extension_len
&&
1113 displayname
[displayname_len
- extension_len
- 1] == '.' &&
1114 strcmp(&displayname
[displayname_len
- extension_len
], extension
) == 0) {
1115 /* Yes. Strip the extension off, and return the result. */
1116 displayname
[displayname_len
- extension_len
- 1] = '\0';
1120 wtap_free_extensions_list(extensions
);
1122 displayname
=g_strdup("");
1125 /* The file we read is a temporary file from a live capture or
1126 a merge operation; we don't mention its name, but, if it's
1127 from a capture, give the source of the capture. */
1129 displayname
= g_strdup(cf
->source
);
1131 displayname
= g_strdup("");
1138 cf_set_tempfile_source(capture_file
*cf
, char *source
)
1145 cf
->source
= g_strdup(source
);
1147 cf
->source
= g_strdup("");
1152 cf_get_tempfile_source(capture_file
*cf
)
1161 /* XXX - use a macro instead? */
1163 cf_get_packet_count(capture_file
*cf
)
1168 /* XXX - use a macro instead? */
1170 cf_is_tempfile(capture_file
*cf
)
1172 return cf
->is_tempfile
;
1176 cf_set_tempfile(capture_file
*cf
, bool is_tempfile
)
1178 cf
->is_tempfile
= is_tempfile
;
1182 /* XXX - use a macro instead? */
1184 cf_set_drops_known(capture_file
*cf
, bool drops_known
)
1186 cf
->drops_known
= drops_known
;
1189 /* XXX - use a macro instead? */
1191 cf_set_drops(capture_file
*cf
, uint32_t drops
)
1196 /* XXX - use a macro instead? */
1198 cf_get_drops_known(capture_file
*cf
)
1200 return cf
->drops_known
;
1203 /* XXX - use a macro instead? */
1205 cf_get_drops(capture_file
*cf
)
1211 cf_set_rfcode(capture_file
*cf
, dfilter_t
*rfcode
)
1213 cf
->rfcode
= rfcode
;
1217 add_packet_to_packet_list(frame_data
*fdata
, capture_file
*cf
,
1218 epan_dissect_t
*edt
, dfilter_t
*dfcode
, column_info
*cinfo
,
1219 wtap_rec
*rec
, Buffer
*buf
, bool add_to_packet_list
)
1221 frame_data_set_before_dissect(fdata
, &cf
->elapsed_time
,
1222 &cf
->provider
.ref
, cf
->provider
.prev_dis
);
1223 cf
->provider
.prev_cap
= fdata
;
1225 if (dfcode
!= NULL
) {
1226 epan_dissect_prime_with_dfilter(edt
, dfcode
);
1229 /* Prepare coloring rules, this ensures that display filter rules containing
1230 * frame.color_rule references are still processed.
1231 * TODO: actually detect that situation or maybe apply other optimizations? */
1232 if (edt
->tree
&& color_filters_used()) {
1233 color_filters_prime_edt(edt
);
1234 fdata
->need_colorize
= 1;
1238 if (!fdata
->visited
) {
1239 /* This is the first pass, so prime the epan_dissect_t with the
1240 hfids postdissectors want on the first pass. */
1241 prime_epan_dissect_with_postdissector_wanted_hfids(edt
);
1244 /* Initialize passed_dfilter here so that dissectors can hide packets. */
1245 /* XXX We might want to add a separate "visible" bit to frame_data instead. */
1246 fdata
->passed_dfilter
= 1;
1248 /* Dissect the frame. */
1249 epan_dissect_run_with_taps(edt
, cf
->cd_t
, rec
,
1250 ws_buffer_start_ptr(buf
),
1253 if (fdata
->passed_dfilter
&& dfcode
!= NULL
) {
1254 fdata
->passed_dfilter
= dfilter_apply_edt(dfcode
, edt
) ? 1 : 0;
1256 if (fdata
->passed_dfilter
&& edt
->pi
.fd
->dependent_frames
) {
1257 /* This frame passed the display filter but it may depend on other
1258 * (potentially not displayed) frames. Find those frames and mark them
1261 g_hash_table_foreach(edt
->pi
.fd
->dependent_frames
, find_and_mark_frame_depended_upon
, cf
->provider
.frames
);
1265 if (fdata
->passed_dfilter
|| fdata
->ref_time
) {
1266 cf
->displayed_count
++;
1267 fdata
->dis_num
= cf
->displayed_count
;
1270 if (add_to_packet_list
) {
1271 /* We fill the needed columns from new_packet_list */
1272 packet_list_append(cinfo
, fdata
);
1275 if (fdata
->passed_dfilter
|| fdata
->ref_time
)
1277 frame_data_set_after_dissect(fdata
, &cf
->cum_bytes
);
1278 /* The only way we use prev_dis is to get the time stamp of
1279 * the previous displayed frame, so ignore it if it doesn't
1280 * have a time stamp, because we're presumably interested in
1281 * the timestamp of the previously displayed frame with a
1282 * time. XXX: What if in the future we want to use the previously
1283 * displayed frame for something else, too?
1285 if (fdata
->has_ts
) {
1286 cf
->provider
.prev_dis
= fdata
;
1289 /* If we haven't yet seen the first frame, this is it. */
1290 if (cf
->first_displayed
== 0)
1291 cf
->first_displayed
= fdata
->num
;
1293 /* This is the last frame we've seen so far. */
1294 cf
->last_displayed
= fdata
->num
;
1297 epan_dissect_reset(edt
);
1301 * Read in a new record.
1302 * Returns true if the packet was added to the packet (record) list,
1306 read_record(capture_file
*cf
, wtap_rec
*rec
, Buffer
*buf
, dfilter_t
*dfcode
,
1307 epan_dissect_t
*edt
, column_info
*cinfo
, int64_t offset
,
1308 fifo_string_cache_t
*frame_dup_cache
, GChecksum
*frame_cksum
)
1314 const char *cksum_string
;
1317 /* Add this packet's link-layer encapsulation type to cf->linktypes, if
1318 it's not already there.
1319 XXX - yes, this is O(N), so if every packet had a different
1320 link-layer encapsulation type, it'd be O(N^2) to read the file, but
1321 there are probably going to be a small number of encapsulation types
1323 if (rec
->rec_type
== REC_TYPE_PACKET
) {
1324 cf_add_encapsulation_type(cf
, rec
->rec_header
.packet_header
.pkt_encap
);
1327 /* The frame number of this packet, if we add it to the set of frames,
1328 would be one more than the count of frames in the file so far. */
1329 frame_data_init(&fdlocal
, cf
->count
+ 1, rec
, offset
, cf
->cum_bytes
);
1332 epan_dissect_t rf_edt
;
1333 column_info
*rf_cinfo
= NULL
;
1335 epan_dissect_init(&rf_edt
, cf
->epan
, true, false);
1336 epan_dissect_prime_with_dfilter(&rf_edt
, cf
->rfcode
);
1337 if (dfilter_requires_columns(cf
->rfcode
)) {
1338 rf_cinfo
= &cf
->cinfo
;
1340 epan_dissect_run(&rf_edt
, cf
->cd_t
, rec
,
1341 ws_buffer_start_ptr(buf
),
1342 &fdlocal
, rf_cinfo
);
1343 passed
= dfilter_apply_edt(cf
->rfcode
, &rf_edt
);
1344 epan_dissect_cleanup(&rf_edt
);
1350 /* This does a shallow copy of fdlocal, which is good enough. */
1351 fdata
= frame_data_sequence_add(cf
->provider
.frames
, &fdlocal
);
1354 if (rec
->block
!= NULL
)
1355 cf
->packet_comment_count
+= wtap_block_count_option(rec
->block
, OPT_COMMENT
);
1356 cf
->f_datalen
= offset
+ fdlocal
.cap_len
;
1358 // Should we check if the frame data is a duplicate, and thus, ignore
1360 if (frame_cksum
!= NULL
&& rec
->rec_type
== REC_TYPE_PACKET
) {
1361 g_checksum_reset(frame_cksum
);
1362 g_checksum_update(frame_cksum
, ws_buffer_start_ptr(buf
), ws_buffer_length(buf
));
1363 cksum_string
= g_strdup(g_checksum_get_string(frame_cksum
));
1364 was_in_cache
= fifo_string_cache_insert(frame_dup_cache
, cksum_string
);
1366 g_free((void *)cksum_string
);
1367 fdata
->ignored
= true;
1368 cf
->ignored_count
++;
1372 /* When a redissection is in progress (or queued), do not process packets.
1373 * This will be done once all (new) packets have been scanned. */
1374 if (!cf
->redissecting
&& cf
->redissection_queued
== RESCAN_NONE
) {
1375 add_packet_to_packet_list(fdata
, cf
, edt
, dfcode
, cinfo
, rec
, buf
, true);
1383 typedef struct _callback_data_t
{
1393 merge_callback(merge_event event
, int num _U_
,
1394 const merge_in_file_t in_files
[], const unsigned in_file_count
,
1398 callback_data_t
*cb_data
= (callback_data_t
*) data
;
1400 ws_assert(cb_data
!= NULL
);
1404 case MERGE_EVENT_INPUT_FILES_OPENED
:
1408 case MERGE_EVENT_FRAME_TYPE_SELECTED
:
1412 case MERGE_EVENT_READY_TO_MERGE
:
1413 /* Get the sum of the sizes of all the files. */
1414 for (i
= 0; i
< in_file_count
; i
++)
1415 cb_data
->f_len
+= in_files
[i
].size
;
1417 cb_data
->prog_timer
= g_timer_new();
1418 g_timer_start(cb_data
->prog_timer
);
1421 case MERGE_EVENT_RECORD_WAS_READ
:
1423 /* Create the progress bar if necessary.
1424 We check on every iteration of the loop, so that it takes no
1425 longer than the standard time to create it (otherwise, for a
1426 large file, we might take considerably longer than that standard
1427 time in order to get to the next progress bar step). */
1428 if (cb_data
->progbar
== NULL
) {
1429 cb_data
->progbar
= delayed_create_progress_dlg(cb_data
->pd_window
, NULL
, NULL
,
1430 false, &cb_data
->stop_flag
, 0.0f
);
1434 * Update the progress bar, but do it only after
1435 * PROGBAR_UPDATE_INTERVAL has elapsed. Calling update_progress_dlg
1436 * and packets_bar_update will likely trigger UI paint events, which
1437 * might take a while depending on the platform and display. Reset
1438 * our timer *after* painting.
1440 if (g_timer_elapsed(cb_data
->prog_timer
, NULL
) > PROGBAR_UPDATE_INTERVAL
) {
1442 int64_t file_pos
= 0;
1443 /* Get the sum of the seek positions in all of the files. */
1444 for (i
= 0; i
< in_file_count
; i
++)
1445 file_pos
+= wtap_read_so_far(in_files
[i
].wth
);
1447 progbar_val
= (float) file_pos
/ (float) cb_data
->f_len
;
1448 if (progbar_val
> 1.0f
) {
1449 /* Some file probably grew while we were reading it.
1450 That "shouldn't happen", so we'll just clip the progress
1455 if (cb_data
->progbar
!= NULL
) {
1456 char status_str
[100];
1457 snprintf(status_str
, sizeof(status_str
),
1458 "%" PRId64
"KB of %" PRId64
"KB",
1459 file_pos
/ 1024, cb_data
->f_len
/ 1024);
1460 update_progress_dlg(cb_data
->progbar
, progbar_val
, status_str
);
1462 g_timer_start(cb_data
->prog_timer
);
1467 case MERGE_EVENT_DONE
:
1468 /* We're done merging the files; destroy the progress bar if it was created. */
1469 if (cb_data
->progbar
!= NULL
)
1470 destroy_progress_dlg(cb_data
->progbar
);
1471 g_timer_destroy(cb_data
->prog_timer
);
1475 return cb_data
->stop_flag
;
1481 cf_merge_files_to_tempfile(void *pd_window
, const char *temp_dir
, char **out_filenamep
,
1482 int in_file_count
, const char *const *in_filenames
,
1483 int file_type
, bool do_append
)
1486 merge_progress_callback_t cb
;
1487 callback_data_t
*cb_data
= g_new0(callback_data_t
, 1);
1489 /* prepare our callback routine */
1490 cb_data
->pd_window
= pd_window
;
1491 cb
.callback_func
= merge_callback
;
1494 cf_callback_invoke(cf_cb_file_merge_started
, NULL
);
1496 /* merge the files */
1497 status
= merge_files_to_tempfile(temp_dir
, out_filenamep
, "wireshark", file_type
,
1499 in_file_count
, do_append
,
1500 IDB_MERGE_MODE_ALL_SAME
, 0 /* snaplen */,
1505 cf_callback_invoke(cf_cb_file_merge_finished
, NULL
);
1508 /* Callers aren't expected to treat an error or an explicit abort
1509 differently - the merge code puts up error dialogs itself, so
1510 they don't have to. */
1517 cf_filter_packets(capture_file
*cf
, char *dftext
, bool force
)
1519 const char *filter_new
= dftext
? dftext
: "";
1520 const char *filter_old
= cf
->dfilter
? cf
->dfilter
: "";
1524 /* if new filter equals old one, do nothing unless told to do so */
1525 /* XXX - The text can be the same without compiling to the same code.
1526 * (Macros, field references, etc.)
1528 if (!force
&& strcmp(filter_new
, filter_old
) == 0) {
1534 if (dftext
== NULL
) {
1535 /* The new filter is an empty filter (i.e., display all packets).
1536 * so leave dfcode==NULL
1540 * We have a filter; make a copy of it (as we'll be saving it),
1541 * and try to compile it.
1543 dftext
= g_strdup(dftext
);
1544 if (!dfilter_compile(dftext
, &dfcode
, &df_err
)) {
1545 /* The attempt failed; report an error. */
1546 simple_message_box(ESD_TYPE_ERROR
, NULL
,
1547 "See the help for a description of the display filter syntax.",
1548 "\"%s\" isn't a valid display filter: %s",
1549 dftext
, df_err
->msg
);
1550 df_error_free(&df_err
);
1556 if (dfcode
== NULL
) {
1557 /* Yes - free the filter text, and set it to null. */
1563 /* We have a valid filter. Replace the current filter. */
1564 g_free(cf
->dfilter
);
1565 cf
->dfilter
= dftext
;
1567 /* We'll recompile this when the rescan starts, or in cf_read()
1568 * if no file is open currently. However, if no file is open and
1569 * we start a new capture, we want to use this rather than
1570 * recompiling in cf_continue_tail() */
1571 dfilter_free(cf
->dfcode
);
1572 cf
->dfcode
= dfcode
;
1574 /* Now rescan the packet list, applying the new filter, but not
1575 * throwing away information constructed on a previous pass.
1576 * If a dissection is already in progress, queue it.
1578 if (cf
->redissection_queued
== RESCAN_NONE
) {
1579 if (cf
->read_lock
) {
1580 cf
->redissection_queued
= RESCAN_SCAN
;
1581 } else if (cf
->state
!= FILE_CLOSED
) {
1582 if (dftext
== NULL
) {
1583 rescan_packets(cf
, "Resetting", "filter", false);
1585 rescan_packets(cf
, "Filtering", dftext
, false);
1594 cf_redissect_packets(capture_file
*cf
)
1596 if (cf
->read_lock
|| cf
->redissection_queued
== RESCAN_SCAN
) {
1597 /* Dissection in progress, signal redissection rather than rescanning. That
1598 * would destroy the current (in-progress) dissection in "cf_read" which
1599 * will cause issues when "cf_read" tries to add packets to the list.
1600 * If a previous rescan was requested, "upgrade" it to a full redissection.
1602 cf
->redissection_queued
= RESCAN_REDISSECT
;
1604 if (cf
->redissection_queued
!= RESCAN_NONE
) {
1605 /* Redissection is (already) queued, wait for "cf_read" to finish. */
1606 /* XXX - what if whatever set and later clears read_lock is *not*
1607 * cf_read, e.g. process_specified_records ? We need to handle a
1608 * queued redissection there too like we do in cf_read.
1613 if (cf
->state
!= FILE_CLOSED
) {
1614 /* Restart dissection in case no cf_read is pending. */
1615 rescan_packets(cf
, "Reprocessing", "all packets", true);
1620 cf_read_record(capture_file
*cf
, const frame_data
*fdata
,
1621 wtap_rec
*rec
, Buffer
*buf
)
1626 if (!wtap_seek_read(cf
->provider
.wth
, fdata
->file_off
, rec
, buf
, &err
, &err_info
)) {
1627 report_cfile_read_failure(cf
->filename
, err
, err_info
);
1634 cf_read_record_no_alert(capture_file
*cf
, const frame_data
*fdata
,
1635 wtap_rec
*rec
, Buffer
*buf
)
1640 if (!wtap_seek_read(cf
->provider
.wth
, fdata
->file_off
, rec
, buf
, &err
, &err_info
)) {
1648 cf_read_current_record(capture_file
*cf
)
1650 return cf_read_record(cf
, cf
->current_frame
, &cf
->rec
, &cf
->buf
);
1653 /* Rescan the list of packets, reconstructing the CList.
1655 "action" describes why we're doing this; it's used in the progress
1658 "action_item" describes what we're doing; it's used in the progress
1661 "redissect" is true if we need to make the dissectors reconstruct
1662 any state information they have (because a preference that affects
1663 some dissector has changed, meaning some dissector might construct
1664 its state differently from the way it was constructed the last time). */
1666 rescan_packets(capture_file
*cf
, const char *action
, const char *action_item
, bool redissect
)
1668 /* Rescan packets new packet list */
1673 progdlg_t
*progbar
= NULL
;
1674 GTimer
*prog_timer
= g_timer_new();
1676 frame_data
*selected_frame
, *preceding_frame
, *following_frame
, *prev_frame
;
1677 int selected_frame_num
, preceding_frame_num
, following_frame_num
, prev_frame_num
;
1678 bool selected_frame_seen
;
1681 char status_str
[100];
1683 dfilter_t
*dfcode
= NULL
;
1685 bool create_proto_tree
;
1686 bool filtering_tap_listeners
= false;
1688 bool add_to_packet_list
= false;
1690 uint32_t frames_count
;
1691 rescan_type queued_rescan_type
= RESCAN_NONE
;
1693 if (cf
->state
== FILE_CLOSED
|| cf
->state
== FILE_READ_PENDING
) {
1697 /* Rescan in progress, clear pending actions. */
1698 cf
->redissection_queued
= RESCAN_NONE
;
1699 ws_assert(!cf
->read_lock
);
1700 cf
->read_lock
= true;
1702 wtap_rec_init(&rec
);
1703 ws_buffer_init(&buf
, 1514);
1705 /* Compile the current display filter.
1706 * The code it compiles to might have changed, e.g. if a display
1707 * filter macro used has changed.
1709 * We assume this will not fail since cf->dfilter is only set in
1710 * cf_filter IFF the filter was valid.
1711 * XXX - This is not necessarily true, if the filter has a FT_IPv4
1712 * or FT_IPv6 field compared to a resolved hostname in it, because
1713 * we do a new host lookup, and that *could* timeout this time
1714 * (though with the read lock above we shouldn't have many lookups at
1715 * once, reducing the chances of that)... (#19612)
1718 compiled
= dfilter_compile(cf
->dfilter
, &dfcode
, NULL
);
1719 ws_assert(compiled
&& dfcode
);
1722 dfilter_free(cf
->dfcode
);
1723 cf
->dfcode
= dfcode
;
1725 /* Do we have any tap listeners with filters? */
1726 filtering_tap_listeners
= have_filtering_tap_listeners();
1728 /* Update references in filters (if any) for the protocol
1729 * tree corresponding to the currently selected frame in the GUI. */
1730 if (cf
->edt
!= NULL
&& cf
->edt
->tree
!= NULL
) {
1732 dfilter_load_field_references(cf
->dfcode
, cf
->edt
->tree
);
1733 if (filtering_tap_listeners
)
1734 tap_listeners_load_field_references(cf
->edt
);
1737 if (cf
->dfcode
!= NULL
) {
1738 dfilter_log_full(LOG_DOMAIN_DFILTER
, LOG_LEVEL_NOISY
, NULL
, -1, NULL
,
1739 cf
->dfcode
, "Rescanning packets with display filter");
1742 /* Get the union of the flags for all tap listeners. */
1743 tap_flags
= union_of_tap_listener_flags();
1745 /* If the display filter or any tap listeners require the columns,
1746 * construct them. */
1747 cinfo
= (tap_listeners_require_columns() ||
1748 dfilter_requires_columns(cf
->dfcode
)) ? &cf
->cinfo
: NULL
;
1751 * Determine whether we need to create a protocol tree.
1754 * we're going to apply a display filter;
1756 * one of the tap listeners is going to apply a filter;
1758 * one of the tap listeners requires a protocol tree;
1760 * we're redissecting and a postdissector wants field
1761 * values or protocols on the first pass.
1764 (cf
->dfcode
!= NULL
|| filtering_tap_listeners
||
1765 (tap_flags
& TL_REQUIRES_PROTO_TREE
) ||
1766 (redissect
&& postdissectors_want_hfids()));
1768 reset_tap_listeners();
1769 /* Which frame, if any, is the currently selected frame?
1770 XXX - should the selected frame or the focus frame be the "current"
1771 frame, that frame being the one from which "Find Frame" searches
1773 selected_frame
= cf
->current_frame
;
1775 /* Mark frame num as not found */
1776 selected_frame_num
= -1;
1778 /* Freeze the packet list while we redo it, so we don't get any
1779 screen updates while it happens. */
1780 packet_list_freeze();
1783 /* We need to re-initialize all the state information that protocols
1784 keep, because some preference that controls a dissector has changed,
1785 which might cause the state information to be constructed differently
1786 by that dissector. */
1788 /* We might receive new packets while redissecting, and we don't
1789 want to dissect those before their time. */
1790 cf
->redissecting
= true;
1792 /* 'reset' dissection session */
1793 epan_free(cf
->epan
);
1794 if (cf
->edt
&& cf
->edt
->pi
.fd
) {
1795 /* All pointers in "per frame proto data" for the currently selected
1796 packet are allocated in wmem_file_scope() and deallocated in epan_free().
1797 Free them here to avoid unintended usage in packet_list_clear(). */
1798 frame_data_destroy(cf
->edt
->pi
.fd
);
1800 cf
->epan
= ws_epan_new(cf
);
1801 cf
->cinfo
.epan
= cf
->epan
;
1803 /* A new Lua tap listener may be registered in lua_prime_all_fields()
1804 called via epan_new() / init_dissection() when reloading Lua plugins. */
1805 if (!create_proto_tree
&& have_filtering_tap_listeners()) {
1806 create_proto_tree
= true;
1808 if (!cinfo
&& tap_listeners_require_columns()) {
1812 /* We need to redissect the packets so we have to discard our old
1813 * packet list store. */
1814 packet_list_clear();
1815 add_to_packet_list
= true;
1818 /* We don't yet know which will be the first and last frames displayed. */
1819 cf
->first_displayed
= 0;
1820 cf
->last_displayed
= 0;
1822 /* We currently don't display any packets */
1823 cf
->displayed_count
= 0;
1825 /* Iterate through the list of frames. Call a routine for each frame
1826 to check whether it should be displayed and, if so, add it to
1827 the display list. */
1828 cf
->provider
.ref
= NULL
;
1829 cf
->provider
.prev_dis
= NULL
;
1830 cf
->provider
.prev_cap
= NULL
;
1833 cf_callback_invoke(cf_cb_file_rescan_started
, cf
);
1835 g_timer_start(prog_timer
);
1836 /* Count of packets at which we've looked. */
1838 /* Progress so far. */
1841 cf
->stop_flag
= false;
1842 start_time
= g_get_monotonic_time();
1844 /* no previous row yet */
1845 prev_frame_num
= -1;
1848 preceding_frame_num
= -1;
1849 preceding_frame
= NULL
;
1850 following_frame_num
= -1;
1851 following_frame
= NULL
;
1853 selected_frame_seen
= false;
1855 frames_count
= cf
->count
;
1857 epan_dissect_init(&edt
, cf
->epan
, create_proto_tree
, false);
1861 * Decryption secrets and name resolution blocks are read while
1862 * sequentially processing records and then passed to the dissector.
1863 * During redissection, the previous information is lost (see epan_free
1864 * above), but they are not read again from the file as only packet
1865 * records are re-read. Therefore reset the wtap secrets and name
1866 * resolution callbacks such that wtap resupplies the callbacks with
1867 * previously read information.
1869 wtap_set_cb_new_ipv4(cf
->provider
.wth
, add_ipv4_name
);
1870 wtap_set_cb_new_ipv6(cf
->provider
.wth
, (wtap_new_ipv6_callback_t
) add_ipv6_name
);
1871 wtap_set_cb_new_secrets(cf
->provider
.wth
, secrets_wtap_callback
);
1874 for (framenum
= 1; framenum
<= frames_count
; framenum
++) {
1875 fdata
= frame_data_sequence_find(cf
->provider
.frames
, framenum
);
1877 /* Create the progress bar if necessary.
1878 We check on every iteration of the loop, so that it takes no
1879 longer than the standard time to create it (otherwise, for a
1880 large file, we might take considerably longer than that standard
1881 time in order to get to the next progress bar step). */
1882 if (progbar
== NULL
)
1883 progbar
= delayed_create_progress_dlg(cf
->window
, action
, action_item
, true,
1888 * Update the progress bar, but do it only after PROGBAR_UPDATE_INTERVAL
1889 * has elapsed. Calling update_progress_dlg and packets_bar_update will
1890 * likely trigger UI paint events, which might take a while depending on
1891 * the platform and display. Reset our timer *after* painting.
1893 if (g_timer_elapsed(prog_timer
, NULL
) > PROGBAR_UPDATE_INTERVAL
) {
1894 /* let's not divide by zero. I should never be started
1895 * with count == 0, so let's assert that
1897 ws_assert(cf
->count
> 0);
1898 progbar_val
= (float) count
/ frames_count
;
1900 if (progbar
!= NULL
) {
1901 snprintf(status_str
, sizeof(status_str
),
1902 "%4u of %u frames", count
, frames_count
);
1903 update_progress_dlg(progbar
, progbar_val
, status_str
);
1906 g_timer_start(prog_timer
);
1909 queued_rescan_type
= cf
->redissection_queued
;
1910 if (queued_rescan_type
!= RESCAN_NONE
) {
1911 /* A redissection was requested while an existing redissection was
1916 if (cf
->stop_flag
) {
1917 /* Well, the user decided to abort the filtering. Just stop.
1919 XXX - go back to the previous filter? Users probably just
1920 want not to wait for a filtering operation to finish;
1921 unless we cancel by having no filter, reverting to the
1922 previous filter will probably be even more expensive than
1923 continuing the filtering, as it involves going back to the
1924 beginning and filtering, and even with no filter we currently
1925 have to re-generate the entire clist, which is also expensive.
1927 I'm not sure what Network Monitor does, but it doesn't appear
1928 to give you an unfiltered display if you cancel. */
1935 /* Since all state for the frame was destroyed, mark the frame
1936 * as not visited, free the GSList referring to the state
1937 * data (the per-frame data itself was freed by
1938 * "init_dissection()"), and null out the GSList pointer. */
1939 frame_data_reset(fdata
);
1940 frames_count
= cf
->count
;
1943 /* Frame dependencies from the previous dissection/filtering are no longer valid. */
1944 fdata
->dependent_of_displayed
= 0;
1946 if (!cf_read_record(cf
, fdata
, &rec
, &buf
))
1947 break; /* error reading the frame */
1949 /* If the previous frame is displayed, and we haven't yet seen the
1950 selected frame, remember that frame - it's the closest one we've
1951 yet seen before the selected frame. */
1952 if (prev_frame_num
!= -1 && !selected_frame_seen
&& prev_frame
->passed_dfilter
) {
1953 preceding_frame_num
= prev_frame_num
;
1954 preceding_frame
= prev_frame
;
1957 add_packet_to_packet_list(fdata
, cf
, &edt
, cf
->dfcode
,
1959 add_to_packet_list
);
1961 /* If this frame is displayed, and this is the first frame we've
1962 seen displayed after the selected frame, remember this frame -
1963 it's the closest one we've yet seen at or after the selected
1965 if (fdata
->passed_dfilter
&& selected_frame_seen
&& following_frame_num
== -1) {
1966 following_frame_num
= fdata
->num
;
1967 following_frame
= fdata
;
1969 if (fdata
== selected_frame
) {
1970 selected_frame_seen
= true;
1971 if (fdata
->passed_dfilter
)
1972 selected_frame_num
= fdata
->num
;
1975 /* Remember this frame - it'll be the previous frame
1976 on the next pass through the loop. */
1977 prev_frame_num
= fdata
->num
;
1979 wtap_rec_reset(&rec
);
1982 epan_dissect_cleanup(&edt
);
1983 wtap_rec_cleanup(&rec
);
1984 ws_buffer_free(&buf
);
1986 /* We are done redissecting the packet list. */
1987 cf
->redissecting
= false;
1990 frames_count
= cf
->count
;
1991 /* Clear out what remains of the visited flags and per-frame data
1994 XXX - that may cause various forms of bogosity when dissecting
1995 these frames, as they won't have been seen by this sequential
1996 pass, but the only alternative I see is to keep scanning them
1997 even though the user requested that the scan stop, and that
1998 would leave the user stuck with an Wireshark grinding on
1999 until it finishes. Should we just stick them with that? */
2000 for (; framenum
<= frames_count
; framenum
++) {
2001 fdata
= frame_data_sequence_find(cf
->provider
.frames
, framenum
);
2002 frame_data_reset(fdata
);
2006 /* We're done filtering the packets; destroy the progress bar if it
2008 if (progbar
!= NULL
)
2009 destroy_progress_dlg(progbar
);
2010 g_timer_destroy(prog_timer
);
2012 /* Unfreeze the packet list. */
2013 if (!add_to_packet_list
)
2014 packet_list_recreate_visible_rows();
2016 /* Compute the time it took to filter the file */
2017 compute_elapsed(cf
, start_time
);
2021 /* It is safe again to execute redissections or sort. */
2022 ws_assert(cf
->read_lock
);
2023 cf
->read_lock
= false;
2025 cf_callback_invoke(cf_cb_file_rescan_finished
, cf
);
2027 if (selected_frame_num
== -1) {
2028 /* The selected frame didn't pass the filter. */
2029 if (selected_frame
== NULL
) {
2030 /* That's because there *was* no selected frame. Make the first
2031 displayed frame the current frame. */
2032 selected_frame_num
= 0;
2034 /* Find the nearest displayed frame to the selected frame (whether
2035 it's before or after that frame) and make that the current frame.
2036 If the next and previous displayed frames are equidistant from the
2037 selected frame, choose the next one. */
2038 ws_assert(following_frame
== NULL
||
2039 following_frame
->num
>= selected_frame
->num
);
2040 ws_assert(preceding_frame
== NULL
||
2041 preceding_frame
->num
<= selected_frame
->num
);
2042 if (following_frame
== NULL
) {
2043 /* No frame after the selected frame passed the filter, so we
2044 have to select the last displayed frame before the selected
2046 selected_frame_num
= preceding_frame_num
;
2047 selected_frame
= preceding_frame
;
2048 } else if (preceding_frame
== NULL
) {
2049 /* No frame before the selected frame passed the filter, so we
2050 have to select the first displayed frame after the selected
2052 selected_frame_num
= following_frame_num
;
2053 selected_frame
= following_frame
;
2055 /* Frames before and after the selected frame passed the filter, so
2056 we'll select the previous frame */
2057 selected_frame_num
= preceding_frame_num
;
2058 selected_frame
= preceding_frame
;
2063 if (selected_frame_num
== -1) {
2064 /* There are no frames displayed at all. */
2065 cf_unselect_packet(cf
);
2067 /* Either the frame that was selected passed the filter, or we've
2068 found the nearest displayed frame to that frame. Select it, make
2069 it the focus row, and make it visible. */
2070 /* Set to invalid to force update of packet list and packet details */
2071 if (selected_frame_num
== 0) {
2072 packet_list_select_row_from_data(NULL
);
2074 if (!packet_list_select_row_from_data(selected_frame
)) {
2075 /* We didn't find a row corresponding to this frame.
2076 This means that the frame isn't being displayed currently,
2077 so we can't select it. */
2078 simple_message_box(ESD_TYPE_INFO
, NULL
,
2079 "The capture file is probably not fully dissected.",
2080 "End of capture exceeded.");
2085 /* If another rescan (due to dfilter change) or redissection (due to profile
2086 * change) was requested, the rescan above is aborted and restarted here. */
2087 if (queued_rescan_type
!= RESCAN_NONE
) {
2088 redissect
= redissect
|| queued_rescan_type
== RESCAN_REDISSECT
;
2089 rescan_packets(cf
, "Reprocessing", "all packets", redissect
);
2095 * Scan through all frame data and recalculate the ref time
2096 * without rereading the file.
2097 * XXX - do we need a progress bar or is this fast enough?
2100 cf_reftime_packets(capture_file
* cf
)
2106 cf
->provider
.ref
= NULL
;
2107 cf
->provider
.prev_dis
= NULL
;
2110 for (framenum
= 1; framenum
<= cf
->count
; framenum
++) {
2111 fdata
= frame_data_sequence_find(cf
->provider
.frames
, framenum
);
2113 /* just add some value here until we know if it is being displayed or not */
2114 fdata
->cum_bytes
= cf
->cum_bytes
+ fdata
->pkt_len
;
2120 if (fdata
->has_ts
) {
2121 /* If we don't have the time stamp of the first packet in the
2122 capture, it's because this is the first packet. Save the time
2123 stamp of this packet as the time stamp of the first packet. */
2124 if (cf
->provider
.ref
== NULL
)
2125 cf
->provider
.ref
= fdata
;
2126 /* if this frames is marked as a reference time frame, reset
2127 firstsec and firstusec to this frame */
2128 if (fdata
->ref_time
)
2129 cf
->provider
.ref
= fdata
;
2131 /* Get the time elapsed between the first packet and this one. */
2132 fdata
->frame_ref_num
= (fdata
!= cf
->provider
.ref
) ? cf
->provider
.ref
->num
: 0;
2133 nstime_delta(&rel_ts
, &fdata
->abs_ts
, &cf
->provider
.ref
->abs_ts
);
2135 /* If it's greater than the current elapsed time, set the elapsed
2136 time to it (we check for "greater than" so as not to be
2137 confused by time moving backwards). */
2138 if ((int32_t)cf
->elapsed_time
.secs
< rel_ts
.secs
2139 || ((int32_t)cf
->elapsed_time
.secs
== rel_ts
.secs
&& (int32_t)cf
->elapsed_time
.nsecs
< rel_ts
.nsecs
)) {
2140 cf
->elapsed_time
= rel_ts
;
2143 /* If this frame is displayed, get the time elapsed between the
2144 previous displayed packet and this packet. */
2145 /* XXX: What if in the future we want to use the previously
2146 * displayed frame for something else, too? Then we'd want
2147 * to store this frame as prev_dis even if it doesn't have a
2149 if ( fdata
->passed_dfilter
) {
2150 /* If we don't have the time stamp of the previous displayed
2151 packet, it's because this is the first displayed packet.
2152 Save the time stamp of this packet as the time stamp of
2153 the previous displayed packet. */
2154 if (cf
->provider
.prev_dis
== NULL
) {
2155 cf
->provider
.prev_dis
= fdata
;
2158 fdata
->prev_dis_num
= cf
->provider
.prev_dis
->num
;
2159 cf
->provider
.prev_dis
= fdata
;
2162 /* If this frame doesn't have a timestamp, don't calculate
2163 anything with relative times. */
2164 /* However, if this frame is marked as a reference time frame,
2165 clear the reference frame so that the next frame with a
2166 timestamp becomes the reference frame. */
2167 if (fdata
->ref_time
) {
2168 cf
->provider
.ref
= NULL
;
2175 if ( (fdata
->passed_dfilter
) || (fdata
->ref_time
) ) {
2176 /* This frame either passed the display filter list or is marked as
2177 a time reference frame. All time reference frames are displayed
2178 even if they don't pass the display filter */
2179 if (fdata
->ref_time
) {
2180 /* if this was a TIME REF frame we should reset the cum_bytes field */
2181 cf
->cum_bytes
= fdata
->pkt_len
;
2182 fdata
->cum_bytes
= cf
->cum_bytes
;
2184 /* increase cum_bytes with this packets length */
2185 cf
->cum_bytes
+= fdata
->pkt_len
;
2198 process_specified_records(capture_file
*cf
, packet_range_t
*range
,
2199 const char *string1
, const char *string2
, bool terminate_is_stop
,
2200 bool (*callback
)(capture_file
*, frame_data
*,
2201 wtap_rec
*, Buffer
*, void *),
2202 void *callback_args
,
2203 bool show_progress_bar
)
2209 psp_return_t ret
= PSP_FINISHED
;
2211 progdlg_t
*progbar
= NULL
;
2212 GTimer
*prog_timer
= g_timer_new();
2215 char progbar_status_str
[100];
2216 range_process_e process_this
;
2218 wtap_rec_init(&rec
);
2219 ws_buffer_init(&buf
, 1514);
2221 g_timer_start(prog_timer
);
2222 /* Count of packets at which we've looked. */
2224 /* Progress so far. */
2227 /* XXX - It should be ok to have multiple readers, so long as nothing
2228 * frees the epan context, e.g. rescan_packets with redissect true,
2229 * or anything that closes the file (including reload and certain forms
2230 * of saving.) This is mostly to stop cf_save_records but should probably
2231 * be handled by callers in order to allow multiple readers (e.g.,
2232 * restarting taps after adding or changing one.) We should probably
2233 * make this a real reader-writer lock.
2235 if (cf
->read_lock
) {
2236 ws_warning("Failing due to nested process_specified_records(\"%s\") call!", cf
->filename
);
2239 cf
->read_lock
= true;
2241 cf
->stop_flag
= false;
2244 packet_range_process_init(range
);
2246 /* Iterate through all the packets, printing the packets that
2247 were selected by the current display filter. */
2248 for (framenum
= 1; framenum
<= cf
->count
; framenum
++) {
2249 fdata
= frame_data_sequence_find(cf
->provider
.frames
, framenum
);
2251 /* Create the progress bar if necessary.
2252 We check on every iteration of the loop, so that it takes no
2253 longer than the standard time to create it (otherwise, for a
2254 large file, we might take considerably longer than that standard
2255 time in order to get to the next progress bar step). */
2256 if (show_progress_bar
&& progbar
== NULL
)
2257 progbar
= delayed_create_progress_dlg(cf
->window
, string1
, string2
,
2263 * Update the progress bar, but do it only after PROGBAR_UPDATE_INTERVAL
2264 * has elapsed. Calling update_progress_dlg and packets_bar_update will
2265 * likely trigger UI paint events, which might take a while depending on
2266 * the platform and display. Reset our timer *after* painting.
2268 if (progbar
&& g_timer_elapsed(prog_timer
, NULL
) > PROGBAR_UPDATE_INTERVAL
) {
2269 /* let's not divide by zero. I should never be started
2270 * with count == 0, so let's assert that
2272 ws_assert(cf
->count
> 0);
2273 progbar_val
= (float) progbar_count
/ cf
->count
;
2275 snprintf(progbar_status_str
, sizeof(progbar_status_str
),
2276 "%4u of %u packets", progbar_count
, cf
->count
);
2277 update_progress_dlg(progbar
, progbar_val
, progbar_status_str
);
2279 g_timer_start(prog_timer
);
2282 if (cf
->stop_flag
) {
2283 /* Well, the user decided to abort the operation. Just stop,
2284 and arrange to return PSP_STOPPED to our caller, so they know
2285 it was stopped explicitly. */
2292 if (range
!= NULL
) {
2293 /* do we have to process this packet? */
2294 process_this
= packet_range_process_packet(range
, fdata
);
2295 if (process_this
== range_process_next
) {
2296 /* this packet uninteresting, continue with next one */
2298 } else if (process_this
== range_processing_finished
) {
2299 /* all interesting packets processed, stop the loop */
2304 /* Get the packet */
2305 if (!cf_read_record(cf
, fdata
, &rec
, &buf
)) {
2306 /* Attempt to get the packet failed. */
2310 /* Process the packet */
2311 if (!callback(cf
, fdata
, &rec
, &buf
, callback_args
)) {
2312 /* Callback failed. We assume it reported the error appropriately. */
2316 wtap_rec_reset(&rec
);
2319 /* We're done printing the packets; destroy the progress bar if
2321 if (progbar
!= NULL
)
2322 destroy_progress_dlg(progbar
);
2323 g_timer_destroy(prog_timer
);
2325 ws_assert(cf
->read_lock
);
2326 cf
->read_lock
= false;
2328 wtap_rec_cleanup(&rec
);
2329 ws_buffer_free(&buf
);
2337 } retap_callback_args_t
;
2340 retap_packet(capture_file
*cf
, frame_data
*fdata
, wtap_rec
*rec
, Buffer
*buf
,
2343 retap_callback_args_t
*args
= (retap_callback_args_t
*)argsp
;
2345 epan_dissect_run_with_taps(&args
->edt
, cf
->cd_t
, rec
,
2346 ws_buffer_start_ptr(buf
),
2347 fdata
, args
->cinfo
);
2348 epan_dissect_reset(&args
->edt
);
2354 cf_retap_packets(capture_file
*cf
)
2356 packet_range_t range
;
2357 retap_callback_args_t callback_args
;
2358 bool create_proto_tree
;
2359 bool filtering_tap_listeners
;
2363 /* Presumably the user closed the capture file. */
2365 return CF_READ_ABORTED
;
2368 /* XXX - If cf->read_lock is true, process_specified_records will fail
2369 * due to a nested call. We fail here so that we don't reset the tap
2370 * listeners if this tap isn't going to succeed.
2372 if (cf
->read_lock
) {
2373 ws_warning("Failing due to nested process_specified_records(\"%s\") call!", cf
->filename
);
2374 return CF_READ_ERROR
;
2377 cf_callback_invoke(cf_cb_file_retap_started
, cf
);
2379 /* Do we have any tap listeners with filters? */
2380 filtering_tap_listeners
= have_filtering_tap_listeners();
2382 /* Update references in filters (if any) for the protocol
2383 * tree corresponding to the currently selected frame in the GUI. */
2384 /* XXX - What if we *don't* have a currently selected frame in the GUI,
2385 * but we did the last time we loaded field references? Then they'll
2386 * match something instead of nothing (unless they've been recompiled).
2387 * Should we have a way to clear the field references even with a NULL tree?
2389 if (cf
->edt
!= NULL
&& cf
->edt
->tree
!= NULL
) {
2390 if (filtering_tap_listeners
)
2391 tap_listeners_load_field_references(cf
->edt
);
2394 /* Get the union of the flags for all tap listeners. */
2395 tap_flags
= union_of_tap_listener_flags();
2397 /* If any tap listeners require the columns, construct them. */
2398 callback_args
.cinfo
= (tap_listeners_require_columns()) ? &cf
->cinfo
: NULL
;
2401 * Determine whether we need to create a protocol tree.
2404 * one of the tap listeners is going to apply a filter;
2406 * one of the tap listeners requires a protocol tree.
2409 (filtering_tap_listeners
|| (tap_flags
& TL_REQUIRES_PROTO_TREE
));
2411 /* Reset the tap listeners. */
2412 reset_tap_listeners();
2413 uint32_t count
= cf
->count
;
2415 epan_dissect_init(&callback_args
.edt
, cf
->epan
, create_proto_tree
, false);
2417 /* Iterate through the list of packets, dissecting all packets and
2418 re-running the taps. */
2419 packet_range_init(&range
, cf
);
2420 packet_range_process_init(&range
);
2422 if (cf
->state
== FILE_READ_IN_PROGRESS
) {
2423 /* We're not done with the sequential read of the file and might
2424 * add more frames while process_specified_records is going. We
2425 * don't want to tap new frames twice, so limit the range to the
2426 * frames already here.
2428 * cf_read sets read_lock so we don't tap in case of an offline
2429 * file, but cf_continue_tail and cf_finish_tail don't, and we
2430 * don't want them to, because tapping new packets in a live
2431 * capture is a common use case.
2433 * Note that most other users of process_specified_records (saving,
2434 * printing) do want to process new packets, unlike taps.
2437 char* range_str
= g_strdup_printf("-%u", count
);
2438 packet_range_convert_str(&range
, range_str
);
2441 /* range_t treats a missing number as meaning 1, not 0, and
2442 * reverses the order if backwards; thus the syntax -0 means
2443 * 0-1, so to only take zero packets we do this.
2445 packet_range_convert_str(&range
, "0");
2447 range
.process
= range_process_user_range
;
2450 ret
= process_specified_records(cf
, &range
, "Recalculating statistics on",
2451 "all packets", true, retap_packet
,
2452 &callback_args
, true);
2454 packet_range_cleanup(&range
);
2455 epan_dissect_cleanup(&callback_args
.edt
);
2457 cf_callback_invoke(cf_cb_file_retap_finished
, cf
);
2461 /* Completed successfully. */
2465 /* Well, the user decided to abort the refiltering.
2466 Return CF_READ_ABORTED so our caller knows they did that. */
2467 return CF_READ_ABORTED
;
2470 /* Error while retapping. */
2471 return CF_READ_ERROR
;
2474 ws_assert_not_reached();
2479 print_args_t
*print_args
;
2480 bool print_header_line
;
2481 char *header_line_buf
;
2482 int header_line_buf_len
;
2483 bool print_formfeed
;
2484 bool print_separator
;
2488 int num_visible_cols
;
2491 } print_callback_args_t
;
2494 print_packet(capture_file
*cf
, frame_data
*fdata
, wtap_rec
*rec
, Buffer
*buf
,
2497 print_callback_args_t
*args
= (print_callback_args_t
*)argsp
;
2503 char bookmark_name
[9+10+1]; /* "__frameNNNNNNNNNN__\0" */
2504 char bookmark_title
[6+10+1]; /* "Frame NNNNNNNNNN__\0" */
2505 col_item_t
* col_item
;
2506 const char* col_text
;
2508 /* Fill in the column information if we're printing the summary
2510 if (args
->print_args
->print_summary
) {
2511 col_custom_prime_edt(&args
->edt
, &cf
->cinfo
);
2512 epan_dissect_run(&args
->edt
, cf
->cd_t
, rec
,
2513 ws_buffer_start_ptr(buf
),
2515 epan_dissect_fill_in_columns(&args
->edt
, false, true);
2517 epan_dissect_run(&args
->edt
, cf
->cd_t
, rec
,
2518 ws_buffer_start_ptr(buf
),
2521 if (args
->print_formfeed
) {
2522 if (!new_page(args
->print_args
->stream
))
2526 * Print another header line if we print a packet summary on the
2529 if (args
->print_args
->print_col_headings
)
2530 args
->print_header_line
= true;
2532 if (args
->print_separator
) {
2533 if (!print_line(args
->print_args
->stream
, 0, ""))
2539 * We generate bookmarks, if the output format supports them.
2540 * The name is "__frameN__".
2542 snprintf(bookmark_name
, sizeof bookmark_name
, "__frame%u__", fdata
->num
);
2544 if (args
->print_args
->print_summary
) {
2545 if (!args
->print_args
->print_col_headings
)
2546 args
->print_header_line
= false;
2547 if (args
->print_header_line
) {
2548 if (!print_line(args
->print_args
->stream
, 0, args
->header_line_buf
))
2550 args
->print_header_line
= false; /* we might not need to print any more */
2552 cp
= &args
->line_buf
[0];
2554 for (i
= 0; i
< args
->num_visible_cols
; i
++) {
2555 col_item
= &cf
->cinfo
.columns
[args
->visible_cols
[i
]];
2556 col_text
= get_column_text(&cf
->cinfo
, args
->visible_cols
[i
]);
2557 /* Find the length of the string for this column. */
2558 column_len
= (int) strlen(col_text
);
2559 if (args
->col_widths
[i
] > column_len
)
2560 column_len
= args
->col_widths
[i
];
2562 /* Make sure there's room in the line buffer for the column; if not,
2563 double its length. */
2564 line_len
+= column_len
+ 1; /* "+1" for space */
2565 if (line_len
> args
->line_buf_len
) {
2566 cp_off
= (int) (cp
- args
->line_buf
);
2567 args
->line_buf_len
= 2 * line_len
;
2568 args
->line_buf
= (char *)g_realloc(args
->line_buf
, args
->line_buf_len
+ 1);
2569 cp
= args
->line_buf
+ cp_off
;
2572 /* Right-justify the packet number column. */
2573 if (col_item
->col_fmt
== COL_NUMBER
|| col_item
->col_fmt
== COL_NUMBER_DIS
)
2574 snprintf(cp
, column_len
+1, "%*s", args
->col_widths
[i
], col_text
);
2576 snprintf(cp
, column_len
+1, "%-*s", args
->col_widths
[i
], col_text
);
2578 if (i
!= args
->num_visible_cols
- 1)
2584 * Generate a bookmark, using the summary line as the title.
2586 if (!print_bookmark(args
->print_args
->stream
, bookmark_name
,
2590 if (!print_line(args
->print_args
->stream
, 0, args
->line_buf
))
2594 * Generate a bookmark, using "Frame N" as the title, as we're not
2595 * printing the summary line.
2597 snprintf(bookmark_title
, sizeof bookmark_title
, "Frame %u", fdata
->num
);
2598 if (!print_bookmark(args
->print_args
->stream
, bookmark_name
,
2601 } /* if (print_summary) */
2603 if (args
->print_args
->print_dissections
!= print_dissections_none
) {
2604 if (args
->print_args
->print_summary
) {
2605 /* Separate the summary line from the tree with a blank line. */
2606 if (!print_line(args
->print_args
->stream
, 0, ""))
2610 /* Print the information in that tree. */
2611 if (!proto_tree_print(args
->print_args
->print_dissections
,
2612 args
->print_args
->print_hex
, &args
->edt
, NULL
,
2613 args
->print_args
->stream
))
2616 /* Print a blank line if we print anything after this (aka more than one packet). */
2617 args
->print_separator
= true;
2619 /* Print a header line if we print any more packet summaries */
2620 if (args
->print_args
->print_col_headings
)
2621 args
->print_header_line
= true;
2624 if (args
->print_args
->print_hex
) {
2625 if (args
->print_args
->print_summary
|| (args
->print_args
->print_dissections
!= print_dissections_none
)) {
2626 if (!print_line(args
->print_args
->stream
, 0, ""))
2629 /* Print the full packet data as hex. */
2630 if (!print_hex_data(args
->print_args
->stream
, &args
->edt
, args
->print_args
->hexdump_options
))
2633 /* Print a blank line if we print anything after this (aka more than one packet). */
2634 args
->print_separator
= true;
2636 /* Print a header line if we print any more packet summaries */
2637 if (args
->print_args
->print_col_headings
)
2638 args
->print_header_line
= true;
2639 } /* if (args->print_args->print_dissections != print_dissections_none) */
2641 epan_dissect_reset(&args
->edt
);
2643 /* do we want to have a formfeed between each packet from now on? */
2644 if (args
->print_args
->print_formfeed
) {
2645 args
->print_formfeed
= true;
2651 epan_dissect_reset(&args
->edt
);
2656 cf_print_packets(capture_file
*cf
, print_args_t
*print_args
,
2657 bool show_progress_bar
)
2659 print_callback_args_t callback_args
;
2662 int i
, cp_off
, column_len
, line_len
;
2663 int num_visible_col
= 0, last_visible_col
= 0, visible_col_count
;
2667 bool proto_tree_needed
;
2669 callback_args
.print_args
= print_args
;
2670 callback_args
.print_header_line
= print_args
->print_col_headings
;
2671 callback_args
.header_line_buf
= NULL
;
2672 callback_args
.header_line_buf_len
= 256;
2673 callback_args
.print_formfeed
= false;
2674 callback_args
.print_separator
= false;
2675 callback_args
.line_buf
= NULL
;
2676 callback_args
.line_buf_len
= 256;
2677 callback_args
.col_widths
= NULL
;
2678 callback_args
.num_visible_cols
= 0;
2679 callback_args
.visible_cols
= NULL
;
2681 if (!print_preamble(print_args
->stream
, cf
->filename
, get_ws_vcs_version_info())) {
2682 destroy_print_stream(print_args
->stream
);
2683 return CF_PRINT_WRITE_ERROR
;
2686 if (print_args
->print_summary
) {
2687 /* We're printing packet summaries. Allocate the header line buffer
2688 and get the column widths. */
2689 callback_args
.header_line_buf
= (char *)g_malloc(callback_args
.header_line_buf_len
+ 1);
2691 /* Find the number of visible columns and the last visible column */
2692 for (i
= 0; i
< prefs
.num_cols
; i
++) {
2694 clp
= g_list_nth(prefs
.col_list
, i
);
2695 if (clp
== NULL
) /* Sanity check, Invalid column requested */
2698 cfmt
= (fmt_data
*) clp
->data
;
2699 if (cfmt
->visible
) {
2701 last_visible_col
= i
;
2705 /* if num_visible_col is 0, we are done */
2706 if (num_visible_col
== 0) {
2707 g_free(callback_args
.header_line_buf
);
2711 /* Find the widths for each of the columns - maximum of the
2712 width of the title and the width of the data - and construct
2713 a buffer with a line containing the column titles. */
2714 callback_args
.num_visible_cols
= num_visible_col
;
2715 callback_args
.col_widths
= g_new(int, num_visible_col
);
2716 callback_args
.visible_cols
= g_new(int, num_visible_col
);
2717 cp
= &callback_args
.header_line_buf
[0];
2719 visible_col_count
= 0;
2720 for (i
= 0; i
< cf
->cinfo
.num_cols
; i
++) {
2722 clp
= g_list_nth(prefs
.col_list
, i
);
2723 if (clp
== NULL
) /* Sanity check, Invalid column requested */
2726 cfmt
= (fmt_data
*) clp
->data
;
2727 if (cfmt
->visible
== false)
2730 /* Save the order of visible columns */
2731 callback_args
.visible_cols
[visible_col_count
] = i
;
2733 /* Don't pad the last column. */
2734 if (i
== last_visible_col
)
2735 callback_args
.col_widths
[visible_col_count
] = 0;
2737 callback_args
.col_widths
[visible_col_count
] = (int) strlen(cf
->cinfo
.columns
[i
].col_title
);
2738 data_width
= get_column_char_width(get_column_format(i
));
2739 if (data_width
> callback_args
.col_widths
[visible_col_count
])
2740 callback_args
.col_widths
[visible_col_count
] = data_width
;
2743 /* Find the length of the string for this column. */
2744 column_len
= (int) strlen(cf
->cinfo
.columns
[i
].col_title
);
2745 if (callback_args
.col_widths
[visible_col_count
] > column_len
)
2746 column_len
= callback_args
.col_widths
[visible_col_count
];
2748 /* Make sure there's room in the line buffer for the column; if not,
2749 double its length. */
2750 line_len
+= column_len
+ 1; /* "+1" for space */
2751 if (line_len
> callback_args
.header_line_buf_len
) {
2752 cp_off
= (int) (cp
- callback_args
.header_line_buf
);
2753 callback_args
.header_line_buf_len
= 2 * line_len
;
2754 callback_args
.header_line_buf
= (char *)g_realloc(callback_args
.header_line_buf
,
2755 callback_args
.header_line_buf_len
+ 1);
2756 cp
= callback_args
.header_line_buf
+ cp_off
;
2759 /* Right-justify the packet number column. */
2760 /* if (cf->cinfo.col_fmt[i] == COL_NUMBER || cf->cinfo.col_fmt[i] == COL_NUMBER_DIS)
2761 snprintf(cp, column_len+1, "%*s", callback_args.col_widths[visible_col_count], cf->cinfo.columns[i].col_title);
2763 snprintf(cp
, column_len
+1, "%-*s", callback_args
.col_widths
[visible_col_count
], cf
->cinfo
.columns
[i
].col_title
);
2765 if (i
!= cf
->cinfo
.num_cols
- 1)
2768 visible_col_count
++;
2772 /* Now start out the main line buffer with the same length as the
2773 header line buffer. */
2774 callback_args
.line_buf_len
= callback_args
.header_line_buf_len
;
2775 callback_args
.line_buf
= (char *)g_malloc(callback_args
.line_buf_len
+ 1);
2776 } /* if (print_summary) */
2778 /* Create the protocol tree, and make it visible, if we're printing
2779 the dissection or the hex data.
2780 XXX - do we need it if we're just printing the hex data? */
2782 callback_args
.print_args
->print_dissections
!= print_dissections_none
||
2783 callback_args
.print_args
->print_hex
||
2784 have_custom_cols(&cf
->cinfo
) || have_field_extractors();
2785 epan_dissect_init(&callback_args
.edt
, cf
->epan
, proto_tree_needed
, proto_tree_needed
);
2787 /* Iterate through the list of packets, printing the packets we were
2789 ret
= process_specified_records(cf
, &print_args
->range
, "Printing",
2790 "selected packets", true, print_packet
,
2791 &callback_args
, show_progress_bar
);
2792 epan_dissect_cleanup(&callback_args
.edt
);
2793 g_free(callback_args
.header_line_buf
);
2794 g_free(callback_args
.line_buf
);
2795 g_free(callback_args
.col_widths
);
2796 g_free(callback_args
.visible_cols
);
2801 /* Completed successfully. */
2805 /* Well, the user decided to abort the printing.
2807 XXX - note that what got generated before they did that
2808 will get printed if we're piping to a print program; we'd
2809 have to write to a file and then hand that to the print
2810 program to make it actually not print anything. */
2814 /* Error while printing.
2816 XXX - note that what got generated before they did that
2817 will get printed if we're piping to a print program; we'd
2818 have to write to a file and then hand that to the print
2819 program to make it actually not print anything. */
2820 destroy_print_stream(print_args
->stream
);
2821 return CF_PRINT_WRITE_ERROR
;
2824 if (!print_finale(print_args
->stream
)) {
2825 destroy_print_stream(print_args
->stream
);
2826 return CF_PRINT_WRITE_ERROR
;
2829 if (!destroy_print_stream(print_args
->stream
))
2830 return CF_PRINT_WRITE_ERROR
;
2838 print_args_t
*print_args
;
2839 json_dumper jdumper
;
2840 } write_packet_callback_args_t
;
2843 write_pdml_packet(capture_file
*cf
, frame_data
*fdata
, wtap_rec
*rec
,
2844 Buffer
*buf
, void *argsp
)
2846 write_packet_callback_args_t
*args
= (write_packet_callback_args_t
*)argsp
;
2848 /* Create the protocol tree, but don't fill in the column information. */
2849 epan_dissect_run(&args
->edt
, cf
->cd_t
, rec
,
2850 ws_buffer_start_ptr(buf
),
2853 /* Write out the information in that tree. */
2854 write_pdml_proto_tree(NULL
, &args
->edt
, &cf
->cinfo
, args
->fh
, false);
2856 epan_dissect_reset(&args
->edt
);
2858 return !ferror(args
->fh
);
2862 cf_write_pdml_packets(capture_file
*cf
, print_args_t
*print_args
)
2864 write_packet_callback_args_t callback_args
;
2868 fh
= ws_fopen(print_args
->file
, "w");
2870 return CF_PRINT_OPEN_ERROR
; /* attempt to open destination failed */
2872 write_pdml_preamble(fh
, cf
->filename
);
2875 return CF_PRINT_WRITE_ERROR
;
2878 callback_args
.fh
= fh
;
2879 callback_args
.print_args
= print_args
;
2880 epan_dissect_init(&callback_args
.edt
, cf
->epan
, true, true);
2882 /* Iterate through the list of packets, printing the packets we were
2884 ret
= process_specified_records(cf
, &print_args
->range
, "Writing PDML",
2885 "selected packets", true,
2886 write_pdml_packet
, &callback_args
, true);
2888 epan_dissect_cleanup(&callback_args
.edt
);
2893 /* Completed successfully. */
2897 /* Well, the user decided to abort the printing. */
2901 /* Error while printing. */
2903 return CF_PRINT_WRITE_ERROR
;
2906 write_pdml_finale(fh
);
2909 return CF_PRINT_WRITE_ERROR
;
2912 /* XXX - check for an error */
2919 write_psml_packet(capture_file
*cf
, frame_data
*fdata
, wtap_rec
*rec
,
2920 Buffer
*buf
, void *argsp
)
2922 write_packet_callback_args_t
*args
= (write_packet_callback_args_t
*)argsp
;
2924 /* Fill in the column information */
2925 col_custom_prime_edt(&args
->edt
, &cf
->cinfo
);
2926 epan_dissect_run(&args
->edt
, cf
->cd_t
, rec
,
2927 ws_buffer_start_ptr(buf
),
2929 epan_dissect_fill_in_columns(&args
->edt
, false, true);
2931 /* Write out the column information. */
2932 write_psml_columns(&args
->edt
, args
->fh
, false);
2934 epan_dissect_reset(&args
->edt
);
2936 return !ferror(args
->fh
);
2940 cf_write_psml_packets(capture_file
*cf
, print_args_t
*print_args
)
2942 write_packet_callback_args_t callback_args
;
2946 bool proto_tree_needed
;
2948 fh
= ws_fopen(print_args
->file
, "w");
2950 return CF_PRINT_OPEN_ERROR
; /* attempt to open destination failed */
2952 write_psml_preamble(&cf
->cinfo
, fh
);
2955 return CF_PRINT_WRITE_ERROR
;
2958 callback_args
.fh
= fh
;
2959 callback_args
.print_args
= print_args
;
2961 /* Fill in the column information, only create the protocol tree
2962 if having custom columns or field extractors. */
2963 proto_tree_needed
= have_custom_cols(&cf
->cinfo
) || have_field_extractors();
2964 epan_dissect_init(&callback_args
.edt
, cf
->epan
, proto_tree_needed
, proto_tree_needed
);
2966 /* Iterate through the list of packets, printing the packets we were
2968 ret
= process_specified_records(cf
, &print_args
->range
, "Writing PSML",
2969 "selected packets", true,
2970 write_psml_packet
, &callback_args
, true);
2972 epan_dissect_cleanup(&callback_args
.edt
);
2977 /* Completed successfully. */
2981 /* Well, the user decided to abort the printing. */
2985 /* Error while printing. */
2987 return CF_PRINT_WRITE_ERROR
;
2990 write_psml_finale(fh
);
2993 return CF_PRINT_WRITE_ERROR
;
2996 /* XXX - check for an error */
3003 write_csv_packet(capture_file
*cf
, frame_data
*fdata
, wtap_rec
*rec
,
3004 Buffer
*buf
, void *argsp
)
3006 write_packet_callback_args_t
*args
= (write_packet_callback_args_t
*)argsp
;
3008 /* Fill in the column information */
3009 col_custom_prime_edt(&args
->edt
, &cf
->cinfo
);
3010 epan_dissect_run(&args
->edt
, cf
->cd_t
, rec
,
3011 ws_buffer_start_ptr(buf
),
3013 epan_dissect_fill_in_columns(&args
->edt
, false, true);
3015 /* Write out the column information. */
3016 write_csv_columns(&args
->edt
, args
->fh
);
3018 epan_dissect_reset(&args
->edt
);
3020 return !ferror(args
->fh
);
3024 cf_write_csv_packets(capture_file
*cf
, print_args_t
*print_args
)
3026 write_packet_callback_args_t callback_args
;
3027 bool proto_tree_needed
;
3031 fh
= ws_fopen(print_args
->file
, "w");
3033 return CF_PRINT_OPEN_ERROR
; /* attempt to open destination failed */
3035 write_csv_column_titles(&cf
->cinfo
, fh
);
3038 return CF_PRINT_WRITE_ERROR
;
3041 callback_args
.fh
= fh
;
3042 callback_args
.print_args
= print_args
;
3044 /* only create the protocol tree if having custom columns or field extractors. */
3045 proto_tree_needed
= have_custom_cols(&cf
->cinfo
) || have_field_extractors();
3046 epan_dissect_init(&callback_args
.edt
, cf
->epan
, proto_tree_needed
, proto_tree_needed
);
3048 /* Iterate through the list of packets, printing the packets we were
3050 ret
= process_specified_records(cf
, &print_args
->range
, "Writing CSV",
3051 "selected packets", true,
3052 write_csv_packet
, &callback_args
, true);
3054 epan_dissect_cleanup(&callback_args
.edt
);
3059 /* Completed successfully. */
3063 /* Well, the user decided to abort the printing. */
3067 /* Error while printing. */
3069 return CF_PRINT_WRITE_ERROR
;
3072 /* XXX - check for an error */
3079 carrays_write_packet(capture_file
*cf
, frame_data
*fdata
, wtap_rec
*rec
,
3080 Buffer
*buf
, void *argsp
)
3082 write_packet_callback_args_t
*args
= (write_packet_callback_args_t
*)argsp
;
3084 epan_dissect_run(&args
->edt
, cf
->cd_t
, rec
,
3085 ws_buffer_start_ptr(buf
),
3087 write_carrays_hex_data(fdata
->num
, args
->fh
, &args
->edt
);
3088 epan_dissect_reset(&args
->edt
);
3090 return !ferror(args
->fh
);
3094 cf_write_carrays_packets(capture_file
*cf
, print_args_t
*print_args
)
3096 write_packet_callback_args_t callback_args
;
3100 fh
= ws_fopen(print_args
->file
, "w");
3103 return CF_PRINT_OPEN_ERROR
; /* attempt to open destination failed */
3107 return CF_PRINT_WRITE_ERROR
;
3110 callback_args
.fh
= fh
;
3111 callback_args
.print_args
= print_args
;
3112 epan_dissect_init(&callback_args
.edt
, cf
->epan
, true, true);
3114 /* Iterate through the list of packets, printing the packets we were
3116 ret
= process_specified_records(cf
, &print_args
->range
,
3118 "selected packets", true,
3119 carrays_write_packet
, &callback_args
, true);
3121 epan_dissect_cleanup(&callback_args
.edt
);
3125 /* Completed successfully. */
3128 /* Well, the user decided to abort the printing. */
3131 /* Error while printing. */
3133 return CF_PRINT_WRITE_ERROR
;
3141 write_json_packet(capture_file
*cf
, frame_data
*fdata
, wtap_rec
*rec
,
3142 Buffer
*buf
, void *argsp
)
3144 write_packet_callback_args_t
*args
= (write_packet_callback_args_t
*)argsp
;
3146 /* Create the protocol tree, but don't fill in the column information. */
3147 epan_dissect_run(&args
->edt
, cf
->cd_t
, rec
,
3148 ws_buffer_start_ptr(buf
),
3151 /* Write out the information in that tree. */
3152 write_json_proto_tree(NULL
, args
->print_args
->print_dissections
,
3153 args
->print_args
->print_hex
,
3154 &args
->edt
, &cf
->cinfo
, proto_node_group_children_by_unique
,
3157 epan_dissect_reset(&args
->edt
);
3159 return !ferror(args
->fh
);
3163 cf_write_json_packets(capture_file
*cf
, print_args_t
*print_args
)
3165 write_packet_callback_args_t callback_args
;
3169 fh
= ws_fopen(print_args
->file
, "w");
3171 return CF_PRINT_OPEN_ERROR
; /* attempt to open destination failed */
3173 callback_args
.jdumper
= write_json_preamble(fh
);
3176 return CF_PRINT_WRITE_ERROR
;
3179 callback_args
.fh
= fh
;
3180 callback_args
.print_args
= print_args
;
3181 epan_dissect_init(&callback_args
.edt
, cf
->epan
, true, true);
3183 /* Iterate through the list of packets, printing the packets we were
3185 ret
= process_specified_records(cf
, &print_args
->range
, "Writing JSON",
3186 "selected packets", true,
3187 write_json_packet
, &callback_args
, true);
3189 epan_dissect_cleanup(&callback_args
.edt
);
3194 /* Completed successfully. */
3198 /* Well, the user decided to abort the printing. */
3202 /* Error while printing. */
3204 return CF_PRINT_WRITE_ERROR
;
3207 write_json_finale(&callback_args
.jdumper
);
3210 return CF_PRINT_WRITE_ERROR
;
3213 /* XXX - check for an error */
3220 cf_find_packet_protocol_tree(capture_file
*cf
, const char *string
,
3221 search_direction dir
, bool multiple
)
3225 mdata
.frame_matched
= false;
3227 mdata
.string
= string
;
3228 mdata
.string_len
= strlen(string
);
3230 mdata
.prev_finfo
= cf
->finfo_selected
;
3231 if (multiple
&& cf
->finfo_selected
&& cf
->edt
) {
3232 if (dir
== SD_FORWARD
) {
3233 proto_tree_children_foreach(cf
->edt
->tree
, match_subtree_text
, &mdata
);
3235 proto_tree_children_foreach(cf
->edt
->tree
, match_subtree_text_reverse
, &mdata
);
3237 if (mdata
.frame_matched
) {
3238 packet_list_select_finfo(mdata
.finfo
);
3242 return find_packet(cf
, match_protocol_tree
, &mdata
, dir
, true);
3246 cf_find_string_protocol_tree(capture_file
*cf
, proto_tree
*tree
)
3249 mdata
.frame_matched
= false;
3251 mdata
.string
= convert_string_case(cf
->sfilter
, cf
->case_type
);
3252 mdata
.string_len
= strlen(mdata
.string
);
3254 mdata
.prev_finfo
= NULL
;
3255 /* Iterate through all the nodes looking for matching text */
3256 if (cf
->dir
== SD_FORWARD
) {
3257 proto_tree_children_foreach(tree
, match_subtree_text
, &mdata
);
3259 proto_tree_children_foreach(tree
, match_subtree_text_reverse
, &mdata
);
3261 g_free((char *)mdata
.string
);
3262 return mdata
.frame_matched
? mdata
.finfo
: NULL
;
3266 match_protocol_tree(capture_file
*cf
, frame_data
*fdata
,
3267 wtap_rec
*rec
, Buffer
*buf
, void *criterion
)
3269 match_data
*mdata
= (match_data
*)criterion
;
3272 /* Load the frame's data. */
3273 if (!cf_read_record(cf
, fdata
, rec
, buf
)) {
3274 /* Attempt to get the packet failed. */
3278 /* Construct the protocol tree, including the displayed text */
3279 epan_dissect_init(&edt
, cf
->epan
, true, true);
3280 /* We don't need the column information */
3281 epan_dissect_run(&edt
, cf
->cd_t
, rec
,
3282 ws_buffer_start_ptr(buf
),
3285 /* Iterate through all the nodes, seeing if they have text that matches. */
3287 mdata
->frame_matched
= false;
3288 mdata
->halt
= false;
3289 mdata
->prev_finfo
= NULL
;
3290 /* We don't care about the direction here, because we're just looking
3291 * for one match and we'll destroy this tree anyway. (We find the actual
3292 * field later in PacketList::selectionChanged().) Forwards is faster.
3294 proto_tree_children_foreach(edt
.tree
, match_subtree_text
, mdata
);
3295 epan_dissect_cleanup(&edt
);
3296 return mdata
->frame_matched
? MR_MATCHED
: MR_NOTMATCHED
;
3300 match_subtree_text(proto_node
*node
, void *data
)
3302 match_data
*mdata
= (match_data
*) data
;
3303 const char *string
= mdata
->string
;
3304 size_t string_len
= mdata
->string_len
;
3305 capture_file
*cf
= mdata
->cf
;
3306 field_info
*fi
= PNODE_FINFO(node
);
3307 char label_str
[ITEM_LABEL_LENGTH
];
3310 uint32_t i
, i_restart
;
3314 /* dissection with an invisible proto tree? */
3317 if (mdata
->frame_matched
) {
3318 /* We already had a match; don't bother doing any more work. */
3322 /* Don't match invisible entries. */
3323 if (proto_item_is_hidden(node
))
3326 if (mdata
->prev_finfo
) {
3327 /* Haven't found the old match, so don't match this node. */
3328 if (fi
== mdata
->prev_finfo
) {
3329 /* Found the old match, look for the next one after this. */
3330 mdata
->prev_finfo
= NULL
;
3333 /* was a free format label produced? */
3335 label_ptr
= fi
->rep
->representation
;
3337 /* no, make a generic label */
3338 label_ptr
= label_str
;
3339 proto_item_fill_label(fi
, label_str
, NULL
);
3343 if (ws_regex_matches(cf
->regex
, label_ptr
)) {
3344 mdata
->frame_matched
= true;
3348 } else if (cf
->case_type
) {
3349 /* Case insensitive match */
3350 label_len
= strlen(label_ptr
);
3352 for (i
= 0; i
< label_len
; i
++) {
3353 if (i_restart
== 0 && c_match
== 0 && (label_len
- i
< string_len
))
3355 c_char
= label_ptr
[i
];
3356 c_char
= g_ascii_toupper(c_char
);
3357 /* If c_match is non-zero, save candidate for retrying full match. */
3358 if (c_match
> 0 && i_restart
== 0 && c_char
== string
[0])
3360 if (c_char
== string
[c_match
]) {
3362 if (c_match
== string_len
) {
3363 mdata
->frame_matched
= true;
3365 /* No need to look further; we have a match */
3368 } else if (i_restart
) {
3375 } else if (strstr(label_ptr
, string
) != NULL
) {
3376 /* Case sensitive match */
3377 mdata
->frame_matched
= true;
3383 /* Recurse into the subtree, if it exists */
3384 if (node
->first_child
!= NULL
)
3385 proto_tree_children_foreach(node
, match_subtree_text
, mdata
);
3389 match_subtree_text_reverse(proto_node
*node
, void *data
)
3391 match_data
*mdata
= (match_data
*) data
;
3392 const char *string
= mdata
->string
;
3393 size_t string_len
= mdata
->string_len
;
3394 capture_file
*cf
= mdata
->cf
;
3395 field_info
*fi
= PNODE_FINFO(node
);
3396 char label_str
[ITEM_LABEL_LENGTH
];
3399 uint32_t i
, i_restart
;
3403 /* dissection with an invisible proto tree? */
3406 /* We don't have an easy way to search backwards in the tree
3407 * (see also, proto_find_field_from_offset()) because we don't
3408 * have a previous node pointer, so we search backwards by
3409 * searching forwards, only stopping if we see the old match
3417 /* Don't match invisible entries. */
3418 if (proto_item_is_hidden(node
))
3421 if (mdata
->prev_finfo
&& fi
== mdata
->prev_finfo
) {
3422 /* Found the old match, use the previous match. */
3427 /* was a free format label produced? */
3429 label_ptr
= fi
->rep
->representation
;
3431 /* no, make a generic label */
3432 label_ptr
= label_str
;
3433 proto_item_fill_label(fi
, label_str
, NULL
);
3437 if (ws_regex_matches(cf
->regex
, label_ptr
)) {
3438 mdata
->frame_matched
= true;
3441 } else if (cf
->case_type
) {
3442 /* Case insensitive match */
3443 label_len
= strlen(label_ptr
);
3445 for (i
= 0; i
< label_len
; i
++) {
3446 if (i_restart
== 0 && c_match
== 0 && (label_len
- i
< string_len
))
3448 c_char
= label_ptr
[i
];
3449 c_char
= g_ascii_toupper(c_char
);
3450 /* If c_match is non-zero, save candidate for retrying full match. */
3451 if (c_match
> 0 && i_restart
== 0 && c_char
== string
[0])
3453 if (c_char
== string
[c_match
]) {
3455 if (c_match
== string_len
) {
3456 mdata
->frame_matched
= true;
3460 } else if (i_restart
) {
3467 } else if (strstr(label_ptr
, string
) != NULL
) {
3468 /* Case sensitive match */
3469 mdata
->frame_matched
= true;
3473 /* Recurse into the subtree, if it exists */
3474 if (node
->first_child
!= NULL
)
3475 proto_tree_children_foreach(node
, match_subtree_text_reverse
, mdata
);
3479 cf_find_packet_summary_line(capture_file
*cf
, const char *string
,
3480 search_direction dir
)
3484 mdata
.string
= string
;
3485 mdata
.string_len
= strlen(string
);
3486 return find_packet(cf
, match_summary_line
, &mdata
, dir
, true);
3490 match_summary_line(capture_file
*cf
, frame_data
*fdata
,
3491 wtap_rec
*rec
, Buffer
*buf
, void *criterion
)
3493 match_data
*mdata
= (match_data
*)criterion
;
3494 const char *string
= mdata
->string
;
3495 size_t string_len
= mdata
->string_len
;
3497 const char *info_column
;
3498 size_t info_column_len
;
3499 match_result result
= MR_NOTMATCHED
;
3501 uint32_t i
, i_restart
;
3505 /* Load the frame's data. */
3506 if (!cf_read_record(cf
, fdata
, rec
, buf
)) {
3507 /* Attempt to get the packet failed. */
3511 /* Don't bother constructing the protocol tree */
3512 epan_dissect_init(&edt
, cf
->epan
, false, false);
3513 /* Get the column information */
3514 epan_dissect_run(&edt
, cf
->cd_t
, rec
,
3515 ws_buffer_start_ptr(buf
),
3518 /* Find the Info column */
3519 for (colx
= 0; colx
< cf
->cinfo
.num_cols
; colx
++) {
3520 if (cf
->cinfo
.columns
[colx
].fmt_matx
[COL_INFO
]) {
3521 /* Found it. See if we match. */
3522 info_column
= get_column_text(edt
.pi
.cinfo
, colx
);
3523 info_column_len
= strlen(info_column
);
3525 if (ws_regex_matches(cf
->regex
, info_column
)) {
3526 result
= MR_MATCHED
;
3529 } else if (cf
->case_type
) {
3530 /* Case insensitive match */
3532 for (i
= 0; i
< info_column_len
; i
++) {
3533 if (i_restart
== 0 && c_match
== 0 && (info_column_len
- i
< string_len
))
3535 c_char
= info_column
[i
];
3536 c_char
= g_ascii_toupper(c_char
);
3537 /* If c_match is non-zero, save candidate for retrying full match. */
3538 if (c_match
> 0 && i_restart
== 0 && c_char
== string
[0])
3540 if (c_char
== string
[c_match
]) {
3542 if (c_match
== string_len
) {
3543 result
= MR_MATCHED
;
3546 } else if (i_restart
) {
3553 } else if (strstr(info_column
, string
) != NULL
) {
3554 /* Case sensitive match */
3555 result
= MR_MATCHED
;
3560 epan_dissect_cleanup(&edt
);
3565 const uint8_t *data
;
3567 ws_mempbrk_pattern
*pattern
;
3568 } cbs_t
; /* "Counted byte string" */
3572 * The current match_* routines only support ASCII case insensitivity and don't
3573 * convert UTF-8 inputs to UTF-16 for matching. The UTF-16 support just
3574 * interleaves with \0 bytes, which works for 7 bit ASCII.
3576 * We could modify them to use the GLib Unicode routines or the International
3577 * Components for Unicode library but it's not apparent that we could do so
3578 * without consuming a lot more CPU and memory or that searching would be
3579 * significantly better.
3581 * XXX: We could test the search string to see if it's all ASCII, and if not
3582 * use Unicode aware routines for case insensitive searches or any UTF-16
3587 cf_find_packet_data(capture_file
*cf
, const uint8_t *string
, size_t string_size
,
3588 search_direction dir
, bool multiple
)
3592 ws_mempbrk_pattern pattern
= {0};
3593 ws_match_function match_function
;
3596 info
.data_len
= string_size
;
3598 /* Regex, String or hex search? */
3600 /* Regular Expression search */
3601 match_function
= (dir
== SD_FORWARD
) ? match_regex
: match_regex_reverse
;
3602 } else if (cf
->string
) {
3603 /* String search - what type of string? */
3604 if (cf
->case_type
) {
3605 needles
[0] = string
[0];
3606 needles
[1] = g_ascii_tolower(needles
[0]);
3608 ws_mempbrk_compile(&pattern
, needles
);
3609 info
.pattern
= &pattern
;
3610 switch (cf
->scs_type
) {
3612 case SCS_NARROW_AND_WIDE
:
3613 match_function
= (dir
== SD_FORWARD
) ? match_narrow_and_wide_case
: match_narrow_and_wide_case_reverse
;
3617 match_function
= (dir
== SD_FORWARD
) ? match_narrow_case
: match_narrow_case_reverse
;
3621 match_function
= (dir
== SD_FORWARD
) ? match_wide_case
: match_wide_case_reverse
;
3625 ws_assert_not_reached();
3630 switch (cf
->scs_type
) {
3632 case SCS_NARROW_AND_WIDE
:
3633 match_function
= (dir
== SD_FORWARD
) ? match_narrow_and_wide
: match_narrow_and_wide_reverse
;
3637 /* Narrow, case-sensitive match is the same as looking
3638 * for a converted hexstring. */
3639 match_function
= (dir
== SD_FORWARD
) ? match_binary
: match_binary_reverse
;
3643 match_function
= (dir
== SD_FORWARD
) ? match_wide
: match_wide_reverse
;
3647 ws_assert_not_reached();
3652 match_function
= (dir
== SD_FORWARD
) ? match_binary
: match_binary_reverse
;
3655 if (multiple
&& cf
->current_frame
&& (cf
->search_pos
|| cf
->search_len
)) {
3656 /* Use the current frame (this will perform the equivalent of
3657 * cf_read_current_record() in match_function).
3659 if (match_function(cf
, cf
->current_frame
, &cf
->rec
, &cf
->buf
, &info
)) {
3660 cf
->search_in_progress
= true;
3662 field_info
*fi
= NULL
;
3663 /* The regex match can match an empty string. */
3664 if (cf
->search_len
) {
3665 fi
= proto_find_field_from_offset(cf
->edt
->tree
, cf
->search_pos
+ cf
->search_len
- 1, cf
->edt
->tvb
);
3667 packet_list_select_finfo(fi
);
3669 packet_list_select_row_from_data(cf
->current_frame
);
3671 cf
->search_in_progress
= false;
3675 cf
->search_pos
= 0; /* Reset the position */
3676 cf
->search_len
= 0; /* Reset length */
3677 return find_packet(cf
, match_function
, &info
, dir
, true);
3681 match_narrow_and_wide(capture_file
*cf
, frame_data
*fdata
,
3682 wtap_rec
*rec
, Buffer
*buf
, void *criterion
)
3684 cbs_t
*info
= (cbs_t
*)criterion
;
3685 const uint8_t *ascii_text
= info
->data
;
3686 size_t textlen
= info
->data_len
;
3687 match_result result
;
3689 uint8_t *pd
, *buf_start
, *buf_end
;
3694 /* Load the frame's data. */
3695 if (!cf_read_record(cf
, fdata
, rec
, buf
)) {
3696 /* Attempt to get the packet failed. */
3700 result
= MR_NOTMATCHED
;
3701 buf_len
= fdata
->cap_len
;
3702 buf_start
= ws_buffer_start_ptr(buf
);
3703 buf_end
= buf_start
+ buf_len
;
3705 if (cf
->search_len
|| cf
->search_pos
) {
3706 /* we want to start searching one byte past the previous match start */
3707 pd
+= cf
->search_pos
+ 1;
3709 for (; pd
< buf_end
; pd
++) {
3710 pd
= (uint8_t *)memchr(pd
, ascii_text
[0], buf_end
- pd
);
3711 if (pd
== NULL
) break;
3712 /* Try narrow match at this start location */
3714 for (i
= 0; pd
+ i
< buf_end
; i
++) {
3716 if (c_char
== ascii_text
[c_match
]) {
3718 if (c_match
== textlen
) {
3719 result
= MR_MATCHED
;
3720 /* Save position and length for highlighting the field. */
3721 cf
->search_pos
= (uint32_t)(pd
- buf_start
);
3722 cf
->search_len
= (uint32_t)(i
+ 1);
3730 /* Now try wide match at the same start location. */
3732 for (i
= 0; pd
+ i
< buf_end
; i
++) {
3734 if (c_char
== ascii_text
[c_match
]) {
3736 if (c_match
== textlen
) {
3737 result
= MR_MATCHED
;
3738 /* Save position and length for highlighting the field. */
3739 cf
->search_pos
= (uint32_t)(pd
- buf_start
);
3740 cf
->search_len
= (uint32_t)(i
+ 1);
3744 if (pd
+ i
>= buf_end
|| pd
[i
] != '\0') break;
3756 match_narrow_and_wide_reverse(capture_file
*cf
, frame_data
*fdata
,
3757 wtap_rec
*rec
, Buffer
*buf
, void *criterion
)
3759 cbs_t
*info
= (cbs_t
*)criterion
;
3760 const uint8_t *ascii_text
= info
->data
;
3761 size_t textlen
= info
->data_len
;
3762 match_result result
;
3764 uint8_t *pd
, *buf_start
, *buf_end
;
3769 /* Load the frame's data. */
3770 if (!cf_read_record(cf
, fdata
, rec
, buf
)) {
3771 /* Attempt to get the packet failed. */
3775 result
= MR_NOTMATCHED
;
3776 /* Has to be room to hold the sought data. */
3777 if (textlen
> fdata
->cap_len
) {
3780 buf_len
= fdata
->cap_len
;
3781 buf_start
= ws_buffer_start_ptr(buf
);
3782 buf_end
= buf_start
+ buf_len
;
3783 pd
= buf_end
- textlen
;
3784 if (cf
->search_len
|| cf
->search_pos
) {
3785 /* we want to start searching one byte before the previous match start */
3786 pd
= buf_start
+ cf
->search_pos
- 1;
3788 for (; pd
< buf_end
; pd
++) {
3789 pd
= (uint8_t *)ws_memrchr(buf_start
, ascii_text
[0], pd
- buf_start
+ 1);
3790 if (pd
== NULL
) break;
3791 /* Try narrow match at this start location */
3793 for (i
= 0; pd
+ i
< buf_end
; i
++) {
3795 if (c_char
== ascii_text
[c_match
]) {
3797 if (c_match
== textlen
) {
3798 result
= MR_MATCHED
;
3799 /* Save position and length for highlighting the field. */
3800 cf
->search_pos
= (uint32_t)(pd
- buf_start
);
3801 cf
->search_len
= (uint32_t)(i
+ 1);
3809 /* Now try wide match at the same start location. */
3811 for (i
= 0; pd
+ i
< buf_end
; i
++) {
3813 if (c_char
== ascii_text
[c_match
]) {
3815 if (c_match
== textlen
) {
3816 result
= MR_MATCHED
;
3817 /* Save position and length for highlighting the field. */
3818 cf
->search_pos
= (uint32_t)(pd
- buf_start
);
3819 cf
->search_len
= (uint32_t)(i
+ 1);
3823 if (pd
+ i
>= buf_end
|| pd
[i
] != '\0') break;
3834 /* Case insensitive match */
3836 match_narrow_and_wide_case(capture_file
*cf
, frame_data
*fdata
,
3837 wtap_rec
*rec
, Buffer
*buf
, void *criterion
)
3839 cbs_t
*info
= (cbs_t
*)criterion
;
3840 const uint8_t *ascii_text
= info
->data
;
3841 size_t textlen
= info
->data_len
;
3842 ws_mempbrk_pattern
*pattern
= info
->pattern
;
3843 match_result result
;
3845 uint8_t *pd
, *buf_start
, *buf_end
;
3850 /* Load the frame's data. */
3851 if (!cf_read_record(cf
, fdata
, rec
, buf
)) {
3852 /* Attempt to get the packet failed. */
3856 ws_assert(pattern
!= NULL
);
3858 result
= MR_NOTMATCHED
;
3859 buf_len
= fdata
->cap_len
;
3860 buf_start
= ws_buffer_start_ptr(buf
);
3861 buf_end
= buf_start
+ buf_len
;
3863 if (cf
->search_len
|| cf
->search_pos
) {
3864 /* we want to start searching one byte past the previous match start */
3865 pd
+= cf
->search_pos
+ 1;
3867 for (; pd
< buf_end
; pd
++) {
3868 pd
= (uint8_t *)ws_mempbrk_exec(pd
, buf_end
- pd
, pattern
, &c_char
);
3869 if (pd
== NULL
) break;
3870 /* Try narrow match at this start location */
3872 for (i
= 0; pd
+ i
< buf_end
; i
++) {
3873 c_char
= g_ascii_toupper(pd
[i
]);
3874 if (c_char
== ascii_text
[c_match
]) {
3876 if (c_match
== textlen
) {
3877 result
= MR_MATCHED
;
3878 /* Save position and length for highlighting the field. */
3879 cf
->search_pos
= (uint32_t)(pd
- buf_start
);
3880 cf
->search_len
= (uint32_t)(i
+ 1);
3888 /* Now try wide match at the same start location. */
3890 for (i
= 0; pd
+ i
< buf_end
; i
++) {
3891 c_char
= g_ascii_toupper(pd
[i
]);
3892 if (c_char
== ascii_text
[c_match
]) {
3894 if (c_match
== textlen
) {
3895 result
= MR_MATCHED
;
3896 /* Save position and length for highlighting the field. */
3897 cf
->search_pos
= (uint32_t)(pd
- buf_start
);
3898 cf
->search_len
= (uint32_t)(i
+ 1);
3902 if (pd
+ i
>= buf_end
|| pd
[i
] != '\0') break;
3914 match_narrow_and_wide_case_reverse(capture_file
*cf
, frame_data
*fdata
,
3915 wtap_rec
*rec
, Buffer
*buf
, void *criterion
)
3917 cbs_t
*info
= (cbs_t
*)criterion
;
3918 const uint8_t *ascii_text
= info
->data
;
3919 size_t textlen
= info
->data_len
;
3920 ws_mempbrk_pattern
*pattern
= info
->pattern
;
3921 match_result result
;
3923 uint8_t *pd
, *buf_start
, *buf_end
;
3928 /* Load the frame's data. */
3929 if (!cf_read_record(cf
, fdata
, rec
, buf
)) {
3930 /* Attempt to get the packet failed. */
3934 ws_assert(pattern
!= NULL
);
3936 result
= MR_NOTMATCHED
;
3937 /* Has to be room to hold the sought data. */
3938 if (textlen
> fdata
->cap_len
) {
3941 buf_len
= fdata
->cap_len
;
3942 buf_start
= ws_buffer_start_ptr(buf
);
3943 buf_end
= buf_start
+ buf_len
;
3944 pd
= buf_end
- textlen
;
3945 if (cf
->search_len
|| cf
->search_pos
) {
3946 /* we want to start searching one byte before the previous match start */
3947 pd
= buf_start
+ cf
->search_pos
- 1;
3949 for (; pd
>= buf_start
; pd
--) {
3950 pd
= (uint8_t *)ws_memrpbrk_exec(buf_start
, pd
- buf_start
+ 1, pattern
, &c_char
);
3951 if (pd
== NULL
) break;
3952 /* Try narrow match at this start location */
3954 for (i
= 0; pd
+ i
< buf_end
; i
++) {
3955 c_char
= g_ascii_toupper(pd
[i
]);
3956 if (c_char
== ascii_text
[c_match
]) {
3958 if (c_match
== textlen
) {
3959 result
= MR_MATCHED
;
3960 /* Save position and length for highlighting the field. */
3961 cf
->search_pos
= (uint32_t)(pd
- buf_start
);
3962 cf
->search_len
= (uint32_t)(i
+ 1);
3970 /* Now try wide match at the same start location. */
3972 for (i
= 0; pd
+ i
< buf_end
; i
++) {
3973 c_char
= g_ascii_toupper(pd
[i
]);
3974 if (c_char
== ascii_text
[c_match
]) {
3976 if (c_match
== textlen
) {
3977 result
= MR_MATCHED
;
3978 /* Save position and length for highlighting the field. */
3979 cf
->search_pos
= (uint32_t)(pd
- buf_start
);
3980 cf
->search_len
= (uint32_t)(i
+ 1);
3984 if (pd
+ i
>= buf_end
|| pd
[i
] != '\0') break;
3995 /* Case insensitive match */
3997 match_narrow_case(capture_file
*cf
, frame_data
*fdata
,
3998 wtap_rec
*rec
, Buffer
*buf
, void *criterion
)
4000 cbs_t
*info
= (cbs_t
*)criterion
;
4001 const uint8_t *ascii_text
= info
->data
;
4002 size_t textlen
= info
->data_len
;
4003 ws_mempbrk_pattern
*pattern
= info
->pattern
;
4004 match_result result
;
4006 uint8_t *pd
, *buf_start
, *buf_end
;
4011 /* Load the frame's data. */
4012 if (!cf_read_record(cf
, fdata
, rec
, buf
)) {
4013 /* Attempt to get the packet failed. */
4017 ws_assert(pattern
!= NULL
);
4019 result
= MR_NOTMATCHED
;
4020 buf_len
= fdata
->cap_len
;
4021 buf_start
= ws_buffer_start_ptr(buf
);
4022 buf_end
= buf_start
+ buf_len
;
4024 if (cf
->search_len
|| cf
->search_pos
) {
4025 /* we want to start searching one byte past the previous match start */
4026 pd
+= cf
->search_pos
+ 1;
4028 for (; pd
< buf_end
; pd
++) {
4029 pd
= (uint8_t *)ws_mempbrk_exec(pd
, buf_end
- pd
, pattern
, &c_char
);
4030 if (pd
== NULL
) break;
4032 for (i
= 0; pd
+ i
< buf_end
; i
++) {
4033 c_char
= g_ascii_toupper(pd
[i
]);
4034 if (c_char
== ascii_text
[c_match
]) {
4036 if (c_match
== textlen
) {
4037 /* Save position and length for highlighting the field. */
4038 result
= MR_MATCHED
;
4039 cf
->search_pos
= (uint32_t)(pd
- buf_start
);
4040 cf
->search_len
= (uint32_t)(i
+ 1);
4054 match_narrow_case_reverse(capture_file
*cf
, frame_data
*fdata
,
4055 wtap_rec
*rec
, Buffer
*buf
, void *criterion
)
4057 cbs_t
*info
= (cbs_t
*)criterion
;
4058 const uint8_t *ascii_text
= info
->data
;
4059 size_t textlen
= info
->data_len
;
4060 ws_mempbrk_pattern
*pattern
= info
->pattern
;
4061 match_result result
;
4063 uint8_t *pd
, *buf_start
, *buf_end
;
4068 /* Load the frame's data. */
4069 if (!cf_read_record(cf
, fdata
, rec
, buf
)) {
4070 /* Attempt to get the packet failed. */
4074 ws_assert(pattern
!= NULL
);
4076 result
= MR_NOTMATCHED
;
4077 /* Has to be room to hold the sought data. */
4078 if (textlen
> fdata
->cap_len
) {
4081 buf_len
= fdata
->cap_len
;
4082 buf_start
= ws_buffer_start_ptr(buf
);
4083 buf_end
= buf_start
+ buf_len
;
4084 pd
= buf_end
- textlen
;
4085 if (cf
->search_len
|| cf
->search_pos
) {
4086 /* we want to start searching one byte before the previous match start */
4087 pd
= buf_start
+ cf
->search_pos
- 1;
4089 for (; pd
>= buf_start
; pd
--) {
4090 pd
= (uint8_t *)ws_memrpbrk_exec(buf_start
, pd
- buf_start
+ 1, pattern
, &c_char
);
4091 if (pd
== NULL
) break;
4093 for (i
= 0; pd
+ i
< buf_end
; i
++) {
4094 c_char
= g_ascii_toupper(pd
[i
]);
4095 if (c_char
== ascii_text
[c_match
]) {
4097 if (c_match
== textlen
) {
4098 /* Save position and length for highlighting the field. */
4099 result
= MR_MATCHED
;
4100 cf
->search_pos
= (uint32_t)(pd
- buf_start
);
4101 cf
->search_len
= (uint32_t)(i
+ 1);
4115 match_wide(capture_file
*cf
, frame_data
*fdata
,
4116 wtap_rec
*rec
, Buffer
*buf
, void *criterion
)
4118 cbs_t
*info
= (cbs_t
*)criterion
;
4119 const uint8_t *ascii_text
= info
->data
;
4120 size_t textlen
= info
->data_len
;
4121 match_result result
;
4123 uint8_t *pd
, *buf_start
, *buf_end
;
4128 /* Load the frame's data. */
4129 if (!cf_read_record(cf
, fdata
, rec
, buf
)) {
4130 /* Attempt to get the packet failed. */
4134 result
= MR_NOTMATCHED
;
4135 buf_len
= fdata
->cap_len
;
4136 buf_start
= ws_buffer_start_ptr(buf
);
4137 buf_end
= buf_start
+ buf_len
;
4139 if (cf
->search_len
|| cf
->search_pos
) {
4140 /* we want to start searching one byte past the previous match start */
4141 pd
+= cf
->search_pos
+ 1;
4143 for (; pd
< buf_end
; pd
++) {
4144 pd
= (uint8_t *)memchr(pd
, ascii_text
[0], buf_end
- pd
);
4145 if (pd
== NULL
) break;
4147 for (i
= 0; pd
+ i
< buf_end
; i
++) {
4149 if (c_char
== ascii_text
[c_match
]) {
4151 if (c_match
== textlen
) {
4152 result
= MR_MATCHED
;
4153 /* Save position and length for highlighting the field. */
4154 cf
->search_pos
= (uint32_t)(pd
- buf_start
);
4155 cf
->search_len
= (uint32_t)(i
+ 1);
4159 if (pd
+ i
>= buf_end
|| pd
[i
] != '\0') break;
4171 match_wide_reverse(capture_file
*cf
, frame_data
*fdata
,
4172 wtap_rec
*rec
, Buffer
*buf
, void *criterion
)
4174 cbs_t
*info
= (cbs_t
*)criterion
;
4175 const uint8_t *ascii_text
= info
->data
;
4176 size_t textlen
= info
->data_len
;
4177 match_result result
;
4179 uint8_t *pd
, *buf_start
, *buf_end
;
4184 /* Load the frame's data. */
4185 if (!cf_read_record(cf
, fdata
, rec
, buf
)) {
4186 /* Attempt to get the packet failed. */
4190 result
= MR_NOTMATCHED
;
4191 /* Has to be room to hold the sought data. */
4192 if (textlen
> fdata
->cap_len
) {
4195 buf_len
= fdata
->cap_len
;
4196 buf_start
= ws_buffer_start_ptr(buf
);
4197 buf_end
= buf_start
+ buf_len
;
4198 pd
= buf_end
- textlen
;
4199 if (cf
->search_len
|| cf
->search_pos
) {
4200 /* we want to start searching one byte before the previous match start */
4201 pd
= buf_start
+ cf
->search_pos
- 1;
4203 for (; pd
< buf_end
; pd
++) {
4204 pd
= (uint8_t *)ws_memrchr(buf_start
, ascii_text
[0], pd
- buf_start
+ 1);
4205 if (pd
== NULL
) break;
4207 for (i
= 0; pd
+ i
< buf_end
; i
++) {
4209 if (c_char
== ascii_text
[c_match
]) {
4211 if (c_match
== textlen
) {
4212 result
= MR_MATCHED
;
4213 /* Save position and length for highlighting the field. */
4214 cf
->search_pos
= (uint32_t)(pd
- buf_start
);
4215 cf
->search_len
= (uint32_t)(i
+ 1);
4219 if (pd
+ i
>= buf_end
|| pd
[i
] != '\0') break;
4230 /* Case insensitive match */
4232 match_wide_case(capture_file
*cf
, frame_data
*fdata
,
4233 wtap_rec
*rec
, Buffer
*buf
, void *criterion
)
4235 cbs_t
*info
= (cbs_t
*)criterion
;
4236 const uint8_t *ascii_text
= info
->data
;
4237 size_t textlen
= info
->data_len
;
4238 ws_mempbrk_pattern
*pattern
= info
->pattern
;
4239 match_result result
;
4241 uint8_t *pd
, *buf_start
, *buf_end
;
4246 /* Load the frame's data. */
4247 if (!cf_read_record(cf
, fdata
, rec
, buf
)) {
4248 /* Attempt to get the packet failed. */
4252 ws_assert(pattern
!= NULL
);
4254 result
= MR_NOTMATCHED
;
4255 buf_len
= fdata
->cap_len
;
4256 buf_start
= ws_buffer_start_ptr(buf
);
4257 buf_end
= buf_start
+ buf_len
;
4259 if (cf
->search_len
|| cf
->search_pos
) {
4260 /* we want to start searching one byte past the previous match start */
4261 pd
+= cf
->search_pos
+ 1;
4263 for (; pd
< buf_end
; pd
++) {
4264 pd
= (uint8_t *)ws_mempbrk_exec(pd
, buf_end
- pd
, pattern
, &c_char
);
4265 if (pd
== NULL
) break;
4267 for (i
= 0; pd
+ i
< buf_end
; i
++) {
4268 c_char
= g_ascii_toupper(pd
[i
]);
4269 if (c_char
== ascii_text
[c_match
]) {
4271 if (c_match
== textlen
) {
4272 result
= MR_MATCHED
;
4273 /* Save position and length for highlighting the field. */
4274 cf
->search_pos
= (uint32_t)(pd
- buf_start
);
4275 cf
->search_len
= (uint32_t)(i
+ 1);
4279 if (pd
+ i
>= buf_end
|| pd
[i
] != '\0') break;
4290 /* Case insensitive match */
4292 match_wide_case_reverse(capture_file
*cf
, frame_data
*fdata
,
4293 wtap_rec
*rec
, Buffer
*buf
, void *criterion
)
4295 cbs_t
*info
= (cbs_t
*)criterion
;
4296 const uint8_t *ascii_text
= info
->data
;
4297 size_t textlen
= info
->data_len
;
4298 ws_mempbrk_pattern
*pattern
= info
->pattern
;
4299 match_result result
;
4301 uint8_t *pd
, *buf_start
, *buf_end
;
4306 /* Load the frame's data. */
4307 if (!cf_read_record(cf
, fdata
, rec
, buf
)) {
4308 /* Attempt to get the packet failed. */
4312 ws_assert(pattern
!= NULL
);
4314 result
= MR_NOTMATCHED
;
4315 /* Has to be room to hold the sought data. */
4316 if (textlen
> fdata
->cap_len
) {
4319 buf_len
= fdata
->cap_len
;
4320 buf_start
= ws_buffer_start_ptr(buf
);
4321 buf_end
= buf_start
+ buf_len
;
4322 pd
= buf_end
- textlen
;
4323 if (cf
->search_len
|| cf
->search_pos
) {
4324 /* we want to start searching one byte before the previous match start */
4325 pd
= buf_start
+ cf
->search_pos
- 1;
4327 for (; pd
>= buf_start
; pd
--) {
4328 pd
= (uint8_t *)ws_memrpbrk_exec(buf_start
, pd
- buf_start
+ 1, pattern
, &c_char
);
4329 if (pd
== NULL
) break;
4331 for (i
= 0; pd
+ i
< buf_end
; i
++) {
4332 c_char
= g_ascii_toupper(pd
[i
]);
4333 if (c_char
== ascii_text
[c_match
]) {
4335 if (c_match
== textlen
) {
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)(i
+ 1);
4343 if (pd
+ i
>= buf_end
|| pd
[i
] != '\0') break;
4355 match_binary(capture_file
*cf
, frame_data
*fdata
,
4356 wtap_rec
*rec
, Buffer
*buf
, void *criterion
)
4358 cbs_t
*info
= (cbs_t
*)criterion
;
4359 size_t datalen
= info
->data_len
;
4360 match_result result
;
4361 const uint8_t *pd
= NULL
, *buf_start
;
4363 /* Load the frame's data. */
4364 if (!cf_read_record(cf
, fdata
, rec
, buf
)) {
4365 /* Attempt to get the packet failed. */
4369 result
= MR_NOTMATCHED
;
4370 buf_start
= ws_buffer_start_ptr(buf
);
4372 if (cf
->search_len
|| cf
->search_pos
) {
4373 /* we want to start searching one byte past the previous match start */
4374 offset
= cf
->search_pos
+ 1;
4376 if (offset
< fdata
->cap_len
) {
4377 pd
= ws_memmem(buf_start
+ offset
, fdata
->cap_len
- offset
, info
->data
, datalen
);
4380 result
= MR_MATCHED
;
4381 /* Save position and length for highlighting the field. */
4382 cf
->search_pos
= (uint32_t)(pd
- buf_start
);
4383 cf
->search_len
= (uint32_t)datalen
;
4390 match_binary_reverse(capture_file
*cf
, frame_data
*fdata
,
4391 wtap_rec
*rec
, Buffer
*buf
, void *criterion
)
4393 cbs_t
*info
= (cbs_t
*)criterion
;
4394 size_t datalen
= info
->data_len
;
4395 match_result result
;
4396 const uint8_t *pd
= NULL
, *buf_start
;
4398 /* Load the frame's data. */
4399 if (!cf_read_record(cf
, fdata
, rec
, buf
)) {
4400 /* Attempt to get the packet failed. */
4404 result
= MR_NOTMATCHED
;
4405 buf_start
= ws_buffer_start_ptr(buf
);
4406 /* Has to be room to hold the sought data. */
4407 if (datalen
> fdata
->cap_len
) {
4410 pd
= buf_start
+ fdata
->cap_len
- datalen
;
4411 if (cf
->search_len
|| cf
->search_pos
) {
4412 /* we want to start searching one byte before the previous match start */
4413 pd
= buf_start
+ cf
->search_pos
- 1;
4415 for (; pd
>= buf_start
; pd
--) {
4416 pd
= (uint8_t *)ws_memrchr(buf_start
, info
->data
[0], pd
- buf_start
+ 1);
4417 if (pd
== NULL
) break;
4418 if (memcmp(pd
, info
->data
, datalen
) == 0) {
4419 result
= MR_MATCHED
;
4420 /* Save position and length for highlighting the field. */
4421 cf
->search_pos
= (uint32_t)(pd
- buf_start
);
4422 cf
->search_len
= (uint32_t)datalen
;
4431 match_regex(capture_file
*cf
, frame_data
*fdata
,
4432 wtap_rec
*rec
, Buffer
*buf
, void *criterion _U_
)
4434 match_result result
= MR_NOTMATCHED
;
4435 size_t result_pos
[2] = {0, 0};
4437 /* Load the frame's data. */
4438 if (!cf_read_record(cf
, fdata
, rec
, buf
)) {
4439 /* Attempt to get the packet failed. */
4444 if (cf
->search_len
|| cf
->search_pos
) {
4445 /* we want to start searching one byte past the previous match start */
4446 offset
= cf
->search_pos
+ 1;
4448 if (offset
< fdata
->cap_len
) {
4449 if (ws_regex_matches_pos(cf
->regex
,
4450 (const char *)ws_buffer_start_ptr(buf
),
4451 fdata
->cap_len
, offset
,
4453 //TODO: A chosen regex can match the empty string (zero length)
4454 // which doesn't make a lot of sense for searching the packet bytes.
4455 // Should we search with the PCRE2_NOTEMPTY option?
4457 /* Save position and length for highlighting the field. */
4458 cf
->search_pos
= (uint32_t)(result_pos
[0]);
4459 cf
->search_len
= (uint32_t)(result_pos
[1] - result_pos
[0]);
4460 result
= MR_MATCHED
;
4467 match_regex_reverse(capture_file
*cf
, frame_data
*fdata
,
4468 wtap_rec
*rec
, Buffer
*buf
, void *criterion _U_
)
4470 match_result result
= MR_NOTMATCHED
;
4471 size_t result_pos
[2] = {0, 0};
4473 /* Load the frame's data. */
4474 if (!cf_read_record(cf
, fdata
, rec
, buf
)) {
4475 /* Attempt to get the packet failed. */
4479 size_t offset
= fdata
->cap_len
- 1;
4480 if (cf
->search_pos
) {
4481 /* we want to start searching one byte before the previous match */
4482 offset
= cf
->search_pos
- 1;
4484 for (; offset
> 0; offset
--) {
4485 if (ws_regex_matches_pos(cf
->regex
,
4486 (const char *)ws_buffer_start_ptr(buf
),
4487 fdata
->cap_len
, offset
,
4489 //TODO: A chosen regex can match the empty string (zero length)
4490 // which doesn't make a lot of sense for searching the packet bytes.
4491 // Should we search with the PCRE2_NOTEMPTY option?
4493 /* Save position and length for highlighting the field. */
4494 cf
->search_pos
= (uint32_t)(result_pos
[0]);
4495 cf
->search_len
= (uint32_t)(result_pos
[1] - result_pos
[0]);
4496 result
= MR_MATCHED
;
4504 cf_find_packet_dfilter(capture_file
*cf
, dfilter_t
*sfcode
,
4505 search_direction dir
, bool start_current
)
4507 return find_packet(cf
, match_dfilter
, sfcode
, dir
, start_current
);
4511 cf_find_packet_dfilter_string(capture_file
*cf
, const char *filter
,
4512 search_direction dir
)
4517 if (!dfilter_compile(filter
, &sfcode
, NULL
)) {
4519 * XXX - this shouldn't happen, as the filter string is machine
4524 if (sfcode
== NULL
) {
4526 * XXX - this shouldn't happen, as the filter string is machine
4531 result
= find_packet(cf
, match_dfilter
, sfcode
, dir
, true);
4532 dfilter_free(sfcode
);
4537 match_dfilter(capture_file
*cf
, frame_data
*fdata
,
4538 wtap_rec
*rec
, Buffer
*buf
, void *criterion
)
4540 dfilter_t
*sfcode
= (dfilter_t
*)criterion
;
4542 match_result result
;
4544 /* Load the frame's data. */
4545 if (!cf_read_record(cf
, fdata
, rec
, buf
)) {
4546 /* Attempt to get the packet failed. */
4550 epan_dissect_init(&edt
, cf
->epan
, true, false);
4551 epan_dissect_prime_with_dfilter(&edt
, sfcode
);
4552 epan_dissect_run(&edt
, cf
->cd_t
, rec
,
4553 ws_buffer_start_ptr(buf
),
4555 result
= dfilter_apply_edt(sfcode
, &edt
) ? MR_MATCHED
: MR_NOTMATCHED
;
4556 epan_dissect_cleanup(&edt
);
4561 cf_find_packet_marked(capture_file
*cf
, search_direction dir
)
4563 return find_packet(cf
, match_marked
, NULL
, dir
, true);
4567 match_marked(capture_file
*cf _U_
, frame_data
*fdata
, wtap_rec
*rec _U_
,
4568 Buffer
*buf _U_
, void *criterion _U_
)
4570 return fdata
->marked
? MR_MATCHED
: MR_NOTMATCHED
;
4574 cf_find_packet_time_reference(capture_file
*cf
, search_direction dir
)
4576 return find_packet(cf
, match_time_reference
, NULL
, dir
, true);
4580 match_time_reference(capture_file
*cf _U_
, frame_data
*fdata
, wtap_rec
*rec _U_
,
4581 Buffer
*buf _U_
, void *criterion _U_
)
4583 return fdata
->ref_time
? MR_MATCHED
: MR_NOTMATCHED
;
4587 find_packet(capture_file
*cf
, ws_match_function match_function
,
4588 void *criterion
, search_direction dir
, bool start_current
)
4590 frame_data
*start_fd
;
4592 uint32_t prev_framenum
;
4596 frame_data
*new_fd
= NULL
;
4597 progdlg_t
*progbar
= NULL
;
4598 GTimer
*prog_timer
= g_timer_new();
4600 bool wrap
= prefs
.gui_find_wrap
;
4603 char status_str
[100];
4604 match_result result
;
4606 wtap_rec_init(&rec
);
4607 ws_buffer_init(&buf
, 1514);
4609 start_fd
= start_current
? cf
->current_frame
: NULL
;
4610 if (start_fd
!= NULL
) {
4611 prev_framenum
= start_fd
->num
;
4613 prev_framenum
= 0; /* No start packet selected. */
4617 /* Iterate through the list of packets, starting at the packet we've
4618 picked, calling a routine to run the filter on the packet, see if
4619 it matches, and stop if so. */
4621 framenum
= prev_framenum
;
4622 if (framenum
== 0 && dir
== SD_BACKWARD
) {
4623 /* If we have no start packet selected, and we're going backwards,
4624 * start at the end (even if wrap is off.)
4626 framenum
= cf
->count
+ 1;
4629 g_timer_start(prog_timer
);
4630 /* Progress so far. */
4633 cf
->stop_flag
= false;
4636 /* Create the progress bar if necessary.
4637 We check on every iteration of the loop, so that it takes no
4638 longer than the standard time to create it (otherwise, for a
4639 large file, we might take considerably longer than that standard
4640 time in order to get to the next progress bar step). */
4641 if (progbar
== NULL
)
4642 progbar
= delayed_create_progress_dlg(cf
->window
, NULL
, NULL
,
4643 false, &cf
->stop_flag
, progbar_val
);
4646 * Update the progress bar, but do it only after PROGBAR_UPDATE_INTERVAL
4647 * has elapsed. Calling update_progress_dlg and packets_bar_update will
4648 * likely trigger UI paint events, which might take a while depending on
4649 * the platform and display. Reset our timer *after* painting.
4651 if (g_timer_elapsed(prog_timer
, NULL
) > PROGBAR_UPDATE_INTERVAL
) {
4652 /* let's not divide by zero. I should never be started
4653 * with count == 0, so let's assert that
4655 ws_assert(cf
->count
> 0);
4657 progbar_val
= (float) count
/ cf
->count
;
4659 snprintf(status_str
, sizeof(status_str
),
4660 "%4u of %u packets", count
, cf
->count
);
4661 update_progress_dlg(progbar
, progbar_val
, status_str
);
4663 g_timer_start(prog_timer
);
4666 if (cf
->stop_flag
) {
4667 /* Well, the user decided to abort the search. Go back to the
4668 frame where we started.
4669 XXX - This ends up selecting the start packet and reporting
4670 "success". Perhaps new_fd should stay NULL? */
4675 /* Go past the current frame. */
4676 if (dir
== SD_BACKWARD
) {
4677 /* Go on to the previous frame. */
4678 if (framenum
<= 1) {
4680 * XXX - other apps have a bit more of a detailed message
4681 * for this, and instead of offering "OK" and "Cancel",
4682 * they offer things such as "Continue" and "Cancel";
4683 * we need an API for popping up alert boxes with
4684 * {Verb} and "Cancel".
4688 statusbar_push_temporary_msg("Search reached the beginning. Continuing at end.");
4689 framenum
= cf
->count
; /* wrap around */
4692 statusbar_push_temporary_msg("Search reached the beginning.");
4693 framenum
= prev_framenum
; /* stay on previous packet */
4698 /* Go on to the next frame. */
4699 if (framenum
== cf
->count
) {
4701 statusbar_push_temporary_msg("Search reached the end. Continuing at beginning.");
4702 framenum
= 1; /* wrap around */
4705 statusbar_push_temporary_msg("Search reached the end.");
4706 framenum
= prev_framenum
; /* stay on previous packet */
4712 fdata
= frame_data_sequence_find(cf
->provider
.frames
, framenum
);
4715 /* Is this packet in the display? */
4716 if (fdata
&& fdata
->passed_dfilter
) {
4717 /* Yes. Does it match the search criterion? */
4718 result
= (*match_function
)(cf
, fdata
, &rec
, &buf
, criterion
);
4719 if (result
== MR_ERROR
) {
4720 /* Error; our caller has reported the error. Go back to the frame
4722 XXX - This ends up selecting the start packet and reporting
4723 "success." Perhaps new_fd should stay NULL? */
4726 } else if (result
== MR_MATCHED
) {
4727 /* Yes. Go to the new frame. */
4731 wtap_rec_reset(&rec
);
4734 if (fdata
== start_fd
) {
4735 /* We're back to the frame we were on originally, and that frame
4736 doesn't match the search filter. The search failed. */
4741 /* We're done scanning the packets; destroy the progress bar if it
4743 if (progbar
!= NULL
)
4744 destroy_progress_dlg(progbar
);
4745 g_timer_destroy(prog_timer
);
4747 if (new_fd
!= NULL
) {
4748 /* We found a frame that's displayed and that matches.
4749 Try to find and select the packet summary list row for that frame. */
4752 cf
->search_in_progress
= true;
4753 found_row
= packet_list_select_row_from_data(new_fd
);
4754 cf
->search_in_progress
= false;
4756 /* We didn't find a row corresponding to this frame.
4757 This means that the frame isn't being displayed currently,
4758 so we can't select it. */
4759 cf
->search_pos
= 0; /* Reset the position */
4760 cf
->search_len
= 0; /* Reset length */
4761 simple_message_box(ESD_TYPE_INFO
, NULL
,
4762 "The capture file is probably not fully dissected.",
4763 "End of capture exceeded.");
4764 succeeded
= false; /* The search succeeded but we didn't find the row */
4766 succeeded
= true; /* The search succeeded and we found the row */
4768 succeeded
= false; /* The search failed */
4769 wtap_rec_cleanup(&rec
);
4770 ws_buffer_free(&buf
);
4775 cf_goto_frame(capture_file
*cf
, unsigned fnumber
, bool exact
)
4779 if (cf
== NULL
|| cf
->provider
.frames
== NULL
) {
4780 /* we don't have a loaded capture file - fix for bugs 11810 & 11989 */
4781 statusbar_push_temporary_msg("There is no file loaded");
4782 return false; /* we failed to go to that packet */
4785 fdata
= frame_data_sequence_find(cf
->provider
.frames
, fnumber
);
4787 if (fdata
== NULL
) {
4788 /* we didn't find a packet with that packet number */
4789 statusbar_push_temporary_msg("There is no packet number %u.", fnumber
);
4790 return false; /* we failed to go to that packet */
4792 if (!fdata
->passed_dfilter
) {
4793 /* that packet currently isn't displayed */
4794 /* XXX - add it to the set of displayed packets? */
4795 if (cf
->first_displayed
== 0 || exact
) {
4796 /* We only want that exact frame, or no frames are displayed. */
4797 statusbar_push_temporary_msg("Packet number %u isn't displayed.", fnumber
);
4798 return false; /* we failed to go to that packet */
4800 if (fdata
->prev_dis_num
== 0) {
4801 /* There is no previous displayed frame, so this frame is
4802 * before the first displayed frame. Go to the first line,
4803 * which is the closest frame.
4805 fdata
= NULL
; /* This will select the first row. */
4806 statusbar_push_temporary_msg("Packet number %u isn't displayed, going to the first displayed packet, %u.", fnumber
, cf
->first_displayed
);
4808 uint32_t delta
= fnumber
- fdata
->prev_dis_num
;
4809 /* The next displayed frame might be closer, we can do an
4810 * O(log n) binary search for the earliest displayed frame
4811 * in the open interval (fnumber, fnumber + delta).
4813 * This is possibly overkill, we could just go to the previous
4817 uint32_t lower_bound
= fnumber
+ 1;
4818 uint32_t upper_bound
= fnumber
+ delta
- 1;
4820 while (lower_bound
<= upper_bound
) {
4821 uint32_t middle
= (lower_bound
+ upper_bound
) / 2;
4822 fdata2
= frame_data_sequence_find(cf
->provider
.frames
, middle
);
4823 if (fdata2
== NULL
) {
4824 /* We don't have a frame of that number, so search before it. */
4825 upper_bound
= middle
- 1;
4828 /* We have a frame of that number. What's the displayed
4829 * frame before it? */
4830 if (fdata2
->prev_dis_num
> fnumber
) {
4831 /* The previous frame that passed the filter is also after
4832 * our target, so our answer is no later than that.
4834 upper_bound
= fdata2
->prev_dis_num
;
4836 /* The previous displayed frame is before fnumber.
4837 * (We already know fnumber itself is not displayed.)
4838 * Is this frame itself displayed?
4840 if (fdata2
->passed_dfilter
) {
4841 /* Yes. So this is our answer. */
4845 /* No. So our answer, if any, is after this frame. */
4846 lower_bound
= middle
+ 1;
4851 statusbar_push_temporary_msg("Packet number %u isn't displayed, going to the next displayed packet, %u.", fnumber
, fdata
->num
);
4853 statusbar_push_temporary_msg("Packet number %u isn't displayed, going to the previous displayed packet, %u.", fnumber
, fdata
->prev_dis_num
);
4854 fdata
= frame_data_sequence_find(cf
->provider
.frames
, fdata
->prev_dis_num
);
4859 if (!packet_list_select_row_from_data(fdata
)) {
4860 /* We didn't find a row corresponding to this frame.
4861 This means that the frame isn't being displayed currently,
4862 so we can't select it. */
4863 simple_message_box(ESD_TYPE_INFO
, NULL
,
4864 "The capture file is probably not fully dissected.",
4865 "End of capture exceeded.");
4868 return true; /* we got to that packet */
4872 * Go to frame specified by currently selected protocol tree item.
4875 cf_goto_framenum(capture_file
*cf
)
4877 const header_field_info
*hfinfo
;
4880 if (cf
->finfo_selected
) {
4881 hfinfo
= cf
->finfo_selected
->hfinfo
;
4883 if (hfinfo
->type
== FT_FRAMENUM
) {
4884 framenum
= fvalue_get_uinteger(cf
->finfo_selected
->value
);
4885 if (framenum
!= 0) {
4886 /* We probably only want to go to the exact match,
4887 * even though "Go to Previous Packet in History" exists.
4889 return cf_goto_frame(cf
, framenum
, true);
4897 /* Select the packet on a given row. */
4899 cf_select_packet(capture_file
*cf
, frame_data
*fdata
)
4901 epan_dissect_t
*old_edt
;
4903 /* check the frame data struct pointer for this frame */
4904 if (fdata
== NULL
) {
4908 /* Get the data in that frame. */
4909 if (!cf_read_record(cf
, fdata
, &cf
->rec
, &cf
->buf
)) {
4913 /* Record that this frame is the current frame. */
4914 cf
->current_frame
= fdata
;
4917 * The change to defer freeing the current epan_dissect_t was in
4918 * commit a2bb94c3b33d53f42534aceb7cc67aab1d1fb1f9; to quote
4919 * that commit's comment:
4921 * Clear GtkTreeStore before freeing edt
4923 * When building current data for packet details treeview we store two
4925 * - Generated string with item label
4926 * - Pointer to node field_info structure
4928 * After epan_dissect_{free, cleanup} pointer to field_info node is no
4929 * longer valid so we should clear GtkTreeStore before freeing.
4931 * XXX - we're no longer using GTK+; is there a way to ensure that
4932 * *nothing* refers to any of the current frame information before
4936 /* Create the logical protocol tree. */
4937 /* We don't need the columns here. */
4938 cf
->edt
= epan_dissect_new(cf
->epan
, true, true);
4940 tap_build_interesting(cf
->edt
);
4941 epan_dissect_run(cf
->edt
, cf
->cd_t
, &cf
->rec
,
4942 ws_buffer_start_ptr(&cf
->buf
),
4943 cf
->current_frame
, NULL
);
4945 if (old_edt
!= NULL
)
4946 epan_dissect_free(old_edt
);
4949 /* Unselect the selected packet, if any. */
4951 cf_unselect_packet(capture_file
*cf
)
4953 epan_dissect_t
*old_edt
= cf
->edt
;
4956 * See the comment in cf_select_packet() about deferring the freeing
4957 * of the old cf->edt.
4961 /* No packet is selected. */
4962 cf
->current_frame
= NULL
;
4964 /* Destroy the epan_dissect_t for the unselected packet. */
4965 if (old_edt
!= NULL
)
4966 epan_dissect_free(old_edt
);
4970 * Mark a particular frame.
4973 cf_mark_frame(capture_file
*cf
, frame_data
*frame
)
4975 if (! frame
->marked
) {
4976 frame
->marked
= true;
4977 if (cf
->count
> cf
->marked_count
)
4983 * Unmark a particular frame.
4986 cf_unmark_frame(capture_file
*cf
, frame_data
*frame
)
4988 if (frame
->marked
) {
4989 frame
->marked
= false;
4990 if (cf
->marked_count
> 0)
4996 * Ignore a particular frame.
4999 cf_ignore_frame(capture_file
*cf
, frame_data
*frame
)
5001 if (! frame
->ignored
) {
5002 frame
->ignored
= true;
5003 if (cf
->count
> cf
->ignored_count
)
5004 cf
->ignored_count
++;
5009 * Un-ignore a particular frame.
5012 cf_unignore_frame(capture_file
*cf
, frame_data
*frame
)
5014 if (frame
->ignored
) {
5015 frame
->ignored
= false;
5016 if (cf
->ignored_count
> 0)
5017 cf
->ignored_count
--;
5022 * Modify the section comment.
5025 cf_update_section_comment(capture_file
*cf
, char *comment
)
5027 wtap_block_t shb_inf
;
5030 /* Get the first SHB. */
5031 /* XXX - support multiple SHBs */
5032 shb_inf
= wtap_file_get_shb(cf
->provider
.wth
, 0);
5034 /* Get the first comment from the SHB. */
5035 /* XXX - support multiple comments */
5036 if (wtap_block_get_nth_string_option_value(shb_inf
, OPT_COMMENT
, 0, &shb_comment
) != WTAP_OPTTYPE_SUCCESS
) {
5037 /* There's no comment - add one. */
5038 wtap_block_add_string_option(shb_inf
, OPT_COMMENT
, comment
, strlen(comment
));
5040 /* See if the comment has changed or not */
5041 if (strcmp(shb_comment
, comment
) == 0) {
5046 /* The comment has changed, let's update it */
5047 wtap_block_set_nth_string_option_value(shb_inf
, OPT_COMMENT
, 0, comment
, strlen(comment
));
5049 /* Mark the file as having unsaved changes */
5050 cf
->unsaved_changes
= true;
5054 * Modify the section comments for a given section.
5057 cf_update_section_comments(capture_file
*cf
, unsigned shb_idx
, char **comments
)
5059 wtap_block_t shb_inf
;
5062 shb_inf
= wtap_file_get_shb(cf
->provider
.wth
, shb_idx
);
5063 if (shb_inf
== NULL
) {
5064 /* Shouldn't happen. XXX: Report it if it does? */
5068 unsigned n_comments
= g_strv_length(comments
);
5072 for (i
= 0; i
< n_comments
; i
++) {
5073 comment
= comments
[i
];
5074 if (wtap_block_get_nth_string_option_value(shb_inf
, OPT_COMMENT
, i
, &shb_comment
) != WTAP_OPTTYPE_SUCCESS
) {
5075 /* There's no comment - add one. */
5076 wtap_block_add_string_option_owned(shb_inf
, OPT_COMMENT
, comment
);
5077 cf
->unsaved_changes
= true;
5079 /* See if the comment has changed or not */
5080 if (strcmp(shb_comment
, comment
) != 0) {
5081 /* The comment has changed, let's update it */
5082 wtap_block_set_nth_string_option_value(shb_inf
, OPT_COMMENT
, 0, comment
, strlen(comment
));
5083 cf
->unsaved_changes
= true;
5088 /* We either transferred ownership of the comments or freed them
5089 * above, so free the array of strings but not the strings themselves. */
5092 /* If there are extra old comments, remove them. Start at the end. */
5093 for (i
= wtap_block_count_option(shb_inf
, OPT_COMMENT
); i
> n_comments
; i
--) {
5094 wtap_block_remove_nth_option_instance(shb_inf
, OPT_COMMENT
, i
- 1);
5095 cf
->unsaved_changes
= true;
5100 * Get the packet block for a packet (record).
5101 * If the block has been edited, it returns the result of the edit,
5102 * otherwise it returns the block from the file.
5103 * NB. Caller must wtap_block_unref() the result when done.
5106 cf_get_packet_block(capture_file
*cf
, const frame_data
*fd
)
5108 /* If this block has been modified, fetch the modified version */
5109 if (fd
->has_modified_block
)
5110 return wtap_block_ref(cap_file_provider_get_modified_block(&cf
->provider
, fd
));
5112 wtap_rec rec
; /* Record metadata */
5113 Buffer buf
; /* Record data */
5116 /* fetch record block */
5117 wtap_rec_init(&rec
);
5118 ws_buffer_init(&buf
, 1514);
5120 if (!cf_read_record(cf
, fd
, &rec
, &buf
))
5121 { /* XXX, what we can do here? */ }
5123 /* rec.block is owned by the record, steal it before it is gone. */
5124 block
= wtap_block_ref(rec
.block
);
5126 wtap_rec_cleanup(&rec
);
5127 ws_buffer_free(&buf
);
5133 * Update(replace) the block on a capture from a frame
5136 cf_set_modified_block(capture_file
*cf
, frame_data
*fd
, const wtap_block_t new_block
)
5138 wtap_block_t pkt_block
= cf_get_packet_block(cf
, fd
);
5140 /* It's possible to further modify the modified block "in place" by doing
5141 * a call to cf_get_packet_block() that returns an already created modified
5142 * block, modifying that, and calling this function.
5143 * If the caller did that, then the block pointers will be equal.
5145 if (pkt_block
== new_block
) {
5146 /* No need to save anything here, the caller changes went right
5148 * Unfortunately we don't have a way to know how many comments were
5149 * in the block before the caller modified it, so tell the caller
5150 * it is its responsibility to update the comment count.
5156 cf
->packet_comment_count
-= wtap_block_count_option(pkt_block
, OPT_COMMENT
);
5159 cf
->packet_comment_count
+= wtap_block_count_option(new_block
, OPT_COMMENT
);
5161 cap_file_provider_set_modified_block(&cf
->provider
, fd
, new_block
);
5163 expert_update_comment_count(cf
->packet_comment_count
);
5166 /* Either way, we have unsaved changes. */
5167 wtap_block_unref(pkt_block
);
5168 cf
->unsaved_changes
= true;
5173 * What types of comments does this capture file have?
5176 cf_comment_types(capture_file
*cf
)
5178 uint32_t comment_types
= 0;
5181 * Does this file have any sections with at least one comment?
5183 for (unsigned section_number
= 0;
5184 section_number
< wtap_file_get_num_shbs(cf
->provider
.wth
);
5186 wtap_block_t shb_inf
;
5189 shb_inf
= wtap_file_get_shb(cf
->provider
.wth
, section_number
);
5191 /* Try to get the first comment from that SHB. */
5192 if (wtap_block_get_nth_string_option_value(shb_inf
, OPT_COMMENT
, 0,
5193 &shb_comment
) == WTAP_OPTTYPE_SUCCESS
) {
5194 /* We succeeded, so this file has at least one section comment. */
5195 comment_types
|= WTAP_COMMENT_PER_SECTION
;
5197 /* We don't need to search any more. */
5201 if (cf
->packet_comment_count
!= 0)
5202 comment_types
|= WTAP_COMMENT_PER_PACKET
;
5203 return comment_types
;
5207 * Add a resolved address to this file's list of resolved addresses.
5210 cf_add_ip_name_from_string(capture_file
*cf
, const char *addr
, const char *name
)
5213 * XXX - support multiple resolved address lists, and add to the one
5214 * attached to this file?
5216 if (!add_ip_name_from_string(addr
, name
))
5219 /* OK, we have unsaved changes. */
5220 cf
->unsaved_changes
= true;
5229 } save_callback_args_t
;
5232 * Save a capture to a file, in a particular format, saving either
5233 * all packets, all currently-displayed packets, or all marked packets.
5235 * Returns true if it succeeds, false otherwise; if it fails, it pops
5236 * up a message box for the failure.
5239 save_record(capture_file
*cf
, frame_data
*fdata
, wtap_rec
*rec
,
5240 Buffer
*buf
, void *argsp
)
5242 save_callback_args_t
*args
= (save_callback_args_t
*)argsp
;
5246 wtap_block_t pkt_block
;
5248 /* Copy the record information from what was read in from the file. */
5251 /* Make changes based on anything that the user has done but that
5252 hasn't been saved yet. */
5253 if (fdata
->has_modified_block
)
5254 pkt_block
= cap_file_provider_get_modified_block(&cf
->provider
, fdata
);
5256 pkt_block
= rec
->block
;
5257 new_rec
.block
= pkt_block
;
5258 new_rec
.block_was_modified
= fdata
->has_modified_block
? true : false;
5260 if (!nstime_is_zero(&fdata
->shift_offset
)) {
5261 if (new_rec
.presence_flags
& WTAP_HAS_TS
) {
5262 nstime_add(&new_rec
.ts
, &fdata
->shift_offset
);
5266 /* and save the packet */
5267 if (!wtap_dump(args
->pdh
, &new_rec
, ws_buffer_start_ptr(buf
), &err
, &err_info
)) {
5268 report_cfile_write_failure(NULL
, args
->fname
, err
, err_info
, fdata
->num
,
5273 /* If we are saving (i.e., replacing the current file with the one we're
5274 * writing), then update the frame data to clear the shift offset.
5275 * This keeps us from having to re-read the entire file.
5276 * We could do this in rescan_file(), but
5277 * 1) Ideally we shouldn't have to call rescan_file if all we're doing
5278 * is changing the timestamps, since that shouldn't change the offsets.
5279 * 2) The long term goal is to try to do the offset adjustment here
5280 * instead of using rescan_file, which should be faster (#1257).
5282 * If we're exporting to a different file, then don't do that.
5284 if (!args
->export
&& new_rec
.presence_flags
& WTAP_HAS_TS
) {
5285 nstime_set_zero(&fdata
->shift_offset
);
5292 * Can this capture file be written out in any format using Wiretap
5293 * rather than by copying the raw data?
5296 cf_can_write_with_wiretap(capture_file
*cf
)
5298 /* We don't care whether we support the comments in this file or not;
5299 if we can't, we'll offer the user the option of discarding the
5301 return wtap_dump_can_write(cf
->linktypes
, 0);
5305 * Should we let the user do a save?
5309 * the file has unsaved changes, and we can save it in some
5310 * format through Wiretap
5314 * the file is a temporary file and has no unsaved changes (so
5315 * that "saving" it just means copying it).
5317 * XXX - we shouldn't allow files to be edited if they can't be saved,
5318 * so cf->unsaved_changes should be true only if the file can be saved.
5320 * We don't care whether we support the comments in this file or not;
5321 * if we can't, we'll offer the user the option of discarding the
5325 cf_can_save(capture_file
*cf
)
5327 if (cf
->unsaved_changes
&& wtap_dump_can_write(cf
->linktypes
, 0)) {
5328 /* Saved changes, and we can write it out with Wiretap. */
5332 if (cf
->is_tempfile
&& !cf
->unsaved_changes
) {
5334 * Temporary file with no unsaved changes, so we can just do a
5340 /* Nothing to save. */
5345 * Should we let the user do a "save as"?
5349 * we can save it in some format through Wiretap
5353 * the file is a temporary file and has no unsaved changes (so
5354 * that "saving" it just means copying it).
5356 * XXX - we shouldn't allow files to be edited if they can't be saved,
5357 * so cf->unsaved_changes should be true only if the file can be saved.
5359 * We don't care whether we support the comments in this file or not;
5360 * if we can't, we'll offer the user the option of discarding the
5364 cf_can_save_as(capture_file
*cf
)
5366 if (wtap_dump_can_write(cf
->linktypes
, 0)) {
5367 /* We can write it out with Wiretap. */
5371 if (cf
->is_tempfile
&& !cf
->unsaved_changes
) {
5373 * Temporary file with no unsaved changes, so we can just do a
5379 /* Nothing to save. */
5384 * Does this file have unsaved data?
5387 cf_has_unsaved_data(capture_file
*cf
)
5390 * If this is a temporary file, or a file with unsaved changes, it
5393 return (cf
->is_tempfile
&& cf
->count
>0) || cf
->unsaved_changes
;
5397 * Quick scan to find packet offsets.
5399 static cf_read_status_t
5400 rescan_file(capture_file
*cf
, const char *fname
, bool is_tempfile
)
5407 int64_t data_offset
;
5408 progdlg_t
*progbar
= NULL
;
5409 GTimer
*prog_timer
= g_timer_new();
5413 char status_str
[100];
5417 /* Close the old handle. */
5418 wtap_close(cf
->provider
.wth
);
5420 /* Open the new file. */
5421 /* XXX: this will go through all open_routines for a matching one. But right
5422 now rescan_file() is only used when a file is being saved to a different
5423 format than the original, and the user is not given a choice of which
5424 reader to use (only which format to save it in), so doing this makes
5425 sense for now. (XXX: Now it is also used when saving a changed file,
5426 e.g. comments or time-shifted frames.) */
5427 cf
->provider
.wth
= wtap_open_offline(fname
, WTAP_TYPE_AUTO
, &err
, &err_info
, true);
5428 if (cf
->provider
.wth
== NULL
) {
5429 report_cfile_open_failure(fname
, err
, err_info
);
5430 return CF_READ_ERROR
;
5433 /* We're scanning a file whose contents should be the same as what
5434 we had before, so we don't discard dissection state etc.. */
5437 /* Set the file name because we need it to set the follow stream filter.
5438 XXX - is that still true? We need it for other reasons, though,
5440 if (cf
->filename
!= NULL
) {
5441 g_free(cf
->filename
);
5443 cf
->filename
= g_strdup(fname
);
5445 /* Indicate whether it's a permanent or temporary file. */
5446 cf
->is_tempfile
= is_tempfile
;
5448 /* No user changes yet. */
5449 cf
->unsaved_changes
= false;
5451 cf
->cd_t
= wtap_file_type_subtype(cf
->provider
.wth
);
5452 if (cf
->linktypes
!= NULL
) {
5453 g_array_free(cf
->linktypes
, TRUE
);
5455 cf
->linktypes
= g_array_sized_new(FALSE
, FALSE
, (unsigned) sizeof(int), 1);
5457 cf
->snap
= wtap_snapshot_length(cf
->provider
.wth
);
5459 name_ptr
= g_filename_display_basename(cf
->filename
);
5461 cf_callback_invoke(cf_cb_file_rescan_started
, cf
);
5463 /* Record the file's compression type.
5464 XXX - do we know this at open time? */
5465 cf
->compression_type
= wtap_get_compression_type(cf
->provider
.wth
);
5467 /* Find the size of the file. */
5468 size
= wtap_file_size(cf
->provider
.wth
, NULL
);
5470 g_timer_start(prog_timer
);
5472 cf
->stop_flag
= false;
5473 start_time
= g_get_monotonic_time();
5476 wtap_rec_init(&rec
);
5477 ws_buffer_init(&buf
, 1514);
5478 while ((wtap_read(cf
->provider
.wth
, &rec
, &buf
, &err
, &err_info
,
5481 fdata
= frame_data_sequence_find(cf
->provider
.frames
, framenum
);
5482 if (G_LIKELY(fdata
!= NULL
)) {
5483 fdata
->file_off
= data_offset
;
5486 cf
->f_datalen
= wtap_read_so_far(cf
->provider
.wth
);
5488 /* Create the progress bar if necessary. */
5489 if (progress_is_slow(progbar
, prog_timer
, size
, cf
->f_datalen
)) {
5490 progbar_val
= calc_progbar_val(cf
, size
, cf
->f_datalen
, status_str
, sizeof(status_str
));
5491 progbar
= delayed_create_progress_dlg(cf
->window
, NULL
, NULL
,
5492 true, &cf
->stop_flag
, progbar_val
);
5496 * Update the progress bar, but do it only after PROGBAR_UPDATE_INTERVAL
5497 * has elapsed. Calling update_progress_dlg and packets_bar_update will
5498 * likely trigger UI paint events, which might take a while depending on
5499 * the platform and display. Reset our timer *after* painting.
5501 if (progbar
&& g_timer_elapsed(prog_timer
, NULL
) > PROGBAR_UPDATE_INTERVAL
) {
5502 progbar_val
= calc_progbar_val(cf
, size
, cf
->f_datalen
, status_str
, sizeof(status_str
));
5503 /* update the packet bar content on the first run or frequently on very large files */
5504 update_progress_dlg(progbar
, progbar_val
, status_str
);
5505 compute_elapsed(cf
, start_time
);
5506 packets_bar_update();
5507 g_timer_start(prog_timer
);
5511 if (cf
->stop_flag
) {
5512 /* Well, the user decided to abort the rescan. Sadly, as this
5513 isn't a reread, recovering is difficult, so we'll just
5514 close the current capture. */
5518 /* Add this packet's link-layer encapsulation type to cf->linktypes, if
5519 it's not already there.
5520 XXX - yes, this is O(N), so if every packet had a different
5521 link-layer encapsulation type, it'd be O(N^2) to read the file, but
5522 there are probably going to be a small number of encapsulation types
5524 if (rec
.rec_type
== REC_TYPE_PACKET
) {
5525 cf_add_encapsulation_type(cf
, rec
.rec_header
.packet_header
.pkt_encap
);
5527 wtap_rec_reset(&rec
);
5529 wtap_rec_cleanup(&rec
);
5530 ws_buffer_free(&buf
);
5532 /* Free the display name */
5535 /* We're done reading the file; destroy the progress bar if it was created. */
5536 if (progbar
!= NULL
)
5537 destroy_progress_dlg(progbar
);
5538 g_timer_destroy(prog_timer
);
5540 /* We're done reading sequentially through the file. */
5541 cf
->state
= FILE_READ_DONE
;
5543 /* Close the sequential I/O side, to free up memory it requires. */
5544 wtap_sequential_close(cf
->provider
.wth
);
5546 /* compute the time it took to load the file */
5547 compute_elapsed(cf
, start_time
);
5549 /* Set the file encapsulation type now; we don't know what it is until
5550 we've looked at all the packets, as we don't know until then whether
5551 there's more than one type (and thus whether it's
5552 WTAP_ENCAP_PER_PACKET). */
5553 cf
->lnk_t
= wtap_file_encap(cf
->provider
.wth
);
5555 cf_callback_invoke(cf_cb_file_rescan_finished
, cf
);
5557 if (cf
->stop_flag
) {
5558 /* Our caller will give up at this point. */
5559 return CF_READ_ABORTED
;
5563 /* Put up a message box noting that the read failed somewhere along
5564 the line. Don't throw out the stuff we managed to read, though,
5566 report_cfile_read_failure(NULL
, err
, err_info
);
5567 return CF_READ_ERROR
;
5573 cf_save_records(capture_file
*cf
, const char *fname
, unsigned save_format
,
5574 wtap_compression_type compression_type
,
5575 bool discard_comments
, bool dont_reopen
)
5577 char *err_info
= "Unknown error";
5578 char *fname_new
= NULL
;
5581 addrinfo_lists_t
*addr_lists
;
5589 save_callback_args_t callback_args
;
5590 callback_args
.export
= false;
5591 bool needs_reload
= false;
5593 /* XXX caller should avoid saving the file while a read is pending
5594 * (e.g. by delaying the save action) */
5595 if (cf
->read_lock
) {
5596 ws_warning("cf_save_records(\"%s\") while the file is being read, potential crash ahead", fname
);
5599 cf_callback_invoke(cf_cb_file_save_started
, (void *)fname
);
5601 addr_lists
= get_addrinfo_list();
5603 if (save_format
== cf
->cd_t
&& compression_type
== cf
->compression_type
5604 && !discard_comments
&& !cf
->unsaved_changes
5605 && (wtap_addrinfo_list_empty(addr_lists
) || wtap_file_type_subtype_supports_block(save_format
, WTAP_BLOCK_NAME_RESOLUTION
) == BLOCK_NOT_SUPPORTED
)) {
5606 /* We're saving in the format it's already in, and we're not discarding
5607 comments, and there are no changes we have in memory that aren't saved
5608 to the file, and we have no name resolution information to write or
5609 the file format we're saving in doesn't support writing name
5610 resolution information, so we can just move or copy the raw data. */
5612 if (cf
->is_tempfile
) {
5613 /* The file being saved is a temporary file from a live
5614 capture, so it doesn't need to stay around under that name;
5615 first, try renaming the capture buffer file to the new name.
5616 This acts as a "safe save", in that, if the file already
5617 exists, the existing file will be removed only if the rename
5620 Sadly, on Windows, as we have the current capture file
5621 open, even MoveFileEx() with MOVEFILE_REPLACE_EXISTING
5622 (to cause the rename to remove an existing target), as
5623 done by ws_stdio_rename() (ws_rename() is #defined to
5624 be ws_stdio_rename() on Windows) will fail.
5626 According to the MSDN documentation for CreateFile(), if,
5627 when we open a capture file, we were to directly do a CreateFile(),
5628 opening with FILE_SHARE_DELETE|FILE_SHARE_READ, and then
5629 convert it to a file descriptor with _open_osfhandle(),
5630 that would allow the file to be renamed out from under us.
5632 However, that doesn't work in practice. Perhaps the problem
5633 is that the process doing the rename is the process that
5634 has the file open. */
5636 if (ws_rename(cf
->filename
, fname
) == 0) {
5637 /* That succeeded - there's no need to copy the source file. */
5638 how_to_save
= SAVE_WITH_MOVE
;
5640 if (errno
== EXDEV
) {
5641 /* They're on different file systems, so we have to copy the
5643 how_to_save
= SAVE_WITH_COPY
;
5645 /* The rename failed, but not because they're on different
5646 file systems - put up an error message. (Or should we
5647 just punt and try to copy? The only reason why I'd
5648 expect the rename to fail and the copy to succeed would
5649 be if we didn't have permission to remove the file from
5650 the temporary directory, and that might be fixable - but
5651 is it worth requiring the user to go off and fix it?) */
5652 report_rename_failure(cf
->filename
, fname
, errno
);
5657 /* Windows - copy the file to its new location. */
5658 how_to_save
= SAVE_WITH_COPY
;
5661 /* It's a permanent file, so we should copy it, and not remove the
5663 how_to_save
= SAVE_WITH_COPY
;
5666 if (how_to_save
== SAVE_WITH_COPY
) {
5667 /* Copy the file, if we haven't moved it. If we're overwriting
5668 an existing file, we do it with a "safe save", by writing
5669 to a new file and, if the write succeeds, renaming the
5670 new file on top of the old file. */
5671 if (file_exists(fname
)) {
5672 fname_new
= ws_strdup_printf("%s~", fname
);
5673 if (!copy_file_binary_mode(cf
->filename
, fname_new
))
5676 if (!copy_file_binary_mode(cf
->filename
, fname
))
5681 /* Either we're saving in a different format or we're saving changes,
5682 such as added, modified, or removed comments, that haven't yet
5683 been written to the underlying file; we can't do that by copying
5684 or moving the capture file, we have to do it by writing the packets
5687 wtap_dump_params params
;
5690 how_to_save
= SAVE_WITH_WTAP
;
5691 wtap_dump_params_init(¶ms
, cf
->provider
.wth
);
5693 /* Determine what file encapsulation type we should use. */
5694 encap
= wtap_dump_required_file_encap_type(cf
->linktypes
);
5695 params
.encap
= encap
;
5697 /* Use the snaplen from cf (XXX - does wtap_dump_params_init handle that?) */
5698 params
.snaplen
= cf
->snap
;
5700 if (file_exists(fname
)) {
5701 /* We're overwriting an existing file; write out to a new file,
5702 and, if that succeeds, rename the new file on top of the
5703 old file. That makes this a "safe save", so that we don't
5704 lose the old file if we have a problem writing out the new
5705 file. (If the existing file is the current capture file,
5706 we *HAVE* to do that, otherwise we're overwriting the file
5707 from which we're reading the packets that we're writing!) */
5708 fname_new
= ws_strdup_printf("%s~", fname
);
5709 pdh
= wtap_dump_open(fname_new
, save_format
, compression_type
, ¶ms
,
5712 pdh
= wtap_dump_open(fname
, save_format
, compression_type
, ¶ms
,
5715 /* XXX idb_inf is documented to be used until wtap_dump_close. */
5716 g_free(params
.idb_inf
);
5717 params
.idb_inf
= NULL
;
5720 report_cfile_dump_open_failure(fname
, err
, err_info
, save_format
);
5724 /* Add address resolution */
5725 wtap_dump_set_addrinfo_list(pdh
, addr_lists
);
5727 /* Iterate through the list of packets, processing all the packets. */
5728 callback_args
.pdh
= pdh
;
5729 callback_args
.fname
= fname
;
5730 callback_args
.file_type
= save_format
;
5731 switch (process_specified_records(cf
, NULL
, "Saving", "packets",
5732 true, save_record
, &callback_args
, true)) {
5735 /* Completed successfully. */
5739 /* The user decided to abort the saving.
5740 If we're writing to a temporary file, remove it.
5741 XXX - should we do so even if we're not writing to a
5743 wtap_dump_close(pdh
, NULL
, &err
, &err_info
);
5744 if (fname_new
!= NULL
)
5745 ws_unlink(fname_new
);
5746 cf_callback_invoke(cf_cb_file_save_stopped
, NULL
);
5747 wtap_dump_params_cleanup(¶ms
);
5748 return CF_WRITE_ABORTED
;
5751 /* Error while saving.
5752 If we're writing to a temporary file, remove it. */
5753 if (fname_new
!= NULL
)
5754 ws_unlink(fname_new
);
5755 wtap_dump_close(pdh
, NULL
, &err
, &err_info
);
5756 wtap_dump_params_cleanup(¶ms
);
5760 if (!wtap_dump_close(pdh
, &needs_reload
, &err
, &err_info
)) {
5761 report_cfile_close_failure(fname
, err
, err_info
);
5762 wtap_dump_params_cleanup(¶ms
);
5766 wtap_dump_params_cleanup(¶ms
);
5769 if (fname_new
!= NULL
) {
5770 /* We wrote out to fname_new, and should rename it on top of
5771 fname. fname_new is now closed, so that should be possible even
5772 on Windows. However, on Windows, we first need to close whatever
5773 file descriptors we have open for fname. */
5775 wtap_fdclose(cf
->provider
.wth
);
5777 /* Now do the rename. */
5778 if (ws_rename(fname_new
, fname
) == -1) {
5779 /* Well, the rename failed. */
5780 report_rename_failure(fname_new
, fname
, errno
);
5782 /* Attempt to reopen the random file descriptor using the
5783 current file's filename. (At this point, the sequential
5784 file descriptor is closed.) */
5785 if (!wtap_fdreopen(cf
->provider
.wth
, cf
->filename
, &err
)) {
5786 /* Oh, well, we're screwed. */
5787 report_cfile_open_failure(cf
->filename
, err
, NULL
);
5795 /* If this was a temporary file, and we didn't do the save by doing
5796 a move, so the tempoary file is still around under its old name,
5798 if (cf
->is_tempfile
&& how_to_save
!= SAVE_WITH_MOVE
) {
5799 /* If this fails, there's not much we can do, so just ignore errors. */
5800 ws_unlink(cf
->filename
);
5803 cf_callback_invoke(cf_cb_file_save_finished
, NULL
);
5804 cf
->unsaved_changes
= false;
5807 switch (how_to_save
) {
5809 case SAVE_WITH_MOVE
:
5810 /* We just moved the file, so the wtap structure refers to the
5811 new file, and all the information other than the filename
5812 and the "is temporary" status applies to the new file; just
5814 g_free(cf
->filename
);
5815 cf
->filename
= g_strdup(fname
);
5816 cf
->is_tempfile
= false;
5817 cf_callback_invoke(cf_cb_file_fast_save_finished
, cf
);
5820 case SAVE_WITH_COPY
:
5821 /* We just copied the file, so all the information other than
5822 the file descriptors, the filename, and the "is temporary"
5823 status applies to the new file; just update that. */
5824 wtap_fdclose(cf
->provider
.wth
);
5825 /* Attempt to reopen the random file descriptor using the
5826 new file's filename. (At this point, the sequential
5827 file descriptor is closed.) */
5828 if (!wtap_fdreopen(cf
->provider
.wth
, fname
, &err
)) {
5829 report_cfile_open_failure(fname
, err
, err_info
);
5832 g_free(cf
->filename
);
5833 cf
->filename
= g_strdup(fname
);
5834 cf
->is_tempfile
= false;
5836 cf_callback_invoke(cf_cb_file_fast_save_finished
, cf
);
5839 case SAVE_WITH_WTAP
:
5840 /* Open and read the file we saved to.
5842 XXX - this is somewhat of a waste; we already have the
5843 packets, all this gets us is updated file type information
5844 (which we could just stuff into "cf"), and having the new
5845 file be the one we have opened and from which we're reading
5846 the data, and it means we have to spend time opening and
5847 reading the file, which could be a significant amount of
5848 time if the file is large.
5850 If the capture-file-writing code were to return the
5851 seek offset of each packet it writes, we could save that
5852 in the frame_data structure for the frame, and just open
5853 the file without reading it again...
5855 ...as long as, for gzipped files, the process of writing
5856 out the file *also* generates the information needed to
5857 support fast random access to the compressed file. */
5858 /* rescan_file will cause us to try all open_routines, so
5859 reset cfile's open_type */
5860 cf
->open_type
= WTAP_TYPE_AUTO
;
5861 /* There are cases when SAVE_WITH_WTAP can result in new packets
5862 being written to the file, e.g ERF records
5863 In that case, we need to reload the whole file */
5865 if (cf_open(cf
, fname
, WTAP_TYPE_AUTO
, false, &err
) == CF_OK
) {
5866 if (cf_read(cf
, /*reloading=*/true) != CF_READ_OK
) {
5867 /* The rescan failed; just close the file. Either
5868 a dialog was popped up for the failure, so the
5869 user knows what happened, or they stopped the
5870 rescan, in which case they know what happened. */
5871 /* XXX: This is inconsistent with normal open/reload behaviour. */
5877 if (rescan_file(cf
, fname
, false) != CF_READ_OK
) {
5878 /* The rescan failed; just close the file. Either
5879 a dialog was popped up for the failure, so the
5880 user knows what happened, or they stopped the
5881 rescan, in which case they know what happened. */
5888 /* If we were told to discard the comments, do so. */
5889 if (discard_comments
) {
5890 /* Remove SHB comment, if any. */
5891 wtap_write_shb_comment(cf
->provider
.wth
, NULL
);
5893 /* remove all user comments */
5894 for (framenum
= 1; framenum
<= cf
->count
; framenum
++) {
5895 fdata
= frame_data_sequence_find(cf
->provider
.frames
, framenum
);
5897 // XXX: This also ignores non-comment options like verdict
5898 fdata
->has_modified_block
= false;
5901 if (cf
->provider
.frames_modified_blocks
) {
5902 g_tree_destroy(cf
->provider
.frames_modified_blocks
);
5903 cf
->provider
.frames_modified_blocks
= NULL
;
5906 cf
->packet_comment_count
= 0;
5912 if (fname_new
!= NULL
) {
5913 /* We were trying to write to a temporary file; get rid of it if it
5914 exists. (We don't care whether this fails, as, if it fails,
5915 there's not much we can do about it. I guess if it failed for
5916 a reason other than "it doesn't exist", we could report an
5917 error, so the user knows there's a junk file that they might
5918 want to clean up.) */
5919 ws_unlink(fname_new
);
5922 cf_callback_invoke(cf_cb_file_save_failed
, NULL
);
5923 return CF_WRITE_ERROR
;
5927 cf_export_specified_packets(capture_file
*cf
, const char *fname
,
5928 packet_range_t
*range
, unsigned save_format
,
5929 wtap_compression_type compression_type
)
5931 char *fname_new
= NULL
;
5935 save_callback_args_t callback_args
;
5936 wtap_dump_params params
;
5939 callback_args
.export
= true;
5940 packet_range_process_init(range
);
5942 /* We're writing out specified packets from the specified capture
5943 file to another file. Even if all captured packets are to be
5944 written, don't special-case the operation - read each packet
5945 and then write it out if it's one of the specified ones. */
5947 wtap_dump_params_init(¶ms
, cf
->provider
.wth
);
5949 /* Determine what file encapsulation type we should use. */
5950 encap
= wtap_dump_required_file_encap_type(cf
->linktypes
);
5951 params
.encap
= encap
;
5953 /* Use the snaplen from cf (XXX - does wtap_dump_params_init handle that?) */
5954 params
.snaplen
= cf
->snap
;
5956 if (file_exists(fname
)) {
5957 /* We're overwriting an existing file; write out to a new file,
5958 and, if that succeeds, rename the new file on top of the
5959 old file. That makes this a "safe save", so that we don't
5960 lose the old file if we have a problem writing out the new
5961 file. (If the existing file is the current capture file,
5962 we *HAVE* to do that, otherwise we're overwriting the file
5963 from which we're reading the packets that we're writing!) */
5964 fname_new
= ws_strdup_printf("%s~", fname
);
5965 pdh
= wtap_dump_open(fname_new
, save_format
, compression_type
, ¶ms
,
5968 pdh
= wtap_dump_open(fname
, save_format
, compression_type
, ¶ms
,
5971 /* XXX idb_inf is documented to be used until wtap_dump_close. */
5972 g_free(params
.idb_inf
);
5973 params
.idb_inf
= NULL
;
5976 report_cfile_dump_open_failure(fname
, err
, err_info
, save_format
);
5980 /* Add address resolution */
5981 wtap_dump_set_addrinfo_list(pdh
, get_addrinfo_list());
5983 /* Iterate through the list of packets, processing the packets we were
5986 XXX - we've already called "packet_range_process_init(range)", but
5987 "process_specified_records()" will do it again. Fortunately,
5988 that's harmless in this case, as we haven't done anything to
5989 "range" since we initialized it. */
5990 callback_args
.pdh
= pdh
;
5991 callback_args
.fname
= fname
;
5992 callback_args
.file_type
= save_format
;
5993 switch (process_specified_records(cf
, range
, "Writing", "specified records",
5994 true, save_record
, &callback_args
, true)) {
5997 /* Completed successfully. */
6001 /* The user decided to abort the saving.
6002 If we're writing to a temporary file, remove it.
6003 XXX - should we do so even if we're not writing to a
6005 wtap_dump_close(pdh
, NULL
, &err
, &err_info
);
6006 if (fname_new
!= NULL
) {
6007 ws_unlink(fname_new
);
6010 wtap_dump_params_cleanup(¶ms
);
6012 return CF_WRITE_ABORTED
;
6015 /* Error while saving. */
6016 wtap_dump_close(pdh
, NULL
, &err
, &err_info
);
6018 * We don't report any error from closing; the error that caused
6019 * process_specified_records() to fail has already been reported.
6024 if (!wtap_dump_close(pdh
, NULL
, &err
, &err_info
)) {
6025 report_cfile_close_failure(fname
, err
, err_info
);
6029 if (fname_new
!= NULL
) {
6030 /* We wrote out to fname_new, and should rename it on top of
6031 fname; fname is now closed, so that should be possible even
6032 on Windows. Do the rename. */
6033 if (ws_rename(fname_new
, fname
) == -1) {
6034 /* Well, the rename failed. */
6035 report_rename_failure(fname_new
, fname
, errno
);
6040 wtap_dump_params_cleanup(¶ms
);
6045 if (fname_new
!= NULL
) {
6046 /* We were trying to write to a temporary file; get rid of it if it
6047 exists. (We don't care whether this fails, as, if it fails,
6048 there's not much we can do about it. I guess if it failed for
6049 a reason other than "it doesn't exist", we could report an
6050 error, so the user knows there's a junk file that they might
6051 want to clean up.) */
6052 ws_unlink(fname_new
);
6055 wtap_dump_params_cleanup(¶ms
);
6057 return CF_WRITE_ERROR
;
6060 /* Reload the current capture file. */
6062 cf_reload(capture_file
*cf
)
6066 cf_status_t cf_status
= CF_OK
;
6069 if (cf
->read_lock
) {
6070 ws_warning("Failing cf_reload(\"%s\") since a read is in progress", cf
->filename
);
6074 /* If the file could be opened, "cf_open()" calls "cf_close()"
6075 to get rid of state for the old capture file before filling in state
6076 for the new capture file. "cf_close()" will remove the file if
6077 it's a temporary file; we don't want that to happen (for one thing,
6078 it'd prevent subsequent reopens from working). Remember whether it's
6079 a temporary file, mark it as not being a temporary file, and then
6080 reopen it as the type of file it was.
6082 Also, "cf_close()" will free "cf->filename", so we must make
6083 a copy of it first. */
6084 filename
= g_strdup(cf
->filename
);
6085 is_tempfile
= cf
->is_tempfile
;
6086 cf
->is_tempfile
= false;
6087 if (cf_open(cf
, filename
, cf
->open_type
, is_tempfile
, &err
) == CF_OK
) {
6088 switch (cf_read(cf
, /*reloading=*/true)) {
6092 /* Just because we got an error, that doesn't mean we were unable
6093 to read any of the file; we handle what we could get from the
6097 case CF_READ_ABORTED
:
6098 /* The user bailed out of re-reading the capture file; the
6099 capture file has been closed. */
6103 /* The open failed, so "cf->is_tempfile" wasn't set to "is_tempfile".
6104 Instead, the file was left open, so we should restore "cf->is_tempfile"
6107 XXX - change the menu? Presumably "cf_open()" will do that;
6108 make sure it does! */
6109 cf
->is_tempfile
= is_tempfile
;
6110 cf_status
= CF_ERROR
;
6112 /* "cf_open()" made a copy of the file name we handed it, so
6113 we should free up our copy. */