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