Revert "TODO: smb2: simplify preauth_hash calculation..."
[wireshark-sm.git] / ringbuffer.c
blob9fbdcdaeb379ba0e02420592049ca714754a854a
1 /* ringbuffer.c
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
9 */
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).
31 #include <config.h>
33 #ifdef HAVE_LIBPCAP
35 #include <stdio.h>
36 #include <string.h>
37 #include <time.h>
38 #include <errno.h>
39 #include <stdlib.h>
40 #include <glib.h>
42 #include <pcap.h>
44 #include <glib.h>
46 #ifdef HAVE_UNISTD_H
47 #include <unistd.h>
48 #endif
50 #ifdef _WIN32
51 #include <wsutil/win32-utils.h>
52 #endif
54 #include "ringbuffer.h"
55 #include <wsutil/array.h>
56 #include <wsutil/file_util.h>
58 #ifdef HAVE_ZLIB
59 #include <zlib.h>
60 #endif
62 /* Ringbuffer file structure */
63 typedef struct _rb_file {
64 gchar *name;
65 } rb_file;
67 #define MAX_FILENAME_QUEUE 100
69 /** Ringbuffer data structure */
70 typedef struct _ringbuf_data {
71 rb_file *files;
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 */
80 FILE *pdh;
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 */
88 } ringbuf_data;
90 static ringbuf_data rb_data;
93 * delete pending uncompressed pcap files.
95 static void
96 CleanupOldCap(gchar* name)
98 ws_statb64 statb;
99 size_t i;
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;
114 if (name) {
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);
120 break;
126 g_mutex_unlock(&rb_data.mutex);
129 #ifdef HAVE_ZLIB
131 * compress capture file
133 static int
134 ringbuf_exec_compress(gchar* name)
136 guint8 *buffer = NULL;
137 gchar* outgz = NULL;
138 int fd = -1;
139 ssize_t nread;
140 gboolean delete_org_file = TRUE;
141 gzFile fi = NULL;
143 fd = ws_open(name, O_RDONLY | O_BINARY, 0000);
144 if (fd < 0) {
145 return -1;
148 outgz = ws_strdup_printf("%s.gz", name);
149 fi = gzopen(outgz, "wb");
150 g_free(outgz);
151 if (fi == NULL) {
152 ws_close(fd);
153 return -1;
156 #define FS_READ_SIZE 65536
157 buffer = (guint8*)g_malloc(FS_READ_SIZE);
158 if (buffer == NULL) {
159 ws_close(fd);
160 gzclose(fi);
161 return -1;
164 while ((nread = ws_read(fd, buffer, FS_READ_SIZE)) > 0) {
165 int n = gzwrite(fi, buffer, (unsigned int)nread);
166 if (n <= 0) {
167 /* mark compression as failed */
168 delete_org_file = FALSE;
169 break;
172 if (nread < 0) {
173 /* mark compression as failed */
174 delete_org_file = FALSE;
176 ws_close(fd);
177 gzclose(fi);
178 g_free(buffer);
180 /* delete the original file only if compression succeeds */
181 if (delete_org_file) {
182 ws_unlink(name);
183 CleanupOldCap(name);
185 g_free(name);
186 return 0;
190 * thread to compress capture file
192 static void*
193 exec_compress_thread(void* arg)
195 ringbuf_exec_compress((gchar*)arg);
196 return NULL;
200 * start a thread to compress capture file
202 static int
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);
207 return 0;
209 #endif
212 * create the next filename and open a new binary file with that name
214 static int
215 ringbuf_open_file(rb_file *rfile, int *err)
217 char filenum[5+1];
218 char timestr[14+1];
219 time_t current_time;
220 struct tm *tm;
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);
227 #ifdef HAVE_ZLIB
228 else if (rb_data.compress_type != NULL && strcmp(rb_data.compress_type, "gzip") == 0) {
229 ringbuf_start_compress_file(rfile);
231 #endif
232 g_free(rfile->name);
235 #ifdef _WIN32
236 _tzset();
237 #endif
238 current_time = time(NULL);
240 snprintf(filenum, sizeof(filenum), "%05u", (rb_data.curr_file_num + 1) % RINGBUFFER_MAX_NUM_FILES);
241 tm = localtime(&current_time);
242 if (tm != NULL)
243 strftime(timestr, sizeof(timestr), "%Y%m%d%H%M%S", tm);
244 else
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);
248 } else {
249 rfile->name = g_strconcat(rb_data.fprefix, "_", filenum, "_", timestr, rb_data.fsuffix, NULL);
252 if (rfile->name == NULL) {
253 if (err != NULL)
254 *err = ENOMEM;
255 return -1;
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) {
262 *err = errno;
265 return rb_data.fd;
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)
275 unsigned int i;
276 char *pfx;
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;
285 rb_data.fd = -1;
286 rb_data.pdh = NULL;
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;
296 } else {
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! */
303 return -1;
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, '.');
311 if (pfx != NULL) {
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
321 appropriately. */
322 pfx[0] = '\0';
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);
326 } else {
327 /* The last component has no suffix. */
328 rb_data.fprefix = g_strdup(capfile_name);
329 rb_data.fsuffix = NULL;
331 g_free(dir_name);
332 g_free(base_name);
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) {
344 return -1;
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();
354 return -1;
357 return rb_data.fd;
361 * Set name of file to which to print ringbuffer file names.
363 gboolean
364 ringbuf_set_print_name(gchar *name, int *err)
366 if (rb_data.name_h != NULL) {
367 if (EOF == fclose(rb_data.name_h)) {
368 if (err != NULL) {
369 *err = errno;
371 return FALSE;
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;
378 } else {
379 if (NULL == (rb_data.name_h = ws_fopen(name, "wt"))) {
380 if (err != NULL) {
381 *err = errno;
383 return FALSE;
386 return TRUE;
390 * Whether the ringbuf filenames are ready.
391 * (Whether ringbuf_init is called and ringbuf_free is not called.)
393 gboolean
394 ringbuf_is_initialized(void)
396 return rb_data.files != NULL;
399 const gchar *
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
408 FILE *
409 ringbuf_init_libpcap_fdopen(int *err)
411 rb_data.pdh = ws_fdopen(rb_data.fd, "wb");
412 if (rb_data.pdh == NULL) {
413 if (err != NULL) {
414 *err = errno;
416 } else {
417 size_t buffsize = IO_BUF_SIZE;
418 #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
419 ws_statb64 statb;
421 if (ws_fstat64(rb_data.fd, &statb) == 0) {
422 if (statb.st_blksize > IO_BUF_SIZE) {
423 buffsize = statb.st_blksize;
426 #endif
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);
432 return rb_data.pdh;
436 * Switches to the next ringbuffer file
438 gboolean
439 ringbuf_switch_file(FILE **pdh, gchar **save_file, int *save_file_fd, int *err)
441 int next_file_index;
442 rb_file *next_rfile = NULL;
444 /* close current file */
446 if (fclose(rb_data.pdh) == EOF) {
447 if (err != NULL) {
448 *err = errno;
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 */
452 rb_data.fd = -1;
453 g_free(rb_data.io_buffer);
454 rb_data.io_buffer = NULL;
455 return FALSE;
458 rb_data.pdh = NULL;
459 rb_data.fd = -1;
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) {
473 return FALSE;
476 if (ringbuf_init_libpcap_fdopen(err) == NULL) {
477 return FALSE;
480 /* switch to the new file */
481 *save_file = next_rfile->name;
482 *save_file_fd = rb_data.fd;
483 (*pdh) = rb_data.pdh;
485 return TRUE;
489 * Calls fclose() for the current ringbuffer file
491 gboolean
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) {
499 if (err != NULL) {
500 *err = errno;
502 ws_close(rb_data.fd);
503 ret_val = FALSE;
505 rb_data.pdh = NULL;
506 rb_data.fd = -1;
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;
523 return ret_val;
527 * Frees all memory allocated by the ringbuffer
529 void
530 ringbuf_free(void)
532 unsigned int i;
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;
553 CleanupOldCap(NULL);
557 * Frees all memory allocated by the ringbuffer
559 void
560 ringbuf_error_cleanup(void)
562 unsigned int i;
564 /* try to close via wtap */
565 if (rb_data.pdh != NULL) {
566 if (fclose(rb_data.pdh) == 0) {
567 rb_data.fd = -1;
569 rb_data.pdh = NULL;
572 /* close directly if still open */
573 if (rb_data.fd != -1) {
574 ws_close(rb_data.fd);
575 rb_data.fd = -1;
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 */
595 ringbuf_free();
598 #endif /* HAVE_LIBPCAP */