the packets, so we know how much we'll ultimately need. */
ws_buffer_init(&cf->buf, 1500);
- /* Create new epan session for dissection.
- * (The old one was freed in cf_close().)
- */
- cf->epan = ws_epan_new(cf);
-
/* We're about to start reading the file. */
cf->state = FILE_READ_IN_PROGRESS;
cf->provider.prev_cap = NULL;
cf->cum_bytes = 0;
+ /* Create new epan session for dissection.
+ * (The old one was freed in cf_close().)
+ */
+ cf->epan = ws_epan_new(cf);
+
packet_list_queue_draw();
cf_callback_invoke(cf_cb_file_opened, cf);
- if ((cf->cd_t == WTAP_FILE_TYPE_SUBTYPE_BER)
- || (cf->cd_t == WTAP_FILE_TYPE_SUBTYPE_PEM)) {
+ if (cf->cd_t == WTAP_FILE_TYPE_SUBTYPE_BER) {
/* tell the BER dissector the file name */
ber_set_filename(cf->filename);
}
/* Die if we're in the middle of reading a file. */
g_assert(cf->state != FILE_READ_IN_PROGRESS);
+ g_assert(!cf->read_lock);
cf_callback_invoke(cf_cb_file_closing, cf);
gboolean compiled;
volatile gboolean is_read_aborted = FALSE;
+ /* The update_progress_dlg call below might end up accepting a user request to
+ * trigger redissection/rescans which can modify/destroy the dissection
+ * context ("cf->epan"). That condition should be prevented by callers, but in
+ * case it occurs let's fail gracefully.
+ */
+ if (cf->read_lock) {
+ g_warning("Failing due to recursive cf_read(\"%s\", %d) call!",
+ cf->filename, reloading);
+ return CF_READ_ERROR;
+ }
+ cf->read_lock = TRUE;
+
/* Compile the current display filter.
* We assume this will not fail since cf->dfilter is only set in
* cf_filter IFF the filter was valid.
packets_bar_update();
g_timer_start(prog_timer);
}
+ /*
+ * The previous GUI triggers should not have destroyed the running
+ * session. If that did happen, it could blow up when read_record tries
+ * to use the destroyed edt.session, so detect it right here.
+ */
+ g_assert(edt.session == cf->epan);
}
if (cf->state == FILE_READ_ABORTED) {
packet_list_select_first_row();
}
+ /* It is safe again to execute redissections. */
+ g_assert(cf->read_lock);
+ cf->read_lock = FALSE;
+
if (is_read_aborted) {
/*
* Well, the user decided to exit Wireshark while reading this *offline*
* cf_continue_tail). Clean up accordingly.
*/
cf_close(cf);
+ cf->redissection_queued = RESCAN_NONE;
return CF_READ_ABORTED;
}
+ if (cf->redissection_queued != RESCAN_NONE) {
+ /* Redissection was queued up. Clear the request and perform it now. */
+ gboolean redissect = cf->redissection_queued == RESCAN_REDISSECT;
+ rescan_packets(cf, "Reprocessing", "all packets", redissect);
+ }
+
if (cf->stop_flag) {
simple_message_box(ESD_TYPE_WARN, NULL,
"The remaining packets in the file were discarded.\n"
return displayname;
}
+gchar *
+cf_get_basename(capture_file *cf)
+{
+ gchar *displayname;
+
+ /* Return a name to use in the GUI for the basename for files to
+ which we save statistics */
+ if (!cf->is_tempfile) {
+ /* Get the last component of the file name, and use that. */
+ if (cf->filename) {
+ displayname = g_filename_display_basename(cf->filename);
+
+ /* If the file name ends with any extension that corresponds
+ to a file type we support - including compressed versions
+ of those files - strip it off. */
+ size_t displayname_len = strlen(displayname);
+ GSList *extensions = wtap_get_all_file_extensions_list();
+ GSList *suffix;
+ for (suffix = extensions; suffix != NULL; suffix = g_slist_next(suffix)) {
+ /* Does the file name end with that extension? */
+ const char *extension = (char *)suffix->data;
+ size_t extension_len = strlen(extension);
+ if (displayname_len > extension_len &&
+ displayname[displayname_len - extension_len - 1] == '.' &&
+ strcmp(&displayname[displayname_len - extension_len], extension) == 0) {
+ /* Yes. Strip the extension off, and return the result. */
+ displayname[displayname_len - extension_len - 1] = '\0';
+ break;
+ }
+ }
+ wtap_free_extensions_list(extensions);
+ } else {
+ displayname=g_strdup("");
+ }
+ } else {
+ /* The file we read is a temporary file from a live capture or
+ a merge operation; we don't mention its name, but, if it's
+ from a capture, give the source of the capture. */
+ if (cf->source) {
+ displayname = g_strdup(cf->source);
+ } else {
+ displayname = g_strdup("");
+ }
+ }
+ return displayname;
+}
+
void cf_set_tempfile_source(capture_file *cf, gchar *source) {
if (cf->source) {
g_free(cf->source);
cf->packet_comment_count++;
cf->f_datalen = offset + fdlocal.cap_len;
- if (!cf->redissecting) {
+ /* When a redissection is in progress (or queued), do not process packets.
+ * This will be done once all (new) packets have been scanned. */
+ if (!cf->redissecting && cf->redissection_queued == RESCAN_NONE) {
add_packet_to_packet_list(fdata, cf, edt, dfcode,
cinfo, rec, buf, TRUE);
}
/* Now rescan the packet list, applying the new filter, but not
- throwing away information constructed on a previous pass. */
- if (cf->state != FILE_CLOSED) {
- if (dftext == NULL) {
- rescan_packets(cf, "Resetting", "Filter", FALSE);
- } else {
- rescan_packets(cf, "Filtering", dftext, FALSE);
+ * throwing away information constructed on a previous pass.
+ * If a dissection is already in progress, queue it.
+ */
+ if (cf->redissection_queued == RESCAN_NONE) {
+ if (cf->read_lock) {
+ cf->redissection_queued = RESCAN_SCAN;
+ } else if (cf->state != FILE_CLOSED) {
+ if (dftext == NULL) {
+ rescan_packets(cf, "Resetting", "Filter", FALSE);
+ } else {
+ rescan_packets(cf, "Filtering", dftext, FALSE);
+ }
}
}
void
cf_redissect_packets(capture_file *cf)
{
+ if (cf->read_lock || cf->redissection_queued == RESCAN_SCAN) {
+ /* Dissection in progress, signal redissection rather than rescanning. That
+ * would destroy the current (in-progress) dissection in "cf_read" which
+ * will cause issues when "cf_read" tries to add packets to the list.
+ * If a previous rescan was requested, "upgrade" it to a full redissection.
+ */
+ cf->redissection_queued = RESCAN_REDISSECT;
+ }
+ if (cf->redissection_queued != RESCAN_NONE) {
+ /* Redissection is (already) queued, wait for "cf_read" to finish. */
+ return;
+ }
+
if (cf->state != FILE_CLOSED) {
+ /* Restart dissection in case no cf_read is pending. */
rescan_packets(cf, "Reprocessing", "all packets", TRUE);
}
}
gboolean add_to_packet_list = FALSE;
gboolean compiled;
guint32 frames_count;
+ gboolean queued_rescan_type = RESCAN_NONE;
+
+ /* Rescan in progress, clear pending actions. */
+ cf->redissection_queued = RESCAN_NONE;
+ g_assert(!cf->read_lock);
+ cf->read_lock = TRUE;
/* Compile the current display filter.
* We assume this will not fail since cf->dfilter is only set in
g_timer_start(prog_timer);
}
+ queued_rescan_type = cf->redissection_queued;
+ if (queued_rescan_type != RESCAN_NONE) {
+ /* A redissection was requested while an existing redissection was
+ * pending. */
+ break;
+ }
+
if (cf->stop_flag) {
/* Well, the user decided to abort the filtering. Just stop.
/* Cleanup and release all dfilter resources */
dfilter_free(dfcode);
+
+ /* It is safe again to execute redissections. */
+ g_assert(cf->read_lock);
+ cf->read_lock = FALSE;
+
+ /* If another rescan (due to dfilter change) or redissection (due to profile
+ * change) was requested, the rescan above is aborted and restarted here. */
+ if (queued_rescan_type != RESCAN_NONE) {
+ redissect = redissect || queued_rescan_type == RESCAN_REDISSECT;
+ rescan_packets(cf, "Reprocessing", "all packets", redissect);
+ }
}
{
guint32 framenum;
frame_data *fdata;
+ wtap_rec rec;
Buffer buf;
psp_return_t ret = PSP_FINISHED;
GTimeVal progbar_start_time;
gchar progbar_status_str[100];
range_process_e process_this;
- wtap_rec rec;
wtap_rec_init(&rec);
ws_buffer_init(&buf, 1500);
/* Progress so far. */
progbar_val = 0.0f;
+ if (cf->read_lock) {
+ g_warning("Failing due to nested process_specified_records(\"%s\") call!", cf->filename);
+ return PSP_FAILED;
+ }
+ cf->read_lock = TRUE;
+
cf->stop_flag = FALSE;
g_get_current_time(&progbar_start_time);
destroy_progress_dlg(progbar);
g_timer_destroy(prog_timer);
+ g_assert(cf->read_lock);
+ cf->read_lock = FALSE;
+
wtap_rec_cleanup(&rec);
ws_buffer_free(&buf);
"all packets", TRUE, retap_packet,
&callback_args, TRUE);
+ packet_range_cleanup(&range);
epan_dissect_cleanup(&callback_args.edt);
cf_callback_invoke(cf_cb_file_retap_finished, cf);
if (args->print_formfeed) {
if (!new_page(args->print_args->stream))
goto fail;
+
+ /*
+ * Print another header line if we print a packet summary on the
+ * new page.
+ */
+ if (args->print_args->print_col_headings)
+ args->print_header_line = TRUE;
} else {
if (args->print_separator) {
if (!print_line(args->print_args->stream, 0, ""))
{
frame_data *start_fd;
guint32 framenum;
+ guint32 prev_framenum;
frame_data *fdata;
frame_data *new_fd = NULL;
progdlg_t *progbar = NULL;
start_fd = cf->current_frame;
if (start_fd != NULL) {
- /* Iterate through the list of packets, starting at the packet we've
- picked, calling a routine to run the filter on the packet, see if
- it matches, and stop if so. */
- count = 0;
- framenum = start_fd->num;
+ prev_framenum = start_fd->num;
+ } else {
+ prev_framenum = 0; /* No start packet selected. */
+ }
- g_timer_start(prog_timer);
- /* Progress so far. */
- progbar_val = 0.0f;
+ /* Iterate through the list of packets, starting at the packet we've
+ picked, calling a routine to run the filter on the packet, see if
+ it matches, and stop if so. */
+ count = 0;
+ framenum = prev_framenum;
- cf->stop_flag = FALSE;
- g_get_current_time(&start_time);
+ g_timer_start(prog_timer);
+ /* Progress so far. */
+ progbar_val = 0.0f;
- title = cf->sfilter?cf->sfilter:"";
- for (;;) {
- /* Create the progress bar if necessary.
- We check on every iteration of the loop, so that it takes no
- longer than the standard time to create it (otherwise, for a
+ cf->stop_flag = FALSE;
+ g_get_current_time(&start_time);
+
+ title = cf->sfilter?cf->sfilter:"";
+ for (;;) {
+ /* Create the progress bar if necessary.
+ We check on every iteration of the loop, so that it takes no
+ longer than the standard time to create it (otherwise, for a
large file, we might take considerably longer than that standard
- time in order to get to the next progress bar step). */
- if (progbar == NULL)
- progbar = delayed_create_progress_dlg(cf->window, "Searching", title,
- FALSE, &cf->stop_flag, &start_time, progbar_val);
+ time in order to get to the next progress bar step). */
+ if (progbar == NULL)
+ progbar = delayed_create_progress_dlg(cf->window, "Searching", title,
+ FALSE, &cf->stop_flag, &start_time, progbar_val);
- /*
- * Update the progress bar, but do it only after PROGBAR_UPDATE_INTERVAL
- * has elapsed. Calling update_progress_dlg and packets_bar_update will
- * likely trigger UI paint events, which might take a while depending on
- * the platform and display. Reset our timer *after* painting.
+ /*
+ * Update the progress bar, but do it only after PROGBAR_UPDATE_INTERVAL
+ * has elapsed. Calling update_progress_dlg and packets_bar_update will
+ * likely trigger UI paint events, which might take a while depending on
+ * the platform and display. Reset our timer *after* painting.
+ */
+ if (g_timer_elapsed(prog_timer, NULL) > PROGBAR_UPDATE_INTERVAL) {
+ /* let's not divide by zero. I should never be started
+ * with count == 0, so let's assert that
*/
- if (g_timer_elapsed(prog_timer, NULL) > PROGBAR_UPDATE_INTERVAL) {
- /* let's not divide by zero. I should never be started
- * with count == 0, so let's assert that
- */
- g_assert(cf->count > 0);
-
- progbar_val = (gfloat) count / cf->count;
+ g_assert(cf->count > 0);
- g_snprintf(status_str, sizeof(status_str),
- "%4u of %u packets", count, cf->count);
- update_progress_dlg(progbar, progbar_val, status_str);
+ progbar_val = (gfloat) count / cf->count;
- g_timer_start(prog_timer);
- }
+ g_snprintf(status_str, sizeof(status_str),
+ "%4u of %u packets", count, cf->count);
+ update_progress_dlg(progbar, progbar_val, status_str);
- if (cf->stop_flag) {
- /* Well, the user decided to abort the search. Go back to the
- frame where we started. */
- new_fd = start_fd;
- break;
- }
+ g_timer_start(prog_timer);
+ }
- /* Go past the current frame. */
- if (dir == SD_BACKWARD) {
- /* Go on to the previous frame. */
- if (framenum == 1) {
- /*
- * XXX - other apps have a bit more of a detailed message
- * for this, and instead of offering "OK" and "Cancel",
- * they offer things such as "Continue" and "Cancel";
- * we need an API for popping up alert boxes with
- * {Verb} and "Cancel".
- */
-
- if (prefs.gui_find_wrap)
- {
- statusbar_push_temporary_msg("Search reached the beginning. Continuing at end.");
- framenum = cf->count; /* wrap around */
- }
- else
- {
- statusbar_push_temporary_msg("Search reached the beginning.");
- framenum = start_fd->num; /* stay on previous packet */
- }
- } else
- framenum--;
- } else {
- /* Go on to the next frame. */
- if (framenum == cf->count) {
- if (prefs.gui_find_wrap)
- {
- statusbar_push_temporary_msg("Search reached the end. Continuing at beginning.");
- framenum = 1; /* wrap around */
- }
- else
- {
- statusbar_push_temporary_msg("Search reached the end.");
- framenum = start_fd->num; /* stay on previous packet */
- }
- } else
- framenum++;
- }
- fdata = frame_data_sequence_find(cf->provider.frames, framenum);
+ if (cf->stop_flag) {
+ /* Well, the user decided to abort the search. Go back to the
+ frame where we started. */
+ new_fd = start_fd;
+ break;
+ }
- count++;
+ /* Go past the current frame. */
+ if (dir == SD_BACKWARD) {
+ /* Go on to the previous frame. */
+ if (framenum <= 1) {
+ /*
+ * XXX - other apps have a bit more of a detailed message
+ * for this, and instead of offering "OK" and "Cancel",
+ * they offer things such as "Continue" and "Cancel";
+ * we need an API for popping up alert boxes with
+ * {Verb} and "Cancel".
+ */
- /* Is this packet in the display? */
- if (fdata->flags.passed_dfilter) {
- /* Yes. Does it match the search criterion? */
- result = (*match_function)(cf, fdata, criterion);
- if (result == MR_ERROR) {
- /* Error; our caller has reported the error. Go back to the frame
- where we started. */
- new_fd = start_fd;
- break;
- } else if (result == MR_MATCHED) {
- /* Yes. Go to the new frame. */
- new_fd = fdata;
- break;
+ if (prefs.gui_find_wrap) {
+ statusbar_push_temporary_msg("Search reached the beginning. Continuing at end.");
+ framenum = cf->count; /* wrap around */
+ } else {
+ statusbar_push_temporary_msg("Search reached the beginning.");
+ framenum = prev_framenum; /* stay on previous packet */
}
- }
+ } else
+ framenum--;
+ } else {
+ /* Go on to the next frame. */
+ if (framenum == cf->count) {
+ if (prefs.gui_find_wrap) {
+ statusbar_push_temporary_msg("Search reached the end. Continuing at beginning.");
+ framenum = 1; /* wrap around */
+ } else {
+ statusbar_push_temporary_msg("Search reached the end.");
+ framenum = prev_framenum; /* stay on previous packet */
+ }
+ } else
+ framenum++;
+ }
+
+ fdata = frame_data_sequence_find(cf->provider.frames, framenum);
+ count++;
- if (fdata == start_fd) {
- /* We're back to the frame we were on originally, and that frame
- doesn't match the search filter. The search failed. */
+ /* Is this packet in the display? */
+ if (fdata && fdata->flags.passed_dfilter) {
+ /* Yes. Does it match the search criterion? */
+ result = (*match_function)(cf, fdata, criterion);
+ if (result == MR_ERROR) {
+ /* Error; our caller has reported the error. Go back to the frame
+ where we started. */
+ new_fd = start_fd;
+ break;
+ } else if (result == MR_MATCHED) {
+ /* Yes. Go to the new frame. */
+ new_fd = fdata;
break;
}
}
- /* We're done scanning the packets; destroy the progress bar if it
- was created. */
- if (progbar != NULL)
- destroy_progress_dlg(progbar);
- g_timer_destroy(prog_timer);
+ if (fdata == start_fd) {
+ /* We're back to the frame we were on originally, and that frame
+ doesn't match the search filter. The search failed. */
+ break;
+ }
}
+ /* We're done scanning the packets; destroy the progress bar if it
+ was created. */
+ if (progbar != NULL)
+ destroy_progress_dlg(progbar);
+ g_timer_destroy(prog_timer);
+
if (new_fd != NULL) {
/* Find and select */
cf->search_in_progress = TRUE;
save_callback_args_t callback_args;
gboolean needs_reload = FALSE;
+ /* XXX caller should avoid saving the file while a read is pending
+ * (e.g. by delaying the save action) */
+ if (cf->read_lock) {
+ g_warning("cf_save_records(\"%s\") while the file is being read, potential crash ahead", fname);
+ }
+
cf_callback_invoke(cf_cb_file_save_started, (gpointer)fname);
addr_lists = get_addrinfo_list();
gboolean is_tempfile;
int err;
+ if (cf->read_lock) {
+ g_warning("Failing cf_reload(\"%s\") since a read is in progress", cf->filename);
+ return;
+ }
+
/* If the file could be opened, "cf_open()" calls "cf_close()"
to get rid of state for the old capture file before filling in state
for the new capture file. "cf_close()" will remove the file if