nexmon – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | /* ringbuffer.c |
2 | * Routines for packet capture windows |
||
3 | * |
||
4 | * Wireshark - Network traffic analyzer |
||
5 | * By Gerald Combs <gerald@wireshark.org> |
||
6 | * Copyright 1998 Gerald Combs |
||
7 | * |
||
8 | * This program is free software; you can redistribute it and/or |
||
9 | * modify it under the terms of the GNU General Public License |
||
10 | * as published by the Free Software Foundation; either version 2 |
||
11 | * of the License, or (at your option) any later version. |
||
12 | * |
||
13 | * This program is distributed in the hope that it will be useful, |
||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
16 | * GNU General Public License for more details. |
||
17 | * |
||
18 | * You should have received a copy of the GNU General Public License |
||
19 | * along with this program; if not, write to the Free Software |
||
20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
||
21 | */ |
||
22 | |||
23 | /* |
||
24 | * <laurent.deniel@free.fr> |
||
25 | * |
||
26 | * Almost completely rewritten in order to: |
||
27 | * |
||
28 | * - be able to use a unlimited number of ringbuffer files |
||
29 | * - close the current file and open (truncating) the next file at switch |
||
30 | * - set the final file name once open (or reopen) |
||
31 | * - avoid the deletion of files that could not be truncated (can't arise now) |
||
32 | * and do not erase empty files |
||
33 | * |
||
34 | * The idea behind that is to remove the limitation of the maximum # of |
||
35 | * ringbuffer files being less than the maximum # of open fd per process |
||
36 | * and to be able to reduce the amount of virtual memory usage (having only |
||
37 | * one file open at most) or the amount of file system usage (by truncating |
||
38 | * the files at switch and not the capture stop, and by closing them which |
||
39 | * makes possible their move or deletion after a switch). |
||
40 | * |
||
41 | */ |
||
42 | |||
43 | #include <config.h> |
||
44 | |||
45 | #ifdef HAVE_LIBPCAP |
||
46 | |||
47 | #include <stdio.h> |
||
48 | #include <string.h> |
||
49 | #include <time.h> |
||
50 | #include <errno.h> |
||
51 | |||
52 | #include <pcap.h> |
||
53 | |||
54 | #include <glib.h> |
||
55 | |||
56 | #include "ringbuffer.h" |
||
57 | #include <wsutil/file_util.h> |
||
58 | |||
59 | |||
60 | /* Ringbuffer file structure */ |
||
61 | typedef struct _rb_file { |
||
62 | gchar *name; |
||
63 | } rb_file; |
||
64 | |||
65 | /* Ringbuffer data structure */ |
||
66 | typedef struct _ringbuf_data { |
||
67 | rb_file *files; |
||
68 | guint num_files; /* Number of ringbuffer files (1 to ...) */ |
||
69 | guint curr_file_num; /* Number of the current file (ever increasing) */ |
||
70 | gchar *fprefix; /* Filename prefix */ |
||
71 | gchar *fsuffix; /* Filename suffix */ |
||
72 | gboolean unlimited; /* TRUE if unlimited number of files */ |
||
73 | |||
74 | int fd; /* Current ringbuffer file descriptor */ |
||
75 | FILE *pdh; |
||
76 | gboolean group_read_access; /* TRUE if files need to be opened with group read access */ |
||
77 | } ringbuf_data; |
||
78 | |||
79 | static ringbuf_data rb_data; |
||
80 | |||
81 | |||
82 | /* |
||
83 | * create the next filename and open a new binary file with that name |
||
84 | */ |
||
85 | static int ringbuf_open_file(rb_file *rfile, int *err) |
||
86 | { |
||
87 | char filenum[5+1]; |
||
88 | char timestr[14+1]; |
||
89 | time_t current_time; |
||
90 | |||
91 | if (rfile->name != NULL) { |
||
92 | if (rb_data.unlimited == FALSE) { |
||
93 | /* remove old file (if any, so ignore error) */ |
||
94 | ws_unlink(rfile->name); |
||
95 | } |
||
96 | g_free(rfile->name); |
||
97 | } |
||
98 | |||
99 | #ifdef _WIN32 |
||
100 | _tzset(); |
||
101 | #endif |
||
102 | current_time = time(NULL); |
||
103 | |||
104 | g_snprintf(filenum, sizeof(filenum), "%05u", (rb_data.curr_file_num + 1) % RINGBUFFER_MAX_NUM_FILES); |
||
105 | /* |
||
106 | * XXX - We trust Windows not to return a time before the Epoch, so |
||
107 | * localtime() doesn't return a null pointer. localtime() can probably |
||
108 | * handle pre-Epoch times on most UN*X systems, and we trust them not |
||
109 | * to return a time before the Epoch in any case. |
||
110 | */ |
||
111 | strftime(timestr, sizeof(timestr), "%Y%m%d%H%M%S", localtime(¤t_time)); |
||
112 | rfile->name = g_strconcat(rb_data.fprefix, "_", filenum, "_", timestr, |
||
113 | rb_data.fsuffix, NULL); |
||
114 | |||
115 | if (rfile->name == NULL) { |
||
116 | if (err != NULL) |
||
117 | *err = ENOMEM; |
||
118 | return -1; |
||
119 | } |
||
120 | |||
121 | rb_data.fd = ws_open(rfile->name, O_RDWR|O_BINARY|O_TRUNC|O_CREAT, |
||
122 | rb_data.group_read_access ? 0640 : 0600); |
||
123 | |||
124 | if (rb_data.fd == -1 && err != NULL) { |
||
125 | *err = errno; |
||
126 | } |
||
127 | |||
128 | return rb_data.fd; |
||
129 | } |
||
130 | |||
131 | /* |
||
132 | * Initialize the ringbuffer data structures |
||
133 | */ |
||
134 | int |
||
135 | ringbuf_init(const char *capfile_name, guint num_files, gboolean group_read_access) |
||
136 | { |
||
137 | unsigned int i; |
||
138 | char *pfx, *last_pathsep; |
||
139 | gchar *save_file; |
||
140 | |||
141 | rb_data.files = NULL; |
||
142 | rb_data.curr_file_num = 0; |
||
143 | rb_data.fprefix = NULL; |
||
144 | rb_data.fsuffix = NULL; |
||
145 | rb_data.unlimited = FALSE; |
||
146 | rb_data.fd = -1; |
||
147 | rb_data.pdh = NULL; |
||
148 | rb_data.group_read_access = group_read_access; |
||
149 | |||
150 | /* just to be sure ... */ |
||
151 | if (num_files <= RINGBUFFER_MAX_NUM_FILES) { |
||
152 | rb_data.num_files = num_files; |
||
153 | } else { |
||
154 | rb_data.num_files = RINGBUFFER_MAX_NUM_FILES; |
||
155 | } |
||
156 | |||
157 | /* Check file name */ |
||
158 | if (capfile_name == NULL) { |
||
159 | /* ringbuffer does not work with temporary files! */ |
||
160 | return -1; |
||
161 | } |
||
162 | |||
163 | /* set file name prefix/suffix */ |
||
164 | |||
165 | save_file = g_strdup(capfile_name); |
||
166 | last_pathsep = strrchr(save_file, G_DIR_SEPARATOR); |
||
167 | pfx = strrchr(save_file,'.'); |
||
168 | if (pfx != NULL && (last_pathsep == NULL || pfx > last_pathsep)) { |
||
169 | /* The pathname has a "." in it, and it's in the last component |
||
170 | of the pathname (because there is either only one component, |
||
171 | i.e. last_pathsep is null as there are no path separators, |
||
172 | or the "." is after the path separator before the last |
||
173 | component. |
||
174 | |||
175 | Treat it as a separator between the rest of the file name and |
||
176 | the file name suffix, and arrange that the names given to the |
||
177 | ring buffer files have the specified suffix, i.e. put the |
||
178 | changing part of the name *before* the suffix. */ |
||
179 | pfx[0] = '\0'; |
||
180 | rb_data.fprefix = g_strdup(save_file); |
||
181 | pfx[0] = '.'; /* restore capfile_name */ |
||
182 | rb_data.fsuffix = g_strdup(pfx); |
||
183 | } else { |
||
184 | /* Either there's no "." in the pathname, or it's in a directory |
||
185 | component, so the last component has no suffix. */ |
||
186 | rb_data.fprefix = g_strdup(save_file); |
||
187 | rb_data.fsuffix = NULL; |
||
188 | } |
||
189 | g_free(save_file); |
||
190 | save_file = NULL; |
||
191 | |||
192 | /* allocate rb_file structures (only one if unlimited since there is no |
||
193 | need to save all file names in that case) */ |
||
194 | |||
195 | if (num_files == RINGBUFFER_UNLIMITED_FILES) { |
||
196 | rb_data.unlimited = TRUE; |
||
197 | rb_data.num_files = 1; |
||
198 | } |
||
199 | |||
200 | rb_data.files = (rb_file *)g_malloc(rb_data.num_files * sizeof(rb_file)); |
||
201 | if (rb_data.files == NULL) { |
||
202 | return -1; |
||
203 | } |
||
204 | |||
205 | for (i=0; i < rb_data.num_files; i++) { |
||
206 | rb_data.files[i].name = NULL; |
||
207 | } |
||
208 | |||
209 | /* create the first file */ |
||
210 | if (ringbuf_open_file(&rb_data.files[0], NULL) == -1) { |
||
211 | ringbuf_error_cleanup(); |
||
212 | return -1; |
||
213 | } |
||
214 | |||
215 | return rb_data.fd; |
||
216 | } |
||
217 | |||
218 | |||
219 | const gchar *ringbuf_current_filename(void) |
||
220 | { |
||
221 | return rb_data.files[rb_data.curr_file_num % rb_data.num_files].name; |
||
222 | } |
||
223 | |||
224 | /* |
||
225 | * Calls ws_fdopen() for the current ringbuffer file |
||
226 | */ |
||
227 | FILE * |
||
228 | ringbuf_init_libpcap_fdopen(int *err) |
||
229 | { |
||
230 | rb_data.pdh = ws_fdopen(rb_data.fd, "wb"); |
||
231 | if (rb_data.pdh == NULL) { |
||
232 | if (err != NULL) { |
||
233 | *err = errno; |
||
234 | } |
||
235 | } |
||
236 | return rb_data.pdh; |
||
237 | } |
||
238 | |||
239 | /* |
||
240 | * Switches to the next ringbuffer file |
||
241 | */ |
||
242 | gboolean |
||
243 | ringbuf_switch_file(FILE **pdh, gchar **save_file, int *save_file_fd, int *err) |
||
244 | { |
||
245 | int next_file_index; |
||
246 | rb_file *next_rfile = NULL; |
||
247 | |||
248 | /* close current file */ |
||
249 | |||
250 | if (fclose(rb_data.pdh) == EOF) { |
||
251 | if (err != NULL) { |
||
252 | *err = errno; |
||
253 | } |
||
254 | ws_close(rb_data.fd); /* XXX - the above should have closed this already */ |
||
255 | rb_data.pdh = NULL; /* it's still closed, we just got an error while closing */ |
||
256 | rb_data.fd = -1; |
||
257 | return FALSE; |
||
258 | } |
||
259 | |||
260 | rb_data.pdh = NULL; |
||
261 | rb_data.fd = -1; |
||
262 | |||
263 | /* get the next file number and open it */ |
||
264 | |||
265 | rb_data.curr_file_num++ /* = next_file_num*/; |
||
266 | next_file_index = (rb_data.curr_file_num) % rb_data.num_files; |
||
267 | next_rfile = &rb_data.files[next_file_index]; |
||
268 | |||
269 | if (ringbuf_open_file(next_rfile, err) == -1) { |
||
270 | return FALSE; |
||
271 | } |
||
272 | |||
273 | if (ringbuf_init_libpcap_fdopen(err) == NULL) { |
||
274 | return FALSE; |
||
275 | } |
||
276 | |||
277 | /* switch to the new file */ |
||
278 | *save_file = next_rfile->name; |
||
279 | *save_file_fd = rb_data.fd; |
||
280 | (*pdh) = rb_data.pdh; |
||
281 | |||
282 | return TRUE; |
||
283 | } |
||
284 | |||
285 | /* |
||
286 | * Calls fclose() for the current ringbuffer file |
||
287 | */ |
||
288 | gboolean |
||
289 | ringbuf_libpcap_dump_close(gchar **save_file, int *err) |
||
290 | { |
||
291 | gboolean ret_val = TRUE; |
||
292 | |||
293 | /* close current file, if it's open */ |
||
294 | if (rb_data.pdh != NULL) { |
||
295 | if (fclose(rb_data.pdh) == EOF) { |
||
296 | if (err != NULL) { |
||
297 | *err = errno; |
||
298 | } |
||
299 | ws_close(rb_data.fd); |
||
300 | ret_val = FALSE; |
||
301 | } |
||
302 | rb_data.pdh = NULL; |
||
303 | rb_data.fd = -1; |
||
304 | } |
||
305 | |||
306 | /* set the save file name to the current file */ |
||
307 | *save_file = rb_data.files[rb_data.curr_file_num % rb_data.num_files].name; |
||
308 | return ret_val; |
||
309 | } |
||
310 | |||
311 | /* |
||
312 | * Frees all memory allocated by the ringbuffer |
||
313 | */ |
||
314 | void |
||
315 | ringbuf_free(void) |
||
316 | { |
||
317 | unsigned int i; |
||
318 | |||
319 | if (rb_data.files != NULL) { |
||
320 | for (i=0; i < rb_data.num_files; i++) { |
||
321 | if (rb_data.files[i].name != NULL) { |
||
322 | g_free(rb_data.files[i].name); |
||
323 | rb_data.files[i].name = NULL; |
||
324 | } |
||
325 | } |
||
326 | g_free(rb_data.files); |
||
327 | rb_data.files = NULL; |
||
328 | } |
||
329 | if (rb_data.fprefix != NULL) { |
||
330 | g_free(rb_data.fprefix); |
||
331 | rb_data.fprefix = NULL; |
||
332 | } |
||
333 | if (rb_data.fsuffix != NULL) { |
||
334 | g_free(rb_data.fsuffix); |
||
335 | rb_data.fsuffix = NULL; |
||
336 | } |
||
337 | } |
||
338 | |||
339 | /* |
||
340 | * Frees all memory allocated by the ringbuffer |
||
341 | */ |
||
342 | void |
||
343 | ringbuf_error_cleanup(void) |
||
344 | { |
||
345 | unsigned int i; |
||
346 | |||
347 | /* try to close via wtap */ |
||
348 | if (rb_data.pdh != NULL) { |
||
349 | if (fclose(rb_data.pdh) == 0) { |
||
350 | rb_data.fd = -1; |
||
351 | } |
||
352 | rb_data.pdh = NULL; |
||
353 | } |
||
354 | |||
355 | /* close directly if still open */ |
||
356 | if (rb_data.fd != -1) { |
||
357 | ws_close(rb_data.fd); |
||
358 | rb_data.fd = -1; |
||
359 | } |
||
360 | |||
361 | if (rb_data.files != NULL) { |
||
362 | for (i=0; i < rb_data.num_files; i++) { |
||
363 | if (rb_data.files[i].name != NULL) { |
||
364 | ws_unlink(rb_data.files[i].name); |
||
365 | } |
||
366 | } |
||
367 | } |
||
368 | /* free the memory */ |
||
369 | ringbuf_free(); |
||
370 | } |
||
371 | |||
372 | #endif /* HAVE_LIBPCAP */ |
||
373 | |||
374 | /* |
||
375 | * Editor modelines - http://www.wireshark.org/tools/modelines.html |
||
376 | * |
||
377 | * Local Variables: |
||
378 | * c-basic-offset: 2 |
||
379 | * tab-width: 8 |
||
380 | * indent-tabs-mode: nil |
||
381 | * End: |
||
382 | * |
||
383 | * ex: set shiftwidth=2 tabstop=8 expandtab: |
||
384 | * :indentSize=2:tabSize=8:noTabs=true: |
||
385 | */ |