2 * Routines for packet capture windows
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 * <laurent.deniel@free.fr>
14 * Almost completely rewritten in order to:
16 * - be able to use a unlimited number of ringbuffer files
17 * - close the current file and open (truncating) the next file at switch
18 * - set the final file name once open (or reopen)
19 * - avoid the deletion of files that could not be truncated (can't arise now)
20 * and do not erase empty files
22 * The idea behind that is to remove the limitation of the maximum # of
23 * ringbuffer files being less than the maximum # of open fd per process
24 * and to be able to reduce the amount of virtual memory usage (having only
25 * one file open at most) or the amount of file system usage (by truncating
26 * the files at switch and not the capture stop, and by closing them which
27 * makes possible their move or deletion after a switch).
51 #include <wsutil/win32-utils.h>
54 #include "ringbuffer.h"
55 #include <wsutil/array.h>
56 #include <wsutil/file_util.h>
59 #define ZLIB_PREFIX(x) zng_ ## x
61 typedef zng_stream zlib_stream
;
64 #define ZLIB_PREFIX(x) x
66 typedef z_stream zlib_stream
;
67 #endif /* HAVE_ZLIB */
70 /* Ringbuffer file structure */
71 typedef struct _rb_file
{
75 #define MAX_FILENAME_QUEUE 100
77 /** Ringbuffer data structure */
78 typedef struct _ringbuf_data
{
80 unsigned num_files
; /**< Number of ringbuffer files (1 to ...) */
81 unsigned curr_file_num
; /**< Number of the current file (ever increasing) */
82 char *fprefix
; /**< Filename prefix */
83 char *fsuffix
; /**< Filename suffix */
84 bool nametimenum
; /**< ...num_time... or ...time_num... */
85 bool unlimited
; /**< true if unlimited number of files */
87 int fd
; /**< Current ringbuffer file descriptor */
89 char *io_buffer
; /**< The IO buffer used to write to the file */
90 bool group_read_access
; /**< true if files need to be opened with group read access */
91 FILE *name_h
; /**< write names of completed files to this handle */
92 char *compress_type
; /**< compress type */
94 GMutex mutex
; /**< mutex for oldnames */
95 char *oldnames
[MAX_FILENAME_QUEUE
]; /**< filename list of pending to be deleted */
98 static ringbuf_data rb_data
;
101 * delete pending uncompressed pcap files.
104 CleanupOldCap(char* name
)
109 g_mutex_lock(&rb_data
.mutex
);
111 /* Delete pending delete file */
112 for (i
= 0; i
< array_length(rb_data
.oldnames
); i
++) {
113 if (rb_data
.oldnames
[i
] != NULL
) {
114 ws_unlink(rb_data
.oldnames
[i
]);
115 if (ws_stat64(rb_data
.oldnames
[i
], &statb
) != 0) {
116 g_free(rb_data
.oldnames
[i
]);
117 rb_data
.oldnames
[i
] = NULL
;
123 /* push the current file to pending list if it failed to delete */
124 if (ws_stat64(name
, &statb
) == 0) {
125 for (i
= 0; i
< array_length(rb_data
.oldnames
); i
++) {
126 if (rb_data
.oldnames
[i
] == NULL
) {
127 rb_data
.oldnames
[i
] = g_strdup(name
);
134 g_mutex_unlock(&rb_data
.mutex
);
137 #if defined (HAVE_ZLIB) || defined (HAVE_ZLIBNG)
139 * compress capture file
142 ringbuf_exec_compress(char* name
)
144 uint8_t *buffer
= NULL
;
148 bool delete_org_file
= true;
151 fd
= ws_open(name
, O_RDONLY
| O_BINARY
, 0000);
156 outgz
= ws_strdup_printf("%s.gz", name
);
157 fi
= ZLIB_PREFIX(gzopen
)(outgz
, "wb");
164 #define FS_READ_SIZE 65536
165 buffer
= (uint8_t*)g_malloc(FS_READ_SIZE
);
166 if (buffer
== NULL
) {
168 ZLIB_PREFIX(gzclose
)(fi
);
172 while ((nread
= ws_read(fd
, buffer
, FS_READ_SIZE
)) > 0) {
173 int n
= ZLIB_PREFIX(gzwrite
)(fi
, buffer
, (unsigned int)nread
);
175 /* mark compression as failed */
176 delete_org_file
= false;
181 /* mark compression as failed */
182 delete_org_file
= false;
185 ZLIB_PREFIX(gzclose
)(fi
);
188 /* delete the original file only if compression succeeds */
189 if (delete_org_file
) {
198 * thread to compress capture file
201 exec_compress_thread(void* arg
)
203 ringbuf_exec_compress((char*)arg
);
208 * start a thread to compress capture file
211 ringbuf_start_compress_file(rb_file
* rfile
)
213 char* name
= g_strdup(rfile
->name
);
214 g_thread_new("exec_compress", &exec_compress_thread
, name
);
220 * create the next filename and open a new binary file with that name
223 ringbuf_open_file(rb_file
*rfile
, int *err
)
230 if (rfile
->name
!= NULL
) {
231 if (rb_data
.unlimited
== false) {
232 /* remove old file (if any, so ignore error) */
233 ws_unlink(rfile
->name
);
235 #if defined (HAVE_ZLIB) || defined (HAVE_ZLIBNG)
236 else if (rb_data
.compress_type
!= NULL
&& strcmp(rb_data
.compress_type
, "gzip") == 0) {
237 ringbuf_start_compress_file(rfile
);
246 current_time
= time(NULL
);
248 snprintf(filenum
, sizeof(filenum
), "%05u", (rb_data
.curr_file_num
+ 1) % RINGBUFFER_MAX_NUM_FILES
);
249 tm
= localtime(¤t_time
);
251 strftime(timestr
, sizeof(timestr
), "%Y%m%d%H%M%S", tm
);
253 (void) g_strlcpy(timestr
, "196912312359", sizeof(timestr
)); /* second before the Epoch */
254 if (rb_data
.nametimenum
) {
255 rfile
->name
= g_strconcat(rb_data
.fprefix
, "_", timestr
, "_", filenum
, rb_data
.fsuffix
, NULL
);
257 rfile
->name
= g_strconcat(rb_data
.fprefix
, "_", filenum
, "_", timestr
, rb_data
.fsuffix
, NULL
);
260 if (rfile
->name
== NULL
) {
266 rb_data
.fd
= ws_open(rfile
->name
, O_RDWR
|O_BINARY
|O_TRUNC
|O_CREAT
,
267 rb_data
.group_read_access
? 0640 : 0600);
269 if (rb_data
.fd
== -1 && err
!= NULL
) {
277 * Initialize the ringbuffer data structures
280 ringbuf_init(const char *capfile_name
, unsigned num_files
, bool group_read_access
,
281 char *compress_type
, bool has_nametimenum
)
285 char *dir_name
, *base_name
;
287 rb_data
.files
= NULL
;
288 rb_data
.curr_file_num
= 0;
289 rb_data
.fprefix
= NULL
;
290 rb_data
.fsuffix
= NULL
;
291 rb_data
.nametimenum
= has_nametimenum
;
292 rb_data
.unlimited
= false;
295 rb_data
.io_buffer
= NULL
;
296 rb_data
.group_read_access
= group_read_access
;
297 rb_data
.name_h
= NULL
;
298 rb_data
.compress_type
= compress_type
;
299 g_mutex_init(&rb_data
.mutex
);
301 /* just to be sure ... */
302 if (num_files
<= RINGBUFFER_MAX_NUM_FILES
) {
303 rb_data
.num_files
= num_files
;
305 rb_data
.num_files
= RINGBUFFER_MAX_NUM_FILES
;
308 /* Check file name */
309 if (capfile_name
== NULL
) {
310 /* ringbuffer does not work with temporary files! */
314 /* set file name prefix/suffix */
316 base_name
= g_path_get_basename(capfile_name
);
317 dir_name
= g_path_get_dirname(capfile_name
);
318 pfx
= strrchr(base_name
, '.');
320 /* The basename has a "." in it.
322 Treat it as a separator between the rest of the file name and
323 the file name suffix, and arrange that the names given to the
324 ring buffer files have the specified suffix, i.e. put the
325 changing part of the name *before* the suffix.
327 XXX - If we ever handle writing compressed files directly
328 (#19159) make sure we deal with any compression suffix
331 rb_data
.fprefix
= g_build_filename(dir_name
, base_name
, NULL
);
332 pfx
[0] = '.'; /* restore capfile_name */
333 rb_data
.fsuffix
= g_strdup(pfx
);
335 /* The last component has no suffix. */
336 rb_data
.fprefix
= g_strdup(capfile_name
);
337 rb_data
.fsuffix
= NULL
;
342 /* allocate rb_file structures (only one if unlimited since there is no
343 need to save all file names in that case) */
345 if (num_files
== RINGBUFFER_UNLIMITED_FILES
) {
346 rb_data
.unlimited
= true;
347 rb_data
.num_files
= 1;
350 rb_data
.files
= g_new(rb_file
, rb_data
.num_files
);
351 if (rb_data
.files
== NULL
) {
355 for (i
=0; i
< rb_data
.num_files
; i
++) {
356 rb_data
.files
[i
].name
= NULL
;
359 /* create the first file */
360 if (ringbuf_open_file(&rb_data
.files
[0], NULL
) == -1) {
361 ringbuf_error_cleanup();
369 * Set name of file to which to print ringbuffer file names.
372 ringbuf_set_print_name(char *name
, int *err
)
374 if (rb_data
.name_h
!= NULL
) {
375 if (EOF
== fclose(rb_data
.name_h
)) {
382 if (!strcmp(name
, "-") || !strcmp(name
, "stdout")) {
383 rb_data
.name_h
= stdout
;
384 } else if (!strcmp(name
, "stderr")) {
385 rb_data
.name_h
= stderr
;
387 if (NULL
== (rb_data
.name_h
= ws_fopen(name
, "wt"))) {
398 * Whether the ringbuf filenames are ready.
399 * (Whether ringbuf_init is called and ringbuf_free is not called.)
402 ringbuf_is_initialized(void)
404 return rb_data
.files
!= NULL
;
408 ringbuf_current_filename(void)
410 return rb_data
.files
[rb_data
.curr_file_num
% rb_data
.num_files
].name
;
414 * Calls ws_fdopen() for the current ringbuffer file
417 ringbuf_init_libpcap_fdopen(int *err
)
419 rb_data
.pdh
= ws_fdopen(rb_data
.fd
, "wb");
420 if (rb_data
.pdh
== NULL
) {
425 size_t buffsize
= IO_BUF_SIZE
;
426 #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
429 if (ws_fstat64(rb_data
.fd
, &statb
) == 0) {
430 if (statb
.st_blksize
> IO_BUF_SIZE
) {
431 buffsize
= statb
.st_blksize
;
435 /* Increase the size of the IO buffer */
436 rb_data
.io_buffer
= (char *)g_realloc(rb_data
.io_buffer
, buffsize
);
437 setvbuf(rb_data
.pdh
, rb_data
.io_buffer
, _IOFBF
, buffsize
);
444 * Switches to the next ringbuffer file
447 ringbuf_switch_file(FILE **pdh
, char **save_file
, int *save_file_fd
, int *err
)
450 rb_file
*next_rfile
= NULL
;
452 /* close current file */
454 if (fclose(rb_data
.pdh
) == EOF
) {
458 ws_close(rb_data
.fd
); /* XXX - the above should have closed this already */
459 rb_data
.pdh
= NULL
; /* it's still closed, we just got an error while closing */
461 g_free(rb_data
.io_buffer
);
462 rb_data
.io_buffer
= NULL
;
469 if (rb_data
.name_h
!= NULL
) {
470 fprintf(rb_data
.name_h
, "%s\n", ringbuf_current_filename());
471 fflush(rb_data
.name_h
);
474 /* get the next file number and open it */
476 rb_data
.curr_file_num
++ /* = next_file_num*/;
477 next_file_index
= (rb_data
.curr_file_num
) % rb_data
.num_files
;
478 next_rfile
= &rb_data
.files
[next_file_index
];
480 if (ringbuf_open_file(next_rfile
, err
) == -1) {
484 if (ringbuf_init_libpcap_fdopen(err
) == NULL
) {
488 /* switch to the new file */
489 *save_file
= next_rfile
->name
;
490 *save_file_fd
= rb_data
.fd
;
491 (*pdh
) = rb_data
.pdh
;
497 * Calls fclose() for the current ringbuffer file
500 ringbuf_libpcap_dump_close(char **save_file
, int *err
)
504 /* close current file, if it's open */
505 if (rb_data
.pdh
!= NULL
) {
506 if (fclose(rb_data
.pdh
) == EOF
) {
510 ws_close(rb_data
.fd
);
515 g_free(rb_data
.io_buffer
);
516 rb_data
.io_buffer
= NULL
;
520 if (rb_data
.name_h
!= NULL
) {
521 fprintf(rb_data
.name_h
, "%s\n", ringbuf_current_filename());
522 fflush(rb_data
.name_h
);
524 if (EOF
== fclose(rb_data
.name_h
)) {
525 /* Can't really do much about this, can we? */
529 /* set the save file name to the current file */
530 *save_file
= rb_data
.files
[rb_data
.curr_file_num
% rb_data
.num_files
].name
;
535 * Frees all memory allocated by the ringbuffer
542 if (rb_data
.files
!= NULL
) {
543 for (i
=0; i
< rb_data
.num_files
; i
++) {
544 if (rb_data
.files
[i
].name
!= NULL
) {
545 g_free(rb_data
.files
[i
].name
);
546 rb_data
.files
[i
].name
= NULL
;
549 g_free(rb_data
.files
);
550 rb_data
.files
= NULL
;
552 if (rb_data
.fprefix
!= NULL
) {
553 g_free(rb_data
.fprefix
);
554 rb_data
.fprefix
= NULL
;
556 if (rb_data
.fsuffix
!= NULL
) {
557 g_free(rb_data
.fsuffix
);
558 rb_data
.fsuffix
= NULL
;
565 * Frees all memory allocated by the ringbuffer
568 ringbuf_error_cleanup(void)
572 /* try to close via wtap */
573 if (rb_data
.pdh
!= NULL
) {
574 if (fclose(rb_data
.pdh
) == 0) {
580 /* close directly if still open */
581 if (rb_data
.fd
!= -1) {
582 ws_close(rb_data
.fd
);
586 if (rb_data
.files
!= NULL
) {
587 for (i
=0; i
< rb_data
.num_files
; i
++) {
588 if (rb_data
.files
[i
].name
!= NULL
) {
589 ws_unlink(rb_data
.files
[i
].name
);
593 g_free(rb_data
.io_buffer
);
594 rb_data
.io_buffer
= NULL
;
596 if (rb_data
.name_h
!= NULL
) {
597 if (EOF
== fclose(rb_data
.name_h
)) {
598 /* Can't really do much about this, can we? */
602 /* free the memory */
606 #endif /* HAVE_LIBPCAP */