Improve error message when binding http port.
[darkstat] / cap.c
diff --git a/cap.c b/cap.c
index f304ec9..d07bf9c 100644 (file)
--- a/cap.c
+++ b/cap.c
@@ -1,5 +1,5 @@
 /* darkstat 3
- * copyright (c) 2001-2009 Emil Mikulic.
+ * copyright (c) 2001-2011 Emil Mikulic.
  *
  * cap.c: interface to libpcap.
  *
@@ -7,12 +7,14 @@
  * GNU General Public License version 2. (see COPYING.GPL)
  */
 
-#include "darkstat.h"
+#include "cdefs.h"
 #include "cap.h"
+#include "config.h"
 #include "conv.h"
 #include "decode.h"
 #include "hosts_db.h"
 #include "localip.h"
+#include "opt.h"
 
 #include <sys/ioctl.h>
 #include <sys/types.h>
@@ -28,8 +30,6 @@
 #include <string.h>
 #include <unistd.h>
 
-extern int want_pppoe, want_macs, want_hexdump;
-
 /* The cap process life-cycle:
  *
  * Init           - cap_init()
@@ -41,7 +41,7 @@ extern int want_pppoe, want_macs, want_hexdump;
 /* Globals - only useful within this module. */
 static pcap_t *pcap = NULL;
 static int pcap_fd = -1;
-static const linkhdr_t *linkhdr = NULL;
+static const struct linkhdr *linkhdr = NULL;
 
 #define CAP_TIMEOUT 500 /* granularity of capture buffer, in milliseconds */
 
@@ -52,47 +52,70 @@ void
 cap_init(const char *device, const char *filter, int promisc)
 {
    char errbuf[PCAP_ERRBUF_SIZE], *tmp_device;
-   int linktype, caplen;
+   int linktype, snaplen, waited;
 
    /* pcap doesn't like device being const */
    tmp_device = xstrdup(device);
 
    /* Open packet capture descriptor. */
-   errbuf[0] = '\0'; /* zero length string */
-   pcap = pcap_open_live(
-      tmp_device,
-      1,          /* snaplen, irrelevant at this point */
-      0,          /* promisc, also irrelevant */
-      CAP_TIMEOUT,
-      errbuf);
-
-   if (pcap == NULL)
-      errx(1, "pcap_open_live(): %s", errbuf);
+   waited = 0;
+   for (;;) {
+      errbuf[0] = '\0'; /* zero length string */
+      pcap = pcap_open_live(
+         tmp_device,
+         1,          /* snaplen, irrelevant at this point */
+         0,          /* promisc, also irrelevant */
+         CAP_TIMEOUT,
+         errbuf);
+      if (pcap != NULL) break; /* success! */
+
+      if ((opt_wait_secs != -1) && strstr(errbuf, "device is not up")) {
+         if ((opt_wait_secs > 0) && (waited >= opt_wait_secs))
+            errx(1, "waited %d secs, giving up: pcap_open_live(): %s",
+               waited, errbuf);
+
+         verbosef("waited %d secs, interface is not up", waited);
+         sleep(1);
+         waited++;
+      }
+      else errx(1, "pcap_open_live(): %s", errbuf);
+   }
 
-   /* Work out the linktype and what caplen it needs. */
+   /* Work out the linktype and what snaplen we need. */
    linktype = pcap_datalink(pcap);
    verbosef("linktype is %d", linktype);
-   if ((linktype == DLT_EN10MB) && want_macs)
-      show_mac_addrs = 1;
+   if ((linktype == DLT_EN10MB) && opt_want_macs)
+      hosts_db_show_macs = 1;
    linkhdr = getlinkhdr(linktype);
    if (linkhdr == NULL)
       errx(1, "unknown linktype %d", linktype);
    if (linkhdr->handler == NULL)
       errx(1, "no handler for linktype %d", linktype);
-   caplen = getcaplen(linkhdr);
-   if (want_pppoe) {
-      caplen += PPPOE_HDR_LEN;
+   snaplen = getsnaplen(linkhdr);
+   if (opt_want_pppoe) {
+      snaplen += PPPOE_HDR_LEN;
       if (linktype != DLT_EN10MB)
          errx(1, "can't do PPPoE decoding on a non-Ethernet linktype");
    }
-   verbosef("caplen is %d", caplen);
+   verbosef("calculated snaplen minimum %d", snaplen);
+#ifdef linux
+   /* Ubuntu 9.04 has a problem where requesting snaplen <= 60 will
+    * give us 42 bytes, and we need at least 54 for TCP headers.
+    *
+    * Hack to set minimum snaplen to tcpdump's default:
+    */
+   snaplen = MAX(snaplen, 96);
+#endif
+   if (opt_want_snaplen > -1)
+      snaplen = opt_want_snaplen;
+   verbosef("using snaplen %d", snaplen);
 
-   /* Close and re-open pcap to use the new caplen. */
+   /* Close and re-open pcap to use the new snaplen. */
    pcap_close(pcap);
    errbuf[0] = '\0'; /* zero length string */
    pcap = pcap_open_live(
       tmp_device,
-      caplen,
+      snaplen,
       promisc,
       CAP_TIMEOUT,
       errbuf);
@@ -195,11 +218,11 @@ cap_fd_set(
 #else
    /* We have a BSD-like BPF, we can select() on it. */
    FD_SET(pcap_fd, read_set);
-   *max_fd = max(*max_fd, pcap_fd);
+   *max_fd = MAX(*max_fd, pcap_fd);
 #endif
 }
 
-unsigned int pkts_recv = 0, pkts_drop = 0;
+unsigned int cap_pkts_recv = 0, cap_pkts_drop = 0;
 
 static void
 cap_stats_update(void)
@@ -211,8 +234,8 @@ cap_stats_update(void)
       return;
    }
 
-   pkts_recv = ps.ps_recv;
-   pkts_drop = ps.ps_drop;
+   cap_pkts_recv = ps.ps_recv;
+   cap_pkts_drop = ps.ps_drop;
 }
 
 /*
@@ -224,7 +247,6 @@ hexdump(const u_char *buf, const uint32_t len)
    uint32_t i, col;
 
    printf("packet of %u bytes:\n", len);
-   col = 0;
    for (i=0, col=0; i<len; i++) {
       if (col == 0) printf(" ");
       printf("%02x", buf[i]);
@@ -250,7 +272,7 @@ hexdump(const u_char *buf, const uint32_t len)
 static void
 callback(u_char *user, const struct pcap_pkthdr *h, const u_char *bytes)
 {
-   if (want_hexdump) hexdump(bytes, h->caplen);
+   if (opt_want_hexdump) hexdump(bytes, h->caplen);
    linkhdr->handler(user, h, bytes);
 }
 
@@ -281,6 +303,10 @@ cap_poll(fd_set *read_set
 
    total = 0;
    for (;;) {
+#ifndef NDEBUG
+      struct timeval t1;
+      gettimeofday(&t1, NULL);
+#endif
       ret = pcap_dispatch(
             pcap,
             -1,               /* count, -1 = entire buffer */
@@ -292,6 +318,19 @@ cap_poll(fd_set *read_set
          return;
       }
 
+#ifndef NDEBUG
+      {
+         struct timeval t2;
+         int td;
+
+         gettimeofday(&t2, NULL);
+         td = (t2.tv_sec - t1.tv_sec) * 1000000 + t2.tv_usec - t1.tv_usec;
+         if (td > CAP_TIMEOUT*1000)
+            warnx("pcap_dispatch blocked for %d usec! (expected <= %d usec)\n",
+               td, CAP_TIMEOUT*1000);
+      }
+#endif
+
       /* Despite count = -1, Linux will only dispatch one packet at a time. */
       total += ret;
 
@@ -303,7 +342,6 @@ cap_poll(fd_set *read_set
       break;
 #endif
    }
-   /*FIXME*/if (want_verbose) fprintf(stderr, "%-20d\r", total);
    cap_stats_update();
 }
 
@@ -338,7 +376,7 @@ cap_from_file(const char *capfile, const char *filter)
    if (linkhdr->handler == NULL)
       errx(1, "no handler for linktype %d", linktype);
    if (linktype == DLT_EN10MB) /* FIXME: impossible with capfile? */
-      show_mac_addrs = 1;
+      hosts_db_show_macs = 1;
 
    /* Set filter expression, if any. */ /* FIXME: factor! */
    if (filter != NULL)