Indentation & whitespace cleanup (including: "4 space tabs" ==> spaces)
[obnox/wireshark/wip.git] / ringbuffer.c
1 /* ringbuffer.c
2  * Routines for packet capture windows
3  *
4  * $Id$
5  *
6  * Wireshark - Network traffic analyzer
7  * By Gerald Combs <gerald@wireshark.org>
8  * Copyright 1998 Gerald Combs
9  *
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.
14  *
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.
19  *
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.
23  */
24
25 /*
26  * <laurent.deniel@free.fr>
27  *
28  * Almost completely rewritten in order to:
29  *
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
35  *
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).
42  *
43  */
44
45 #ifdef HAVE_CONFIG_H
46 #include "config.h"
47 #endif
48
49 #ifdef HAVE_LIBPCAP
50
51 #ifdef HAVE_FCNTL_H
52 #include <fcntl.h>
53 #endif
54
55 #ifdef HAVE_UNISTD_H
56 #include <unistd.h>
57 #endif
58
59 #include <stdio.h>
60 #include <string.h>
61 #include <time.h>
62 #include <errno.h>
63
64 #include <pcap.h>
65
66 #include <glib.h>
67
68 #include "pcapio.h"
69 #include "ringbuffer.h"
70 #include <wsutil/file_util.h>
71
72
73 /* Ringbuffer file structure */
74 typedef struct _rb_file {
75   gchar         *name;
76 } rb_file;
77
78 /* Ringbuffer data structure */
79 typedef struct _ringbuf_data {
80   rb_file      *files;
81   guint         num_files;           /* Number of ringbuffer files (1 to ...) */
82   guint         curr_file_num;       /* Number of the current file (ever increasing) */
83   gchar        *fprefix;             /* Filename prefix */
84   gchar        *fsuffix;             /* Filename suffix */
85   gboolean      unlimited;           /* TRUE if unlimited number of files */
86
87   int           fd;                  /* Current ringbuffer file descriptor */
88   FILE         *pdh;
89 } ringbuf_data;
90
91 static ringbuf_data rb_data;
92
93
94 /*
95  * create the next filename and open a new binary file with that name
96  */
97 static int ringbuf_open_file(rb_file *rfile, int *err)
98 {
99   char    filenum[5+1];
100   char    timestr[14+1];
101   time_t  current_time;
102
103   if (rfile->name != NULL) {
104     if (rb_data.unlimited == FALSE) {
105       /* remove old file (if any, so ignore error) */
106       ws_unlink(rfile->name);
107     }
108     g_free(rfile->name);
109   }
110
111 #ifdef _WIN32
112   _tzset();
113 #endif
114   current_time = time(NULL);
115
116   g_snprintf(filenum, sizeof(filenum), "%05u", (rb_data.curr_file_num + 1) % 100000);
117   strftime(timestr, sizeof(timestr), "%Y%m%d%H%M%S", localtime(&current_time));
118   rfile->name = g_strconcat(rb_data.fprefix, "_", filenum, "_", timestr,
119                             rb_data.fsuffix, NULL);
120
121   if (rfile->name == NULL) {
122     *err = ENOMEM;
123     return -1;
124   }
125
126   rb_data.fd = ws_open(rfile->name, O_RDWR|O_BINARY|O_TRUNC|O_CREAT, 0600);
127
128   if (rb_data.fd == -1 && err != NULL) {
129     *err = errno;
130   }
131
132   return rb_data.fd;
133 }
134
135 /*
136  * Initialize the ringbuffer data structures
137  */
138 int
139 ringbuf_init(const char *capfile_name, guint num_files)
140 {
141   unsigned int i;
142   char        *pfx, *last_pathsep;
143   gchar       *save_file;
144
145   rb_data.files = NULL;
146   rb_data.curr_file_num = 0;
147   rb_data.fprefix = NULL;
148   rb_data.fsuffix = NULL;
149   rb_data.unlimited = FALSE;
150   rb_data.fd = -1;
151   rb_data.pdh = NULL;
152
153   /* just to be sure ... */
154   if (num_files <= RINGBUFFER_MAX_NUM_FILES) {
155     rb_data.num_files = num_files;
156   } else {
157     rb_data.num_files = RINGBUFFER_MAX_NUM_FILES;
158   }
159
160   /* Check file name */
161   if (capfile_name == NULL) {
162     /* ringbuffer does not work with temporary files! */
163     return -1;
164   }
165
166   /* set file name prefix/suffix */
167
168   save_file = g_strdup(capfile_name);
169   last_pathsep = strrchr(save_file, G_DIR_SEPARATOR);
170   pfx = strrchr(save_file,'.');
171   if (pfx != NULL && (last_pathsep == NULL || pfx > last_pathsep)) {
172     /* The pathname has a "." in it, and it's in the last component
173        of the pathname (because there is either only one component,
174        i.e. last_pathsep is null as there are no path separators,
175        or the "." is after the path separator before the last
176        component.
177
178        Treat it as a separator between the rest of the file name and
179        the file name suffix, and arrange that the names given to the
180        ring buffer files have the specified suffix, i.e. put the
181        changing part of the name *before* the suffix. */
182     pfx[0] = '\0';
183     rb_data.fprefix = g_strdup(save_file);
184     pfx[0] = '.'; /* restore capfile_name */
185     rb_data.fsuffix = g_strdup(pfx);
186   } else {
187     /* Either there's no "." in the pathname, or it's in a directory
188        component, so the last component has no suffix. */
189     rb_data.fprefix = g_strdup(save_file);
190     rb_data.fsuffix = NULL;
191   }
192   g_free(save_file);
193   save_file = NULL;
194
195   /* allocate rb_file structures (only one if unlimited since there is no
196      need to save all file names in that case) */
197
198   if (num_files == RINGBUFFER_UNLIMITED_FILES) {
199     rb_data.unlimited = TRUE;
200     rb_data.num_files = 1;
201   }
202
203   rb_data.files = (rb_file *)g_malloc(rb_data.num_files * sizeof(rb_file));
204   if (rb_data.files == NULL) {
205     return -1;
206   }
207
208   for (i=0; i < rb_data.num_files; i++) {
209     rb_data.files[i].name = NULL;
210   }
211
212   /* create the first file */
213   if (ringbuf_open_file(&rb_data.files[0], NULL) == -1) {
214     ringbuf_error_cleanup();
215     return -1;
216   }
217
218   return rb_data.fd;
219 }
220
221
222 const gchar *ringbuf_current_filename(void)
223 {
224   return rb_data.files[rb_data.curr_file_num % rb_data.num_files].name;
225 }
226
227 /*
228  * Calls libpcap_fdopen() for the current ringbuffer file
229  */
230 FILE *
231 ringbuf_init_libpcap_fdopen(int *err)
232 {
233   rb_data.pdh = libpcap_fdopen(rb_data.fd, err);
234   return rb_data.pdh;
235 }
236
237 /*
238  * Switches to the next ringbuffer file
239  */
240 gboolean
241 ringbuf_switch_file(FILE **pdh, gchar **save_file, int *save_file_fd, int *err)
242 {
243   int     next_file_index;
244   rb_file *next_rfile = NULL;
245
246   /* close current file */
247
248   if (!libpcap_dump_close(rb_data.pdh, err)) {
249     ws_close(rb_data.fd);       /* XXX - the above should have closed this already */
250     rb_data.pdh = NULL; /* it's still closed, we just got an error while closing */
251     rb_data.fd = -1;
252     return FALSE;
253   }
254
255   rb_data.pdh = NULL;
256   rb_data.fd  = -1;
257
258   /* get the next file number and open it */
259
260   rb_data.curr_file_num++ /* = next_file_num*/;
261   next_file_index = (rb_data.curr_file_num) % rb_data.num_files;
262   next_rfile = &rb_data.files[next_file_index];
263
264   if (ringbuf_open_file(next_rfile, err) == -1) {
265     return FALSE;
266   }
267
268   if (ringbuf_init_libpcap_fdopen(err) == NULL) {
269     return FALSE;
270   }
271
272   /* switch to the new file */
273   *save_file = next_rfile->name;
274   *save_file_fd = rb_data.fd;
275   (*pdh) = rb_data.pdh;
276
277   return TRUE;
278 }
279
280 /*
281  * Calls libpcap_dump_close() for the current ringbuffer file
282  */
283 gboolean
284 ringbuf_libpcap_dump_close(gchar **save_file, int *err)
285 {
286   gboolean  ret_val = TRUE;
287
288   /* close current file, if it's open */
289   if (rb_data.pdh != NULL) {
290     if (!libpcap_dump_close(rb_data.pdh, err)) {
291       ws_close(rb_data.fd);
292       ret_val = FALSE;
293     }
294
295     rb_data.pdh = NULL;
296     rb_data.fd  = -1;
297   }
298
299   /* set the save file name to the current file */
300   *save_file = rb_data.files[rb_data.curr_file_num % rb_data.num_files].name;
301   return ret_val;
302 }
303
304 /*
305  * Frees all memory allocated by the ringbuffer
306  */
307 void
308 ringbuf_free()
309 {
310   unsigned int i;
311
312   if (rb_data.files != NULL) {
313     for (i=0; i < rb_data.num_files; i++) {
314       if (rb_data.files[i].name != NULL) {
315         g_free(rb_data.files[i].name);
316         rb_data.files[i].name = NULL;
317       }
318     }
319     g_free(rb_data.files);
320     rb_data.files = NULL;
321   }
322   if (rb_data.fprefix != NULL) {
323     g_free(rb_data.fprefix);
324     rb_data.fprefix = NULL;
325   }
326   if (rb_data.fsuffix != NULL) {
327     g_free(rb_data.fsuffix);
328     rb_data.fsuffix = NULL;
329   }
330 }
331
332 /*
333  * Frees all memory allocated by the ringbuffer
334  */
335 void
336 ringbuf_error_cleanup(void)
337 {
338   unsigned int i;
339
340   /* try to close via wtap */
341   if (rb_data.pdh != NULL) {
342     if (libpcap_dump_close(rb_data.pdh, NULL)) {
343       rb_data.fd = -1;
344     }
345     rb_data.pdh = NULL;
346   }
347
348   /* close directly if still open */
349   /* XXX - it shouldn't still be open; "libpcap_dump_close()" should leave the
350      file closed even if it fails */
351   if (rb_data.fd != -1) {
352     ws_close(rb_data.fd);
353     rb_data.fd = -1;
354   }
355
356   if (rb_data.files != NULL) {
357     for (i=0; i < rb_data.num_files; i++) {
358       if (rb_data.files[i].name != NULL) {
359         ws_unlink(rb_data.files[i].name);
360       }
361     }
362   }
363   /* free the memory */
364   ringbuf_free();
365 }
366
367 #endif /* HAVE_LIBPCAP */