2 * Routines for packet capture windows
4 * $Id: ringbuffer.c,v 1.3 2002/06/23 20:30:01 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 if ((rb_data.files[i].start_pos = ftell(fh)) < 0) {
232 rb_data.files[0].is_new = FALSE;
233 return rb_data.files[0].pdh;
237 * Switches to the next ringbuffer file
240 ringbuf_switch_file(capture_file *cf, wtap_dumper **pdh, int *err)
244 gboolean err_on_next = FALSE;
246 /* flush the current file */
247 fh = wtap_dump_file(rb_data.files[rb_data.curr_file_num].pdh);
249 errno = WTAP_ERR_CANT_CLOSE;
250 if (fflush(fh) == EOF) {
257 /* get the next file number */
258 next_file_num = (rb_data.curr_file_num + 1) % rb_data.num_files;
259 /* prepare the file if it was already used */
260 if (!rb_data.files[next_file_num].is_new) {
261 /* rewind to the position after the file header */
262 fh = wtap_dump_file(rb_data.files[next_file_num].pdh);
263 if (fseek(fh, rb_data.files[next_file_num].start_pos, SEEK_SET) < 0) {
265 /* Don't return straight away: have caller report correct save_file */
268 wtap_set_bytes_dumped(rb_data.files[next_file_num].pdh,
269 rb_data.files[next_file_num].start_pos);
270 /* set the absolute file number */
271 rb_data.files[next_file_num].number += rb_data.num_files;
276 rb_data.files[next_file_num].creation_time = time(NULL);
277 /* switch to the new file */
278 cf->save_file = rb_data.files[next_file_num].name;
279 cf->save_file_fd = rb_data.files[next_file_num].fd;
280 (*pdh) = rb_data.files[next_file_num].pdh;
281 /* mark the file as used */
282 rb_data.files[next_file_num].is_new = FALSE;
283 /* finally set the current file number */
284 rb_data.curr_file_num = next_file_num;
293 * Calls wtap_dump_close() for all ringbuffer files
296 ringbuf_wtap_dump_close(capture_file *cf, int *err)
307 /* close all files */
308 for (i=0; i<rb_data.num_files; i++) {
309 fh = wtap_dump_file(rb_data.files[i].pdh);
312 errno = WTAP_ERR_CANT_CLOSE;
313 if (fflush(fh) == EOF) {
318 /* If the file's not a new one, remove it as it hasn't been truncated
319 and thus contains garbage at the end.
321 We don't remove it if it's new - it's incomplete, but at least
322 the stuff before the incomplete record is usable. */
323 close(rb_data.files[i].fd);
324 if (!rb_data.files[i].is_new) {
325 unlink(rb_data.files[i].name);
330 /* Truncate the file to the current size. This must be done in order
331 to get rid of the 'garbage' packets at the end of the file from
333 if (!rb_data.files[i].is_new) {
334 if (ftruncate(rb_data.files[i].fd,ftell(fh)) != 0) {
335 /* could not truncate the file */
340 /* remove the file since it contains garbage at the end */
341 close(rb_data.files[i].fd);
342 unlink(rb_data.files[i].name);
347 if (!wtap_dump_close(rb_data.files[i].pdh, err)) {
348 /* error only if it is a used file */
349 if (!rb_data.files[i].is_new) {
353 if (!rb_data.files[i].is_new) {
354 /* rename the file */
355 snprintf(filenum,5+1,"%05d",rb_data.files[i].number);
356 strftime(timestr,14+1,"%Y%m%d%H%M%S",
357 localtime(&(rb_data.files[i].creation_time)));
358 new_name = g_strconcat(rb_data.fprefix,"_", filenum, "_", timestr,
359 rb_data.fsuffix, NULL);
360 if (rename(rb_data.files[i].name, new_name) != 0) {
361 /* save the latest error */
368 g_free(rb_data.files[i].name);
369 rb_data.files[i].name = new_name;
372 /* this file has never been used - remove it */
373 unlink(rb_data.files[i].name);
376 /* make the current file the save file */
377 cf->save_file = rb_data.files[rb_data.curr_file_num].name;
382 * Frees all memory allocated by the ringbuffer
389 if (rb_data.files != NULL) {
390 for (i=0; i < rb_data.num_files; i++) {
391 g_free(rb_data.files[i].name);
392 rb_data.files[i].name = NULL;
395 rb_data.files = NULL;
397 g_free(rb_data.fprefix);
398 g_free(rb_data.fsuffix);
402 * Frees all memory allocated by the ringbuffer
405 ringbuf_error_cleanup(void)
409 if (rb_data.files == NULL) {
414 for (i=0; i<rb_data.num_files; i++) {
415 /* try to close via wtap */
416 if (rb_data.files[i].pdh != NULL) {
417 if (wtap_dump_close(rb_data.files[i].pdh, NULL)) {
419 rb_data.files[i].fd = -1;
422 /* close directly if still open */
423 if (rb_data.files[i].fd != -1) {
424 close(rb_data.files[i].fd);
426 /* remove the other files, the initial file will be handled
427 by the calling funtion */
428 if (rb_data.files[i].name != NULL) {
429 unlink(rb_data.files[i].name);
432 /* free the memory */
436 #endif /* HAVE_LIBPCAP */