#include <wsutil/tempfile.h>
#include <wsutil/file_util.h>
#include <wsutil/filesystem.h>
-#include <wsutil/ws_version_info.h>
+#include <ws_version_info.h>
#include <wiretap/merge.h>
void *criterion);
static match_result match_binary(capture_file *cf, frame_data *fdata,
void *criterion);
+static match_result match_regex(capture_file *cf, frame_data *fdata,
+ void *criterion);
static match_result match_dfilter(capture_file *cf, frame_data *fdata,
void *criterion);
static match_result match_marked(capture_file *cf, frame_data *fdata,
static void cf_rename_failure_alert_box(const char *filename, int err);
static void cf_close_failure_alert_box(const char *filename, int err);
static void ref_time_packets(capture_file *cf);
-/* Update the progress bar this many times when reading a file. */
-#define N_PROGBAR_UPDATES 100
-/* We read around 200k/100ms don't update the progress bar more often than that */
-#define MIN_QUANTUM 200000
-#define MIN_NUMBER_OF_PACKET 1500
+
+/* Seconds spent processing packets between pushing UI updates. */
+#define PROGBAR_UPDATE_INTERVAL 0.150
+
+/* Show the progress bar after this many seconds. */
+#define PROGBAR_SHOW_DELAY 0.5
/*
* We could probably use g_signal_...() instead of the callbacks below but that
epan->data = cf;
epan->get_frame_ts = ws_get_frame_ts;
epan->get_interface_name = cap_file_get_interface_name;
+ epan->get_interface_description = cap_file_get_interface_description;
epan->get_user_comment = ws_get_user_comment;
return epan;
cf->prev_cap = NULL;
cf->cum_bytes = 0;
- /* Adjust timestamp precision if auto is selected, col width will be adjusted */
- cf_timestamp_auto_precision(cf);
- /* XXX needed ? */
packet_list_queue_draw();
cf_callback_invoke(cf_cb_file_opened, cf);
cf_callback_invoke(cf_cb_file_closed, cf);
}
+/*
+ * TRUE if the progress dialog doesn't exist and it looks like we'll
+ * take > 2s to load, FALSE otherwise.
+ */
+static inline gboolean
+progress_is_slow(progdlg_t *progdlg, GTimer *prog_timer, gint64 size, gint64 pos)
+{
+ double elapsed;
+
+ if (progdlg) return FALSE;
+ elapsed = g_timer_elapsed(prog_timer, NULL);
+ if ((elapsed / 2 > PROGBAR_SHOW_DELAY && (size / pos) > 2) /* It looks like we're going to be slow. */
+ || elapsed > PROGBAR_SHOW_DELAY) { /* We are indeed slow. */
+ return TRUE;
+ }
+ return FALSE;
+}
+
static float
calc_progbar_val(capture_file *cf, gint64 size, gint64 file_pos, gchar *status_str, gulong status_size)
{
int err = 0;
gchar *err_info = NULL;
gchar *name_ptr;
- progdlg_t *progbar = NULL;
+ progdlg_t *volatile progbar = NULL;
+ GTimer *prog_timer = g_timer_new();
GTimeVal start_time;
epan_dissect_t edt;
dfilter_t *dfcode;
gint64 file_pos;
gint64 data_offset;
- gint64 progbar_quantum;
- gint64 progbar_nextstep;
float progbar_val;
gchar status_str[100];
/* Find the size of the file. */
size = wtap_file_size(cf->wth, NULL);
- /* Update the progress bar when it gets to this value. */
- progbar_nextstep = 0;
- /* When we reach the value that triggers a progress bar update,
- bump that value by this amount. */
- if (size >= 0) {
- progbar_quantum = size/N_PROGBAR_UPDATES;
- if (progbar_quantum < MIN_QUANTUM)
- progbar_quantum = MIN_QUANTUM;
- }else
- progbar_quantum = 0;
+ g_timer_start(prog_timer);
while ((wtap_read(cf->wth, &err, &err_info, &data_offset))) {
if (size >= 0) {
count++;
file_pos = wtap_read_so_far(cf->wth);
- /* Create the progress bar if necessary.
- * Check whether it should be created or not every MIN_NUMBER_OF_PACKET
- */
- if ((progbar == NULL) && !(count % MIN_NUMBER_OF_PACKET)) {
+ /* Create the progress bar if necessary. */
+ if (progress_is_slow(progbar, prog_timer, size, file_pos)) {
progbar_val = calc_progbar_val(cf, size, file_pos, status_str, sizeof(status_str));
if (reloading)
progbar = delayed_create_progress_dlg(cf->window, "Reloading", name_ptr,
TRUE, &cf->stop_flag, &start_time, progbar_val);
}
- /* Update the progress bar, but do it only N_PROGBAR_UPDATES times;
- when we update it, we have to run the GTK+ main loop to get it
- to repaint what's pending, and doing so may involve an "ioctl()"
- to see if there's any pending input from an X server, and doing
- that for every packet can be costly, especially on a big file. */
- if (file_pos >= progbar_nextstep) {
- if (progbar != NULL) {
- progbar_val = calc_progbar_val(cf, size, file_pos, status_str, sizeof(status_str));
- /* update the packet bar content on the first run or frequently on very large files */
- update_progress_dlg(progbar, progbar_val, status_str);
- packets_bar_update();
- }
- progbar_nextstep += progbar_quantum;
+ /*
+ * 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 (progbar && g_timer_elapsed(prog_timer, NULL) > PROGBAR_UPDATE_INTERVAL) {
+ progbar_val = calc_progbar_val(cf, size, file_pos, status_str, sizeof(status_str));
+ /* update the packet bar content on the first run or frequently on very large files */
+ update_progress_dlg(progbar, progbar_val, status_str);
+ packets_bar_update();
+ g_timer_start(prog_timer);
}
}
/* We're done reading the file; destroy the progress bar if it was created. */
if (progbar != NULL)
destroy_progress_dlg(progbar);
+ g_timer_destroy(prog_timer);
/* We're done reading sequentially through the file. */
cf->state = FILE_READ_DONE;
if (dfcode != NULL) {
epan_dissect_prime_dfilter(edt, dfcode);
}
+#if 0
+ /* Prepare coloring rules, this ensures that display filter rules containing
+ * frame.color_rule references are still processed.
+ * TODO: actually detect that situation or maybe apply other optimizations? */
+ if (edt->tree && color_filters_used()) {
+ color_filters_prime_edt(edt);
+ fdata->flags.need_colorize = 1;
+ }
+#endif
/* Dissect the frame. */
epan_dissect_run_with_taps(edt, cf->cd_t, phdr, frame_tvbuff_new(fdata, buf), fdata, cinfo);
frame_data_set_after_dissect(fdata, &cf->cum_bytes);
cf->prev_dis = fdata;
- /* If we haven't yet seen the first frame, this is it.
-
- XXX - we must do this before we add the row to the display,
- as, if the display's GtkCList's selection mode is
- GTK_SELECTION_BROWSE, when the first entry is added to it,
- "cf_select_packet()" will be called, and it will fetch the row
- data for the 0th row, and will get a null pointer rather than
- "fdata", as "gtk_clist_append()" won't yet have returned and
- thus "gtk_clist_set_row_data()" won't yet have been called.
-
- We thus need to leave behind bread crumbs so that
- "cf_select_packet()" can find this frame. See the comment
- in "cf_select_packet()". */
+ /* If we haven't yet seen the first frame, this is it. */
if (cf->first_displayed == 0)
cf->first_displayed = fdata->num;
typedef struct _callback_data_t {
+ gpointer pd_window;
gint64 f_len;
- gint64 progbar_nextstep;
- gint64 progbar_quantum;
GTimeVal start_time;
progdlg_t *progbar;
+ GTimer *prog_timer;
gboolean stop_flag;
} callback_data_t;
for (i = 0; i < in_file_count; i++)
cb_data->f_len += in_files[i].size;
- /* When we reach the value that triggers a progress bar update,
- bump that value by this amount. */
- cb_data->progbar_quantum = cb_data->f_len / N_PROGBAR_UPDATES;
+ cb_data->prog_timer = g_timer_new();
+ g_timer_start(cb_data->prog_timer);
g_get_current_time(&cb_data->start_time);
break;
large file, we might take considerably longer than that standard
time in order to get to the next progress bar step). */
if (cb_data->progbar == NULL) {
- cb_data->progbar = delayed_create_progress_dlg(NULL, "Merging", "files",
+ cb_data->progbar = delayed_create_progress_dlg(cb_data->pd_window, "Merging", "files",
FALSE, &cb_data->stop_flag, &cb_data->start_time, 0.0f);
}
- /* Update the progress bar, but do it only N_PROGBAR_UPDATES times;
- when we update it, we have to run the GTK+ main loop to get it
- to repaint what's pending, and doing so may involve an "ioctl()"
- to see if there's any pending input from an X server, and doing
- that for every packet can be costly, especially on a big file. */
- if (data_offset >= cb_data->progbar_nextstep) {
+ /*
+ * 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(cb_data->prog_timer, NULL) > PROGBAR_UPDATE_INTERVAL) {
float progbar_val;
gint64 file_pos = 0;
/* Get the sum of the seek positions in all of the files. */
file_pos / 1024, cb_data->f_len / 1024);
update_progress_dlg(cb_data->progbar, progbar_val, status_str);
}
- cb_data->progbar_nextstep += cb_data->progbar_quantum;
+ g_timer_start(cb_data->prog_timer);
}
}
break;
/* We're done merging the files; destroy the progress bar if it was created. */
if (cb_data->progbar != NULL)
destroy_progress_dlg(cb_data->progbar);
+ g_timer_destroy(cb_data->prog_timer);
break;
}
cf_status_t
-cf_merge_files(char **out_filenamep, int in_file_count,
- char *const *in_filenames, int file_type, gboolean do_append)
+cf_merge_files_to_tempfile(gpointer pd_window, char **out_filenamep,
+ int in_file_count, char *const *in_filenames,
+ int file_type, gboolean do_append)
{
- char *out_filename;
- char *tmpname;
- int out_fd;
int err = 0;
gchar *err_info = NULL;
- int err_fileno;
+ guint err_fileno;
merge_result status;
merge_progress_callback_t cb;
-
-
- if (*out_filenamep != NULL) {
- out_filename = *out_filenamep;
- out_fd = ws_open(out_filename, O_CREAT|O_TRUNC|O_BINARY, 0600);
- if (out_fd == -1)
- err = errno;
- } else {
- out_fd = create_tempfile(&tmpname, "wireshark");
- if (out_fd == -1)
- err = errno;
- out_filename = g_strdup(tmpname);
- *out_filenamep = out_filename;
- }
- if (out_fd == -1) {
- cf_open_failure_alert_box(out_filename, err, NULL, TRUE, file_type);
- return CF_ERROR;
- }
+ callback_data_t *cb_data = g_new0(callback_data_t, 1);
/* prepare our callback routine */
+ cb_data->pd_window = pd_window;
cb.callback_func = merge_callback;
- cb.data = g_malloc0(sizeof(callback_data_t));
+ cb.data = cb_data;
+
+ cf_callback_invoke(cf_cb_file_merge_started, NULL);
/* merge the files */
- status = merge_files(out_fd, out_filename, file_type,
- (const char *const *) in_filenames, in_file_count,
- do_append, IDB_MERGE_MODE_ALL_SAME, 0 /* snaplen */,
- "Wireshark", &cb, &err, &err_info, &err_fileno);
+ status = merge_files_to_tempfile(out_filenamep, "wireshark", file_type,
+ (const char *const *) in_filenames,
+ in_file_count, do_append,
+ IDB_MERGE_MODE_ALL_SAME, 0 /* snaplen */,
+ "Wireshark", &cb, &err, &err_info,
+ &err_fileno);
g_free(cb.data);
case MERGE_ERR_CANT_OPEN_INFILE:
cf_open_failure_alert_box(in_filenames[err_fileno], err, err_info,
FALSE, 0);
- ws_close(out_fd);
break;
case MERGE_ERR_CANT_OPEN_OUTFILE:
- cf_open_failure_alert_box(out_filename, err, err_info, TRUE,
+ cf_open_failure_alert_box(*out_filenamep, err, err_info, TRUE,
file_type);
- ws_close(out_fd);
break;
case MERGE_ERR_CANT_READ_INFILE: /* fall through */
}
g_free(err_info);
- /* for general case, no need to close out_fd: file handle associated to this file
- descriptor was already closed by the call to wtap_dump_close() in merge_files() */
+
+ cf_callback_invoke(cf_cb_file_merge_finished, NULL);
if (status != MERGE_OK) {
/* Callers aren't expected to treat an error or an explicit abort
guint32 framenum;
frame_data *fdata;
progdlg_t *progbar = NULL;
+ GTimer *prog_timer = g_timer_new();
int count;
frame_data *selected_frame, *preceding_frame, *following_frame, *prev_frame;
int selected_frame_num, preceding_frame_num, following_frame_num, prev_frame_num;
float progbar_val;
GTimeVal start_time;
gchar status_str[100];
- int progbar_nextstep;
- int progbar_quantum;
epan_dissect_t edt;
dfilter_t *dfcode;
column_info *cinfo;
cf->epan = ws_epan_new(cf);
cf->cinfo.epan = cf->epan;
+ /* A new Lua tap listener may be registered in lua_prime_all_fields()
+ called via epan_new() / init_dissection() when reloading Lua plugins. */
+ if (!create_proto_tree && have_filtering_tap_listeners()) {
+ create_proto_tree = TRUE;
+ }
+
/* We need to redissect the packets so we have to discard our old
* packet list store. */
packet_list_clear();
cf_callback_invoke(cf_cb_file_rescan_started, cf);
- /* Update the progress bar when it gets to this value. */
- progbar_nextstep = 0;
- /* When we reach the value that triggers a progress bar update,
- bump that value by this amount. */
- progbar_quantum = cf->count/N_PROGBAR_UPDATES;
+ g_timer_start(prog_timer);
/* Count of packets at which we've looked. */
count = 0;
/* Progress so far. */
&start_time,
progbar_val);
- /* Update the progress bar, but do it only N_PROGBAR_UPDATES times;
- when we update it, we have to run the GTK+ main loop to get it
- to repaint what's pending, and doing so may involve an "ioctl()"
- to see if there's any pending input from an X server, and doing
- that for every packet can be costly, especially on a big file. */
- if (count >= progbar_nextstep) {
+ /*
+ * 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
*/
update_progress_dlg(progbar, progbar_val, status_str);
}
- progbar_nextstep += progbar_quantum;
+ g_timer_start(prog_timer);
}
if (cf->stop_flag) {
was created. */
if (progbar != NULL)
destroy_progress_dlg(progbar);
+ g_timer_destroy(prog_timer);
/* Unfreeze the packet list. */
if (!add_to_packet_list)
/*
- * Scan trough all frame data and recalculate the ref time
+ * Scan through all frame data and recalculate the ref time
* without rereading the file.
* XXX - do we need a progres bar or is this fast enough?
*/
const char *string1, const char *string2, gboolean terminate_is_stop,
gboolean (*callback)(capture_file *, frame_data *,
struct wtap_pkthdr *, const guint8 *, void *),
- void *callback_args)
+ void *callback_args,
+ gboolean show_progress_bar)
{
guint32 framenum;
frame_data *fdata;
psp_return_t ret = PSP_FINISHED;
progdlg_t *progbar = NULL;
+ GTimer *prog_timer = g_timer_new();
int progbar_count;
float progbar_val;
GTimeVal progbar_start_time;
gchar progbar_status_str[100];
- int progbar_nextstep;
- int progbar_quantum;
range_process_e process_this;
struct wtap_pkthdr phdr;
wtap_phdr_init(&phdr);
ws_buffer_init(&buf, 1500);
- /* Update the progress bar when it gets to this value. */
- progbar_nextstep = 0;
- /* When we reach the value that triggers a progress bar update,
- bump that value by this amount. */
- progbar_quantum = cf->count/N_PROGBAR_UPDATES;
+ g_timer_start(prog_timer);
/* Count of packets at which we've looked. */
progbar_count = 0;
/* Progress so far. */
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)
+ if (show_progress_bar && progbar == NULL)
progbar = delayed_create_progress_dlg(cf->window, string1, string2,
terminate_is_stop,
&cf->stop_flag,
&progbar_start_time,
progbar_val);
- /* Update the progress bar, but do it only N_PROGBAR_UPDATES times;
- when we update it, we have to run the GTK+ main loop to get it
- to repaint what's pending, and doing so may involve an "ioctl()"
- to see if there's any pending input from an X server, and doing
- that for every packet can be costly, especially on a big file. */
- if (progbar_count >= progbar_nextstep) {
+ /*
+ * 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 (progbar && 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) progbar_count / cf->count;
- if (progbar != NULL) {
- g_snprintf(progbar_status_str, sizeof(progbar_status_str),
- "%4u of %u packets", progbar_count, cf->count);
- update_progress_dlg(progbar, progbar_val, progbar_status_str);
- }
+ g_snprintf(progbar_status_str, sizeof(progbar_status_str),
+ "%4u of %u packets", progbar_count, cf->count);
+ update_progress_dlg(progbar, progbar_val, progbar_status_str);
- progbar_nextstep += progbar_quantum;
+ g_timer_start(prog_timer);
}
if (cf->stop_flag) {
it was created. */
if (progbar != NULL)
destroy_progress_dlg(progbar);
+ g_timer_destroy(prog_timer);
wtap_phdr_cleanup(&phdr);
ws_buffer_free(&buf);
ret = process_specified_records(cf, &range, "Recalculating statistics on",
"all packets", TRUE, retap_packet,
- &callback_args);
+ &callback_args, TRUE);
epan_dissect_cleanup(&callback_args.edt);
}
cf_print_status_t
-cf_print_packets(capture_file *cf, print_args_t *print_args)
+cf_print_packets(capture_file *cf, print_args_t *print_args,
+ gboolean show_progress_bar)
{
print_callback_args_t callback_args;
gint data_width;
proto_tree_needed =
callback_args.print_args->print_dissections != print_dissections_none ||
callback_args.print_args->print_hex ||
- have_custom_cols(&cf->cinfo);
+ have_custom_cols(&cf->cinfo) || have_field_extractors();
epan_dissect_init(&callback_args.edt, cf->epan, proto_tree_needed, proto_tree_needed);
/* Iterate through the list of packets, printing the packets we were
told to print. */
ret = process_specified_records(cf, &print_args->range, "Printing",
"selected packets", TRUE, print_packet,
- &callback_args);
+ &callback_args, show_progress_bar);
epan_dissect_cleanup(&callback_args.edt);
g_free(callback_args.header_line_buf);
g_free(callback_args.line_buf);
typedef struct {
FILE *fh;
epan_dissect_t edt;
+ print_args_t *print_args;
} write_packet_callback_args_t;
static gboolean
epan_dissect_run(&args->edt, cf->cd_t, phdr, frame_tvbuff_new(fdata, pd), fdata, NULL);
/* Write out the information in that tree. */
- write_pdml_proto_tree(&args->edt, args->fh);
+ write_pdml_proto_tree(NULL, NULL, PF_NONE, &args->edt, args->fh);
epan_dissect_reset(&args->edt);
}
callback_args.fh = fh;
+ callback_args.print_args = print_args;
epan_dissect_init(&callback_args.edt, cf->epan, TRUE, TRUE);
/* Iterate through the list of packets, printing the packets we were
told to print. */
ret = process_specified_records(cf, &print_args->range, "Writing PDML",
"selected packets", TRUE,
- write_pdml_packet, &callback_args);
+ write_pdml_packet, &callback_args, TRUE);
epan_dissect_cleanup(&callback_args.edt);
}
callback_args.fh = fh;
+ callback_args.print_args = print_args;
/* Fill in the column information, only create the protocol tree
- if having custom columns. */
- proto_tree_needed = have_custom_cols(&cf->cinfo);
+ if having custom columns or field extractors. */
+ proto_tree_needed = have_custom_cols(&cf->cinfo) || have_field_extractors();
epan_dissect_init(&callback_args.edt, cf->epan, proto_tree_needed, proto_tree_needed);
/* Iterate through the list of packets, printing the packets we were
told to print. */
ret = process_specified_records(cf, &print_args->range, "Writing PSML",
"selected packets", TRUE,
- write_psml_packet, &callback_args);
+ write_psml_packet, &callback_args, TRUE);
epan_dissect_cleanup(&callback_args.edt);
}
callback_args.fh = fh;
+ callback_args.print_args = print_args;
- /* only create the protocol tree if having custom columns. */
- proto_tree_needed = have_custom_cols(&cf->cinfo);
+ /* only create the protocol tree if having custom columns or field extractors. */
+ proto_tree_needed = have_custom_cols(&cf->cinfo) || have_field_extractors();
epan_dissect_init(&callback_args.edt, cf->epan, proto_tree_needed, proto_tree_needed);
/* Iterate through the list of packets, printing the packets we were
told to print. */
ret = process_specified_records(cf, &print_args->range, "Writing CSV",
"selected packets", TRUE,
- write_csv_packet, &callback_args);
+ write_csv_packet, &callback_args, TRUE);
epan_dissect_cleanup(&callback_args.edt);
}
callback_args.fh = fh;
+ callback_args.print_args = print_args;
epan_dissect_init(&callback_args.edt, cf->epan, TRUE, TRUE);
/* Iterate through the list of packets, printing the packets we were
told to print. */
ret = process_specified_records(cf, &print_args->range,
- "Writing C Arrays",
- "selected packets", TRUE,
- carrays_write_packet, &callback_args);
+ "Writing C Arrays",
+ "selected packets", TRUE,
+ carrays_write_packet, &callback_args, TRUE);
+
+ epan_dissect_cleanup(&callback_args.edt);
+
+ switch (ret) {
+ case PSP_FINISHED:
+ /* Completed successfully. */
+ break;
+ case PSP_STOPPED:
+ /* Well, the user decided to abort the printing. */
+ break;
+ case PSP_FAILED:
+ /* Error while printing. */
+ fclose(fh);
+ return CF_PRINT_WRITE_ERROR;
+ }
+
+ fclose(fh);
+ return CF_PRINT_OK;
+}
+
+static gboolean
+write_json_packet(capture_file *cf, frame_data *fdata,
+ struct wtap_pkthdr *phdr, const guint8 *pd,
+ void *argsp)
+{
+ write_packet_callback_args_t *args = (write_packet_callback_args_t *)argsp;
+
+ /* Create the protocol tree, but don't fill in the column information. */
+ epan_dissect_run(&args->edt, cf->cd_t, phdr, frame_tvbuff_new(fdata, pd), fdata, NULL);
+
+ /* Write out the information in that tree. */
+ write_json_proto_tree(NULL, args->print_args, NULL, PF_NONE, &args->edt, args->fh);
+
+ epan_dissect_reset(&args->edt);
+
+ return !ferror(args->fh);
+}
+
+cf_print_status_t
+cf_write_json_packets(capture_file *cf, print_args_t *print_args)
+{
+ write_packet_callback_args_t callback_args;
+ FILE *fh;
+ psp_return_t ret;
+
+ fh = ws_fopen(print_args->file, "w");
+ if (fh == NULL)
+ return CF_PRINT_OPEN_ERROR; /* attempt to open destination failed */
+
+ write_json_preamble(fh);
+ if (ferror(fh)) {
+ fclose(fh);
+ return CF_PRINT_WRITE_ERROR;
+ }
+
+ callback_args.fh = fh;
+ callback_args.print_args = print_args;
+ epan_dissect_init(&callback_args.edt, cf->epan, TRUE, TRUE);
+
+ /* Iterate through the list of packets, printing the packets we were
+ told to print. */
+ ret = process_specified_records(cf, &print_args->range, "Writing PDML",
+ "selected packets", TRUE,
+ write_json_packet, &callback_args, TRUE);
epan_dissect_cleanup(&callback_args.edt);
switch (ret) {
+
case PSP_FINISHED:
/* Completed successfully. */
break;
+
case PSP_STOPPED:
/* Well, the user decided to abort the printing. */
break;
+
case PSP_FAILED:
/* Error while printing. */
fclose(fh);
return CF_PRINT_WRITE_ERROR;
}
+ write_json_finale(fh);
+ if (ferror(fh)) {
+ fclose(fh);
+ return CF_PRINT_WRITE_ERROR;
+ }
+
+ /* XXX - check for an error */
fclose(fh);
+
return CF_PRINT_OK;
}
proto_item_fill_label(fi, label_str);
}
- /* Does that label match? */
- label_len = strlen(label_ptr);
- for (i = 0; i < label_len; i++) {
- c_char = label_ptr[i];
- if (cf->case_type)
- c_char = g_ascii_toupper(c_char);
- if (c_char == string[c_match]) {
- c_match++;
- if (c_match == string_len) {
- /* No need to look further; we have a match */
- mdata->frame_matched = TRUE;
- mdata->finfo = fi;
- return;
- }
- } else
- c_match = 0;
+ if (cf->regex) {
+ if (g_regex_match(cf->regex, label_ptr, (GRegexMatchFlags) 0, NULL)) {
+ mdata->frame_matched = TRUE;
+ mdata->finfo = fi;
+ return;
+ }
+ } else {
+ /* Does that label match? */
+ label_len = strlen(label_ptr);
+ for (i = 0; i < label_len; i++) {
+ c_char = label_ptr[i];
+ if (cf->case_type)
+ c_char = g_ascii_toupper(c_char);
+ if (c_char == string[c_match]) {
+ c_match++;
+ if (c_match == string_len) {
+ /* No need to look further; we have a match */
+ mdata->frame_matched = TRUE;
+ mdata->finfo = fi;
+ return;
+ }
+ } else
+ c_match = 0;
+ }
}
/* Recurse into the subtree, if it exists */
/* Found it. See if we match. */
info_column = edt.pi.cinfo->columns[colx].col_data;
info_column_len = strlen(info_column);
- for (i = 0; i < info_column_len; i++) {
- c_char = info_column[i];
- if (cf->case_type)
- c_char = g_ascii_toupper(c_char);
- if (c_char == string[c_match]) {
- c_match++;
- if (c_match == string_len) {
- result = MR_MATCHED;
- break;
- }
- } else
- c_match = 0;
+ if (cf->regex) {
+ if (g_regex_match(cf->regex, info_column, (GRegexMatchFlags) 0, NULL)) {
+ result = MR_MATCHED;
+ break;
+ }
+ } else {
+ for (i = 0; i < info_column_len; i++) {
+ c_char = info_column[i];
+ if (cf->case_type)
+ c_char = g_ascii_toupper(c_char);
+ if (c_char == string[c_match]) {
+ c_match++;
+ if (c_match == string_len) {
+ result = MR_MATCHED;
+ break;
+ }
+ } else
+ c_match = 0;
+ }
}
break;
}
info.data = string;
info.data_len = string_size;
- /* String or hex search? */
- if (cf->string) {
+ /* Regex, String or hex search? */
+ if (cf->regex) {
+ /* Regular Expression search */
+ return find_packet(cf, match_regex, NULL, dir);
+ } else if (cf->string) {
/* String search - what type of string? */
switch (cf->scs_type) {
result = MR_MATCHED;
cf->search_pos = i; /* Save the position of the last character
for highlighting the field. */
+ cf->search_len = (guint32)textlen;
break;
}
}
result = MR_MATCHED;
cf->search_pos = i; /* Save the position of the last character
for highlighting the field. */
+ cf->search_len = (guint32)textlen;
break;
}
}
result = MR_MATCHED;
cf->search_pos = i; /* Save the position of the last character
for highlighting the field. */
+ cf->search_len = (guint32)textlen;
break;
}
i += 1;
result = MR_MATCHED;
cf->search_pos = i; /* Save the position of the last character
for highlighting the field. */
+ cf->search_len = (guint32)datalen;
break;
}
}
return result;
}
+static match_result
+match_regex(capture_file *cf, frame_data *fdata, void *criterion _U_)
+{
+ match_result result = MR_NOTMATCHED;
+ GMatchInfo *match_info = NULL;
+
+ /* Load the frame's data. */
+ if (!cf_read_record(cf, fdata)) {
+ /* Attempt to get the packet failed. */
+ return MR_ERROR;
+ }
+
+ if (g_regex_match_full(cf->regex, (const gchar *)ws_buffer_start_ptr(&cf->buf), fdata->cap_len,
+ 0, (GRegexMatchFlags) 0, &match_info, NULL))
+ {
+ gint start_pos = 0, end_pos = 0;
+ g_match_info_fetch_pos (match_info, 0, &start_pos, &end_pos);
+ cf->search_pos = end_pos - 1;
+ cf->search_len = end_pos - start_pos;
+ result = MR_MATCHED;
+ }
+ return result;
+}
+
gboolean
cf_find_packet_dfilter(capture_file *cf, dfilter_t *sfcode,
search_direction dir)
frame_data *fdata;
frame_data *new_fd = NULL;
progdlg_t *progbar = NULL;
+ GTimer *prog_timer = g_timer_new();
int count;
gboolean found;
float progbar_val;
GTimeVal start_time;
gchar status_str[100];
- int progbar_nextstep;
- int progbar_quantum;
const char *title;
match_result result;
count = 0;
framenum = start_fd->num;
- /* Update the progress bar when it gets to this value. */
- progbar_nextstep = 0;
- /* When we reach the value that triggers a progress bar update,
- bump that value by this amount. */
- progbar_quantum = cf->count/N_PROGBAR_UPDATES;
+ g_timer_start(prog_timer);
/* Progress so far. */
progbar_val = 0.0f;
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 N_PROGBAR_UPDATES times;
- when we update it, we have to run the GTK+ main loop to get it
- to repaint what's pending, and doing so may involve an "ioctl()"
- to see if there's any pending input from an X server, and doing
- that for every packet can be costly, especially on a big file. */
- if (count >= progbar_nextstep) {
+ /*
+ * 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
*/
progbar_val = (gfloat) count / cf->count;
- if (progbar != NULL) {
- g_snprintf(status_str, sizeof(status_str),
- "%4u of %u packets", count, cf->count);
- update_progress_dlg(progbar, progbar_val, status_str);
- }
+ g_snprintf(status_str, sizeof(status_str),
+ "%4u of %u packets", count, cf->count);
+ update_progress_dlg(progbar, progbar_val, status_str);
- progbar_nextstep += progbar_quantum;
+ g_timer_start(prog_timer);
}
if (cf->stop_flag) {
was created. */
if (progbar != NULL)
destroy_progress_dlg(progbar);
+ g_timer_destroy(prog_timer);
}
if (new_fd != NULL) {
found = packet_list_select_row_from_data(new_fd);
cf->search_in_progress = FALSE;
cf->search_pos = 0; /* Reset the position */
+ cf->search_len = 0; /* Reset length */
if (!found) {
/* We didn't find a row corresponding to this frame.
This means that the frame isn't being displayed currently,
{
frame_data *fdata;
- if (cf == NULL) {
- /* we don't have a loaded capture file - fix for bug 11810*/
+ if (cf == NULL || cf->frames == NULL) {
+ /* we don't have a loaded capture file - fix for bugs 11810 & 11989 */
statusbar_push_temporary_msg("There is no file loaded");
return FALSE; /* we failed to go to that packet */
}
return TRUE; /* we got to that packet */
}
-gboolean
-cf_goto_top_frame(void)
-{
- /* Find and select */
- packet_list_select_first_row();
- return TRUE; /* we got to that packet */
-}
-
-gboolean
-cf_goto_bottom_frame(void)
-{
- /* Find and select */
- packet_list_select_last_row();
- return TRUE; /* we got to that packet */
-}
-
/*
* Go to frame specified by currently selected protocol tree item.
*/
/* Get the frame data struct pointer for this frame */
fdata = packet_list_get_row_data(row);
- if (fdata == NULL) {
- /* XXX - if a GtkCList's selection mode is GTK_SELECTION_BROWSE, when
- the first entry is added to it by "real_insert_row()", that row
- is selected (see "real_insert_row()", in "ui/gtk/gtkclist.c", in both
- our version and the vanilla GTK+ version).
-
- This means that a "select-row" signal is emitted; this causes
- "packet_list_select_cb()" to be called, which causes "cf_select_packet()"
- to be called.
-
- "cf_select_packet()" fetches, above, the data associated with the
- row that was selected; however, as "gtk_clist_append()", which
- called "real_insert_row()", hasn't yet returned, we haven't yet
- associated any data with that row, so we get back a null pointer.
-
- We can't assume that there's only one frame in the frame list,
- either, as we may be filtering the display.
-
- We therefore assume that, if "row" is 0, i.e. the first row
- is being selected, and "cf->first_displayed" equals
- "cf->last_displayed", i.e. there's only one frame being
- displayed, that frame is the frame we want.
-
- This means we have to set "cf->first_displayed" and
- "cf->last_displayed" before adding the row to the
- GtkCList; see the comment in "add_packet_to_packet_list()". */
-
- if (row == 0 && cf->first_displayed == cf->last_displayed)
- fdata = frame_data_sequence_find(cf->frames, cf->first_displayed);
- }
-
- /* If fdata _still_ isn't set simply give up. */
if (fdata == NULL) {
return;
}
const gchar *
cf_read_shb_comment(capture_file *cf)
{
- /* Get info from SHB */
- return wtap_file_get_shb_comment(cf->wth);
+ wtap_block_t shb_inf;
+ char *shb_comment;
+
+ /* Get the SHB. */
+ /* XXX - support multiple SHBs */
+ shb_inf = wtap_file_get_shb(cf->wth);
+
+ /* Get the first comment from the SHB. */
+ /* XXX - support multiple comments */
+ if (wtap_block_get_nth_string_option_value(shb_inf, OPT_COMMENT, 0, &shb_comment) != WTAP_OPTTYPE_SUCCESS)
+ return NULL;
+ return shb_comment;
}
void
cf_update_capture_comment(capture_file *cf, gchar *comment)
{
- const gchar *shb_comment;
-
- /* Get info from SHB */
- shb_comment = wtap_file_get_shb_comment(cf->wth);
-
- /* See if the comment has changed or not */
- if (shb_comment) {
+ wtap_block_t shb_inf;
+ gchar *shb_comment;
+
+ /* Get the SHB. */
+ /* XXX - support multiple SHBs */
+ shb_inf = wtap_file_get_shb(cf->wth);
+
+ /* Get the first comment from the SHB. */
+ /* XXX - support multiple comments */
+ if (wtap_block_get_nth_string_option_value(shb_inf, OPT_COMMENT, 0, &shb_comment) != WTAP_OPTTYPE_SUCCESS) {
+ /* There's no comment - add one. */
+ wtap_block_add_string_option(shb_inf, OPT_COMMENT, comment, strlen(comment));
+ } else {
+ /* See if the comment has changed or not */
if (strcmp(shb_comment, comment) == 0) {
g_free(comment);
return;
}
- }
- /* The comment has changed, let's update it */
- wtap_write_shb_comment(cf->wth, comment);
+ /* The comment has changed, let's update it */
+ wtap_block_set_nth_string_option_value(shb_inf, OPT_COMMENT, 0, comment, strlen(comment));
+ }
/* Mark the file as having unsaved changes */
cf->unsaved_changes = TRUE;
}
return comment_types;
}
+/*
+ * Add a resolved address to this file's list of resolved addresses.
+ */
+gboolean
+cf_add_ip_name_from_string(capture_file *cf, const char *addr, const char *name)
+{
+ /*
+ * XXX - support multiple resolved address lists, and add to the one
+ * attached to this file?
+ */
+ if (!add_ip_name_from_string(addr, name))
+ return FALSE;
+
+ /* OK, we have unsaved changes. */
+ cf->unsaved_changes = TRUE;
+ return TRUE;
+}
+
#ifdef WANT_PACKET_EDITOR
static gint
g_direct_compare_func(gconstpointer a, gconstpointer b, gpointer user_data _U_)
modified_frame_data *mfd = (modified_frame_data *)g_malloc(sizeof(modified_frame_data));
mfd->phdr = *phdr;
- mfd->pd = pd;
+ mfd->pd = (char *)pd;
if (cf->edited_frames == NULL)
cf->edited_frames = g_tree_new_full(g_direct_compare_func, NULL, NULL,
hdr.presence_flags |= WTAP_HAS_INTERFACE_ID;
if (phdr->presence_flags & WTAP_HAS_PACK_FLAGS)
hdr.presence_flags |= WTAP_HAS_PACK_FLAGS;
- hdr.ts.secs = fdata->abs_ts.secs;
- hdr.ts.nsecs = fdata->abs_ts.nsecs;
+ hdr.ts = phdr->ts;
hdr.caplen = phdr->caplen;
hdr.len = phdr->len;
- hdr.pkt_encap = fdata->lnk_t;
+ hdr.pkt_encap = phdr->pkt_encap;
/* pcapng */
hdr.interface_id = phdr->interface_id; /* identifier of the interface. */
/* options */
gchar *name_ptr;
gint64 data_offset;
progdlg_t *progbar = NULL;
+ GTimer *prog_timer = g_timer_new();
gint64 size;
float progbar_val;
GTimeVal start_time;
gchar status_str[100];
- gint64 progbar_nextstep;
- gint64 progbar_quantum;
guint32 framenum;
frame_data *fdata;
int count = 0;
/* Find the size of the file. */
size = wtap_file_size(cf->wth, NULL);
- /* Update the progress bar when it gets to this value. */
- progbar_nextstep = 0;
- /* When we reach the value that triggers a progress bar update,
- bump that value by this amount. */
- if (size >= 0) {
- progbar_quantum = size/N_PROGBAR_UPDATES;
- if (progbar_quantum < MIN_QUANTUM)
- progbar_quantum = MIN_QUANTUM;
- }else
- progbar_quantum = 0;
+ g_timer_start(prog_timer);
cf->stop_flag = FALSE;
g_get_current_time(&start_time);
count++;
cf->f_datalen = wtap_read_so_far(cf->wth);
- /* Create the progress bar if necessary.
- * Check whether it should be created or not every MIN_NUMBER_OF_PACKET
- */
- if ((progbar == NULL) && !(count % MIN_NUMBER_OF_PACKET)) {
+ /* Create the progress bar if necessary. */
+ if (progress_is_slow(progbar, prog_timer, size, cf->f_datalen)) {
progbar_val = calc_progbar_val(cf, size, cf->f_datalen, status_str, sizeof(status_str));
progbar = delayed_create_progress_dlg(cf->window, "Rescanning", name_ptr,
TRUE, &cf->stop_flag, &start_time, progbar_val);
}
- /* Update the progress bar, but do it only N_PROGBAR_UPDATES times;
- when we update it, we have to run the GTK+ main loop to get it
- to repaint what's pending, and doing so may involve an "ioctl()"
- to see if there's any pending input from an X server, and doing
- that for every packet can be costly, especially on a big file. */
- if (cf->f_datalen >= progbar_nextstep) {
- if (progbar != NULL) {
- progbar_val = calc_progbar_val(cf, size, cf->f_datalen, status_str, sizeof(status_str));
- /* update the packet bar content on the first run or frequently on very large files */
- update_progress_dlg(progbar, progbar_val, status_str);
- packets_bar_update();
- }
- progbar_nextstep += progbar_quantum;
+ /*
+ * 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 (progbar && g_timer_elapsed(prog_timer, NULL) > PROGBAR_UPDATE_INTERVAL) {
+ progbar_val = calc_progbar_val(cf, size, cf->f_datalen, status_str, sizeof(status_str));
+ /* update the packet bar content on the first run or frequently on very large files */
+ update_progress_dlg(progbar, progbar_val, status_str);
+ packets_bar_update();
+ g_timer_start(prog_timer);
}
}
/* We're done reading the file; destroy the progress bar if it was created. */
if (progbar != NULL)
destroy_progress_dlg(progbar);
+ g_timer_destroy(prog_timer);
/* We're done reading sequentially through the file. */
cf->state = FILE_READ_DONE;
or moving the capture file, we have to do it by writing the packets
out in Wiretap. */
- wtapng_section_t *shb_hdr = NULL;
+ GArray *shb_hdrs = NULL;
wtapng_iface_descriptions_t *idb_inf = NULL;
- wtapng_name_res_t *nrb_hdr = NULL;
+ GArray *nrb_hdrs = NULL;
int encap;
/* XXX: what free's this shb_hdr? */
- shb_hdr = wtap_file_get_shb_for_new_file(cf->wth);
+ shb_hdrs = wtap_file_get_shb_for_new_file(cf->wth);
idb_inf = wtap_file_get_idb_info(cf->wth);
- nrb_hdr = wtap_file_get_nrb_for_new_file(cf->wth);
+ nrb_hdrs = wtap_file_get_nrb_for_new_file(cf->wth);
/* Determine what file encapsulation type we should use. */
encap = wtap_dump_file_encap_type(cf->linktypes);
from which we're reading the packets that we're writing!) */
fname_new = g_strdup_printf("%s~", fname);
pdh = wtap_dump_open_ng(fname_new, save_format, encap, cf->snap,
- compressed, shb_hdr, idb_inf, nrb_hdr, &err);
+ compressed, shb_hdrs, idb_inf, nrb_hdrs, &err);
} else {
pdh = wtap_dump_open_ng(fname, save_format, encap, cf->snap,
- compressed, shb_hdr, idb_inf, nrb_hdr, &err);
+ compressed, shb_hdrs, idb_inf, nrb_hdrs, &err);
}
g_free(idb_inf);
idb_inf = NULL;
callback_args.fname = fname;
callback_args.file_type = save_format;
switch (process_specified_records(cf, NULL, "Saving", "packets",
- TRUE, save_record, &callback_args)) {
+ TRUE, save_record, &callback_args, TRUE)) {
case PSP_FINISHED:
/* Completed successfully. */
int err;
wtap_dumper *pdh;
save_callback_args_t callback_args;
- wtapng_section_t *shb_hdr = NULL;
+ GArray *shb_hdrs = NULL;
wtapng_iface_descriptions_t *idb_inf = NULL;
- wtapng_name_res_t *nrb_hdr = NULL;
+ GArray *nrb_hdrs = NULL;
int encap;
cf_callback_invoke(cf_cb_file_export_specified_packets_started, (gpointer)fname);
and then write it out if it's one of the specified ones. */
/* XXX: what free's this shb_hdr? */
- shb_hdr = wtap_file_get_shb_for_new_file(cf->wth);
+ shb_hdrs = wtap_file_get_shb_for_new_file(cf->wth);
idb_inf = wtap_file_get_idb_info(cf->wth);
- nrb_hdr = wtap_file_get_nrb_for_new_file(cf->wth);
+ nrb_hdrs = wtap_file_get_nrb_for_new_file(cf->wth);
/* Determine what file encapsulation type we should use. */
encap = wtap_dump_file_encap_type(cf->linktypes);
from which we're reading the packets that we're writing!) */
fname_new = g_strdup_printf("%s~", fname);
pdh = wtap_dump_open_ng(fname_new, save_format, encap, cf->snap,
- compressed, shb_hdr, idb_inf, nrb_hdr, &err);
+ compressed, shb_hdrs, idb_inf, nrb_hdrs, &err);
} else {
pdh = wtap_dump_open_ng(fname, save_format, encap, cf->snap,
- compressed, shb_hdr, idb_inf, nrb_hdr, &err);
+ compressed, shb_hdrs, idb_inf, nrb_hdrs, &err);
}
g_free(idb_inf);
idb_inf = NULL;
callback_args.fname = fname;
callback_args.file_type = save_format;
switch (process_specified_records(cf, range, "Writing", "specified records",
- TRUE, save_record, &callback_args)) {
+ TRUE, save_record, &callback_args, TRUE)) {
case PSP_FINISHED:
/* Completed successfully. */