forked from osmocom/wireshark
add support for compression of capture file
This commit is contained in:
parent
9d6ebdc8a5
commit
c14ea41233
|
@ -440,6 +440,10 @@ sync_pipe_start(capture_options *capture_opts, capture_session *cap_session, inf
|
|||
for (i = 0; i < argc; i++) {
|
||||
g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "argv[%d]: %s", i, argv[i]);
|
||||
}
|
||||
if (capture_opts->compress_type) {
|
||||
argv = sync_pipe_add_arg(argv, &argc, "--compress-type");
|
||||
argv = sync_pipe_add_arg(argv, &argc, capture_opts->compress_type);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
/* init SECURITY_ATTRIBUTES */
|
||||
|
|
|
@ -118,6 +118,7 @@ capture_opts_init(capture_options *capture_opts)
|
|||
capture_opts->capture_child = FALSE;
|
||||
capture_opts->print_file_names = FALSE;
|
||||
capture_opts->print_name_to = NULL;
|
||||
capture_opts->compress_type = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -978,6 +979,21 @@ capture_opts_add_opt(capture_options *capture_opts, int opt, const char *optarg_
|
|||
}
|
||||
}
|
||||
break;
|
||||
case LONGOPT_COMPRESS_TYPE: /* compress type */
|
||||
if (capture_opts->compress_type) {
|
||||
cmdarg_err("--compress-type can be set only once");
|
||||
return 1;
|
||||
}
|
||||
if (strcmp(optarg_str_p, "none") == 0) {
|
||||
;
|
||||
} else if (strcmp(optarg_str_p, "gzip") == 0) {
|
||||
;
|
||||
} else {
|
||||
cmdarg_err("parameter of --compress-type can be 'none' or 'gzip'");
|
||||
return 1;
|
||||
}
|
||||
capture_opts->compress_type = g_strdup(optarg_str_p);
|
||||
break;
|
||||
default:
|
||||
/* the caller is responsible to send us only the right opt's */
|
||||
g_assert_not_reached();
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include <sys/types.h> /* for gid_t */
|
||||
|
||||
#include <caputils/capture_ifinfo.h>
|
||||
#include "ringbuffer.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
|
@ -45,6 +46,7 @@ extern "C" {
|
|||
#define LONGOPT_NUM_CAP_COMMENT LONGOPT_BASE_CAPTURE+1
|
||||
#define LONGOPT_LIST_TSTAMP_TYPES LONGOPT_BASE_CAPTURE+2
|
||||
#define LONGOPT_SET_TSTAMP_TYPE LONGOPT_BASE_CAPTURE+3
|
||||
#define LONGOPT_COMPRESS_TYPE LONGOPT_BASE_CAPTURE+4
|
||||
|
||||
/*
|
||||
* Options for capturing common to all capturing programs.
|
||||
|
@ -85,7 +87,8 @@ extern "C" {
|
|||
{"snapshot-length", required_argument, NULL, 's'}, \
|
||||
{"linktype", required_argument, NULL, 'y'}, \
|
||||
{"list-time-stamp-types", no_argument, NULL, LONGOPT_LIST_TSTAMP_TYPES}, \
|
||||
{"time-stamp-type", required_argument, NULL, LONGOPT_SET_TSTAMP_TYPE},
|
||||
{"time-stamp-type", required_argument, NULL, LONGOPT_SET_TSTAMP_TYPE}, \
|
||||
{"compress-type", required_argument, NULL, LONGOPT_COMPRESS_TYPE},
|
||||
|
||||
|
||||
#define OPTSTRING_CAPTURE_COMMON \
|
||||
|
@ -317,6 +320,7 @@ typedef struct capture_options_tag {
|
|||
/* internally used (don't touch from outside) */
|
||||
gboolean output_to_pipe; /**< save_file is a pipe (named or stdout) */
|
||||
gboolean capture_child; /**< hidden option: Wireshark child mode */
|
||||
gchar *compress_type; /**< compress type */
|
||||
} capture_options;
|
||||
|
||||
/* initialize the capture_options with some reasonable values */
|
||||
|
|
|
@ -3396,7 +3396,8 @@ capture_loop_open_output(capture_options *capture_opts, int *save_file_fd,
|
|||
/* ringbuffer is enabled */
|
||||
*save_file_fd = ringbuf_init(capfile_name,
|
||||
(capture_opts->has_ring_num_files) ? capture_opts->ring_num_files : 0,
|
||||
capture_opts->group_read_access);
|
||||
capture_opts->group_read_access,
|
||||
capture_opts->compress_type);
|
||||
|
||||
/* capfile_name is unused as the ringbuffer provides its own filename. */
|
||||
if (*save_file_fd != -1) {
|
||||
|
@ -4903,6 +4904,7 @@ main(int argc, char *argv[])
|
|||
#ifdef HAVE_PCAP_CREATE
|
||||
case 'I': /* Monitor mode */
|
||||
#endif
|
||||
case LONGOPT_COMPRESS_TYPE: /* compress type */
|
||||
status = capture_opts_add_opt(&global_capture_opts, opt, optarg, &start_capture);
|
||||
if (status != 0) {
|
||||
exit_main(status);
|
||||
|
|
139
ringbuffer.c
139
ringbuffer.c
|
@ -36,20 +36,35 @@
|
|||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <glib.h>
|
||||
|
||||
#include "wspcap.h"
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <wsutil/win32-utils.h>
|
||||
#endif
|
||||
|
||||
#include "ringbuffer.h"
|
||||
#include <wsutil/file_util.h>
|
||||
|
||||
#ifdef HAVE_ZLIB
|
||||
#include <zlib.h>
|
||||
#endif
|
||||
|
||||
/* Ringbuffer file structure */
|
||||
typedef struct _rb_file {
|
||||
gchar *name;
|
||||
} rb_file;
|
||||
|
||||
#define MAX_FILENAME_QUEUE 100
|
||||
|
||||
/** Ringbuffer data structure */
|
||||
typedef struct _ringbuf_data {
|
||||
rb_file *files;
|
||||
|
@ -64,10 +79,125 @@ typedef struct _ringbuf_data {
|
|||
char *io_buffer; /**< The IO buffer used to write to the file */
|
||||
gboolean group_read_access; /**< TRUE if files need to be opened with group read access */
|
||||
FILE *name_h; /**< write names of completed files to this handle */
|
||||
gchar *compress_type; /**< compress type */
|
||||
|
||||
GMutex mutex; /**< mutex for oldnames */
|
||||
gchar *oldnames[MAX_FILENAME_QUEUE]; /**< filename list of pending to be deleted */
|
||||
} ringbuf_data;
|
||||
|
||||
static ringbuf_data rb_data;
|
||||
|
||||
/*
|
||||
* delete pending uncompressed pcap files.
|
||||
*/
|
||||
static void CleanupOldCap(gchar* name)
|
||||
{
|
||||
ws_statb64 statb;
|
||||
size_t i;
|
||||
|
||||
g_mutex_lock(&rb_data.mutex);
|
||||
|
||||
/* Delete pending delete file */
|
||||
for (i = 0; i < sizeof(rb_data.oldnames) / sizeof(rb_data.oldnames[0]); i++) {
|
||||
if (rb_data.oldnames[i] != NULL) {
|
||||
ws_unlink(rb_data.oldnames[i]);
|
||||
if (ws_stat64(rb_data.oldnames[i], &statb) != 0) {
|
||||
g_free(rb_data.oldnames[i]);
|
||||
rb_data.oldnames[i] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (name) {
|
||||
/* push the current file to pending list if it failed to delete */
|
||||
if (ws_stat64(name, &statb) == 0) {
|
||||
for (i = 0; i < sizeof(rb_data.oldnames) / sizeof(rb_data.oldnames[0]); i++) {
|
||||
if (rb_data.oldnames[i] == NULL) {
|
||||
rb_data.oldnames[i] = g_strdup(name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
g_mutex_unlock(&rb_data.mutex);
|
||||
}
|
||||
|
||||
/*
|
||||
* compress capture file
|
||||
*/
|
||||
static int ringbuf_exec_compress(gchar* name)
|
||||
{
|
||||
guint8 *buffer = NULL;
|
||||
gchar* outgz = NULL;
|
||||
int fd = -1;
|
||||
ssize_t nread;
|
||||
gboolean delete_org_file = TRUE;
|
||||
gzFile fi = NULL;
|
||||
|
||||
fd = ws_open(name, O_RDONLY | O_BINARY, 0000);
|
||||
if (fd < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
outgz = g_strdup_printf("%s.gz", name);
|
||||
fi = gzopen(outgz, "wb");
|
||||
g_free(outgz);
|
||||
if (fi == NULL) {
|
||||
ws_close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
#define FS_READ_SIZE 65536
|
||||
buffer = (guint8*)g_malloc(FS_READ_SIZE);
|
||||
if (buffer == NULL) {
|
||||
ws_close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
while ((nread = ws_read(fd, buffer, FS_READ_SIZE)) > 0) {
|
||||
int n = gzwrite(fi, buffer, (unsigned int)nread);
|
||||
if (n <= 0) {
|
||||
/* mark compression as failed */
|
||||
delete_org_file = FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (nread < 0) {
|
||||
/* mark compression as failed */
|
||||
delete_org_file = FALSE;
|
||||
}
|
||||
ws_close(fd);
|
||||
gzclose(fi);
|
||||
g_free(buffer);
|
||||
|
||||
/* delete the original file only if compression succeeds */
|
||||
if (delete_org_file) {
|
||||
ws_unlink(name);
|
||||
CleanupOldCap(name);
|
||||
}
|
||||
g_free(name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* thread to compress capture file
|
||||
*/
|
||||
static void* exec_compress_thread(void* arg)
|
||||
{
|
||||
ringbuf_exec_compress((gchar*)arg);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* start a thread to compress capture file
|
||||
*/
|
||||
static int ringbuf_start_compress_file(rb_file* rfile)
|
||||
{
|
||||
gchar* name = g_strdup(rfile->name);
|
||||
g_thread_new("exec_compress", &exec_compress_thread, name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* create the next filename and open a new binary file with that name
|
||||
|
@ -84,6 +214,9 @@ static int ringbuf_open_file(rb_file *rfile, int *err)
|
|||
/* remove old file (if any, so ignore error) */
|
||||
ws_unlink(rfile->name);
|
||||
}
|
||||
else if (rb_data.compress_type != NULL && strcmp(rb_data.compress_type, "gzip") == 0) {
|
||||
ringbuf_start_compress_file(rfile);
|
||||
}
|
||||
g_free(rfile->name);
|
||||
}
|
||||
|
||||
|
@ -121,7 +254,7 @@ static int ringbuf_open_file(rb_file *rfile, int *err)
|
|||
* Initialize the ringbuffer data structures
|
||||
*/
|
||||
int
|
||||
ringbuf_init(const char *capfile_name, guint num_files, gboolean group_read_access)
|
||||
ringbuf_init(const char *capfile_name, guint num_files, gboolean group_read_access, gchar *compress_type)
|
||||
{
|
||||
unsigned int i;
|
||||
char *pfx, *last_pathsep;
|
||||
|
@ -137,6 +270,8 @@ ringbuf_init(const char *capfile_name, guint num_files, gboolean group_read_acce
|
|||
rb_data.io_buffer = NULL;
|
||||
rb_data.group_read_access = group_read_access;
|
||||
rb_data.name_h = NULL;
|
||||
rb_data.compress_type = compress_type;
|
||||
g_mutex_init(&rb_data.mutex);
|
||||
|
||||
/* just to be sure ... */
|
||||
if (num_files <= RINGBUFFER_MAX_NUM_FILES) {
|
||||
|
@ -397,6 +532,8 @@ ringbuf_free(void)
|
|||
g_free(rb_data.fsuffix);
|
||||
rb_data.fsuffix = NULL;
|
||||
}
|
||||
|
||||
CleanupOldCap(NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
/* Maximum number for FAT filesystems */
|
||||
#define RINGBUFFER_WARN_NUM_FILES 65535
|
||||
|
||||
int ringbuf_init(const char *capture_name, guint num_files, gboolean group_read_access);
|
||||
int ringbuf_init(const char *capture_name, guint num_files, gboolean group_read_access, gchar* compress_type);
|
||||
gboolean ringbuf_is_initialized(void);
|
||||
const gchar *ringbuf_current_filename(void);
|
||||
FILE *ringbuf_init_libpcap_fdopen(int *err);
|
||||
|
|
1
tshark.c
1
tshark.c
|
@ -1103,6 +1103,7 @@ main(int argc, char *argv[])
|
|||
#ifdef CAN_SET_CAPTURE_BUFFER_SIZE
|
||||
case 'B': /* Buffer size */
|
||||
#endif
|
||||
case LONGOPT_COMPRESS_TYPE: /* compress type */
|
||||
/* These are options only for packet capture. */
|
||||
#ifdef HAVE_LIBPCAP
|
||||
exit_status = capture_opts_add_opt(&global_capture_opts, opt, optarg, &start_capture);
|
||||
|
|
|
@ -206,6 +206,8 @@ CaptureOptionsDialog::CaptureOptionsDialog(QWidget *parent) :
|
|||
|
||||
ui->filenameLineEdit->setPlaceholderText(tr("Leave blank to use a temporary file"));
|
||||
|
||||
ui->rbCompressionNone->setChecked(true);
|
||||
|
||||
// Changes in interface selections or capture filters should be propagated
|
||||
// to the main welcome screen where they will be applied to the global
|
||||
// capture options.
|
||||
|
@ -1089,6 +1091,17 @@ bool CaptureOptionsDialog::saveOptionsToPreferences()
|
|||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
g_free(global_capture_opts.compress_type);
|
||||
|
||||
if (ui->rbCompressionNone->isChecked() ) {
|
||||
global_capture_opts.compress_type = NULL;
|
||||
} else if (ui->rbCompressionGzip->isChecked() ) {
|
||||
global_capture_opts.compress_type = qstring_strdup("gzip");
|
||||
} else {
|
||||
global_capture_opts.compress_type = NULL;
|
||||
}
|
||||
|
||||
prefs_main_write();
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -6,15 +6,15 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>950</width>
|
||||
<height>440</height>
|
||||
<width>1198</width>
|
||||
<height>988</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_12">
|
||||
<item>
|
||||
<widget class="QTabWidget" name="tabWidget">
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
<number>1</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="inputTab">
|
||||
<attribute name="title">
|
||||
|
@ -277,12 +277,12 @@
|
|||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QCheckBox" name="PktCheckBox">
|
||||
<property name="text">
|
||||
<string>after</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Switch to the next file after the specified number of packets have been captured.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>after</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
|
@ -310,12 +310,12 @@
|
|||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QCheckBox" name="MBCheckBox">
|
||||
<property name="text">
|
||||
<string>after</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Switch to the next file after the file size exceeds the specified file size.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>after</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
|
@ -364,12 +364,12 @@
|
|||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QCheckBox" name="SecsCheckBox">
|
||||
<property name="text">
|
||||
<string>after</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Switch to the next file when the time capturing to the current file exceeds the specified time.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>after</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
|
@ -418,13 +418,13 @@
|
|||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QCheckBox" name="IntervalSecsCheckBox">
|
||||
<property name="text">
|
||||
<string>when time is a multiple of</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Switch to the next file when the (wall clock) time is an even multiple of the specified interval.
|
||||
For example, use 1 hour to have a new file created every hour on the hour.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>when time is a multiple of</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
|
@ -456,6 +456,9 @@ For example, use 1 hour to have a new file created every hour on the hour.</stri
|
|||
<string>Switch to the next file when the (wall clock) time is an even multiple of the specified interval.
|
||||
For example, use 1 hour to have a new file created every hour on the hour.</string>
|
||||
</property>
|
||||
<property name="currentIndex">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>seconds</string>
|
||||
|
@ -471,9 +474,6 @@ For example, use 1 hour to have a new file created every hour on the hour.</stri
|
|||
<string>hours</string>
|
||||
</property>
|
||||
</item>
|
||||
<property name="currentIndex">
|
||||
<number>2</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
|
@ -529,6 +529,35 @@ For example, use 1 hour to have a new file created every hour on the hour.</stri
|
|||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="gbCompression">
|
||||
<property name="title">
|
||||
<string>compression</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||
<item>
|
||||
<widget class="QRadioButton" name="rbCompressionNone">
|
||||
<property name="text">
|
||||
<string>None</string>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">buttonGroup</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="rbCompressionGzip">
|
||||
<property name="text">
|
||||
<string>gzip</string>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">buttonGroup</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_2">
|
||||
<property name="orientation">
|
||||
|
@ -545,6 +574,7 @@ For example, use 1 hour to have a new file created every hour on the hour.</stri
|
|||
</layout>
|
||||
<zorder>gbNewFileAuto</zorder>
|
||||
<zorder>gbCaptureToFile</zorder>
|
||||
<zorder>gbCompression</zorder>
|
||||
</widget>
|
||||
<widget class="QWidget" name="optionsTab">
|
||||
<attribute name="title">
|
||||
|
@ -902,4 +932,7 @@ For example, use 1 hour to have a new file created every hour on the hour.</stri
|
|||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
<buttongroups>
|
||||
<buttongroup name="buttonGroup"/>
|
||||
</buttongroups>
|
||||
</ui>
|
||||
|
|
Loading…
Reference in New Issue