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>
62 /* Ringbuffer file structure */
63 typedef struct _rb_file
{
67 #define MAX_FILENAME_QUEUE 100
69 /** Ringbuffer data structure */
70 typedef struct _ringbuf_data
{
72 guint num_files
; /**< Number of ringbuffer files (1 to ...) */
73 guint curr_file_num
; /**< Number of the current file (ever increasing) */
74 gchar
*fprefix
; /**< Filename prefix */
75 gchar
*fsuffix
; /**< Filename suffix */
76 gboolean nametimenum
; /**< ...num_time... or ...time_num... */
77 gboolean unlimited
; /**< TRUE if unlimited number of files */
79 int fd
; /**< Current ringbuffer file descriptor */
81 char *io_buffer
; /**< The IO buffer used to write to the file */
82 gboolean group_read_access
; /**< TRUE if files need to be opened with group read access */
83 FILE *name_h
; /**< write names of completed files to this handle */
84 gchar
*compress_type
; /**< compress type */
86 GMutex mutex
; /**< mutex for oldnames */
87 gchar
*oldnames
[MAX_FILENAME_QUEUE
]; /**< filename list of pending to be deleted */
90 static ringbuf_data rb_data
;
93 * delete pending uncompressed pcap files.
96 CleanupOldCap(gchar
* name
)
101 g_mutex_lock(&rb_data
.mutex
);
103 /* Delete pending delete file */
104 for (i
= 0; i
< array_length(rb_data
.oldnames
); i
++) {
105 if (rb_data
.oldnames
[i
] != NULL
) {
106 ws_unlink(rb_data
.oldnames
[i
]);
107 if (ws_stat64(rb_data
.oldnames
[i
], &statb
) != 0) {
108 g_free(rb_data
.oldnames
[i
]);
109 rb_data
.oldnames
[i
] = NULL
;
115 /* push the current file to pending list if it failed to delete */
116 if (ws_stat64(name
, &statb
) == 0) {
117 for (i
= 0; i
< array_length(rb_data
.oldnames
); i
++) {
118 if (rb_data
.oldnames
[i
] == NULL
) {
119 rb_data
.oldnames
[i
] = g_strdup(name
);
126 g_mutex_unlock(&rb_data
.mutex
);
131 * compress capture file
134 ringbuf_exec_compress(gchar
* name
)
136 guint8
*buffer
= NULL
;
140 gboolean delete_org_file
= TRUE
;
143 fd
= ws_open(name
, O_RDONLY
| O_BINARY
, 0000);
148 outgz
= ws_strdup_printf("%s.gz", name
);
149 fi
= gzopen(outgz
, "wb");
156 #define FS_READ_SIZE 65536
157 buffer
= (guint8
*)g_malloc(FS_READ_SIZE
);
158 if (buffer
== NULL
) {
164 while ((nread
= ws_read(fd
, buffer
, FS_READ_SIZE
)) > 0) {
165 int n
= gzwrite(fi
, buffer
, (unsigned int)nread
);
167 /* mark compression as failed */
168 delete_org_file
= FALSE
;
173 /* mark compression as failed */
174 delete_org_file
= FALSE
;
180 /* delete the original file only if compression succeeds */
181 if (delete_org_file
) {
190 * thread to compress capture file
193 exec_compress_thread(void* arg
)
195 ringbuf_exec_compress((gchar
*)arg
);
200 * start a thread to compress capture file
203 ringbuf_start_compress_file(rb_file
* rfile
)
205 gchar
* name
= g_strdup(rfile
->name
);
206 g_thread_new("exec_compress", &exec_compress_thread
, name
);
212 * create the next filename and open a new binary file with that name
215 ringbuf_open_file(rb_file
*rfile
, int *err
)
222 if (rfile
->name
!= NULL
) {
223 if (rb_data
.unlimited
== FALSE
) {
224 /* remove old file (if any, so ignore error) */
225 ws_unlink(rfile
->name
);
228 else if (rb_data
.compress_type
!= NULL
&& strcmp(rb_data
.compress_type
, "gzip") == 0) {
229 ringbuf_start_compress_file(rfile
);
238 current_time
= time(NULL
);
240 snprintf(filenum
, sizeof(filenum
), "%05u", (rb_data
.curr_file_num
+ 1) % RINGBUFFER_MAX_NUM_FILES
);
241 tm
= localtime(¤t_time
);
243 strftime(timestr
, sizeof(timestr
), "%Y%m%d%H%M%S", tm
);
245 (void) g_strlcpy(timestr
, "196912312359", sizeof(timestr
)); /* second before the Epoch */
246 if (rb_data
.nametimenum
) {
247 rfile
->name
= g_strconcat(rb_data
.fprefix
, "_", timestr
, "_", filenum
, rb_data
.fsuffix
, NULL
);
249 rfile
->name
= g_strconcat(rb_data
.fprefix
, "_", filenum
, "_", timestr
, rb_data
.fsuffix
, NULL
);
252 if (rfile
->name
== NULL
) {
258 rb_data
.fd
= ws_open(rfile
->name
, O_RDWR
|O_BINARY
|O_TRUNC
|O_CREAT
,
259 rb_data
.group_read_access
? 0640 : 0600);
261 if (rb_data
.fd
== -1 && err
!= NULL
) {
269 * Initialize the ringbuffer data structures
272 ringbuf_init(const char *capfile_name
, guint num_files
, gboolean group_read_access
,
273 gchar
*compress_type
, gboolean has_nametimenum
)
277 char *dir_name
, *base_name
;
279 rb_data
.files
= NULL
;
280 rb_data
.curr_file_num
= 0;
281 rb_data
.fprefix
= NULL
;
282 rb_data
.fsuffix
= NULL
;
283 rb_data
.nametimenum
= has_nametimenum
;
284 rb_data
.unlimited
= FALSE
;
287 rb_data
.io_buffer
= NULL
;
288 rb_data
.group_read_access
= group_read_access
;
289 rb_data
.name_h
= NULL
;
290 rb_data
.compress_type
= compress_type
;
291 g_mutex_init(&rb_data
.mutex
);
293 /* just to be sure ... */
294 if (num_files
<= RINGBUFFER_MAX_NUM_FILES
) {
295 rb_data
.num_files
= num_files
;
297 rb_data
.num_files
= RINGBUFFER_MAX_NUM_FILES
;
300 /* Check file name */
301 if (capfile_name
== NULL
) {
302 /* ringbuffer does not work with temporary files! */
306 /* set file name prefix/suffix */
308 base_name
= g_path_get_basename(capfile_name
);
309 dir_name
= g_path_get_dirname(capfile_name
);
310 pfx
= strrchr(base_name
, '.');
312 /* The basename has a "." in it.
314 Treat it as a separator between the rest of the file name and
315 the file name suffix, and arrange that the names given to the
316 ring buffer files have the specified suffix, i.e. put the
317 changing part of the name *before* the suffix.
319 XXX - If we ever handle writing compressed files directly
320 (#19159) make sure we deal with any compression suffix
323 rb_data
.fprefix
= g_build_filename(dir_name
, base_name
, NULL
);
324 pfx
[0] = '.'; /* restore capfile_name */
325 rb_data
.fsuffix
= g_strdup(pfx
);
327 /* The last component has no suffix. */
328 rb_data
.fprefix
= g_strdup(capfile_name
);
329 rb_data
.fsuffix
= NULL
;
334 /* allocate rb_file structures (only one if unlimited since there is no
335 need to save all file names in that case) */
337 if (num_files
== RINGBUFFER_UNLIMITED_FILES
) {
338 rb_data
.unlimited
= TRUE
;
339 rb_data
.num_files
= 1;
342 rb_data
.files
= g_new(rb_file
, rb_data
.num_files
);
343 if (rb_data
.files
== NULL
) {
347 for (i
=0; i
< rb_data
.num_files
; i
++) {
348 rb_data
.files
[i
].name
= NULL
;
351 /* create the first file */
352 if (ringbuf_open_file(&rb_data
.files
[0], NULL
) == -1) {
353 ringbuf_error_cleanup();
361 * Set name of file to which to print ringbuffer file names.
364 ringbuf_set_print_name(gchar
*name
, int *err
)
366 if (rb_data
.name_h
!= NULL
) {
367 if (EOF
== fclose(rb_data
.name_h
)) {
374 if (!strcmp(name
, "-") || !strcmp(name
, "stdout")) {
375 rb_data
.name_h
= stdout
;
376 } else if (!strcmp(name
, "stderr")) {
377 rb_data
.name_h
= stderr
;
379 if (NULL
== (rb_data
.name_h
= ws_fopen(name
, "wt"))) {
390 * Whether the ringbuf filenames are ready.
391 * (Whether ringbuf_init is called and ringbuf_free is not called.)
394 ringbuf_is_initialized(void)
396 return rb_data
.files
!= NULL
;
400 ringbuf_current_filename(void)
402 return rb_data
.files
[rb_data
.curr_file_num
% rb_data
.num_files
].name
;
406 * Calls ws_fdopen() for the current ringbuffer file
409 ringbuf_init_libpcap_fdopen(int *err
)
411 rb_data
.pdh
= ws_fdopen(rb_data
.fd
, "wb");
412 if (rb_data
.pdh
== NULL
) {
417 size_t buffsize
= IO_BUF_SIZE
;
418 #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
421 if (ws_fstat64(rb_data
.fd
, &statb
) == 0) {
422 if (statb
.st_blksize
> IO_BUF_SIZE
) {
423 buffsize
= statb
.st_blksize
;
427 /* Increase the size of the IO buffer */
428 rb_data
.io_buffer
= (char *)g_realloc(rb_data
.io_buffer
, buffsize
);
429 setvbuf(rb_data
.pdh
, rb_data
.io_buffer
, _IOFBF
, buffsize
);
436 * Switches to the next ringbuffer file
439 ringbuf_switch_file(FILE **pdh
, gchar
**save_file
, int *save_file_fd
, int *err
)
442 rb_file
*next_rfile
= NULL
;
444 /* close current file */
446 if (fclose(rb_data
.pdh
) == EOF
) {
450 ws_close(rb_data
.fd
); /* XXX - the above should have closed this already */
451 rb_data
.pdh
= NULL
; /* it's still closed, we just got an error while closing */
453 g_free(rb_data
.io_buffer
);
454 rb_data
.io_buffer
= NULL
;
461 if (rb_data
.name_h
!= NULL
) {
462 fprintf(rb_data
.name_h
, "%s\n", ringbuf_current_filename());
463 fflush(rb_data
.name_h
);
466 /* get the next file number and open it */
468 rb_data
.curr_file_num
++ /* = next_file_num*/;
469 next_file_index
= (rb_data
.curr_file_num
) % rb_data
.num_files
;
470 next_rfile
= &rb_data
.files
[next_file_index
];
472 if (ringbuf_open_file(next_rfile
, err
) == -1) {
476 if (ringbuf_init_libpcap_fdopen(err
) == NULL
) {
480 /* switch to the new file */
481 *save_file
= next_rfile
->name
;
482 *save_file_fd
= rb_data
.fd
;
483 (*pdh
) = rb_data
.pdh
;
489 * Calls fclose() for the current ringbuffer file
492 ringbuf_libpcap_dump_close(gchar
**save_file
, int *err
)
494 gboolean ret_val
= TRUE
;
496 /* close current file, if it's open */
497 if (rb_data
.pdh
!= NULL
) {
498 if (fclose(rb_data
.pdh
) == EOF
) {
502 ws_close(rb_data
.fd
);
507 g_free(rb_data
.io_buffer
);
508 rb_data
.io_buffer
= NULL
;
512 if (rb_data
.name_h
!= NULL
) {
513 fprintf(rb_data
.name_h
, "%s\n", ringbuf_current_filename());
514 fflush(rb_data
.name_h
);
516 if (EOF
== fclose(rb_data
.name_h
)) {
517 /* Can't really do much about this, can we? */
521 /* set the save file name to the current file */
522 *save_file
= rb_data
.files
[rb_data
.curr_file_num
% rb_data
.num_files
].name
;
527 * Frees all memory allocated by the ringbuffer
534 if (rb_data
.files
!= NULL
) {
535 for (i
=0; i
< rb_data
.num_files
; i
++) {
536 if (rb_data
.files
[i
].name
!= NULL
) {
537 g_free(rb_data
.files
[i
].name
);
538 rb_data
.files
[i
].name
= NULL
;
541 g_free(rb_data
.files
);
542 rb_data
.files
= NULL
;
544 if (rb_data
.fprefix
!= NULL
) {
545 g_free(rb_data
.fprefix
);
546 rb_data
.fprefix
= NULL
;
548 if (rb_data
.fsuffix
!= NULL
) {
549 g_free(rb_data
.fsuffix
);
550 rb_data
.fsuffix
= NULL
;
557 * Frees all memory allocated by the ringbuffer
560 ringbuf_error_cleanup(void)
564 /* try to close via wtap */
565 if (rb_data
.pdh
!= NULL
) {
566 if (fclose(rb_data
.pdh
) == 0) {
572 /* close directly if still open */
573 if (rb_data
.fd
!= -1) {
574 ws_close(rb_data
.fd
);
578 if (rb_data
.files
!= NULL
) {
579 for (i
=0; i
< rb_data
.num_files
; i
++) {
580 if (rb_data
.files
[i
].name
!= NULL
) {
581 ws_unlink(rb_data
.files
[i
].name
);
585 g_free(rb_data
.io_buffer
);
586 rb_data
.io_buffer
= NULL
;
588 if (rb_data
.name_h
!= NULL
) {
589 if (EOF
== fclose(rb_data
.name_h
)) {
590 /* Can't really do much about this, can we? */
594 /* free the memory */
598 #endif /* HAVE_LIBPCAP */