HACK: pinfo->private_data points to smb_info again
[wireshark-wip.git] / capture.c
blob2131ad683c0c6c966356716fe7581c1792ef37a9
1 /* capture.c
2 * Routines for packet capture
4 * $Id$
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 #include "config.h"
27 #ifdef HAVE_LIBPCAP
29 #ifdef HAVE_UNISTD_H
30 #include <unistd.h>
31 #endif
33 #include <stdio.h>
34 #include <string.h>
36 #include <glib.h>
38 #include <epan/packet.h>
39 #include <epan/dfilter/dfilter.h>
40 #include "file.h"
41 #include "capture.h"
42 #include "capture_ifinfo.h"
43 #include "capture_sync.h"
44 #include "capture_info.h"
45 #include "capture_ui_utils.h"
46 #include "ui/util.h"
47 #include "capture-pcap-util.h"
48 #include <epan/prefs.h>
50 #ifdef _WIN32
51 #include "capture-wpcap.h"
52 #endif
54 #include "ui/simple_dialog.h"
55 #include "ui/ui_util.h"
57 #include "wsutil/file_util.h"
58 #include "log.h"
60 typedef struct if_stat_cache_item_s {
61 char *name;
62 struct pcap_stat ps;
63 } if_stat_cache_item_t;
65 struct if_stat_cache_s {
66 int stat_fd;
67 int fork_child;
68 GList *cache_list; /* List of if_stat_chache_entry_t */
71 /* this callback mechanism should possibly be replaced by the g_signal_...() stuff (if I only would know how :-) */
72 typedef struct {
73 capture_callback_t cb_fct;
74 gpointer user_data;
75 } capture_callback_data_t;
77 static GList *capture_callbacks = NULL;
79 static void
80 capture_callback_invoke(int event, capture_session *cap_session)
82 capture_callback_data_t *cb;
83 GList *cb_item = capture_callbacks;
85 /* there should be at least one interested */
86 g_assert(cb_item != NULL);
88 while(cb_item != NULL) {
89 cb = (capture_callback_data_t *)cb_item->data;
90 cb->cb_fct(event, cap_session, cb->user_data);
91 cb_item = g_list_next(cb_item);
96 void
97 capture_callback_add(capture_callback_t func, gpointer user_data)
99 capture_callback_data_t *cb;
101 cb = (capture_callback_data_t *)g_malloc(sizeof(capture_callback_data_t));
102 cb->cb_fct = func;
103 cb->user_data = user_data;
105 capture_callbacks = g_list_append(capture_callbacks, cb);
108 void
109 capture_callback_remove(capture_callback_t func)
111 capture_callback_data_t *cb;
112 GList *cb_item = capture_callbacks;
114 while(cb_item != NULL) {
115 cb = (capture_callback_data_t *)cb_item->data;
116 if(cb->cb_fct == func) {
117 capture_callbacks = g_list_remove(capture_callbacks, cb);
118 g_free(cb);
119 return;
121 cb_item = g_list_next(cb_item);
124 g_assert_not_reached();
128 * Start a capture.
130 * @return TRUE if the capture starts successfully, FALSE otherwise.
132 gboolean
133 capture_start(capture_options *capture_opts, capture_session *cap_session, void(*update_cb)(void))
135 gboolean ret;
136 guint i;
137 GString *source = g_string_new("");
139 cap_session->state = CAPTURE_PREPARING;
140 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture Start ...");
141 #ifdef _WIN32
142 if (capture_opts->ifaces->len < 2) {
143 #else
144 if (capture_opts->ifaces->len < 4) {
145 #endif
146 for (i = 0; i < capture_opts->ifaces->len; i++) {
147 interface_options interface_opts;
149 interface_opts = g_array_index(capture_opts->ifaces, interface_options, i);
150 if (i > 0) {
151 if (capture_opts->ifaces->len > 2) {
152 g_string_append_printf(source, ",");
154 g_string_append_printf(source, " ");
155 if (i == capture_opts->ifaces->len - 1) {
156 g_string_append_printf(source, "and ");
159 g_string_append_printf(source, "%s", get_iface_description_for_interface(capture_opts, i));
160 if ((interface_opts.cfilter != NULL) &&
161 (strlen(interface_opts.cfilter) > 0)) {
162 g_string_append_printf(source, " (%s)", interface_opts.cfilter);
165 } else {
166 g_string_append_printf(source, "%u interfaces", capture_opts->ifaces->len);
168 cf_set_tempfile_source((capture_file *)cap_session->cf, source->str);
169 g_string_free(source, TRUE);
170 /* try to start the capture child process */
171 ret = sync_pipe_start(capture_opts, cap_session, update_cb);
172 if(!ret) {
173 if(capture_opts->save_file != NULL) {
174 g_free(capture_opts->save_file);
175 capture_opts->save_file = NULL;
178 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture Start failed!");
179 cap_session->state = CAPTURE_STOPPED;
180 } else {
181 /* the capture child might not respond shortly after bringing it up */
182 /* (for example: it will block if no input arrives from an input capture pipe (e.g. mkfifo)) */
184 /* to prevent problems, bring the main GUI into "capture mode" right after a successful */
185 /* spawn/exec of the capture child, without waiting for any response from it */
186 capture_callback_invoke(capture_cb_capture_prepared, cap_session);
188 if(capture_opts->show_info)
189 capture_info_open(cap_session);
192 return ret;
196 void
197 capture_stop(capture_session *cap_session)
199 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture Stop ...");
201 capture_callback_invoke(capture_cb_capture_stopping, cap_session);
203 /* stop the capture child gracefully */
204 sync_pipe_stop(cap_session);
208 void
209 capture_restart(capture_session *cap_session)
211 capture_options *capture_opts = cap_session->capture_opts;
213 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture Restart");
215 capture_opts->restart = TRUE;
216 capture_stop(cap_session);
220 void
221 capture_kill_child(capture_session *cap_session)
223 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_INFO, "Capture Kill");
225 /* kill the capture child */
226 sync_pipe_kill(cap_session->fork_child);
229 /* We've succeeded in doing a (non real-time) capture; try to read it into a new capture file */
230 static gboolean
231 capture_input_read_all(capture_session *cap_session, gboolean is_tempfile,
232 gboolean drops_known, guint32 drops)
234 capture_options *capture_opts = cap_session->capture_opts;
235 int err;
237 /* Capture succeeded; attempt to open the capture file. */
238 if (cf_open((capture_file *)cap_session->cf, capture_opts->save_file, is_tempfile, &err) != CF_OK) {
239 /* We're not doing a capture any more, so we don't have a save file. */
240 return FALSE;
243 /* Set the read filter to NULL. */
244 /* XXX - this is odd here; try to put it somewhere where it fits better */
245 cf_set_rfcode((capture_file *)cap_session->cf, NULL);
247 /* Get the packet-drop statistics.
249 XXX - there are currently no packet-drop statistics stored
250 in libpcap captures, and that's what we're reading.
252 At some point, we will add support in Wiretap to return
253 packet-drop statistics for capture file formats that store it,
254 and will make "cf_read()" get those statistics from Wiretap.
255 We clear the statistics (marking them as "not known") in
256 "cf_open()", and "cf_read()" will only fetch them and mark
257 them as known if Wiretap supplies them, so if we get the
258 statistics now, after calling "cf_open()" but before calling
259 "cf_read()", the values we store will be used by "cf_read()".
261 If a future libpcap capture file format stores the statistics,
262 we'll put them into the capture file that we write, and will
263 thus not have to set them here - "cf_read()" will get them from
264 the file and use them. */
265 if (drops_known) {
266 cf_set_drops_known((capture_file *)cap_session->cf, TRUE);
268 /* XXX - on some systems, libpcap doesn't bother filling in
269 "ps_ifdrop" - it doesn't even set it to zero - so we don't
270 bother looking at it.
272 Ideally, libpcap would have an interface that gave us
273 several statistics - perhaps including various interface
274 error statistics - and would tell us which of them it
275 supplies, allowing us to display only the ones it does. */
276 cf_set_drops((capture_file *)cap_session->cf, drops);
279 /* read in the packet data */
280 switch (cf_read((capture_file *)cap_session->cf, FALSE)) {
282 case CF_READ_OK:
283 case CF_READ_ERROR:
284 /* Just because we got an error, that doesn't mean we were unable
285 to read any of the file; we handle what we could get from the
286 file. */
287 break;
289 case CF_READ_ABORTED:
290 /* User wants to quit program. Exit by leaving the main loop,
291 so that any quit functions we registered get called. */
292 main_window_nested_quit();
293 return FALSE;
296 /* if we didn't capture even a single packet, close the file again */
297 if(cf_get_packet_count((capture_file *)cap_session->cf) == 0 && !capture_opts->restart) {
298 simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK,
299 "%sNo packets captured!%s\n"
300 "\n"
301 "As no data was captured, closing the %scapture file!\n"
302 "\n"
303 "\n"
304 "Help about capturing can be found at:\n"
305 "\n"
306 " http://wiki.wireshark.org/CaptureSetup"
307 #ifdef _WIN32
308 "\n\n"
309 "Wireless (Wi-Fi/WLAN):\n"
310 "Try to switch off promiscuous mode in the Capture Options!"
311 #endif
313 simple_dialog_primary_start(), simple_dialog_primary_end(),
314 (cf_is_tempfile((capture_file *)cap_session->cf)) ? "temporary " : "");
315 cf_close((capture_file *)cap_session->cf);
317 return TRUE;
321 /* capture child tells us we have a new (or the first) capture file */
322 gboolean
323 capture_input_new_file(capture_session *cap_session, gchar *new_file)
325 capture_options *capture_opts = cap_session->capture_opts;
326 gboolean is_tempfile;
327 int err;
329 if(cap_session->state == CAPTURE_PREPARING) {
330 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture started!");
332 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "File: \"%s\"", new_file);
334 g_assert(cap_session->state == CAPTURE_PREPARING || cap_session->state == CAPTURE_RUNNING);
336 /* free the old filename */
337 if(capture_opts->save_file != NULL) {
338 /* we start a new capture file, close the old one (if we had one before). */
339 /* (we can only have an open capture file in real_time_mode!) */
340 if( ((capture_file *) cap_session->cf)->state != FILE_CLOSED) {
341 if(capture_opts->real_time_mode) {
342 capture_callback_invoke(capture_cb_capture_update_finished, cap_session);
343 cf_finish_tail((capture_file *)cap_session->cf, &err);
344 cf_close((capture_file *)cap_session->cf);
345 } else {
346 capture_callback_invoke(capture_cb_capture_fixed_finished, cap_session);
349 g_free(capture_opts->save_file);
350 is_tempfile = FALSE;
351 cf_set_tempfile((capture_file *)cap_session->cf, FALSE);
352 } else {
353 /* we didn't have a save_file before; must be a tempfile */
354 is_tempfile = TRUE;
355 cf_set_tempfile((capture_file *)cap_session->cf, TRUE);
358 /* save the new filename */
359 capture_opts->save_file = g_strdup(new_file);
361 /* if we are in real-time mode, open the new file now */
362 if(capture_opts->real_time_mode) {
363 /* Attempt to open the capture file and set up to read from it. */
364 switch(cf_open((capture_file *)cap_session->cf, capture_opts->save_file, is_tempfile, &err)) {
365 case CF_OK:
366 break;
367 case CF_ERROR:
368 /* Don't unlink (delete) the save file - leave it around,
369 for debugging purposes. */
370 g_free(capture_opts->save_file);
371 capture_opts->save_file = NULL;
372 return FALSE;
374 } else {
375 capture_callback_invoke(capture_cb_capture_prepared, cap_session);
378 if(capture_opts->show_info) {
379 if (!capture_info_new_file(new_file))
380 return FALSE;
383 if(capture_opts->real_time_mode) {
384 capture_callback_invoke(capture_cb_capture_update_started, cap_session);
385 } else {
386 capture_callback_invoke(capture_cb_capture_fixed_started, cap_session);
388 cap_session->state = CAPTURE_RUNNING;
390 return TRUE;
394 /* capture child tells us we have new packets to read */
395 void
396 capture_input_new_packets(capture_session *cap_session, int to_read)
398 capture_options *capture_opts = cap_session->capture_opts;
399 int err;
401 g_assert(capture_opts->save_file);
403 if(capture_opts->real_time_mode) {
404 /* Read from the capture file the number of records the child told us it added. */
405 switch (cf_continue_tail((capture_file *)cap_session->cf, to_read, &err)) {
407 case CF_READ_OK:
408 case CF_READ_ERROR:
409 /* Just because we got an error, that doesn't mean we were unable
410 to read any of the file; we handle what we could get from the
411 file.
413 XXX - abort on a read error? */
414 capture_callback_invoke(capture_cb_capture_update_continue, cap_session);
415 break;
417 case CF_READ_ABORTED:
418 /* Kill the child capture process; the user wants to exit, and we
419 shouldn't just leave it running. */
420 capture_kill_child(cap_session);
421 break;
423 } else {
424 /* increase the capture file packet counter by the number of incoming packets */
425 cf_set_packet_count((capture_file *)cap_session->cf,
426 cf_get_packet_count((capture_file *)cap_session->cf) + to_read);
427 cf_fake_continue_tail((capture_file *)cap_session->cf);
429 capture_callback_invoke(capture_cb_capture_fixed_continue, cap_session);
432 /* update the main window so we get events (e.g. from the stop toolbar button) */
433 /* This causes a hang on Windows (see bug 7305). Do we need this on any platform? */
434 #ifndef _WIN32
435 main_window_update();
436 #endif
438 if(capture_opts->show_info)
439 capture_info_new_packets(to_read);
443 /* Capture child told us how many dropped packets it counted.
445 void
446 capture_input_drops(capture_session *cap_session, guint32 dropped)
448 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_INFO, "%u packet%s dropped", dropped, plurality(dropped, "", "s"));
450 g_assert(cap_session->state == CAPTURE_RUNNING);
452 cf_set_drops_known((capture_file *)cap_session->cf, TRUE);
453 cf_set_drops((capture_file *)cap_session->cf, dropped);
457 /* Capture child told us that an error has occurred while starting/running
458 the capture.
459 The buffer we're handed has *two* null-terminated strings in it - a
460 primary message and a secondary message, one right after the other.
461 The secondary message might be a null string.
463 void
464 capture_input_error_message(capture_session *cap_session, char *error_msg,
465 char *secondary_error_msg)
467 gchar *safe_error_msg;
468 gchar *safe_secondary_error_msg;
470 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Error message from child: \"%s\", \"%s\"",
471 error_msg, secondary_error_msg);
473 g_assert(cap_session->state == CAPTURE_PREPARING || cap_session->state == CAPTURE_RUNNING);
475 safe_error_msg = simple_dialog_format_message(error_msg);
476 if (*secondary_error_msg != '\0') {
477 /* We have both primary and secondary messages. */
478 safe_secondary_error_msg = simple_dialog_format_message(secondary_error_msg);
479 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s%s%s\n\n%s",
480 simple_dialog_primary_start(), safe_error_msg,
481 simple_dialog_primary_end(), safe_secondary_error_msg);
482 g_free(safe_secondary_error_msg);
483 } else {
484 /* We have only a primary message. */
485 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s%s%s",
486 simple_dialog_primary_start(), safe_error_msg,
487 simple_dialog_primary_end());
489 g_free(safe_error_msg);
491 /* the capture child will close the sync_pipe if required, nothing to do for now */
494 /* Capture child told us that an error has occurred while parsing a
495 capture filter when starting/running the capture.
497 void
498 capture_input_cfilter_error_message(capture_session *cap_session, guint i,
499 char *error_message)
501 capture_options *capture_opts = cap_session->capture_opts;
502 dfilter_t *rfcode = NULL;
503 gchar *safe_cfilter;
504 gchar *safe_descr;
505 gchar *safe_cfilter_error_msg;
506 interface_options interface_opts;
508 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture filter error message from child: \"%s\"", error_message);
510 g_assert(cap_session->state == CAPTURE_PREPARING || cap_session->state == CAPTURE_RUNNING);
511 g_assert(i < capture_opts->ifaces->len);
513 interface_opts = g_array_index(capture_opts->ifaces, interface_options, i);
514 safe_cfilter = simple_dialog_format_message(interface_opts.cfilter);
515 safe_descr = simple_dialog_format_message(interface_opts.descr);
516 safe_cfilter_error_msg = simple_dialog_format_message(error_message);
517 /* Did the user try a display filter? */
518 if (dfilter_compile(interface_opts.cfilter, &rfcode) && rfcode != NULL) {
519 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
520 "%sInvalid capture filter \"%s\" for interface %s!%s\n"
521 "\n"
522 "That string looks like a valid display filter; however, it isn't a valid\n"
523 "capture filter (%s).\n"
524 "\n"
525 "Note that display filters and capture filters don't have the same syntax,\n"
526 "so you can't use most display filter expressions as capture filters.\n"
527 "\n"
528 "See the User's Guide for a description of the capture filter syntax.",
529 simple_dialog_primary_start(), safe_cfilter, safe_descr,
530 simple_dialog_primary_end(), safe_cfilter_error_msg);
531 dfilter_free(rfcode);
532 } else {
533 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
534 "%sInvalid capture filter \"%s\" for interface %s!%s\n"
535 "\n"
536 "That string isn't a valid capture filter (%s).\n"
537 "See the User's Guide for a description of the capture filter syntax.",
538 simple_dialog_primary_start(), safe_cfilter, safe_descr,
539 simple_dialog_primary_end(), safe_cfilter_error_msg);
541 g_free(safe_cfilter_error_msg);
542 g_free(safe_descr);
543 g_free(safe_cfilter);
545 /* the capture child will close the sync_pipe if required, nothing to do for now */
548 /* capture child closed its side of the pipe, do the required cleanup */
549 void
550 capture_input_closed(capture_session *cap_session, gchar *msg)
552 capture_options *capture_opts = cap_session->capture_opts;
553 int err;
554 int packet_count_save;
556 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture stopped!");
557 g_assert(cap_session->state == CAPTURE_PREPARING || cap_session->state == CAPTURE_RUNNING);
559 if (msg != NULL)
560 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s", msg);
562 if(cap_session->state == CAPTURE_PREPARING) {
563 /* We didn't start a capture; note that the attempt to start it
564 failed. */
565 capture_callback_invoke(capture_cb_capture_failed, cap_session);
566 } else {
567 /* We started a capture; process what's left of the capture file if
568 we were in "update list of packets in real time" mode, or process
569 all of it if we weren't. */
570 if(capture_opts->real_time_mode) {
571 cf_read_status_t status;
573 /* Read what remains of the capture file. */
574 status = cf_finish_tail((capture_file *)cap_session->cf, &err);
576 /* XXX: If -Q (quit-after-cap) then cf->count clr'd below so save it first */
577 packet_count_save = cf_get_packet_count((capture_file *)cap_session->cf);
578 /* Tell the GUI we are not doing a capture any more.
579 Must be done after the cf_finish_tail(), so file lengths are
580 correctly displayed */
581 capture_callback_invoke(capture_cb_capture_update_finished, cap_session);
583 /* Finish the capture. */
584 switch (status) {
586 case CF_READ_OK:
587 if ((packet_count_save == 0) && !capture_opts->restart) {
588 simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK,
589 "%sNo packets captured!%s\n"
590 "\n"
591 "As no data was captured, closing the %scapture file!\n"
592 "\n"
593 "\n"
594 "Help about capturing can be found at:\n"
595 "\n"
596 " http://wiki.wireshark.org/CaptureSetup"
597 #ifdef _WIN32
598 "\n\n"
599 "Wireless (Wi-Fi/WLAN):\n"
600 "Try to switch off promiscuous mode in the Capture Options!"
601 #endif
603 simple_dialog_primary_start(), simple_dialog_primary_end(),
604 cf_is_tempfile((capture_file *)cap_session->cf) ? "temporary " : "");
605 cf_close((capture_file *)cap_session->cf);
607 break;
608 case CF_READ_ERROR:
609 /* Just because we got an error, that doesn't mean we were unable
610 to read any of the file; we handle what we could get from the
611 file. */
612 break;
614 case CF_READ_ABORTED:
615 /* Exit by leaving the main loop, so that any quit functions
616 we registered get called. */
617 main_window_quit();
618 break;
620 } else {
621 /* first of all, we are not doing a capture any more */
622 capture_callback_invoke(capture_cb_capture_fixed_finished, cap_session);
624 /* this is a normal mode capture and if no error happened, read in the capture file data */
625 if(capture_opts->save_file != NULL) {
626 capture_input_read_all(cap_session, cf_is_tempfile((capture_file *)cap_session->cf),
627 cf_get_drops_known((capture_file *)cap_session->cf), cf_get_drops((capture_file *)cap_session->cf));
632 if(capture_opts->show_info)
633 capture_info_close();
635 cap_session->state = CAPTURE_STOPPED;
637 /* if we couldn't open a capture file, there's nothing more for us to do */
638 if(capture_opts->save_file == NULL) {
639 cf_close((capture_file *)cap_session->cf);
640 return;
643 /* does the user wants to restart the current capture? */
644 if(capture_opts->restart) {
645 capture_opts->restart = FALSE;
647 ws_unlink(capture_opts->save_file);
649 /* If we have a ring buffer, the original save file has been overwritten
650 with the "ring filename". Restore it before starting again */
651 if ((capture_opts->multi_files_on) && (capture_opts->orig_save_file != NULL)) {
652 g_free(capture_opts->save_file);
653 capture_opts->save_file = g_strdup(capture_opts->orig_save_file);
656 /* if it was a tempfile, throw away the old filename (so it will become a tempfile again) */
657 if(cf_is_tempfile((capture_file *)cap_session->cf)) {
658 g_free(capture_opts->save_file);
659 capture_opts->save_file = NULL;
662 /* ... and start the capture again */
663 if (capture_opts->ifaces->len == 0) {
664 collect_ifaces(capture_opts);
667 /* close the currently loaded capture file */
668 cf_close((capture_file *)cap_session->cf);
670 capture_start(capture_opts, cap_session,NULL); /*XXX is this NULL ok or we need an update_cb???*/
671 } else {
672 /* We're not doing a capture any more, so we don't have a save file. */
673 g_free(capture_opts->save_file);
674 capture_opts->save_file = NULL;
678 if_stat_cache_t *
679 capture_stat_start(capture_options *capture_opts) {
680 int stat_fd, fork_child;
681 gchar *msg;
682 if_stat_cache_t *sc = NULL;
683 if_stat_cache_item_t *sc_item;
684 guint i;
685 interface_t device;
687 /* Fire up dumpcap. */
689 * XXX - on systems with BPF, the number of BPF devices limits the
690 * number of devices on which you can capture simultaneously.
692 * This means that
694 * 1) this might fail if you run out of BPF devices
696 * and
698 * 2) opening every interface could leave too few BPF devices
699 * for *other* programs.
701 * It also means the system could end up getting a lot of traffic
702 * that it has to pass through the networking stack and capture
703 * mechanism, so opening all the devices and presenting packet
704 * counts might not always be a good idea.
706 if (sync_interface_stats_open(&stat_fd, &fork_child, &msg, NULL) == 0) {
707 sc = (if_stat_cache_t *)g_malloc(sizeof(if_stat_cache_t));
708 sc->stat_fd = stat_fd;
709 sc->fork_child = fork_child;
710 sc->cache_list = NULL;
712 /* Initialize the cache */
713 for (i = 0; i < capture_opts->all_ifaces->len; i++) {
714 device = g_array_index(capture_opts->all_ifaces, interface_t, i);
715 if (device.type != IF_PIPE && &(device.if_info)) {
716 sc_item = (if_stat_cache_item_t *)g_malloc0(sizeof(if_stat_cache_item_t));
717 sc_item->name = g_strdup(device.if_info.name);
718 sc->cache_list = g_list_append(sc->cache_list, sc_item);
722 return sc;
725 #define MAX_STAT_LINE_LEN 500
727 static void
728 capture_stat_cache_update(if_stat_cache_t *sc) {
729 gchar stat_line[MAX_STAT_LINE_LEN] = "";
730 gchar **stat_parts;
731 GList *sc_entry;
732 if_stat_cache_item_t *sc_item;
734 if (!sc)
735 return;
737 while (sync_pipe_gets_nonblock(sc->stat_fd, stat_line, MAX_STAT_LINE_LEN) > 0) {
738 g_strstrip(stat_line);
739 stat_parts = g_strsplit(stat_line, "\t", 3);
740 if (stat_parts[0] == NULL || stat_parts[1] == NULL ||
741 stat_parts[2] == NULL) {
742 g_strfreev(stat_parts);
743 continue;
745 for (sc_entry = sc->cache_list; sc_entry != NULL; sc_entry = g_list_next(sc_entry)) {
746 sc_item = (if_stat_cache_item_t *)sc_entry->data;
747 if (strcmp(sc_item->name, stat_parts[0]) == 0) {
748 sc_item->ps.ps_recv = (u_int) strtoul(stat_parts[1], NULL, 10);
749 sc_item->ps.ps_drop = (u_int) strtoul(stat_parts[2], NULL, 10);
752 g_strfreev(stat_parts);
756 gboolean
757 capture_stats(if_stat_cache_t *sc, char *ifname, struct pcap_stat *ps) {
758 GList *sc_entry;
759 if_stat_cache_item_t *sc_item;
761 if (!sc || !ifname || !ps) {
762 return FALSE;
765 capture_stat_cache_update(sc);
766 for (sc_entry = sc->cache_list; sc_entry != NULL; sc_entry = g_list_next(sc_entry)) {
767 sc_item = (if_stat_cache_item_t *)sc_entry->data;
768 if (strcmp(sc_item->name, ifname) == 0) {
769 memcpy(ps, &sc_item->ps, sizeof(struct pcap_stat));
770 return TRUE;
773 return FALSE;
776 void
777 capture_stat_stop(if_stat_cache_t *sc) {
778 GList *sc_entry;
779 if_stat_cache_item_t *sc_item;
780 int ret;
781 gchar *msg;
783 if (!sc)
784 return;
786 ret = sync_interface_stats_close(&sc->stat_fd, &sc->fork_child, &msg);
787 if (ret == -1) {
788 /* XXX - report failure? */
789 g_free(msg);
792 for (sc_entry = sc->cache_list; sc_entry != NULL; sc_entry = g_list_next(sc_entry)) {
793 sc_item = (if_stat_cache_item_t *)sc_entry->data;
794 g_free(sc_item->name);
795 g_free(sc_item);
797 g_free(sc);
800 #endif /* HAVE_LIBPCAP */