diff options
author | Maksim Salau <maksim.salau@gmail.com> | 2019-07-18 21:20:03 +0300 |
---|---|---|
committer | Anders Broman <a.broman58@gmail.com> | 2019-07-20 07:29:33 +0000 |
commit | 40e0e5d282daf3b21bc614a64e4e16e289f65768 (patch) | |
tree | 845eaae50a8febfb6567f5187724de31536060df /wiretap/candump.c | |
parent | c43bd0def1aaf6db2febcd008d7e83021ef85427 (diff) |
wiretap: candump: Don't generate a temporary PCAP file
It's preferable to parse text files and generate packets on demand,
rather than generate a temporary PCAP file and dump all available
packets into it.
Parsing on the fly has a benefit of handling damaged files up to the
point of damage, while the approach with a temporary file doesn't
allow either to report that the original file is damaged or perform
conversion in the first place.
This version works faster than the previous one.
Command:
time ./run/tshark -r ./candump-2019-07-01_111120.log.gz > /dev/null
The test file is attached to the bug 15889
The current version:
real 0m0,597s
user 0m0,533s
sys 0m0,118s
The previous version:
real 0m2,176s
user 0m1,966s
sys 0m0,100s
Bug: 15889
Change-Id: I862ce47752531c2e9d9459f5d865c1fc08f32fea
Reviewed-on: https://code.wireshark.org/review/34007
Petri-Dish: Anders Broman <a.broman58@gmail.com>
Tested-by: Petri Dish Buildbot
Reviewed-by: Anders Broman <a.broman58@gmail.com>
Diffstat (limited to 'wiretap/candump.c')
-rw-r--r-- | wiretap/candump.c | 311 |
1 files changed, 105 insertions, 206 deletions
diff --git a/wiretap/candump.c b/wiretap/candump.c index 0fe484d322..987e304f18 100644 --- a/wiretap/candump.c +++ b/wiretap/candump.c @@ -13,10 +13,9 @@ #include <wtap-int.h> #include <file_wrappers.h> #include <epan/exported_pdu.h> -#include <wsutil/tempfile.h> -#include <wsutil/os_version_info.h> #include <string.h> #include <inttypes.h> +#include <errno.h> #include "candump.h" #include "candump_priv.h" @@ -26,10 +25,9 @@ static gboolean candump_read(wtap *wth, wtap_rec *rec, Buffer *buf, static gboolean candump_seek_read(wtap *wth, gint64 seek_off, wtap_rec *rec, Buffer *buf, int *err, gchar **err_info); -static void candump_close(wtap *wth); -static gboolean -candump_add_packet(wtap_dumper *wdh, const msg_t *msg, int *err, char **err_info) +static void +candump_write_packet(wtap_rec *rec, Buffer *buf, const msg_t *msg) { static const char *can_proto_name = "can-hostendian"; static const char *canfd_proto_name = "canfd"; @@ -38,9 +36,7 @@ candump_add_packet(wtap_dumper *wdh, const msg_t *msg, int *err, char **err_info guint header_length; guint packet_length; guint frame_length; - - guint8 buf[128]; - wtap_rec rec; + guint8 *buf_data; /* Adjust proto name length to be aligned on 4 byte boundary */ proto_name_length += (proto_name_length % 4) ? (4 - (proto_name_length % 4)) : 0; @@ -49,10 +45,15 @@ candump_add_packet(wtap_dumper *wdh, const msg_t *msg, int *err, char **err_info frame_length = msg->is_fd ? sizeof(canfd_frame_t) : sizeof(can_frame_t); packet_length = header_length + frame_length; - memset(buf, 0, sizeof(buf)); - buf[1] = EXP_PDU_TAG_PROTO_NAME; - buf[3] = proto_name_length; - memcpy(buf + 4, proto_name, strlen(proto_name)); + ws_buffer_clean(buf); + ws_buffer_assure_space(buf, packet_length); + buf_data = ws_buffer_start_ptr(buf); + + memset(buf_data, 0, packet_length); + + buf_data[1] = EXP_PDU_TAG_PROTO_NAME; + buf_data[3] = proto_name_length; + memcpy(buf_data + 4, proto_name, strlen(proto_name)); if (msg->is_fd) { @@ -64,7 +65,7 @@ candump_add_packet(wtap_dumper *wdh, const msg_t *msg, int *err, char **err_info canfd_frame.len = msg->data.length; memcpy(canfd_frame.data, msg->data.data, msg->data.length); - memcpy(buf + header_length, (guint8 *)&canfd_frame, sizeof(canfd_frame)); + memcpy(buf_data + header_length, (guint8 *)&canfd_frame, sizeof(canfd_frame)); } else { @@ -75,224 +76,102 @@ candump_add_packet(wtap_dumper *wdh, const msg_t *msg, int *err, char **err_info can_frame.can_dlc = msg->data.length; memcpy(can_frame.data, msg->data.data, msg->data.length); - memcpy(buf + header_length, (guint8 *)&can_frame, sizeof(can_frame)); + memcpy(buf_data + header_length, (guint8 *)&can_frame, sizeof(can_frame)); } - memset(&rec, 0, sizeof(rec)); - rec.rec_type = REC_TYPE_PACKET; - rec.presence_flags = WTAP_HAS_TS; - rec.ts = msg->ts; - rec.tsprec = WTAP_TSPREC_USEC; - - rec.rec_header.packet_header.caplen = packet_length; - rec.rec_header.packet_header.len = packet_length; + rec->rec_type = REC_TYPE_PACKET; + rec->presence_flags = WTAP_HAS_TS; + rec->ts = msg->ts; + rec->tsprec = WTAP_TSPREC_USEC; - return wtap_dump(wdh, &rec, buf, err, err_info); + rec->rec_header.packet_header.caplen = packet_length; + rec->rec_header.packet_header.len = packet_length; } -static gchar * -candump_dump(GSList *packets, int *err, char **err_info) +static gboolean +candump_parse(FILE_T fh, msg_t *msg, gint64 *offset, int *err, char **err_info) { - gchar *filename; - int import_file_fd; - wtap_dumper *wdh; - GSList *packet; - - /* pcapng defs */ - GArray *shb_hdrs = g_array_new(FALSE, FALSE, sizeof(wtap_block_t)); - wtap_block_t shb_hdr; - wtapng_iface_descriptions_t *idb_inf = NULL; - wtap_block_t int_data; - wtapng_if_descr_mandatory_t *int_data_mand; - GString *os_info_str; - gsize opt_len; - gchar *opt_str = NULL; - - static const gchar *opt_comment = "File converted to Exported PDU format during opening"; - static const gchar *if_name = "Fake IF"; + candump_state_t state; + gboolean ok; + gint64 seek_off; #ifdef CANDUMP_DEBUG - ws_debug_printf("%s: Creating a temporary file\n", G_STRFUNC); + ws_debug_printf("%s: Trying candump file decoder\n", G_STRFUNC); #endif - import_file_fd = create_tempfile(&filename, "Wireshark_PDU_candump_", NULL); - - /* Now open a file and dump to it */ - /* Create data for SHB */ - os_info_str = g_string_new(""); - get_os_version_info(os_info_str); - - shb_hdr = wtap_block_create(WTAP_BLOCK_NG_SECTION); - /* options */ - wtap_block_add_string_option(shb_hdr, OPT_COMMENT, opt_comment, - strlen(opt_comment)); - /* - * UTF-8 string containing the name of the operating system used to create - * this section. - */ - opt_len = os_info_str->len; - opt_str = g_string_free(os_info_str, FALSE); - if (opt_str) - { - wtap_block_add_string_option(shb_hdr, OPT_SHB_OS, opt_str, opt_len); - g_free(opt_str); - } - /* - * UTF-8 string containing the name of the application used to create - * this section. Avoid the precise version (get_appname_and_version) to - * avoid wiretap rebuilds when only the version changes. - */ - wtap_block_add_string_option_format(shb_hdr, OPT_SHB_USERAPPL, "Wireshark %s", VERSION); + memset(&state, 0, sizeof(state)); + state.fh = fh; - /* Add header to the array */ - g_array_append_val(shb_hdrs, shb_hdr); - - /* Create fake IDB info */ - idb_inf = g_new(wtapng_iface_descriptions_t, 1); - idb_inf->interface_data = g_array_new(FALSE, FALSE, sizeof(wtap_block_t)); - - /* create the fake interface data */ - int_data = wtap_block_create(WTAP_BLOCK_IF_DESCR); - int_data_mand = (wtapng_if_descr_mandatory_t *)wtap_block_get_mandatory_data(int_data); - int_data_mand->wtap_encap = WTAP_ENCAP_WIRESHARK_UPPER_PDU; - int_data_mand->time_units_per_second = 1000000; /* default microsecond resolution */ - int_data_mand->snap_len = WTAP_MAX_PACKET_SIZE_STANDARD; - - wtap_block_add_string_option(int_data, OPT_IDB_NAME, if_name, strlen(if_name)); - int_data_mand->num_stat_entries = 0; /* Number of ISB:s */ - int_data_mand->interface_statistics = NULL; - - g_array_append_val(idb_inf->interface_data, int_data); - - const wtap_dump_params params = { - .encap = WTAP_ENCAP_WIRESHARK_UPPER_PDU, - .snaplen = WTAP_MAX_PACKET_SIZE_STANDARD, - .shb_hdrs = shb_hdrs, - .idb_inf = idb_inf, - }; + do + { + if (file_eof(fh)) + return FALSE; + seek_off = file_tell(fh); #ifdef CANDUMP_DEBUG - ws_debug_printf("%s: Opening the temporary file for writing\n", G_STRFUNC); + ws_debug_printf("%s: Starting parser at offset %" PRIi64 "\n", G_STRFUNC, seek_off); #endif - wdh = wtap_dump_fdopen(import_file_fd, WTAP_FILE_TYPE_SUBTYPE_PCAPNG, - WTAP_UNCOMPRESSED, ¶ms, err); + state.file_bytes_read = 0; + ok = run_candump_parser(&state, err, err_info); + + /* Rewind the file to the offset we have finished parsing */ + if (file_seek(fh, seek_off + state.file_bytes_read, SEEK_SET, err) == -1) + { + g_free(*err_info); + *err = errno; + *err_info = g_strdup(g_strerror(errno)); + return FALSE; + } + } + while (ok && !state.is_msg_valid); - if (!wdh) - goto error_open; + if (!ok) + return FALSE; #ifdef CANDUMP_DEBUG - ws_debug_printf("%s: Writing packet data into the file\n", G_STRFUNC); + ws_debug_printf("%s: Success\n", G_STRFUNC); #endif - /* OK we've opened a new pcapng file and written the headers, time to do the packets */ - for (packet = packets; packet; packet = g_slist_next(packet)) - { - if (!candump_add_packet(wdh, (msg_t *)packet->data, err, err_info)) - goto error_write; - } -#ifdef CANDUMP_DEBUG - ws_debug_printf("%s: Closing the file\n", G_STRFUNC); -#endif - /* Close the written file */ - if (!wtap_dump_close(wdh, err)) - goto error_write; - - goto exit; - -error_write: - wtap_dump_close(wdh, err); - ws_unlink(filename); -error_open: - g_free(filename); - filename = NULL; -exit: - wtap_block_array_free(shb_hdrs); - wtap_free_idb_info(idb_inf); - - return filename; + if (offset) + *offset = seek_off; + + if (msg) + *msg = state.msg; + + return TRUE; } -static wtap_open_return_val -candump_parse(candump_priv_t **priv, wtap *wth, int *err, char **err_info) +wtap_open_return_val +candump_open(wtap *wth, int *err, char **err_info) { - GSList *packets; - gchar *filename; - wtap *fh; + if (!candump_parse(wth->fh, NULL, NULL, err, err_info)) + { + g_free(*err_info); -#ifdef CANDUMP_DEBUG - ws_debug_printf("%s: Trying candump file decoder\n", G_STRFUNC); -#endif - packets = run_candump_parser(wth->fh, err, err_info); + *err = 0; + *err_info = NULL; - if (!packets) return WTAP_OPEN_NOT_MINE; - - if (*err) - { - g_slist_free_full(packets, g_free); - return WTAP_OPEN_ERROR; } #ifdef CANDUMP_DEBUG - ws_debug_printf("%s: Creating a PCAPNG file with data we've just read\n", G_STRFUNC); + ws_debug_printf("%s: This is our file\n", G_STRFUNC); #endif - /* Dump packets into a temporary file */ - filename = candump_dump(packets, err, err_info); - g_slist_free_full(packets, g_free); - if (!filename) - return WTAP_OPEN_ERROR; - -#ifdef CANDUMP_DEBUG - ws_debug_printf("%s: Opening the newly created file\n", G_STRFUNC); -#endif - /* Now open the file for reading */ - fh = wtap_open_offline(filename, WTAP_TYPE_AUTO, - err, err_info, - (wth->random_fh ? TRUE : FALSE)); - - if (!fh) + if (file_seek(wth->fh, 0, SEEK_SET, err) == -1) { - g_free(filename); - return WTAP_OPEN_ERROR; - } - - *priv = g_new0(candump_priv_t, 1); - - (*priv)->tmp_file = fh; - (*priv)->tmp_filename = filename; + *err = errno; + *err_info = g_strdup(g_strerror(errno)); -#ifdef CANDUMP_DEBUG - ws_debug_printf("%s: Ok\n", G_STRFUNC); -#endif - return WTAP_OPEN_MINE; -} - -wtap_open_return_val -candump_open(wtap *wth, int *err, char **err_info) -{ - wtap_open_return_val ret; - candump_priv_t *priv = NULL; - - ret = candump_parse(&priv, wth, err, err_info); - - if (ret != WTAP_OPEN_MINE) - return ret; - - if (!priv) return WTAP_OPEN_ERROR; + } - /* Copy header section block from the temp file */ - wtap_block_copy(g_array_index(wth->shb_hdrs, wtap_block_t, 0), g_array_index(priv->tmp_file->shb_hdrs, wtap_block_t, 0)); - - wth->priv = priv; - wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_PCAPNG; - wth->file_encap = priv->tmp_file->file_encap; - wth->file_tsprec = priv->tmp_file->file_tsprec; + wth->priv = NULL; + wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_UNKNOWN; + wth->file_encap = WTAP_ENCAP_WIRESHARK_UPPER_PDU; + wth->file_tsprec = WTAP_TSPREC_USEC; wth->subtype_read = candump_read; wth->subtype_seek_read = candump_seek_read; - wth->subtype_close = candump_close; - wth->snapshot_length = 0; return WTAP_OPEN_MINE; } @@ -301,28 +180,48 @@ static gboolean candump_read(wtap *wth, wtap_rec *rec, Buffer *buf, int *err, gchar **err_info, gint64 *data_offset) { - candump_priv_t *priv = (candump_priv_t *)wth->priv; + msg_t msg; - return wtap_read(priv->tmp_file, rec, buf, err, err_info, data_offset); +#ifdef CANDUMP_DEBUG + ws_debug_printf("%s: Try reading at offset %" PRIi64 "\n", G_STRFUNC, file_tell(wth->fh)); +#endif + if (!candump_parse(wth->fh, &msg, data_offset, err, err_info)) + return FALSE; + +#ifdef CANDUMP_DEBUG + ws_debug_printf("%s: Stopped at offset %" PRIi64 "\n", G_STRFUNC, file_tell(wth->fh)); +#endif + + candump_write_packet(rec, buf, &msg); + + return TRUE; } static gboolean candump_seek_read(wtap *wth , gint64 seek_off, wtap_rec *rec, Buffer *buf, int *err, gchar **err_info) { - candump_priv_t *priv = (candump_priv_t *)wth->priv; + msg_t msg; - return wtap_seek_read(priv->tmp_file, seek_off, rec, buf, err, err_info); -} +#ifdef CANDUMP_DEBUG + ws_debug_printf("%s: Read at offset %" PRIi64 "\n", G_STRFUNC, seek_off); +#endif -static void candump_close(wtap *wth) -{ - candump_priv_t *priv = (candump_priv_t *)wth->priv; + if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1) + { + *err = errno; + *err_info = g_strdup(g_strerror(errno)); + + return FALSE; + } + + if (!candump_parse(wth->random_fh, &msg, NULL, err, err_info)) + return FALSE; + + candump_write_packet(rec, buf, &msg); - wtap_close(priv->tmp_file); - ws_unlink(priv->tmp_filename); - g_free(priv->tmp_filename); + return TRUE; } /* |