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