2 * Routines for packet capture windows
4 * $Id: ringbuffer.c,v 1.2 2002/05/04 10:10:42 guy 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_TYPES_H
40 #include <sys/types.h>
43 #ifdef HAVE_SYS_STAT_H
56 #ifdef NEED_SNPRINTF_H
60 #include "wiretap/wtap.h"
61 #include "ringbuffer.h"
63 /* Win32 needs the O_BINARY flag for open() */
68 /* Ringbuffer file structure */
69 typedef struct _rb_file {
79 /* Ringbuffer data structure */
80 typedef struct _ringbuf_data {
82 guint num_files; /* Number of ringbuffer files */
83 guint curr_file_num; /* Number of the current file */
84 gchar* fprefix; /* Filename prefix */
85 gchar* fsuffix; /* Filename suffix */
88 /* Create the ringbuffer data structure */
89 static ringbuf_data rb_data;
92 * Initialize the ringbuffer data structure
95 ringbuf_init(const char *capfile_name, guint num_files)
101 char save_file_num[3+1];
103 /* just to be sure ... */
104 if (num_files <= RINGBUFFER_MAX_NUM_FILES) {
105 rb_data.num_files = num_files;
107 rb_data.num_files = RINGBUFFER_MAX_NUM_FILES;
110 /* Check file name */
111 if (capfile_name == NULL) {
112 /* ringbuffer does not work with temporary files! */
116 /* Open the initial file */
117 save_file_fd = open(capfile_name, O_RDWR|O_BINARY|O_TRUNC|O_CREAT, 0600);
118 if (save_file_fd == -1) {
123 /* allocate memory */
124 rb_data.files = (rb_file *)calloc(num_files, sizeof(rb_file));
125 if (rb_data.files == NULL) {
126 /* could not allocate memory */
131 rb_data.fprefix = NULL;
132 rb_data.fsuffix = NULL;
133 for (i=0; i<rb_data.num_files; i++) {
134 rb_data.files[i].name = NULL;
135 rb_data.files[i].fd = -1;
138 /* get file name prefix/suffix */
139 save_file = g_strdup(capfile_name);
140 pfx = strrchr(save_file,'.');
143 rb_data.fprefix = g_strdup(save_file);
144 pfx[0] = '.'; /* restore capfile_name */
145 rb_data.fsuffix = g_strdup(pfx);
147 rb_data.fprefix = g_strdup(save_file);
148 rb_data.fsuffix = NULL;
156 /* save the initial file parameters */
157 rb_data.files[0].name = g_strdup(capfile_name);
158 rb_data.files[0].fd = save_file_fd;
159 rb_data.files[0].creation_time = time(NULL);
160 rb_data.files[0].number = 0;
161 rb_data.files[0].is_new = TRUE;
163 /* create the other files */
164 for (i=1; i<rb_data.num_files; i++) {
165 /* create a file name */
166 snprintf(save_file_num,3+1,"%03d",i);
167 save_file = g_strconcat(capfile_name, ".", save_file_num, NULL);
169 save_file_fd = open(save_file, O_RDWR|O_BINARY|O_TRUNC|O_CREAT, 0600);
170 if (save_file_fd != -1) {
171 rb_data.files[i].name = save_file;
172 rb_data.files[i].fd = save_file_fd;
173 rb_data.files[i].creation_time = time(NULL);
174 rb_data.files[i].number = i;
175 rb_data.files[i].is_new = TRUE;
177 /* could not open a file */
178 ringbuf_error_cleanup();
184 rb_data.curr_file_num = 0;
185 return rb_data.files[0].fd;
189 * Calls wtap_dump_fdopen() for all ringbuffer files
192 ringbuf_init_wtap_dump_fdopen(int filetype, int linktype,
193 int snaplen, int *err)
198 for (i=0; i<rb_data.num_files; i++) {
199 rb_data.files[i].pdh = wtap_dump_fdopen(rb_data.files[i].fd, filetype,
200 linktype, snaplen, err);
201 if (rb_data.files[i].pdh == NULL) {
202 /* could not open file */
206 * Flush out the capture file header, as written by "wtap_dump_fdopen()".
208 * XXX - this relies on Wiretap writing out data sequentially,
209 * and writing the entire capture file header when the file
210 * is created. That happens to be true for libpcap files,
211 * which are Ethereal's native capture files, and which are
212 * therefore the capture file types we're writing, but is not
213 * true for all the capture file types Wiretap can write.
215 fh = wtap_dump_file(rb_data.files[i].pdh);
216 if (fflush(fh) == EOF) {
222 rb_data.files[i].start_pos = ftell(fh);
227 rb_data.files[0].is_new = FALSE;
228 return rb_data.files[0].pdh;
232 * Switches to the next ringbuffer file
235 ringbuf_switch_file(capture_file *cf, wtap_dumper **pdh, int *err)
240 /* flush the current file */
241 fh = wtap_dump_file(rb_data.files[rb_data.curr_file_num].pdh);
243 errno = WTAP_ERR_CANT_CLOSE;
244 if (fflush(fh) == EOF) {
251 /* get the next file number */
252 next_file_num = (rb_data.curr_file_num + 1) % rb_data.num_files;
253 /* prepare the file if it was already used */
254 if (!rb_data.files[next_file_num].is_new) {
255 /* rewind to the position after the file header */
256 fh = wtap_dump_file(rb_data.files[next_file_num].pdh);
257 fseek(fh, rb_data.files[next_file_num].start_pos, SEEK_SET);
258 wtap_set_bytes_dumped(rb_data.files[next_file_num].pdh,
259 rb_data.files[next_file_num].start_pos);
260 /* set the absolute file number */
261 rb_data.files[next_file_num].number += rb_data.num_files;
266 rb_data.files[next_file_num].creation_time = time(NULL);
267 /* switch to the new file */
268 cf->save_file = rb_data.files[next_file_num].name;
269 cf->save_file_fd = rb_data.files[next_file_num].fd;
270 (*pdh) = rb_data.files[next_file_num].pdh;
271 /* mark the file as used */
272 rb_data.files[next_file_num].is_new = FALSE;
273 /* finally set the current file number */
274 rb_data.curr_file_num = next_file_num;
280 * Calls wtap_dump_close() for all ringbuffer files
283 ringbuf_wtap_dump_close(capture_file *cf, int *err)
294 /* close all files */
295 for (i=0; i<rb_data.num_files; i++) {
296 fh = wtap_dump_file(rb_data.files[i].pdh);
299 errno = WTAP_ERR_CANT_CLOSE;
300 if (fflush(fh) == EOF) {
305 /* If the file's not a new one, remove it as it hasn't been truncated
306 and thus contains garbage at the end.
308 We don't remove it if it's new - it's incomplete, but at least
309 the stuff before the incomplete record is usable. */
310 close(rb_data.files[i].fd);
311 if (!rb_data.files[i].is_new) {
312 unlink(rb_data.files[i].name);
317 /* Truncate the file to the current size. This must be done in order
318 to get rid of the 'garbage' packets at the end of the file from
320 if (!rb_data.files[i].is_new) {
321 if (ftruncate(rb_data.files[i].fd,ftell(fh)) != 0) {
322 /* could not truncate the file */
327 /* remove the file since it contains garbage at the end */
328 close(rb_data.files[i].fd);
329 unlink(rb_data.files[i].name);
334 if (!wtap_dump_close(rb_data.files[i].pdh, err)) {
335 /* error only if it is a used file */
336 if (!rb_data.files[i].is_new) {
340 if (!rb_data.files[i].is_new) {
341 /* rename the file */
342 snprintf(filenum,5+1,"%05d",rb_data.files[i].number);
343 strftime(timestr,14+1,"%Y%m%d%H%M%S",
344 localtime(&(rb_data.files[i].creation_time)));
345 new_name = g_strconcat(rb_data.fprefix,"_", filenum, "_", timestr,
346 rb_data.fsuffix, NULL);
347 if (rename(rb_data.files[i].name, new_name) != 0) {
348 /* save the latest error */
355 g_free(rb_data.files[i].name);
356 rb_data.files[i].name = new_name;
359 /* this file has never been used - remove it */
360 unlink(rb_data.files[i].name);
363 /* make the current file the save file */
364 cf->save_file = rb_data.files[rb_data.curr_file_num].name;
369 * Frees all memory allocated by the ringbuffer
376 if (rb_data.files != NULL) {
377 for (i=0; i < rb_data.num_files; i++) {
378 g_free(rb_data.files[i].name);
379 rb_data.files[i].name = NULL;
382 rb_data.files = NULL;
384 g_free(rb_data.fprefix);
385 g_free(rb_data.fsuffix);
389 * Frees all memory allocated by the ringbuffer
392 ringbuf_error_cleanup(void)
396 if (rb_data.files == NULL) {
401 for (i=0; i<rb_data.num_files; i++) {
402 /* try to close via wtap */
403 if (rb_data.files[i].pdh != NULL) {
404 if (wtap_dump_close(rb_data.files[i].pdh, NULL)) {
406 rb_data.files[i].fd = -1;
409 /* close directly if still open */
410 if (rb_data.files[i].fd != -1) {
411 close(rb_data.files[i].fd);
413 /* remove the other files, the initial file will be handled
414 by the calling funtion */
415 if (rb_data.files[i].name != NULL) {
416 unlink(rb_data.files[i].name);
419 /* free the memory */
423 #endif /* HAVE_LIBPCAP */