In Ethereal, attempt to get the packet statistics from libpcap when
authorGuy Harris <guy@alum.mit.edu>
Sun, 11 Feb 2001 09:28:17 +0000 (09:28 -0000)
committerGuy Harris <guy@alum.mit.edu>
Sun, 11 Feb 2001 09:28:17 +0000 (09:28 -0000)
capturing; if we succeed, display the packet drops count as the "Drops"
value in the status line and as the "Dropped packets" statistics in the
summary dialog box, otherwise don't display it at all.

In Tethereal, attempt to get the packet statistics from libpcap when
capturing; if we succeed, and if there were any dropped packets, print
out the count of dropped packets when the capture finishes.

svn path=/trunk/; revision=3016

capture.c
capture.h
file.c
file.h
gtk/main.c
gtk/packet_win.c
gtk/summary_dlg.c
summary.c
summary.h
tethereal.c

index 44e2cd7853af9658006249d1c06d7225c50fda0c..b8a0fa2faf30b6a49d98970c9e7583dc18fd6e36 100644 (file)
--- a/capture.c
+++ b/capture.c
@@ -1,7 +1,7 @@
 /* capture.c
  * Routines for packet capture windows
  *
- * $Id: capture.c,v 1.138 2001/02/10 09:08:14 guy Exp $
+ * $Id: capture.c,v 1.139 2001/02/11 09:28:15 guy Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@zing.org>
@@ -268,6 +268,8 @@ do_capture(char *capfile_name)
   char *msg;
   int err;
   int capture_succeeded;
+  gboolean stats_known;
+  struct pcap_stat stats;
 
   if (capfile_name != NULL) {
     /* Try to open/create the specified file for use as a capture buffer. */
@@ -556,7 +558,7 @@ do_capture(char *capfile_name)
     }
   } else {
     /* Not sync mode. */
-    capture_succeeded = capture();
+    capture_succeeded = capture(&stats_known, &stats);
     if (quit_after_cap) {
       /* DON'T unlink the save file.  Presumably someone wants it. */
       gtk_exit(0);
@@ -566,6 +568,39 @@ do_capture(char *capfile_name)
       if ((err = open_cap_file(cfile.save_file, is_tempfile, &cfile)) == 0) {
         /* Set the read filter to NULL. */
         cfile.rfcode = NULL;
+
+        /* Get the packet-drop statistics.
+
+           XXX - there are currently no packet-drop statistics stored
+           in libpcap captures, and that's what we're reading.
+
+           At some point, we will add support in Wiretap to return
+          packet-drop statistics for capture file formats that store it,
+          and will make "read_cap_file()" get those statistics from
+          Wiretap.  We clear the statistics (marking them as "not known")
+          in "open_cap_file()", and "read_cap_file()" will only fetch
+          them and mark them as known if Wiretap supplies them, so if
+          we get the statistics now, after calling "open_cap_file()" but
+          before calling "read_cap_file()", the values we store will
+          be used by "read_cap_file()".
+
+           If a future libpcap capture file format stores the statistics,
+           we'll put them into the capture file that we write, and will
+          thus not have to set them here - "read_cap_file()" will get
+          them from the file and use them. */
+        if (stats_known) {
+          cfile.drops_known = TRUE;
+
+          /* XXX - on some systems, libpcap doesn't bother filling in
+             "ps_ifdrop" - it doesn't even set it to zero - so we don't
+             bother looking at it.
+
+             Ideally, libpcap would have an interface that gave us
+             several statistics - perhaps including various interface
+             error statistics - and would tell us which of them it
+             supplies, allowing us to display only the ones it does. */
+          cfile.drops = stats.ps_drop;
+        }
         switch (read_cap_file(&cfile, &err)) {
 
         case READ_SUCCESS:
@@ -1111,7 +1146,7 @@ static loop_data   ld;
 /* Do the low-level work of a capture.
    Returns TRUE if it succeeds, FALSE otherwise. */
 int
-capture(void)
+capture(gboolean *stats_known, struct pcap_stat *stats)
 {
   GtkWidget  *cap_w, *main_vb, *stop_bt, *counts_tb;
   pcap_t     *pch;
@@ -1144,7 +1179,7 @@ capture(void)
       const gchar *title;
       gint *value_ptr;
       GtkWidget *label, *value, *percent;
-  } stats[] = {
+  } counts[] = {
       { "Total", &ld.counts.total },
       { "SCTP", &ld.counts.sctp },
       { "TCP", &ld.counts.tcp },
@@ -1158,7 +1193,7 @@ capture(void)
       { "Other", &ld.counts.other }
   };
 
-#define N_STATS (sizeof stats / sizeof stats[0])
+#define N_COUNTS (sizeof counts / sizeof counts[0])
 
   /* Initialize Windows Socket if we are in a WIN32 OS 
      This needs to be done before querying the interface for network/netmask */
@@ -1192,6 +1227,9 @@ capture(void)
   ld.counts.other   = 0;
   ld.pdh            = NULL;
 
+  /* We haven't yet gotten the capture statistics. */
+  *stats_known      = FALSE;
+
   /* Open the network interface to capture from it. */
   pch = pcap_open_live(cfile.iface, cfile.snap, promisc_mode,
                        CAP_READ_TIMEOUT, err_str);
@@ -1375,33 +1413,33 @@ capture(void)
   gtk_widget_show(main_vb);
 
   /* Individual statistic elements */
-  counts_tb = gtk_table_new(N_STATS, 3, TRUE);
+  counts_tb = gtk_table_new(N_COUNTS, 3, TRUE);
   gtk_box_pack_start(GTK_BOX(main_vb), counts_tb, TRUE, TRUE, 3);
   gtk_widget_show(counts_tb);
 
-  for (i = 0; i < N_STATS; i++) {
-      stats[i].label = gtk_label_new(stats[i].title);
-      gtk_misc_set_alignment(GTK_MISC(stats[i].label), 0.0f, 0.0f);
+  for (i = 0; i < N_COUNTS; i++) {
+      counts[i].label = gtk_label_new(counts[i].title);
+      gtk_misc_set_alignment(GTK_MISC(counts[i].label), 0.0f, 0.0f);
 
-      stats[i].value = gtk_label_new("0");
-      gtk_misc_set_alignment(GTK_MISC(stats[i].value), 0.0f, 0.0f);
+      counts[i].value = gtk_label_new("0");
+      gtk_misc_set_alignment(GTK_MISC(counts[i].value), 0.0f, 0.0f);
 
-      stats[i].percent = gtk_label_new("0.0%");
-      gtk_misc_set_alignment(GTK_MISC(stats[i].percent), 0.0f, 0.0f);
+      counts[i].percent = gtk_label_new("0.0%");
+      gtk_misc_set_alignment(GTK_MISC(counts[i].percent), 0.0f, 0.0f);
 
       gtk_table_attach_defaults(GTK_TABLE(counts_tb),
-                                stats[i].label, 0, 1, i, i + 1);
+                                counts[i].label, 0, 1, i, i + 1);
 
       gtk_table_attach(GTK_TABLE(counts_tb),
-                       stats[i].value,
+                       counts[i].value,
                        1, 2, i, i + 1, 0, 0, 5, 0);
 
       gtk_table_attach_defaults(GTK_TABLE(counts_tb),
-                                stats[i].percent, 2, 3, i, i + 1);
+                                counts[i].percent, 2, 3, i, i + 1);
 
-      gtk_widget_show(stats[i].label);
-      gtk_widget_show(stats[i].value);
-      gtk_widget_show(stats[i].percent);
+      gtk_widget_show(counts[i].label);
+      gtk_widget_show(counts[i].value);
+      gtk_widget_show(counts[i].percent);
   }
 
   /* allow user to either click a stop button, or the close button on
@@ -1506,16 +1544,16 @@ capture(void)
     if (cur_time > upd_time) {
       upd_time = cur_time;
 
-      for (i = 0; i < N_STATS; i++) {
+      for (i = 0; i < N_COUNTS; i++) {
           snprintf(label_str, sizeof(label_str), "%d",
-                   *stats[i].value_ptr);
+                   *counts[i].value_ptr);
 
-          gtk_label_set(GTK_LABEL(stats[i].value), label_str);
+          gtk_label_set(GTK_LABEL(counts[i].value), label_str);
 
           snprintf(label_str, sizeof(label_str), "(%.1f%%)",
-                   pct(*stats[i].value_ptr, ld.counts.total));
+                   pct(*counts[i].value_ptr, ld.counts.total));
 
-          gtk_label_set(GTK_LABEL(stats[i].percent), label_str);
+          gtk_label_set(GTK_LABEL(counts[i].percent), label_str);
       }
 
       /* do sync here, too */
@@ -1561,7 +1599,13 @@ capture(void)
     close(pipe_fd);
   else
 #endif
+  {
+    /* Get the capture statistics, so we know how many packets were
+       dropped. */
+    if (pcap_stats(pch, stats) >= 0)
+      *stats_known = TRUE;
     pcap_close(pch);
+  }
 
 #ifdef WIN32
   /* Shut down windows sockets */
index bc65142e321aa577765fed3e60c397317c16cc72..ec173e75bdbd9b78452d5f9869d3c6446b2473e8 100644 (file)
--- a/capture.h
+++ b/capture.h
@@ -1,7 +1,7 @@
 /* capture.h
  * Definitions for packet capture windows
  *
- * $Id: capture.h,v 1.24 2000/10/11 06:01:14 guy Exp $
+ * $Id: capture.h,v 1.25 2001/02/11 09:28:15 guy Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@zing.org>
@@ -42,7 +42,7 @@ extern gboolean capture_child;        /* if this is the child for "-S" */
 void   do_capture(char *capfile_name);
 
 /* Do the low-level work of a capture. */
-int    capture(void);
+int    capture(gboolean *stats_known, struct pcap_stat *stats);
 
 /* Stop a capture from a menu item. */
 void   capture_stop(void);
diff --git a/file.c b/file.c
index 67470101f06bdc6819b3c6d88445b9376223c099..2cf10d547b0f9b552bd42416df17e09549390129 100644 (file)
--- a/file.c
+++ b/file.c
@@ -1,7 +1,7 @@
 /* file.c
  * File I/O routines
  *
- * $Id: file.c,v 1.231 2001/02/10 09:08:14 guy Exp $
+ * $Id: file.c,v 1.232 2001/02/11 09:28:15 guy Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@zing.org>
@@ -170,6 +170,7 @@ open_cap_file(char *fname, gboolean is_tempfile, capture_file *cf)
 
   cf->cd_t      = wtap_file_type(cf->wth);
   cf->count     = 0;
+  cf->drops_known = FALSE;
   cf->drops     = 0;
   cf->esec      = 0;
   cf->eusec     = 0;
@@ -265,7 +266,8 @@ set_display_filename(capture_file *cf)
 {
   gchar  *name_ptr;
   size_t  msg_len;
-  gchar  *done_fmt = " File: %s  Drops: %u";
+  static const gchar done_fmt_nodrops[] = " File: %s";
+  static const gchar done_fmt_drops[] = " File: %s  Drops: %u";
   gchar  *done_msg;
   gchar  *win_name_fmt = "%s - Ethereal";
   gchar  *win_name;
@@ -280,9 +282,15 @@ set_display_filename(capture_file *cf)
     name_ptr = "<capture>";
   }
 
-  msg_len = strlen(name_ptr) + strlen(done_fmt) + 64;
-  done_msg = g_malloc(msg_len);
-  snprintf(done_msg, msg_len, done_fmt, name_ptr, cf->drops);
+  if (cf->drops_known) {
+    msg_len = strlen(name_ptr) + strlen(done_fmt_drops) + 64;
+    done_msg = g_malloc(msg_len);
+    snprintf(done_msg, msg_len, done_fmt_drops, name_ptr, cf->drops);
+  } else {
+    msg_len = strlen(name_ptr) + strlen(done_fmt_nodrops);
+    done_msg = g_malloc(msg_len);
+    snprintf(done_msg, msg_len, done_fmt_nodrops, name_ptr);
+  }
   gtk_statusbar_push(GTK_STATUSBAR(info_bar), file_ctx, done_msg);
   g_free(done_msg);
 
diff --git a/file.h b/file.h
index b42cd582dfeada648cc9482a8ae42ab5a97c3886..a71c7e556a2e3ee449c8033034a2d24d11ddf243 100644 (file)
--- a/file.h
+++ b/file.h
@@ -1,7 +1,7 @@
 /* file.h
  * Definitions for file structures and routines
  *
- * $Id: file.h,v 1.80 2001/02/01 20:21:13 gram Exp $
+ * $Id: file.h,v 1.81 2001/02/11 09:28:15 guy Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@zing.org>
@@ -68,6 +68,7 @@ typedef struct _capture_file {
   int          lnk_t;     /* Link-layer type with which to save capture */
   guint32      vers;      /* Version.  For tcpdump minor is appended to major */
   guint32      count;     /* Packet count */
+  gboolean     drops_known; /* TRUE if we know how many packets were dropped */
   guint32      drops;     /* Dropped packets */
   guint32      esec;      /* Elapsed seconds */
   guint32      eusec;     /* Elapsed microseconds */
index a956fc7c4064f0d50b0f590ffa72e0cb7fbb2f26..cf9859ebd1a6582bcbc27c7e04831b1d39818fc1 100644 (file)
@@ -1,6 +1,6 @@
 /* main.c
  *
- * $Id: main.c,v 1.178 2001/02/08 03:55:45 guy Exp $
+ * $Id: main.c,v 1.179 2001/02/11 09:28:17 guy Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@ethereal.com>
@@ -693,6 +693,8 @@ main(int argc, char *argv[])
   gchar               *save_file = NULL;
   GList               *if_list;
   gchar                err_str[PCAP_ERRBUF_SIZE];
+  gboolean             stats_known;
+  struct pcap_stat     stats;
 #else
   gboolean             capture_option_specified = FALSE;
 #endif
@@ -1226,7 +1228,8 @@ main(int argc, char *argv[])
        a temporary file and fork off *another* child process (so don't
        call "do_capture()"). */
 
-       capture();
+       /* XXX - hand these stats to the parent process */
+       capture(&stats_known, &stats);
 
        /* The capture is done; there's nothing more for us to do. */
        gtk_exit(0);
index 760033f8d8db4b929346d6e98bf297e1580a6ec7..09a649c49c8389508e672a65ac09fdafb484c8ef 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright 2000, Jeffrey C. Foster <jfoste@woodward.com>
  *
- * $Id: packet_win.c,v 1.17 2001/02/01 20:21:22 gram Exp $
+ * $Id: packet_win.c,v 1.18 2001/02/11 09:28:17 guy Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@zing.org>
@@ -50,7 +50,6 @@
 #include "main.h"
 #include "timestamp.h"
 #include "packet.h"
-#include "capture.h"
 #include "summary.h"
 #include "file.h"
 #include "menu.h"
index 08e0cbb9b276b1b98b16c34a9138102cad7e85bb..64c50371a0c28e6e2881ef5337919d14274650eb 100644 (file)
@@ -1,7 +1,7 @@
 /* summary_dlg.c
  * Routines for capture file summary window
  *
- * $Id: summary_dlg.c,v 1.8 2000/08/21 18:20:19 deniel Exp $
+ * $Id: summary_dlg.c,v 1.9 2001/02/11 09:28:17 guy Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@zing.org>
@@ -142,8 +142,10 @@ summary_open_cb(GtkWidget *w, gpointer d)
   }
 
   /* Dropped count */
-  snprintf(string_buff, SUM_STR_MAX, "Dropped packets: %i", summary.drops);
-  add_string_to_box(string_buff, data_box);
+  if (summary.drops_known) {
+    snprintf(string_buff, SUM_STR_MAX, "Dropped packets: %u", summary.drops);
+    add_string_to_box(string_buff, data_box);
+  }
 
   /* Byte count */
   snprintf(string_buff, SUM_STR_MAX, "Bytes of traffic: %d", summary.bytes);
index 90717a91f09193934911e52075a9d1853ffb95a2..3da60a62b142ab5ac312d374749ae69a9af5f01e 100644 (file)
--- a/summary.c
+++ b/summary.c
@@ -1,7 +1,7 @@
 /* summary.c
  * Routines for capture file summary info
  *
- * $Id: summary.c,v 1.19 2000/08/21 18:20:11 deniel Exp $
+ * $Id: summary.c,v 1.20 2001/02/11 09:28:15 guy Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@zing.org>
@@ -94,6 +94,7 @@ summary_fill_in(summary_tally *st)
   st->snap = cfile.snap;
   st->elapsed_time = secs_usecs(cfile.esec, cfile.eusec);
   st->packet_count = cfile.count;
+  st->drops_known = cfile.drops_known;
   st->drops = cfile.drops;
   st->iface = cfile.iface;
   st->dfilter = cfile.dfilter;
index ed64ae669ab71e22a26a565385f5cab6905d8dde..c12d27c9d20777890a28fcf7dcdabeefc751ab59 100644 (file)
--- a/summary.h
+++ b/summary.h
@@ -1,7 +1,7 @@
 /* summary.h
  * Definitions for capture file summary data
  *
- * $Id: summary.h,v 1.5 2000/08/21 18:20:12 deniel Exp $
+ * $Id: summary.h,v 1.6 2001/02/11 09:28:15 guy Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@zing.org>
@@ -40,7 +40,8 @@ typedef struct _summary_tally {
     long       file_length;    /* file length in bytes */
     int                encap_type;     /* wiretap encapsulation type */
     int                snap;           /* snapshot length */
-    int         drops;         /* number of packet drops */
+    gboolean    drops_known;   /* TRUE if number of packet drops is known */
+    guint32     drops;         /* number of packet drops */
     const char *iface;         /* interface name */
     const char *dfilter;       /* display filter */
     const char *cfilter;       /* capture filter */
index ee96b8328f71a9c8067c1d6ef943ff34a9aa7103..6b91df19255324d4bb4bb9156230f43a6fa15a0e 100644 (file)
@@ -1,6 +1,6 @@
 /* tethereal.c
  *
- * $Id: tethereal.c,v 1.65 2001/02/10 09:08:14 guy Exp $
+ * $Id: tethereal.c,v 1.66 2001/02/11 09:28:15 guy Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@zing.org>
@@ -544,6 +544,7 @@ capture(int packet_count, int out_file_type)
   static const char ppamsg[] = "can't find PPA for ";
   char       *libpcap_warn;
 #endif
+  struct pcap_stat stats;
 
   /* Initialize the table of conversations. */
   epan_conversation_init();
@@ -660,13 +661,20 @@ capture(int packet_count, int out_file_type)
   printf("Capturing on %s\n", cfile.iface);
 
   inpkts = pcap_loop(ld.pch, packet_count, capture_pcap_cb, (u_char *) &ld);
-  pcap_close(ld.pch);
 
-  /* Send a newline if we were printing packet counts to stdout */
   if (cfile.save_file != NULL) {
+    /* We're saving to a file, which means we're printing packet counts
+       to the standard output.  Send a newline so that we move to the
+       line after the packet count. */
     printf("\n");
   }
 
+  /* Get the capture statistics, and, if any packets were dropped, report
+     that. */
+  if (pcap_stats(ld.pch, &stats) >= 0)
+    printf("%u packets dropped\n", stats.ps_drop);
+  pcap_close(ld.pch);
+
   return TRUE;
 
 error:
@@ -1364,6 +1372,7 @@ open_cap_file(char *fname, gboolean is_tempfile, capture_file *cf)
 
   cf->cd_t      = wtap_file_type(cf->wth);
   cf->count     = 0;
+  cf->drops_known = FALSE;
   cf->drops     = 0;
   cf->esec      = 0;
   cf->eusec     = 0;