2 * Routines for packet capture windows
4 * $Id: ringbuffer.c,v 1.1 2001/12/04 08:45:04 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 * XXX - this relies on Wiretap writing out data sequentially,
207 * and writing the entire capture file header when the file
208 * is created. That happens to be true for libpcap files,
209 * which are Ethereal's native capture files, and which are
210 * therefore the capture file types we're writing, but is not
211 * true for all the capture file types Wiretap can write.
213 fh = wtap_dump_file(rb_data.files[i].pdh);
215 rb_data.files[i].start_pos = ftell(fh);
220 rb_data.files[0].is_new = FALSE;
221 return rb_data.files[0].pdh;
225 * Switches to the next ringbuffer file
228 ringbuf_switch_file(capture_file *cf, wtap_dumper **pdh, int *err)
233 /* flush the current file */
234 fh = wtap_dump_file(rb_data.files[rb_data.curr_file_num].pdh);
237 /* get the next file number */
238 next_file_num = (rb_data.curr_file_num + 1) % rb_data.num_files;
239 /* prepare the file if it was already used */
240 if (!rb_data.files[next_file_num].is_new) {
241 /* rewind to the position after the file header */
242 fh = wtap_dump_file(rb_data.files[next_file_num].pdh);
243 fseek(fh, rb_data.files[next_file_num].start_pos, SEEK_SET);
244 wtap_set_bytes_dumped(rb_data.files[next_file_num].pdh,
245 rb_data.files[next_file_num].start_pos);
246 /* set the absolute file number */
247 rb_data.files[next_file_num].number += rb_data.num_files;
252 rb_data.files[next_file_num].creation_time = time(NULL);
253 /* switch to the new file */
254 cf->save_file = rb_data.files[next_file_num].name;
255 cf->save_file_fd = rb_data.files[next_file_num].fd;
256 (*pdh) = rb_data.files[next_file_num].pdh;
257 /* mark the file as used */
258 rb_data.files[next_file_num].is_new = FALSE;
259 /* finally set the current file number */
260 rb_data.curr_file_num = next_file_num;
266 * Calls wtap_dump_close() for all ringbuffer files
269 ringbuf_wtap_dump_close(capture_file *cf, int *err)
280 /* close all files */
281 for (i=0; i<rb_data.num_files; i++) {
282 fh = wtap_dump_file(rb_data.files[i].pdh);
286 /* Truncate the file to the current size. This must be done in order
287 to get rid of the 'garbage' packets at the end of the file from
289 if (!rb_data.files[i].is_new) {
290 if (ftruncate(rb_data.files[i].fd,ftell(fh)) != 0) {
291 /* could not truncate the file */
296 /* remove the file since it contains garbage at the end */
297 close(rb_data.files[i].fd);
298 unlink(rb_data.files[i].name);
303 if (!wtap_dump_close(rb_data.files[i].pdh, err)) {
304 /* error only if it is a used file */
305 if (!rb_data.files[i].is_new) {
309 if (!rb_data.files[i].is_new) {
310 /* rename the file */
311 snprintf(filenum,5+1,"%05d",rb_data.files[i].number);
312 strftime(timestr,14+1,"%Y%m%d%H%M%S",
313 localtime(&(rb_data.files[i].creation_time)));
314 new_name = g_strconcat(rb_data.fprefix,"_", filenum, "_", timestr,
315 rb_data.fsuffix, NULL);
316 if (rename(rb_data.files[i].name, new_name) != 0) {
317 /* save the latest error */
324 g_free(rb_data.files[i].name);
325 rb_data.files[i].name = new_name;
328 /* this file has never been used - remove it */
329 unlink(rb_data.files[i].name);
332 /* make the current file the save file */
333 cf->save_file = rb_data.files[rb_data.curr_file_num].name;
338 * Frees all memory allocated by the ringbuffer
345 if (rb_data.files != NULL) {
346 for (i=0; i < rb_data.num_files; i++) {
347 g_free(rb_data.files[i].name);
348 rb_data.files[i].name = NULL;
351 rb_data.files = NULL;
353 g_free(rb_data.fprefix);
354 g_free(rb_data.fsuffix);
358 * Frees all memory allocated by the ringbuffer
361 ringbuf_error_cleanup()
366 if (rb_data.files == NULL) {
371 for (i=0; i<rb_data.num_files; i++) {
372 /* try to close via wtap */
373 if (rb_data.files[i].pdh != NULL) {
374 if (wtap_dump_close(rb_data.files[i].pdh, &err) == TRUE) {
376 rb_data.files[i].fd = -1;
379 /* close directly if still open */
380 if (rb_data.files[i].fd != -1) {
381 close(rb_data.files[i].fd);
383 /* remove the other files, the initial file will be handled
384 by the calling funtion */
385 if (rb_data.files[i].name != NULL) {
386 unlink(rb_data.files[i].name);
389 /* free the memory */
393 #endif /* HAVE_LIBPCAP */