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