2 * Routines for packet capture
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.
38 #include <epan/packet.h>
39 #include <epan/dfilter/dfilter.h>
42 #include "capture_ifinfo.h"
43 #include "capture_sync.h"
44 #include "capture_info.h"
45 #include "capture_ui_utils.h"
47 #include "capture-pcap-util.h"
48 #include <epan/prefs.h>
51 #include "capture-wpcap.h"
54 #include "ui/simple_dialog.h"
55 #include "ui/ui_util.h"
57 #include "wsutil/file_util.h"
60 typedef struct if_stat_cache_item_s
{
63 } if_stat_cache_item_t
;
65 struct if_stat_cache_s
{
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 :-) */
73 capture_callback_t cb_fct
;
75 } capture_callback_data_t
;
77 static GList
*capture_callbacks
= NULL
;
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
);
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
));
103 cb
->user_data
= user_data
;
105 capture_callbacks
= g_list_append(capture_callbacks
, cb
);
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
);
121 cb_item
= g_list_next(cb_item
);
124 g_assert_not_reached();
130 * @return TRUE if the capture starts successfully, FALSE otherwise.
133 capture_start(capture_options
*capture_opts
, capture_session
*cap_session
, void(*update_cb
)(void))
137 GString
*source
= g_string_new("");
139 cap_session
->state
= CAPTURE_PREPARING
;
140 g_log(LOG_DOMAIN_CAPTURE
, G_LOG_LEVEL_MESSAGE
, "Capture Start ...");
142 if (capture_opts
->ifaces
->len
< 2) {
144 if (capture_opts
->ifaces
->len
< 4) {
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
);
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
);
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
);
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
;
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
);
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
);
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
);
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 */
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
;
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. */
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. */
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
)) {
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
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();
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"
301 "As no data was captured, closing the %scapture file!\n"
304 "Help about capturing can be found at:\n"
306 " http://wiki.wireshark.org/CaptureSetup"
309 "Wireless (Wi-Fi/WLAN):\n"
310 "Try to switch off promiscuous mode in the Capture Options!"
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
);
321 /* capture child tells us we have a new (or the first) capture file */
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
;
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
);
346 capture_callback_invoke(capture_cb_capture_fixed_finished
, cap_session
);
349 g_free(capture_opts
->save_file
);
351 cf_set_tempfile((capture_file
*)cap_session
->cf
, FALSE
);
353 /* we didn't have a save_file before; must be a tempfile */
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
)) {
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
;
375 capture_callback_invoke(capture_cb_capture_prepared
, cap_session
);
378 if(capture_opts
->show_info
) {
379 if (!capture_info_new_file(new_file
))
383 if(capture_opts
->real_time_mode
) {
384 capture_callback_invoke(capture_cb_capture_update_started
, cap_session
);
386 capture_callback_invoke(capture_cb_capture_fixed_started
, cap_session
);
388 cap_session
->state
= CAPTURE_RUNNING
;
394 /* capture child tells us we have new packets to read */
396 capture_input_new_packets(capture_session
*cap_session
, int to_read
)
398 capture_options
*capture_opts
= cap_session
->capture_opts
;
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
)) {
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
413 XXX - abort on a read error? */
414 capture_callback_invoke(capture_cb_capture_update_continue
, cap_session
);
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
);
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? */
435 main_window_update();
438 if(capture_opts
->show_info
)
439 capture_info_new_packets(to_read
);
443 /* Capture child told us how many dropped packets it counted.
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
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.
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
);
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.
498 capture_input_cfilter_error_message(capture_session
*cap_session
, guint i
,
501 capture_options
*capture_opts
= cap_session
->capture_opts
;
502 dfilter_t
*rfcode
= NULL
;
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"
522 "That string looks like a valid display filter; however, it isn't a valid\n"
523 "capture filter (%s).\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"
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
);
533 simple_dialog(ESD_TYPE_ERROR
, ESD_BTN_OK
,
534 "%sInvalid capture filter \"%s\" for interface %s!%s\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
);
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 */
550 capture_input_closed(capture_session
*cap_session
, gchar
*msg
)
552 capture_options
*capture_opts
= cap_session
->capture_opts
;
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
);
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
565 capture_callback_invoke(capture_cb_capture_failed
, cap_session
);
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. */
587 if ((packet_count_save
== 0) && !capture_opts
->restart
) {
588 simple_dialog(ESD_TYPE_INFO
, ESD_BTN_OK
,
589 "%sNo packets captured!%s\n"
591 "As no data was captured, closing the %scapture file!\n"
594 "Help about capturing can be found at:\n"
596 " http://wiki.wireshark.org/CaptureSetup"
599 "Wireless (Wi-Fi/WLAN):\n"
600 "Try to switch off promiscuous mode in the Capture Options!"
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
);
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
614 case CF_READ_ABORTED
:
615 /* Exit by leaving the main loop, so that any quit functions
616 we registered get called. */
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
);
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???*/
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
;
679 capture_stat_start(capture_options
*capture_opts
) {
680 int stat_fd
, fork_child
;
682 if_stat_cache_t
*sc
= NULL
;
683 if_stat_cache_item_t
*sc_item
;
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.
694 * 1) this might fail if you run out of BPF devices
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
);
725 #define MAX_STAT_LINE_LEN 500
728 capture_stat_cache_update(if_stat_cache_t
*sc
) {
729 gchar stat_line
[MAX_STAT_LINE_LEN
] = "";
732 if_stat_cache_item_t
*sc_item
;
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
);
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
);
757 capture_stats(if_stat_cache_t
*sc
, char *ifname
, struct pcap_stat
*ps
) {
759 if_stat_cache_item_t
*sc_item
;
761 if (!sc
|| !ifname
|| !ps
) {
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
));
777 capture_stat_stop(if_stat_cache_t
*sc
) {
779 if_stat_cache_item_t
*sc_item
;
786 ret
= sync_interface_stats_close(&sc
->stat_fd
, &sc
->fork_child
, &msg
);
788 /* XXX - report failure? */
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
);
800 #endif /* HAVE_LIBPCAP */