Add cf_fake_continue_tail() which is called when real-time capture
[obnox/wireshark/wip.git] / capture.c
1 /* capture.c
2  * Routines for packet capture
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 #ifdef HAVE_CONFIG_H
26 # include "config.h"
27 #endif
28
29 #ifdef HAVE_LIBPCAP
30
31 #ifdef HAVE_UNISTD_H
32 #include <unistd.h>
33 #endif
34
35 #include <stdio.h>
36 #include <string.h>
37
38 #include <glib.h>
39
40 #include <epan/packet.h>
41 #include <epan/dfilter/dfilter.h>
42 #include "file.h"
43 #include "capture.h"
44 #include "capture_ifinfo.h"
45 #include "capture_sync.h"
46 #include "capture_info.h"
47 #include "capture_ui_utils.h"
48 #include "util.h"
49 #include "capture-pcap-util.h"
50 #include "simple_dialog.h"
51 #include <epan/prefs.h>
52
53 #ifdef _WIN32
54 #include "capture-wpcap.h"
55 #endif
56 #include "ui_util.h"
57 #include "wsutil/file_util.h"
58 #include "log.h"
59
60 typedef struct if_stat_cache_item_s {
61     char *name;
62     struct pcap_stat ps;
63 } if_stat_cache_item_t;
64
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 */
69 };
70
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;
76
77 static GList *capture_callbacks = NULL;
78
79 static void
80 capture_callback_invoke(int event, capture_options *capture_opts)
81 {
82     capture_callback_data_t *cb;
83     GList *cb_item = capture_callbacks;
84
85     /* there should be at least one interested */
86     g_assert(cb_item != NULL);
87
88     while(cb_item != NULL) {
89         cb = cb_item->data;
90         cb->cb_fct(event, capture_opts, cb->user_data);
91         cb_item = g_list_next(cb_item);
92     }
93 }
94
95
96 void
97 capture_callback_add(capture_callback_t func, gpointer user_data)
98 {
99     capture_callback_data_t *cb;
100
101     cb = g_malloc(sizeof(capture_callback_data_t));
102     cb->cb_fct = func;
103     cb->user_data = user_data;
104
105     capture_callbacks = g_list_append(capture_callbacks, cb);
106 }
107
108 void
109 capture_callback_remove(capture_callback_t func)
110 {
111     capture_callback_data_t *cb;
112     GList *cb_item = capture_callbacks;
113
114     while(cb_item != NULL) {
115         cb = cb_item->data;
116         if(cb->cb_fct == func) {
117             capture_callbacks = g_list_remove(capture_callbacks, cb);
118             g_free(cb);
119             return;
120         }
121         cb_item = g_list_next(cb_item);
122     }
123
124     g_assert_not_reached();
125 }
126
127 /**
128  * Start a capture.
129  *
130  * @return TRUE if the capture starts successfully, FALSE otherwise.
131  */
132 gboolean
133 capture_start(capture_options *capture_opts)
134 {
135   gboolean ret;
136   GString *source = g_string_new("");
137
138   /* close the currently loaded capture file */
139   cf_close(capture_opts->cf);
140
141   g_assert(capture_opts->state == CAPTURE_STOPPED);
142   capture_opts->state = CAPTURE_PREPARING;
143
144   g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture Start ...");
145
146   g_string_printf(source, "%s", get_iface_description(capture_opts));
147   if(capture_opts->cfilter && capture_opts->cfilter[0]) {
148     g_string_append_printf(source, " (%s)", capture_opts->cfilter);
149   }
150   cf_set_tempfile_source(capture_opts->cf, source->str);
151   g_string_free(source, TRUE);
152
153   /* try to start the capture child process */
154   ret = sync_pipe_start(capture_opts);
155   if(!ret) {
156       if(capture_opts->save_file != NULL) {
157           g_free(capture_opts->save_file);
158           capture_opts->save_file = NULL;
159       }
160
161       g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture Start failed!");
162       capture_opts->state = CAPTURE_STOPPED;
163   } else {
164       /* the capture child might not respond shortly after bringing it up */
165       /* (for example: it will block if no input arrives from an input capture pipe (e.g. mkfifo)) */
166
167       /* to prevent problems, bring the main GUI into "capture mode" right after a successful */
168       /* spawn/exec of the capture child, without waiting for any response from it */
169       capture_callback_invoke(capture_cb_capture_prepared, capture_opts);
170
171       if(capture_opts->show_info)
172         capture_info_open(capture_opts);
173   }
174
175   return ret;
176 }
177
178
179 void
180 capture_stop(capture_options *capture_opts)
181 {
182   g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture Stop ...");
183
184   capture_callback_invoke(capture_cb_capture_stopping, capture_opts);
185
186   /* stop the capture child gracefully */
187   sync_pipe_stop(capture_opts);
188 }
189
190
191 void
192 capture_restart(capture_options *capture_opts)
193 {
194     g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture Restart");
195
196     capture_opts->restart = TRUE;
197     capture_stop(capture_opts);
198 }
199
200
201 void
202 capture_kill_child(capture_options *capture_opts)
203 {
204   g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_INFO, "Capture Kill");
205
206   /* kill the capture child */
207   sync_pipe_kill(capture_opts->fork_child);
208 }
209
210
211
212 /* We've succeeded in doing a (non real-time) capture; try to read it into a new capture file */
213 static gboolean
214 capture_input_read_all(capture_options *capture_opts, gboolean is_tempfile, gboolean drops_known,
215 guint32 drops)
216 {
217   int err;
218
219   /* Capture succeeded; attempt to open the capture file. */
220   if (cf_open(capture_opts->cf, capture_opts->save_file, is_tempfile, &err) != CF_OK) {
221     /* We're not doing a capture any more, so we don't have a save file. */
222     return FALSE;
223   }
224   
225   /* Set the read filter to NULL. */
226   /* XXX - this is odd here; try to put it somewhere where it fits better */
227   cf_set_rfcode(capture_opts->cf, NULL);
228
229   /* Get the packet-drop statistics.
230
231      XXX - there are currently no packet-drop statistics stored
232      in libpcap captures, and that's what we're reading.
233
234      At some point, we will add support in Wiretap to return
235      packet-drop statistics for capture file formats that store it,
236      and will make "cf_read()" get those statistics from Wiretap.
237      We clear the statistics (marking them as "not known") in
238      "cf_open()", and "cf_read()" will only fetch them and mark
239      them as known if Wiretap supplies them, so if we get the
240      statistics now, after calling "cf_open()" but before calling
241      "cf_read()", the values we store will be used by "cf_read()".
242
243      If a future libpcap capture file format stores the statistics,
244      we'll put them into the capture file that we write, and will
245      thus not have to set them here - "cf_read()" will get them from
246      the file and use them. */
247   if (drops_known) {
248     cf_set_drops_known(capture_opts->cf, TRUE);
249
250     /* XXX - on some systems, libpcap doesn't bother filling in
251        "ps_ifdrop" - it doesn't even set it to zero - so we don't
252        bother looking at it.
253
254        Ideally, libpcap would have an interface that gave us
255        several statistics - perhaps including various interface
256        error statistics - and would tell us which of them it
257        supplies, allowing us to display only the ones it does. */
258     cf_set_drops(capture_opts->cf, drops);
259   }
260
261   /* read in the packet data */
262   switch (cf_read(capture_opts->cf, FALSE)) {
263
264   case CF_READ_OK:
265   case CF_READ_ERROR:
266     /* Just because we got an error, that doesn't mean we were unable
267        to read any of the file; we handle what we could get from the
268        file. */
269     break;
270
271   case CF_READ_ABORTED:
272     /* User wants to quit program. Exit by leaving the main loop,
273        so that any quit functions we registered get called. */
274     main_window_nested_quit();
275     return FALSE;
276   }
277
278   /* if we didn't capture even a single packet, close the file again */
279   if(cf_get_packet_count(capture_opts->cf) == 0 && !capture_opts->restart) {
280     simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK,
281 "%sNo packets captured!%s\n"
282 "\n"
283 "As no data was captured, closing the %scapture file!\n"
284 "\n"
285 "\n"
286 "Help about capturing can be found at:\n"
287 "\n"
288 "       http://wiki.wireshark.org/CaptureSetup"
289 #ifdef _WIN32
290 "\n\n"
291 "Wireless (Wi-Fi/WLAN):\n"
292 "Try to switch off promiscuous mode in the Capture Options!"
293 #endif
294 "",
295     simple_dialog_primary_start(), simple_dialog_primary_end(),
296     (cf_is_tempfile(capture_opts->cf)) ? "temporary " : "");
297     cf_close(capture_opts->cf);
298   }
299   return TRUE;
300 }
301
302
303 /* capture child tells us we have a new (or the first) capture file */
304 gboolean
305 capture_input_new_file(capture_options *capture_opts, gchar *new_file)
306 {
307   gboolean is_tempfile;
308   int  err;
309
310   if(capture_opts->state == CAPTURE_PREPARING) {
311     g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture started!");
312   }
313   g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "File: \"%s\"", new_file);
314
315   g_assert(capture_opts->state == CAPTURE_PREPARING || capture_opts->state == CAPTURE_RUNNING);
316
317   /* free the old filename */
318   if(capture_opts->save_file != NULL) {
319     /* we start a new capture file, close the old one (if we had one before). */
320     /* (we can only have an open capture file in real_time_mode!) */
321     if( ((capture_file *) capture_opts->cf)->state != FILE_CLOSED) {
322         capture_callback_invoke(capture_cb_capture_update_finished, capture_opts);
323         cf_finish_tail(capture_opts->cf, &err);
324         cf_close(capture_opts->cf);
325     }
326     g_free(capture_opts->save_file);
327     is_tempfile = FALSE;
328     cf_set_tempfile(capture_opts->cf, FALSE);
329   } else {
330     /* we didn't have a save_file before; must be a tempfile */
331     is_tempfile = TRUE;
332     cf_set_tempfile(capture_opts->cf, TRUE);
333   }
334
335   /* save the new filename */
336   capture_opts->save_file = g_strdup(new_file);
337
338   /* if we are in real-time mode, open the new file now */
339   if(capture_opts->real_time_mode) {
340     /* Attempt to open the capture file and set up to read from it. */
341     switch(cf_start_tail(capture_opts->cf, capture_opts->save_file, is_tempfile, &err)) {
342     case CF_OK:
343       break;
344     case CF_ERROR:
345       /* Don't unlink (delete) the save file - leave it around,
346          for debugging purposes. */
347       g_free(capture_opts->save_file);
348       capture_opts->save_file = NULL;
349       return FALSE;
350     }
351   }
352
353   if(capture_opts->show_info) {
354     if (!capture_info_new_file(new_file))
355       return FALSE;
356   }
357
358   if(capture_opts->real_time_mode) {
359     capture_callback_invoke(capture_cb_capture_update_started, capture_opts);
360   } else {
361     capture_callback_invoke(capture_cb_capture_fixed_started, capture_opts);
362   }
363   capture_opts->state = CAPTURE_RUNNING;
364
365   return TRUE;
366 }
367
368
369 /* capture child tells us we have new packets to read */
370 void
371 capture_input_new_packets(capture_options *capture_opts, int to_read)
372 {
373   int  err;
374
375
376   g_assert(capture_opts->save_file);
377
378   if(capture_opts->real_time_mode) {
379     /* Read from the capture file the number of records the child told us it added. */
380     switch (cf_continue_tail(capture_opts->cf, to_read, &err)) {
381
382     case CF_READ_OK:
383     case CF_READ_ERROR:
384       /* Just because we got an error, that doesn't mean we were unable
385          to read any of the file; we handle what we could get from the
386          file.
387
388          XXX - abort on a read error? */
389          capture_callback_invoke(capture_cb_capture_update_continue, capture_opts);
390       break;
391
392     case CF_READ_ABORTED:
393       /* Kill the child capture process; the user wants to exit, and we
394          shouldn't just leave it running. */
395       capture_kill_child(capture_opts);
396       break;
397     }
398   } else {
399     /* increase the capture file packet counter by the number of incoming packets */
400     cf_set_packet_count(capture_opts->cf,
401         cf_get_packet_count(capture_opts->cf) + to_read);
402     cf_fake_continue_tail(capture_opts->cf);
403
404     capture_callback_invoke(capture_cb_capture_fixed_continue, capture_opts);
405   }
406
407   /* update the main window so we get events (e.g. from the stop toolbar button) */
408   main_window_update();
409
410   if(capture_opts->show_info)
411     capture_info_new_packets(to_read);
412 }
413
414
415 /* Capture child told us how many dropped packets it counted.
416  */
417 void
418 capture_input_drops(capture_options *capture_opts, guint32 dropped)
419 {
420   g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_INFO, "%u packet%s dropped", dropped, plurality(dropped, "", "s"));
421
422   g_assert(capture_opts->state == CAPTURE_RUNNING);
423
424   cf_set_drops_known(capture_opts->cf, TRUE);
425   cf_set_drops(capture_opts->cf, dropped);
426 }
427
428
429 /* Capture child told us that an error has occurred while starting/running
430    the capture.
431    The buffer we're handed has *two* null-terminated strings in it - a
432    primary message and a secondary message, one right after the other.
433    The secondary message might be a null string.
434  */
435 void
436 capture_input_error_message(capture_options *capture_opts, char *error_msg, char *secondary_error_msg)
437 {
438   gchar *safe_error_msg;
439   gchar *safe_secondary_error_msg;
440
441   g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Error message from child: \"%s\", \"%s\"",
442         error_msg, secondary_error_msg);
443
444   g_assert(capture_opts->state == CAPTURE_PREPARING || capture_opts->state == CAPTURE_RUNNING);
445
446   safe_error_msg = simple_dialog_format_message(error_msg);
447   if (*secondary_error_msg != '\0') {
448     /* We have both primary and secondary messages. */
449     safe_secondary_error_msg = simple_dialog_format_message(secondary_error_msg);
450     simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s%s%s\n\n%s",
451                   simple_dialog_primary_start(), safe_error_msg,
452                   simple_dialog_primary_end(), safe_secondary_error_msg);
453     g_free(safe_secondary_error_msg);
454   } else {
455     /* We have only a primary message. */
456     simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s%s%s",
457                   simple_dialog_primary_start(), safe_error_msg,
458                   simple_dialog_primary_end());
459   }
460   g_free(safe_error_msg);
461
462   /* the capture child will close the sync_pipe if required, nothing to do for now */
463 }
464
465
466
467 /* Capture child told us that an error has occurred while parsing a
468    capture filter when starting/running the capture.
469  */
470 void
471 capture_input_cfilter_error_message(capture_options *capture_opts, char *error_message)
472 {
473   dfilter_t   *rfcode = NULL;
474   gchar *safe_cfilter = simple_dialog_format_message(capture_opts->cfilter);
475   gchar *safe_cfilter_error_msg = simple_dialog_format_message(error_message);
476
477   g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture filter error message from child: \"%s\"", error_message);
478
479   g_assert(capture_opts->state == CAPTURE_PREPARING || capture_opts->state == CAPTURE_RUNNING);
480
481   /* Did the user try a display filter? */
482   if (dfilter_compile(capture_opts->cfilter, &rfcode) && rfcode != NULL) {
483     simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
484       "%sInvalid capture filter: \"%s\"!%s\n"
485       "\n"
486       "That string looks like a valid display filter; however, it isn't a valid\n"
487       "capture filter (%s).\n"
488       "\n"
489       "Note that display filters and capture filters don't have the same syntax,\n"
490       "so you can't use most display filter expressions as capture filters.\n"
491       "\n"
492       "See the User's Guide for a description of the capture filter syntax.",
493       simple_dialog_primary_start(), safe_cfilter,
494       simple_dialog_primary_end(), safe_cfilter_error_msg);
495       dfilter_free(rfcode);
496   } else {
497     simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
498       "%sInvalid capture filter: \"%s\"!%s\n"
499       "\n"
500       "That string isn't a valid capture filter (%s).\n"
501       "See the User's Guide for a description of the capture filter syntax.",
502       simple_dialog_primary_start(), safe_cfilter,
503       simple_dialog_primary_end(), safe_cfilter_error_msg);
504   }
505   g_free(safe_cfilter_error_msg);
506   g_free(safe_cfilter);
507
508   /* the capture child will close the sync_pipe if required, nothing to do for now */
509 }
510
511
512 /* capture child closed its side of the pipe, do the required cleanup */
513 void
514 capture_input_closed(capture_options *capture_opts, gchar *msg)
515 {
516     int  err;
517     int  packet_count_save;
518
519     g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture stopped!");
520     g_assert(capture_opts->state == CAPTURE_PREPARING || capture_opts->state == CAPTURE_RUNNING);
521
522     if (msg != NULL)
523         simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s", msg);
524
525     /* if we didn't start the capture, do a fake start. */
526     /* (happens if we got an error message - we won't get a filename then). */
527     if(capture_opts->state == CAPTURE_PREPARING) {
528         if(capture_opts->real_time_mode) {
529             capture_callback_invoke(capture_cb_capture_update_started, capture_opts);
530         } else {
531             capture_callback_invoke(capture_cb_capture_fixed_started, capture_opts);
532         }
533     }
534
535     if(capture_opts->real_time_mode) {
536         cf_read_status_t status;
537
538         /* Read what remains of the capture file. */
539         status = cf_finish_tail(capture_opts->cf, &err);
540
541         /* XXX: If -Q (quit-after-cap) then cf->count clr'd below so save it first */
542         packet_count_save = cf_get_packet_count(capture_opts->cf);
543         /* Tell the GUI we are not doing a capture any more.
544                    Must be done after the cf_finish_tail(), so file lengths are 
545                    correctly displayed */
546         capture_callback_invoke(capture_cb_capture_update_finished, capture_opts);
547
548         /* Finish the capture. */
549         switch (status) {
550
551         case CF_READ_OK:
552             if ((packet_count_save == 0) && !capture_opts->restart) {
553                 simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK,
554 "%sNo packets captured!%s\n"
555 "\n"
556 "As no data was captured, closing the %scapture file!\n"
557 "\n"
558 "\n"
559 "Help about capturing can be found at:\n"
560 "\n"
561 "       http://wiki.wireshark.org/CaptureSetup"
562 #ifdef _WIN32
563 "\n\n"
564 "Wireless (Wi-Fi/WLAN):\n"
565 "Try to switch off promiscuous mode in the Capture Options!"
566 #endif
567 "",
568               simple_dialog_primary_start(), simple_dialog_primary_end(),
569               cf_is_tempfile(capture_opts->cf) ? "temporary " : "");
570               cf_close(capture_opts->cf);
571             }
572             break;
573         case CF_READ_ERROR:
574           /* Just because we got an error, that doesn't mean we were unable
575              to read any of the file; we handle what we could get from the
576              file. */
577           break;
578
579         case CF_READ_ABORTED:
580           /* Exit by leaving the main loop, so that any quit functions
581              we registered get called. */
582           main_window_quit();
583         }
584
585     } else {
586         /* first of all, we are not doing a capture any more */
587         capture_callback_invoke(capture_cb_capture_fixed_finished, capture_opts);
588
589         /* this is a normal mode capture and if no error happened, read in the capture file data */
590         if(capture_opts->save_file != NULL) {
591             capture_input_read_all(capture_opts, cf_is_tempfile(capture_opts->cf),
592                 cf_get_drops_known(capture_opts->cf), cf_get_drops(capture_opts->cf));
593         }
594     }
595
596     if(capture_opts->show_info)
597       capture_info_close();
598
599     capture_opts->state = CAPTURE_STOPPED;
600
601     /* if we couldn't open a capture file, there's nothing more for us to do */
602     if(capture_opts->save_file == NULL) {
603         cf_close(capture_opts->cf);
604         return;
605     }
606
607     /* does the user wants to restart the current capture? */
608     if(capture_opts->restart) {
609         capture_opts->restart = FALSE;
610
611         ws_unlink(capture_opts->save_file);
612
613         /* if it was a tempfile, throw away the old filename (so it will become a tempfile again) */
614         if(cf_is_tempfile(capture_opts->cf)) {
615             g_free(capture_opts->save_file);
616             capture_opts->save_file = NULL;
617         }
618
619         /* ... and start the capture again */
620         capture_start(capture_opts);
621     } else {
622         /* We're not doing a capture any more, so we don't have a save file. */
623         g_free(capture_opts->save_file);
624         capture_opts->save_file = NULL;
625     }
626 }
627
628 if_stat_cache_t *
629 capture_stat_start(GList *if_list) {
630     int stat_fd, fork_child;
631     gchar *msg;
632     if_stat_cache_t *sc = NULL;
633     GList *if_entry;
634     if_info_t *if_info;
635     if_stat_cache_item_t *sc_item;
636
637     /* Fire up dumpcap. */
638     /*
639      * XXX - on systems with BPF, the number of BPF devices limits the
640      * number of devices on which you can capture simultaneously.
641      *
642      * This means that
643      *
644      *  1) this might fail if you run out of BPF devices
645      *
646      * and
647      *
648      *  2) opening every interface could leave too few BPF devices
649      *     for *other* programs.
650      *
651      * It also means the system could end up getting a lot of traffic
652      * that it has to pass through the networking stack and capture
653      * mechanism, so opening all the devices and presenting packet
654      * counts might not always be a good idea.
655      */
656      if (sync_interface_stats_open(&stat_fd, &fork_child, &msg) == 0) {
657         sc = g_malloc(sizeof(if_stat_cache_t));
658         sc->stat_fd = stat_fd;
659         sc->fork_child = fork_child;
660         sc->cache_list = NULL;
661
662         /* Initialize the cache */
663         for (if_entry = if_list; if_entry != NULL; if_entry = g_list_next(if_entry)) {
664             if_info = if_entry->data;
665             sc_item = g_malloc0(sizeof(if_stat_cache_item_t));
666             sc_item->name = g_strdup(if_info->name);
667             sc->cache_list = g_list_append(sc->cache_list, sc_item);
668         }
669     }
670     return sc;
671 }
672
673 #define MAX_STAT_LINE_LEN 500
674
675 static void
676 capture_stat_cache_update(if_stat_cache_t *sc) {
677     gchar stat_line[MAX_STAT_LINE_LEN];
678     gchar **stat_parts;
679     GList *sc_entry;
680     if_stat_cache_item_t *sc_item;
681
682     if (!sc)
683         return;
684
685     while (sync_pipe_gets_nonblock(sc->stat_fd, stat_line, MAX_STAT_LINE_LEN) > 0) {
686         g_strstrip(stat_line);
687         stat_parts = g_strsplit(stat_line, "\t", 3);
688         if (stat_parts[0] == NULL || stat_parts[1] == NULL ||
689             stat_parts[2] == NULL) {
690             g_strfreev(stat_parts);
691             continue;
692         }
693         for (sc_entry = sc->cache_list; sc_entry != NULL; sc_entry = g_list_next(sc_entry)) {
694             sc_item = sc_entry->data;
695             if (strcmp(sc_item->name, stat_parts[0]) == 0) {
696                 sc_item->ps.ps_recv = (u_int) strtoul(stat_parts[1], NULL, 10);
697                 sc_item->ps.ps_drop = (u_int) strtoul(stat_parts[2], NULL, 10);
698             }
699         }
700         g_strfreev(stat_parts);
701     }
702 }
703
704 gboolean
705 capture_stats(if_stat_cache_t *sc, char *ifname, struct pcap_stat *ps) {
706     GList *sc_entry;
707     if_stat_cache_item_t *sc_item;
708
709     if (!sc || !ifname || !ps) {
710         return FALSE;
711     }
712
713     capture_stat_cache_update(sc);
714     for (sc_entry = sc->cache_list; sc_entry != NULL; sc_entry = g_list_next(sc_entry)) {
715         sc_item = sc_entry->data;
716         if (strcmp(sc_item->name, ifname) == 0) {
717             memcpy(ps, &sc_item->ps, sizeof(struct pcap_stat));
718             return TRUE;
719         }
720     }
721     return FALSE;
722 }
723
724 void
725 capture_stat_stop(if_stat_cache_t *sc) {
726     GList *sc_entry;
727     if_stat_cache_item_t *sc_item;
728     int ret;
729     gchar *msg;
730
731     if (!sc)
732         return;
733
734     ret = sync_interface_stats_close(&sc->stat_fd, &sc->fork_child, &msg);
735     if (ret == -1) {
736         /* XXX - report failure? */
737         g_free(msg);
738     }
739
740     for (sc_entry = sc->cache_list; sc_entry != NULL; sc_entry = g_list_next(sc_entry)) {
741         sc_item = sc_entry->data;
742         g_free(sc_item->name);
743         g_free(sc_item);
744     }
745     g_free(sc);
746 }
747
748 #endif /* HAVE_LIBPCAP */