]> The Tcpdump Group git mirrors - libpcap/commitdiff
Add a "pcap_get_selectable_fd()" API to get an FD on which you can do a
authorguy <guy>
Fri, 21 Nov 2003 10:19:33 +0000 (10:19 +0000)
committerguy <guy>
Fri, 21 Nov 2003 10:19:33 +0000 (10:19 +0000)
"select()" or "poll()" - or -1 if that won't work.

13 files changed:
pcap-bpf.c
pcap-dag.c
pcap-dlpi.c
pcap-int.h
pcap-linux.c
pcap-nit.c
pcap-pf.c
pcap-snit.c
pcap-snoop.c
pcap.3
pcap.c
pcap.h
savefile.c

index 82cc7fdd16cf79619d573d1160747d13752ea53b..3f6bba2c6f4daa4660607dddad1a69834a55acff 100644 (file)
@@ -20,7 +20,7 @@
  */
 #ifndef lint
 static const char rcsid[] _U_ =
-    "@(#) $Header: /tcpdump/master/libpcap/pcap-bpf.c,v 1.69 2003-11-20 02:02:38 guy Exp $ (LBL)";
+    "@(#) $Header: /tcpdump/master/libpcap/pcap-bpf.c,v 1.70 2003-11-21 10:19:33 guy Exp $ (LBL)";
 #endif
 
 #ifdef HAVE_CONFIG_H
@@ -33,6 +33,7 @@ static const char rcsid[] _U_ =
 #include <sys/socket.h>
 #include <sys/file.h>
 #include <sys/ioctl.h>
+#include <sys/utsname.h>
 
 #include <net/if.h>
 
@@ -495,6 +496,7 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
 #endif
        u_int v;
        pcap_t *p;
+       struct utsname osinfo;
 
 #ifdef HAVE_DAG_API
        if (strstr(device, "dag")) {
@@ -760,6 +762,60 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
        memset(p->buffer, 0x0, p->bufsize);
 #endif
 
+       /*
+        * On most BPF platforms, either you can do a "select()" or
+        * "poll()" on a BPF file descriptor and it works correctly,
+        * or you can do it and it will return "readable" if the
+        * hold buffer is full but not if the timeout expires *and*
+        * a non-blocking read will, if the hold buffer is empty
+        * but the store buffer isn't empty, rotate the buffers
+        * and return what packets are available.
+        *
+        * In the latter case, the fact that a non-blocking read
+        * will give you the available packets means you can work
+        * around the failure of "select()" and "poll()" to wake up
+        * and return "readable" when the timeout expires by using
+        * the timeout as the "select()" or "poll()" timeout, putting
+        * the BPF descriptor into non-blocking mode, and read from
+        * it regardless of whether "select()" reports it as readable
+        * or not.
+        *
+        * However, in FreeBSD 4.3 and 4.4, "select()" and "poll()"
+        * won't wake up and return "readable" if the timer expires
+        * and non-blocking reads return EWOULDBLOCK if the hold
+        * buffer is empty, even if the store buffer is non-empty.
+        *
+        * This means the workaround in question won't work.
+        *
+        * Therefore, on FreeBSD 4.3 and 4.4, we set "p->selectable_fd"
+        * to -1, which means "sorry, you can't use 'select()' or 'poll()'
+        * here".  On all other BPF platforms, we set it to the FD for
+        * the BPF device; in NetBSD, OpenBSD, and Darwin, a non-blocking
+        * read will, if the hold buffer is empty and the store buffer
+        * isn't empty, rotate the buffers and return what packets are
+        * there (and in sufficiently recent versions of OpenBSD
+        * "select()" and "poll()" should work correctly).
+        *
+        * XXX - what about AIX?
+        */
+       if (uname(&osinfo) == 0) {
+               /*
+                * We can check what OS this is.
+                */
+               if (strcmp(osinfo.sysname, "FreeBSD") == 0 &&
+                   (strcmp(osinfo.release, "4.3") == 0 ||
+                    strcmp(osinfo.release, "4.4") == 0))
+                       p->selectable_fd = -1;
+               else
+                       p->selectable_fd = p->fd;
+       } else {
+               /*
+                * We can't find out what OS this is, so assume we can
+                * do a "select()" or "poll()".
+                */
+               p->selectable_fd = p->fd;
+       }
+
        p->read_op = pcap_read_bpf;
        p->setfilter_op = pcap_setfilter_bpf;
        p->set_datalink_op = pcap_set_datalink_bpf;
index 44b989ba2460af85f2992ce74688fb0dc4f272b0..fa0182493753057d3cc5afea56f6102fe7acecda 100644 (file)
@@ -29,7 +29,7 @@
 
 #ifndef lint
 static const char rcsid[] _U_ =
-    "@(#) $Header: /tcpdump/master/libpcap/pcap-dag.c,v 1.13 2003-11-20 02:02:38 guy Exp $ (LBL)";
+    "@(#) $Header: /tcpdump/master/libpcap/pcap-dag.c,v 1.14 2003-11-21 10:19:33 guy Exp $ (LBL)";
 #endif
 
 #ifdef HAVE_CONFIG_H
@@ -469,6 +469,11 @@ pcap_t *dag_open_live(const char *device, int snaplen, int promisc, int to_ms, c
        goto fail;
   }
 
+  /*
+   * "select()" and "poll()" don't (yet) work on DAG device descriptors.
+   */
+  handle->selectable_fd = -1;
+
 #ifdef linux
   handle->md.device = (char *)device;
 #else
index 4a9eafd4c516162137702e59fc637723e827d167..1e7055b6e603ec7a69a566294a99c6d2ea90cfb4 100644 (file)
@@ -38,7 +38,7 @@
 
 #ifndef lint
 static const char rcsid[] _U_ =
-    "@(#) $Header: /tcpdump/master/libpcap/pcap-dlpi.c,v 1.93 2003-11-20 02:02:38 guy Exp $ (LBL)";
+    "@(#) $Header: /tcpdump/master/libpcap/pcap-dlpi.c,v 1.94 2003-11-21 10:19:34 guy Exp $ (LBL)";
 #endif
 
 #ifdef HAVE_CONFIG_H
@@ -704,6 +704,12 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
                goto bad;
        }
 
+       /*
+        * "p->fd" is an FD for a STREAMS device, so "select()" and
+        * "poll()" should work on it.
+        */
+       p->selectable_fd = p->fd;
+
        p->read_op = pcap_read_dlpi;
        p->setfilter_op = install_bpf_program;  /* no kernel filtering */
        p->set_datalink_op = NULL;      /* can't change data link type */
index fda88958002000becdcbfa00d4aa029395eaebe5..996d05a3e5bd448ac7b9cae9f79d971b9cc869f2 100644 (file)
@@ -30,7 +30,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * @(#) $Header: /tcpdump/master/libpcap/pcap-int.h,v 1.57 2003-11-20 02:02:39 guy Exp $ (LBL)
+ * @(#) $Header: /tcpdump/master/libpcap/pcap-int.h,v 1.58 2003-11-21 10:19:34 guy Exp $ (LBL)
  */
 
 #ifndef pcap_int_h
@@ -101,6 +101,7 @@ struct pcap {
        int nonblock;
 #else
        int fd;
+       int selectable_fd;
 #endif /* WIN32 */
        int snapshot;
        int linktype;
index b59d4ed234f89c4f950fd21359f77aa4620eec0a..50883b66738e068345cd4b26d8aea063a173077f 100644 (file)
@@ -27,7 +27,7 @@
 
 #ifndef lint
 static const char rcsid[] _U_ =
-    "@(#) $Header: /tcpdump/master/libpcap/pcap-linux.c,v 1.101 2003-11-20 02:02:39 guy Exp $ (LBL)";
+    "@(#) $Header: /tcpdump/master/libpcap/pcap-linux.c,v 1.102 2003-11-21 10:19:34 guy Exp $ (LBL)";
 #endif
 
 /*
@@ -397,6 +397,12 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
                return NULL;
        }
 
+       /*
+        * "handle->fd" is a socket, so "select()" and "poll()"
+        * should work on it.
+        */
+       handle->selectable_fd = handle->fd;
+
        handle->read_op = pcap_read_linux;
        handle->setfilter_op = pcap_setfilter_linux;
        handle->set_datalink_op = NULL; /* can't change data link type */
index 3f6461048430e3134a2c9ff6449208a00b7c6752..6aebc90f2d49741786986ca33df11f61e6f0e912 100644 (file)
@@ -20,7 +20,7 @@
  */
 #ifndef lint
 static const char rcsid[] _U_ =
-    "@(#) $Header: /tcpdump/master/libpcap/pcap-nit.c,v 1.52 2003-11-20 02:02:40 guy Exp $ (LBL)";
+    "@(#) $Header: /tcpdump/master/libpcap/pcap-nit.c,v 1.53 2003-11-21 10:19:35 guy Exp $ (LBL)";
 #endif
 
 #ifdef HAVE_CONFIG_H
@@ -280,6 +280,11 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
                goto bad;
        }
 
+       /*
+        * "handle->fd" is a socket, so "select()" should work on it.
+        */
+       p->selectable_fd = p->fd;
+
        p->read_op = pcap_read_nit;
        p->setfilter_op = install_bpf_program;  /* no kernel filtering */
        p->set_datalink_op = NULL;      /* can't change data link type */
index f2bd1291df50169b43a85293a46af630df1e0ff5..1df621918fc6ff9f0f312b5bd0733dac0f02538f 100644 (file)
--- a/pcap-pf.c
+++ b/pcap-pf.c
@@ -24,7 +24,7 @@
 
 #ifndef lint
 static const char rcsid[] _U_ =
-    "@(#) $Header: /tcpdump/master/libpcap/pcap-pf.c,v 1.81 2003-11-20 02:02:40 guy Exp $ (LBL)";
+    "@(#) $Header: /tcpdump/master/libpcap/pcap-pf.c,v 1.82 2003-11-21 10:19:35 guy Exp $ (LBL)";
 #endif
 
 #ifdef HAVE_CONFIG_H
@@ -434,6 +434,11 @@ your system may not be properly configured; see the packetfilter(4) man page\n",
                goto bad;
        }
 
+       /*
+        * "select()" and "poll()" work on packetfilter devices.
+        */
+       p->selectable_fd = p->fd;
+
        p->read_op = pcap_read_pf;
        p->setfilter_op = pcap_setfilter_pf;
        p->set_datalink_op = NULL;      /* can't change data link type */
index 4c08b166f54f3dcb36dfee406a3306c3b4a07bef..20a688937fc1c7dcaed2a37c95147ec28d8f411f 100644 (file)
@@ -25,7 +25,7 @@
 
 #ifndef lint
 static const char rcsid[] _U_ =
-    "@(#) $Header: /tcpdump/master/libpcap/pcap-snit.c,v 1.68 2003-11-20 02:02:40 guy Exp $ (LBL)";
+    "@(#) $Header: /tcpdump/master/libpcap/pcap-snit.c,v 1.69 2003-11-21 10:19:35 guy Exp $ (LBL)";
 #endif
 
 #ifdef HAVE_CONFIG_H
@@ -338,6 +338,12 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
                goto bad;
        }
 
+       /*
+        * "p->fd" is an FD for a STREAMS device, so "select()" and
+        * "poll()" should work on it.
+        */
+       p->selectable_fd = p->fd;
+
        p->read_op = pcap_read_snit;
        p->setfilter_op = install_bpf_program;  /* no kernel filtering */
        p->set_datalink_op = NULL;      /* can't change data link type */
index 0feaf7e43e70a674057901346697759a6a656642..d216ba9b1a988162057045d90b6167cb8629e5f4 100644 (file)
@@ -20,7 +20,7 @@
  */
 #ifndef lint
 static const char rcsid[] _U_ =
-    "@(#) $Header: /tcpdump/master/libpcap/pcap-snoop.c,v 1.48 2003-11-20 02:02:40 guy Exp $ (LBL)";
+    "@(#) $Header: /tcpdump/master/libpcap/pcap-snoop.c,v 1.49 2003-11-21 10:19:35 guy Exp $ (LBL)";
 #endif
 
 #ifdef HAVE_CONFIG_H
@@ -323,6 +323,11 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
                goto bad;
        }
 
+       /*
+        * "handle->fd" is a socket, so "select()" should work on it.
+        */
+       p->selectable_fd = p->fd;
+
        p->read_op = pcap_read_snoop;
        p->setfilter_op = install_bpf_program;  /* no kernel filtering */
        p->set_datalink_op = NULL;      /* can't change data link type */
diff --git a/pcap.3 b/pcap.3
index 290a994f84b67da6e34c6b9050826587224fcf4f..6f356c0e92860233ab7ee71abe349f162cc58d3b 100644 (file)
--- a/pcap.3
+++ b/pcap.3
@@ -1,4 +1,4 @@
-.\" @(#) $Header: /tcpdump/master/libpcap/Attic/pcap.3,v 1.54 2003-11-18 22:14:24 guy Exp $
+.\" @(#) $Header: /tcpdump/master/libpcap/Attic/pcap.3,v 1.55 2003-11-21 10:19:36 guy Exp $
 .\"
 .\" Copyright (c) 1994, 1996, 1997
 .\"    The Regents of the University of California.  All rights reserved.
@@ -19,7 +19,7 @@
 .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
 .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 .\"
-.TH PCAP 3 "18 November 2003"
+.TH PCAP 3 "21 November 2003"
 .SH NAME
 pcap \- Packet Capture library
 .SH SYNOPSIS
diff --git a/pcap.c b/pcap.c
index aa584cbedf29821a54cb7b43598f3980f8f76227..8dd34b911fa70ca40d7192e8431275c57d5d7812 100644 (file)
--- a/pcap.c
+++ b/pcap.c
@@ -33,7 +33,7 @@
 
 #ifndef lint
 static const char rcsid[] _U_ =
-    "@(#) $Header: /tcpdump/master/libpcap/pcap.c,v 1.68 2003-11-20 02:02:41 guy Exp $ (LBL)";
+    "@(#) $Header: /tcpdump/master/libpcap/pcap.c,v 1.69 2003-11-21 10:19:36 guy Exp $ (LBL)";
 #endif
 
 #ifdef HAVE_CONFIG_H
@@ -500,6 +500,14 @@ pcap_fileno(pcap_t *p)
 #endif
 }
 
+#ifndef WIN32
+int
+pcap_get_selectable_fd(pcap_t *p)
+{
+       return (p->selectable_fd);
+}
+#endif
+
 void
 pcap_perror(pcap_t *p, char *prefix)
 {
diff --git a/pcap.h b/pcap.h
index da05938aa0798583871c0e251a0abe2612524e41..0695c1e09a95111a5f17bcc5631c60c7fd74f222 100644 (file)
--- a/pcap.h
+++ b/pcap.h
@@ -31,7 +31,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * @(#) $Header: /tcpdump/master/libpcap/pcap.h,v 1.47 2003-11-18 22:14:25 guy Exp $ (LBL)
+ * @(#) $Header: /tcpdump/master/libpcap/pcap.h,v 1.48 2003-11-21 10:19:36 guy Exp $ (LBL)
  */
 
 #ifndef lib_pcap_h
@@ -241,6 +241,13 @@ int pcap_setmintocopy(pcap_t *p, int size);
 #define MODE_CAPT 0
 #define MODE_STAT 1
 
+#else
+/*
+ * UN*X definitions
+ */
+
+int    pcap_get_selectable_fd(pcap_t *);
+
 #endif /* WIN32 */
 
 #ifdef __cplusplus
index fa0130b0b76599fe125e6437dce5879fe38a961c..036fc0d1bd1da29689d8870b0b7ecdb23acc0790 100644 (file)
@@ -30,7 +30,7 @@
 
 #ifndef lint
 static const char rcsid[] _U_ =
-    "@(#) $Header: /tcpdump/master/libpcap/savefile.c,v 1.97 2003-11-20 02:02:41 guy Exp $ (LBL)";
+    "@(#) $Header: /tcpdump/master/libpcap/savefile.c,v 1.98 2003-11-21 10:19:37 guy Exp $ (LBL)";
 #endif
 
 #ifdef HAVE_CONFIG_H
@@ -600,6 +600,12 @@ pcap_open_offline(const char *fname, char *errbuf)
                break;
        }
 
+       /*
+        * You can do "select()" and "poll()" on plain files on most
+        * platforms, and should be able to do so on pipes.
+        */
+       p->selectable_fd = fileno(fp);
+
        p->read_op = pcap_offline_read;
        p->setfilter_op = install_bpf_program;
        p->set_datalink_op = NULL;      /* we don't support munging link-layer headers */