]> 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_ =
  */
 #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
 #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/socket.h>
 #include <sys/file.h>
 #include <sys/ioctl.h>
+#include <sys/utsname.h>
 
 #include <net/if.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;
 #endif
        u_int v;
        pcap_t *p;
+       struct utsname osinfo;
 
 #ifdef HAVE_DAG_API
        if (strstr(device, "dag")) {
 
 #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
 
        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;
        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_ =
 
 #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
 #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;
   }
 
        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
 #ifdef linux
   handle->md.device = (char *)device;
 #else
index 4a9eafd4c516162137702e59fc637723e827d167..1e7055b6e603ec7a69a566294a99c6d2ea90cfb4 100644 (file)
@@ -38,7 +38,7 @@
 
 #ifndef lint
 static const char rcsid[] _U_ =
 
 #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
 #endif
 
 #ifdef HAVE_CONFIG_H
@@ -704,6 +704,12 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
                goto bad;
        }
 
                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 */
        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.
  *
  * 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
  */
 
 #ifndef pcap_int_h
@@ -101,6 +101,7 @@ struct pcap {
        int nonblock;
 #else
        int fd;
        int nonblock;
 #else
        int fd;
+       int selectable_fd;
 #endif /* WIN32 */
        int snapshot;
        int linktype;
 #endif /* WIN32 */
        int snapshot;
        int linktype;
index b59d4ed234f89c4f950fd21359f77aa4620eec0a..50883b66738e068345cd4b26d8aea063a173077f 100644 (file)
@@ -27,7 +27,7 @@
 
 #ifndef lint
 static const char rcsid[] _U_ =
 
 #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
 
 /*
 #endif
 
 /*
@@ -397,6 +397,12 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
                return NULL;
        }
 
                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 */
        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_ =
  */
 #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
 #endif
 
 #ifdef HAVE_CONFIG_H
@@ -280,6 +280,11 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
                goto bad;
        }
 
                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 */
        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_ =
 
 #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
 #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;
        }
 
                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 */
        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_ =
 
 #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
 #endif
 
 #ifdef HAVE_CONFIG_H
@@ -338,6 +338,12 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
                goto bad;
        }
 
                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 */
        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_ =
  */
 #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
 #endif
 
 #ifdef HAVE_CONFIG_H
@@ -323,6 +323,11 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
                goto bad;
        }
 
                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 */
        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.
 .\"
 .\" 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.
 .\"
 .\" 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
 .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_ =
 
 #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
 #endif
 
 #ifdef HAVE_CONFIG_H
@@ -500,6 +500,14 @@ pcap_fileno(pcap_t *p)
 #endif
 }
 
 #endif
 }
 
+#ifndef WIN32
+int
+pcap_get_selectable_fd(pcap_t *p)
+{
+       return (p->selectable_fd);
+}
+#endif
+
 void
 pcap_perror(pcap_t *p, char *prefix)
 {
 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.
  *
  * 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
  */
 
 #ifndef lib_pcap_h
@@ -241,6 +241,13 @@ int pcap_setmintocopy(pcap_t *p, int size);
 #define MODE_CAPT 0
 #define MODE_STAT 1
 
 #define MODE_CAPT 0
 #define MODE_STAT 1
 
+#else
+/*
+ * UN*X definitions
+ */
+
+int    pcap_get_selectable_fd(pcap_t *);
+
 #endif /* WIN32 */
 
 #ifdef __cplusplus
 #endif /* WIN32 */
 
 #ifdef __cplusplus
index fa0130b0b76599fe125e6437dce5879fe38a961c..036fc0d1bd1da29689d8870b0b7ecdb23acc0790 100644 (file)
@@ -30,7 +30,7 @@
 
 #ifndef lint
 static const char rcsid[] _U_ =
 
 #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
 #endif
 
 #ifdef HAVE_CONFIG_H
@@ -600,6 +600,12 @@ pcap_open_offline(const char *fname, char *errbuf)
                break;
        }
 
                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 */
        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 */