2 * Routines for packet capture windows
4 * $Id: ringbuffer.c,v 1.7 2003/06/22 16:06:03 deniel Exp $
6 * Ethereal - Network traffic analyzer
7 * By Gerald Combs <gerald@ethereal.com>
8 * Copyright 1998 Gerald Combs
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26 * <laurent.deniel@free.fr>
28 * Almost completely rewritten in order to:
30 * - be able to use a unlimited number of ringbuffer files
31 * - close the current file and open (truncating) the next file at switch
32 * - set the final file name once open (or reopen)
33 * - avoid the deletion of files that could not be truncated (can't arise now)
34 * and do not erase empty files
36 * The idea behind that is to remove the limitation of the maximum # of
37 * ringbuffer files being less than the maximum # of open fd per process
38 * and to be able to reduce the amount of virtual memory usage (having only
39 * one file open at most) or the amount of file system usage (by truncating
40 * the files at switch and not the capture stop, and by closing them which
41 * makes possible their move or deletion after a switch).
59 #ifdef HAVE_SYS_STAT_H
72 #ifdef NEED_SNPRINTF_H
76 #include "wiretap/wtap.h"
77 #include "ringbuffer.h"
79 /* Win32 needs the O_BINARY flag for open() */
84 /* Ringbuffer file structure */
85 typedef struct _rb_file {
89 /* Ringbuffer data structure */
90 typedef struct _ringbuf_data {
92 guint num_files; /* Number of ringbuffer files */
93 guint curr_file_num; /* Number of the current file */
94 gchar *fprefix; /* Filename prefix */
95 gchar *fsuffix; /* Filename suffix */
96 gboolean unlimited; /* TRUE if unlimited number of files */
101 int fd; /* Current ringbuffer file descriptor */
105 static ringbuf_data rb_data;
107 static int ringbuf_open_file(rb_file *rfile, int *err)
113 if (rfile->name != NULL) {
114 if (rb_data.unlimited == FALSE) {
115 /* remove old file (if any, so ignore error) */
124 current_time = time(NULL);
128 snprintf(filenum, sizeof(filenum), "%05d", rb_data.number);
129 strftime(timestr, sizeof(timestr), "%Y%m%d%H%M%S", localtime(¤t_time));
130 rfile->name = g_strconcat(rb_data.fprefix, "_", filenum, "_", timestr,
131 rb_data.fsuffix, NULL);
133 if (rfile->name == NULL) {
138 rb_data.fd = open(rfile->name, O_RDWR|O_BINARY|O_TRUNC|O_CREAT, 0600);
140 if (rb_data.fd == -1 && err != NULL) {
148 * Initialize the ringbuffer data structures
151 ringbuf_init(const char *capfile_name, guint num_files)
157 rb_data.files = NULL;
158 rb_data.curr_file_num = 0;
159 rb_data.fprefix = NULL;
160 rb_data.fsuffix = NULL;
161 rb_data.unlimited = FALSE;
166 /* just to be sure ... */
167 if (num_files <= RINGBUFFER_MAX_NUM_FILES) {
168 rb_data.num_files = num_files;
170 rb_data.num_files = RINGBUFFER_MAX_NUM_FILES;
173 /* Check file name */
174 if (capfile_name == NULL) {
175 /* ringbuffer does not work with temporary files! */
179 /* set file name prefix/suffix */
181 save_file = g_strdup(capfile_name);
182 pfx = strrchr(save_file,'.');
185 rb_data.fprefix = g_strdup(save_file);
186 pfx[0] = '.'; /* restore capfile_name */
187 rb_data.fsuffix = g_strdup(pfx);
189 rb_data.fprefix = g_strdup(save_file);
190 rb_data.fsuffix = NULL;
195 /* allocate rb_file structures (only one if unlimited since there is no
196 need to save all file names in that case) */
198 if (num_files == RINGBUFFER_UNLIMITED_FILES) {
199 rb_data.unlimited = TRUE;
200 rb_data.num_files = 1;
203 rb_data.files = g_malloc(rb_data.num_files * sizeof(rb_file));
204 if (rb_data.files == NULL) {
208 for (i=0; i < rb_data.num_files; i++) {
209 rb_data.files[i].name = NULL;
212 /* create the first file */
213 if (ringbuf_open_file(&rb_data.files[0], NULL) == -1) {
214 ringbuf_error_cleanup();
222 * Calls wtap_dump_fdopen() for the current ringbuffer file
225 ringbuf_init_wtap_dump_fdopen(int filetype, int linktype, int snaplen, int *err)
228 rb_data.filetype = filetype;
229 rb_data.linktype = linktype;
230 rb_data.snaplen = snaplen;
232 rb_data.pdh = wtap_dump_fdopen(rb_data.fd, filetype, linktype, snaplen, err);
238 * Switches to the next ringbuffer file
241 ringbuf_switch_file(capture_file *cf, wtap_dumper **pdh, int *err)
244 rb_file *next_rfile = NULL;
246 /* close current file */
248 if (!wtap_dump_close(rb_data.pdh, err)) {
257 /* get the next file number and open it */
259 next_file_num = (rb_data.curr_file_num + 1) % rb_data.num_files;
260 next_rfile = &rb_data.files[next_file_num];
262 if (ringbuf_open_file(next_rfile, err) == -1) {
266 if (ringbuf_init_wtap_dump_fdopen(rb_data.filetype, rb_data.linktype,
267 rb_data.snaplen, err) == NULL) {
271 /* switch to the new file */
272 rb_data.curr_file_num = next_file_num;
273 cf->save_file = next_rfile->name;
274 cf->save_file_fd = rb_data.fd;
275 (*pdh) = rb_data.pdh;
281 * Calls wtap_dump_close() for the current ringbuffer file
284 ringbuf_wtap_dump_close(capture_file *cf, int *err)
286 gboolean ret_val = TRUE;
288 /* close current file */
290 if (!wtap_dump_close(rb_data.pdh, err)) {
298 cf->save_file = rb_data.files[rb_data.curr_file_num].name;
303 * Frees all memory allocated by the ringbuffer
310 if (rb_data.files != NULL) {
311 for (i=0; i < rb_data.num_files; i++) {
312 if (rb_data.files[i].name != NULL) {
313 g_free(rb_data.files[i].name);
314 rb_data.files[i].name = NULL;
317 g_free(rb_data.files);
318 rb_data.files = NULL;
320 if (rb_data.fprefix != NULL) {
321 g_free(rb_data.fprefix);
322 rb_data.fprefix = NULL;
324 if (rb_data.fsuffix != NULL) {
325 g_free(rb_data.fsuffix);
326 rb_data.fsuffix = NULL;
331 * Frees all memory allocated by the ringbuffer
334 ringbuf_error_cleanup(void)
338 /* try to close via wtap */
339 if (rb_data.pdh != NULL) {
340 if (wtap_dump_close(rb_data.pdh, NULL)) {
346 /* close directly if still open */
347 if (rb_data.fd != -1) {
352 for (i=0; i < rb_data.num_files; i++) {
353 if (rb_data.files[i].name != NULL) {
354 unlink(rb_data.files[i].name);
357 /* free the memory */
361 #endif /* HAVE_LIBPCAP */