2 * Routines for packet capture windows
4 * $Id: ringbuffer.c,v 1.5 2002/08/28 21:00:41 jmayer 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.
39 #ifdef HAVE_SYS_STAT_H
52 #ifdef NEED_SNPRINTF_H
56 #include "wiretap/wtap.h"
57 #include "ringbuffer.h"
59 /* Win32 needs the O_BINARY flag for open() */
64 /* Ringbuffer file structure */
65 typedef struct _rb_file {
75 /* Ringbuffer data structure */
76 typedef struct _ringbuf_data {
78 guint num_files; /* Number of ringbuffer files */
79 guint curr_file_num; /* Number of the current file */
80 gchar* fprefix; /* Filename prefix */
81 gchar* fsuffix; /* Filename suffix */
84 /* Create the ringbuffer data structure */
85 static ringbuf_data rb_data;
88 * Initialize the ringbuffer data structure
91 ringbuf_init(const char *capfile_name, guint num_files)
97 char save_file_num[3+1];
99 /* just to be sure ... */
100 if (num_files <= RINGBUFFER_MAX_NUM_FILES) {
101 rb_data.num_files = num_files;
103 rb_data.num_files = RINGBUFFER_MAX_NUM_FILES;
106 /* Check file name */
107 if (capfile_name == NULL) {
108 /* ringbuffer does not work with temporary files! */
112 /* Open the initial file */
113 save_file_fd = open(capfile_name, O_RDWR|O_BINARY|O_TRUNC|O_CREAT, 0600);
114 if (save_file_fd == -1) {
119 /* allocate memory */
120 rb_data.files = (rb_file *)calloc(num_files, sizeof(rb_file));
121 if (rb_data.files == NULL) {
122 /* could not allocate memory */
127 rb_data.fprefix = NULL;
128 rb_data.fsuffix = NULL;
129 for (i=0; i<rb_data.num_files; i++) {
130 rb_data.files[i].name = NULL;
131 rb_data.files[i].fd = -1;
134 /* get file name prefix/suffix */
135 save_file = g_strdup(capfile_name);
136 pfx = strrchr(save_file,'.');
139 rb_data.fprefix = g_strdup(save_file);
140 pfx[0] = '.'; /* restore capfile_name */
141 rb_data.fsuffix = g_strdup(pfx);
143 rb_data.fprefix = g_strdup(save_file);
144 rb_data.fsuffix = NULL;
152 /* save the initial file parameters */
153 rb_data.files[0].name = g_strdup(capfile_name);
154 rb_data.files[0].fd = save_file_fd;
155 rb_data.files[0].creation_time = time(NULL);
156 rb_data.files[0].number = 0;
157 rb_data.files[0].is_new = TRUE;
159 /* create the other files */
160 for (i=1; i<rb_data.num_files; i++) {
161 /* create a file name */
162 snprintf(save_file_num,3+1,"%03d",i);
163 save_file = g_strconcat(capfile_name, ".", save_file_num, NULL);
165 save_file_fd = open(save_file, O_RDWR|O_BINARY|O_TRUNC|O_CREAT, 0600);
166 if (save_file_fd != -1) {
167 rb_data.files[i].name = save_file;
168 rb_data.files[i].fd = save_file_fd;
169 rb_data.files[i].creation_time = time(NULL);
170 rb_data.files[i].number = i;
171 rb_data.files[i].is_new = TRUE;
173 /* could not open a file */
174 ringbuf_error_cleanup();
180 rb_data.curr_file_num = 0;
181 return rb_data.files[0].fd;
185 * Calls wtap_dump_fdopen() for all ringbuffer files
188 ringbuf_init_wtap_dump_fdopen(int filetype, int linktype,
189 int snaplen, int *err)
194 for (i=0; i<rb_data.num_files; i++) {
195 rb_data.files[i].pdh = wtap_dump_fdopen(rb_data.files[i].fd, filetype,
196 linktype, snaplen, err);
197 if (rb_data.files[i].pdh == NULL) {
198 /* could not open file */
202 * Flush out the capture file header, as written by "wtap_dump_fdopen()".
204 * XXX - this relies on Wiretap writing out data sequentially,
205 * and writing the entire capture file header when the file
206 * is created. That happens to be true for libpcap files,
207 * which are Ethereal's native capture files, and which are
208 * therefore the capture file types we're writing, but is not
209 * true for all the capture file types Wiretap can write.
211 fh = wtap_dump_file(rb_data.files[i].pdh);
212 if (fflush(fh) == EOF) {
218 if ((rb_data.files[i].start_pos = ftell(fh)) < 0) {
228 rb_data.files[0].is_new = FALSE;
229 return rb_data.files[0].pdh;
233 * Switches to the next ringbuffer file
236 ringbuf_switch_file(capture_file *cf, wtap_dumper **pdh, int *err)
240 gboolean err_on_next = FALSE;
242 /* flush the current file */
243 fh = wtap_dump_file(rb_data.files[rb_data.curr_file_num].pdh);
245 errno = WTAP_ERR_CANT_CLOSE;
246 if (fflush(fh) == EOF) {
253 /* get the next file number */
254 next_file_num = (rb_data.curr_file_num + 1) % rb_data.num_files;
255 /* prepare the file if it was already used */
256 if (!rb_data.files[next_file_num].is_new) {
257 /* rewind to the position after the file header */
258 fh = wtap_dump_file(rb_data.files[next_file_num].pdh);
259 if (fseek(fh, rb_data.files[next_file_num].start_pos, SEEK_SET) < 0) {
261 /* Don't return straight away: have caller report correct save_file */
264 wtap_set_bytes_dumped(rb_data.files[next_file_num].pdh,
265 rb_data.files[next_file_num].start_pos);
266 /* set the absolute file number */
267 rb_data.files[next_file_num].number += rb_data.num_files;
272 rb_data.files[next_file_num].creation_time = time(NULL);
273 /* switch to the new file */
274 cf->save_file = rb_data.files[next_file_num].name;
275 cf->save_file_fd = rb_data.files[next_file_num].fd;
276 (*pdh) = rb_data.files[next_file_num].pdh;
277 /* mark the file as used */
278 rb_data.files[next_file_num].is_new = FALSE;
279 /* finally set the current file number */
280 rb_data.curr_file_num = next_file_num;
289 * Calls wtap_dump_close() for all ringbuffer files
292 ringbuf_wtap_dump_close(capture_file *cf, int *err)
303 /* close all files */
304 for (i=0; i<rb_data.num_files; i++) {
305 fh = wtap_dump_file(rb_data.files[i].pdh);
308 errno = WTAP_ERR_CANT_CLOSE;
309 if (fflush(fh) == EOF) {
314 /* If the file's not a new one, remove it as it hasn't been truncated
315 and thus contains garbage at the end.
317 We don't remove it if it's new - it's incomplete, but at least
318 the stuff before the incomplete record is usable. */
319 close(rb_data.files[i].fd);
320 if (!rb_data.files[i].is_new) {
321 unlink(rb_data.files[i].name);
326 /* Truncate the file to the current size. This must be done in order
327 to get rid of the 'garbage' packets at the end of the file from
329 if (!rb_data.files[i].is_new) {
330 if (ftruncate(rb_data.files[i].fd,ftell(fh)) != 0) {
331 /* could not truncate the file */
336 /* remove the file since it contains garbage at the end */
337 close(rb_data.files[i].fd);
338 unlink(rb_data.files[i].name);
343 if (!wtap_dump_close(rb_data.files[i].pdh, err)) {
344 /* error only if it is a used file */
345 if (!rb_data.files[i].is_new) {
349 if (!rb_data.files[i].is_new) {
350 /* rename the file */
351 snprintf(filenum,5+1,"%05d",rb_data.files[i].number);
352 strftime(timestr,14+1,"%Y%m%d%H%M%S",
353 localtime(&(rb_data.files[i].creation_time)));
354 new_name = g_strconcat(rb_data.fprefix,"_", filenum, "_", timestr,
355 rb_data.fsuffix, NULL);
356 if (rename(rb_data.files[i].name, new_name) != 0) {
357 /* save the latest error */
364 g_free(rb_data.files[i].name);
365 rb_data.files[i].name = new_name;
368 /* this file has never been used - remove it */
369 unlink(rb_data.files[i].name);
372 /* make the current file the save file */
373 cf->save_file = rb_data.files[rb_data.curr_file_num].name;
378 * Frees all memory allocated by the ringbuffer
385 if (rb_data.files != NULL) {
386 for (i=0; i < rb_data.num_files; i++) {
387 g_free(rb_data.files[i].name);
388 rb_data.files[i].name = NULL;
391 rb_data.files = NULL;
393 g_free(rb_data.fprefix);
394 g_free(rb_data.fsuffix);
398 * Frees all memory allocated by the ringbuffer
401 ringbuf_error_cleanup(void)
405 if (rb_data.files == NULL) {
410 for (i=0; i<rb_data.num_files; i++) {
411 /* try to close via wtap */
412 if (rb_data.files[i].pdh != NULL) {
413 if (wtap_dump_close(rb_data.files[i].pdh, NULL)) {
415 rb_data.files[i].fd = -1;
418 /* close directly if still open */
419 if (rb_data.files[i].fd != -1) {
420 close(rb_data.files[i].fd);
422 /* remove the other files, the initial file will be handled
423 by the calling funtion */
424 if (rb_data.files[i].name != NULL) {
425 unlink(rb_data.files[i].name);
428 /* free the memory */
432 #endif /* HAVE_LIBPCAP */