]> The Tcpdump Group git mirrors - libpcap/commitdiff
Add a new API to handle some non-select()able devices.
authorGuy Harris <[email protected]>
Sat, 20 Jan 2018 03:39:29 +0000 (19:39 -0800)
committerGuy Harris <[email protected]>
Sat, 20 Jan 2018 03:39:29 +0000 (19:39 -0800)
DAG adapters don't support blocking until packets arrive; a program
using select()/poll()/epoll()/kqueue-based event loop must periodically
poll DAG pcap_t's to see if they have packets available.  Add
pcap_get_required_select_timeout(), which returns a pointer to a struct
timeval containing the appropriate timeout interval if polling is
required and NULL if polling isn't required or isn't supported.

Clean up the pcap_get_selectable_fd() documentation while we're at it.

CMakeLists.txt
Makefile.in
pcap-dag.c
pcap-int.h
pcap.c
pcap/pcap.h
pcap_get_required_select_timeout.3pcap [new file with mode: 0644]
pcap_get_selectable_fd.3pcap

index bf0a4765cf7737cf231f44b18f7941c129bac160..3ec8464ea8e53edf6afcc681149ac6732c2afee1 100644 (file)
@@ -1719,6 +1719,7 @@ set(MAN3PCAP_NOEXPAND
        pcap_fileno.3pcap
        pcap_findalldevs.3pcap
        pcap_freecode.3pcap
+       pcap_get_required_select_timeout.3pcap
        pcap_get_selectable_fd.3pcap
        pcap_geterr.3pcap
        pcap_inject.3pcap
index c3d2a3bdd9c0ca13e5ce110c543cbb0cd90ceee4..79840e22a860260bb799d61686c70b4ecb8f89ff 100644 (file)
@@ -187,6 +187,7 @@ MAN3PCAP_NOEXPAND = \
        pcap_fileno.3pcap \
        pcap_findalldevs.3pcap \
        pcap_freecode.3pcap \
+       pcap_get_required_select_timeout.3pcap \
        pcap_get_selectable_fd.3pcap \
        pcap_geterr.3pcap \
        pcap_inject.3pcap \
index 7046db23e397cea3f7df8ab889dcb701ad442c16..ae37b10c21494e5832306977b4d2fb48e0c2cf33 100644 (file)
@@ -185,6 +185,8 @@ struct pcap_dag {
        int     dag_timeout;    /* timeout specified to pcap_open_live.
                                 * Same as in linux above, introduce
                                 * generally? */
+       struct timeval required_select_timeout;
+                               /* Timeout caller must use in event loops */
 };
 
 typedef struct pcap_dag_node {
@@ -798,6 +800,13 @@ static int dag_activate(pcap_t* p)
                goto faildetach;
        }
 
+       /* Use the poll time as the required select timeout for callers
+        * who are using select()/etc. in an event loop waiting for
+        * packets to arrive.
+        */
+       pd->required_select_timeout = poll;
+       p->required_select_timeout = &pd->required_select_timeout;
+
        /*
         * Turn a negative snapshot value (invalid), a snapshot value of
         * 0 (unspecified), or a value bigger than the normal maximum
index 516b49c3561e02ad2e4e80f00c33c886044fcec4..2af36f1776c79a46282a1a9caa24d5850d3f7c11 100644 (file)
@@ -161,7 +161,6 @@ struct pcap {
        HANDLE handle;
 #else
        int fd;
-       int selectable_fd;
 #endif /* _WIN32 */
 
        /*
@@ -210,7 +209,7 @@ struct pcap {
        u_char *pkt;
 
 #ifdef _WIN32
-       struct pcap_stat stat;          /* used for pcap_stats_ex() */
+       struct pcap_stat stat;  /* used for pcap_stats_ex() */
 #endif
 
        /* We're accepting only packets in this direction/these directions. */
@@ -221,6 +220,23 @@ struct pcap {
         */
        int bpf_codegen_flags;
 
+#ifndef _WIN32
+       int selectable_fd;      /* FD on which select()/poll()/epoll()/kevent()/etc. can be done */
+
+       /*
+        * In case there either is no selectable FD, or there is but
+        * it doesn't necessarily work (e.g., if it doesn't get notified
+        * if the packet capture timeout expires before the buffer
+        * fills up), this points to a timeout that should be used
+        * in select()/poll()/epoll()/kevent() call.  The pcap_t should
+        * be put into non-blocking mode, and, if the timeout expires on
+        * the call, an attempt should be made to read packets from all
+        * pcap_t's with a required timeout, and the code must be
+        * prepared not to see any packets from the attempt.
+        */
+       struct timeval *required_select_timeout;
+#endif
+
        /*
         * Placeholder for filter code if bpf not in kernel.
         */
diff --git a/pcap.c b/pcap.c
index ba2b37fcb2d3cd07c1e378e0b6b13fe688ff8051..5dbdf1a3b86b025681a8a8fa2683a3778694fd7e 100644 (file)
--- a/pcap.c
+++ b/pcap.c
@@ -2099,6 +2099,7 @@ pcap_alloc_pcap_t(char *ebuf, size_t size)
 #else
        p->fd = -1;     /* not opened yet */
        p->selectable_fd = -1;
+       p->required_select_timeout = NULL;
 #endif
 
        if (size == 0) {
@@ -3066,6 +3067,12 @@ pcap_get_selectable_fd(pcap_t *p)
 {
        return (p->selectable_fd);
 }
+
+struct timeval *
+pcap_get_required_select_timeout(pcap_t *p)
+{
+       return (p->required_select_timeout);
+}
 #endif
 
 void
index d32e2a9a74710b0dd17a97b1d46ac3605b58d914..94ca2114d81ca9b2c271ef4eab593bacb2878a53 100644 (file)
@@ -597,6 +597,7 @@ PCAP_API void       bpf_dump(const struct bpf_program *, int);
    */
 
   PCAP_API int pcap_get_selectable_fd(pcap_t *);
+  PCAP_API struct timeval *pcap_get_required_select_timeout(pcap_t *);
 
 #endif /* _WIN32/MSDOS/UN*X */
 
diff --git a/pcap_get_required_select_timeout.3pcap b/pcap_get_required_select_timeout.3pcap
new file mode 100644 (file)
index 0000000..8ef6611
--- /dev/null
@@ -0,0 +1,84 @@
+.\" Copyright (c) 1994, 1996, 1997
+.\"    The Regents of the University of California.  All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that: (1) source code distributions
+.\" retain the above copyright notice and this paragraph in its entirety, (2)
+.\" distributions including binary code include the above copyright notice and
+.\" this paragraph in its entirety in the documentation or other materials
+.\" provided with the distribution, and (3) all advertising materials mentioning
+.\" features or use of this software display the following acknowledgement:
+.\" ``This product includes software developed by the University of California,
+.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
+.\" the University nor the names of its contributors may be used to endorse
+.\" or promote products derived from this software without specific prior
+.\" written permission.
+.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.TH PCAP_GET_REQUIRED_SELECT_TIMEOUT 3PCAP "19 January 2018"
+.SH NAME
+pcap_get_required_select_timeout \- get a file descriptor on which a
+select() can be done for a live capture
+.SH SYNOPSIS
+.nf
+.ft B
+#include <pcap/pcap.h>
+.ft
+.LP
+.ft B
+struct timeval *pcap_get_required_select_timeout(pcap_t *p);
+.ft
+.fi
+.SH DESCRIPTION
+.B pcap_get_required_select_timeout()
+returns, on UNIX, a pointer to a
+.B struct timeval
+containing a value that must be used as the minimum timeout in
+.BR select() ,
+.BR poll() ,
+.BR epoll() ,
+and
+.B kevent()
+calls if
+.B pcap_get_selectable_fd()
+returns \-1.
+.PP
+The timeout that should be used in those calls must be no larger than
+the smallest of all timeouts returned by
+.B pcap_get_required_select_timeout()
+for devices from which packets will be captured.
+.PP
+The device for which
+.B pcap_get_selectable_fd()
+returned \-1 must be put in non-blocking mode with
+.BR pcap_setnonblock() ,
+and an attempt must always be made to read packets from the device
+when the
+.BR select() ,
+.BR poll() ,
+.BR epoll() ,
+or
+.B kevent()
+call returns.
+.PP
+Note that a device on which a read can be done without blocking may,
+on some platforms, not have any packets to read if the packet buffer
+timeout has expired.  A call to
+.B pcap_dispatch()
+or
+.B pcap_next_ex()
+will return 0 in this case, but will not block.
+.PP
+.B pcap_get_required_select_timeout()
+is not available on Windows.
+.SH RETURN VALUE
+A pointer to a
+.B struct timeval
+is returned if the timeout is required; otherwise
+.B NULL
+is returned.
+.SH SEE ALSO
+pcap(3PCAP), pcap_get_selectable_fd(3PCAP), select(2), poll(2),
+epoll(2), kqueue(2)
index aa457a23d9c341269c04a5f8436c07824670f1cd..c1c617c7da39c2eff772e362eaf761391838c9c5 100644 (file)
@@ -38,26 +38,41 @@ which one can
 do a
 .BR select() ,
 .BR poll() ,
+.BR epoll() ,
+.BR kevent() ,
 or other such call
 to wait for it to be possible to read packets without blocking, if such
-a descriptor exists, or \-1, if no such descriptor exists.  Some network
-devices opened with
+a descriptor exists, or \-1, if no such descriptor exists.
+.PP
+Some network devices opened with
 .B pcap_create()
 and
 .BR pcap_activate() ,
 or with
 .BR pcap_open_live() ,
-do not support
-.B select()
-or
-.B poll()
-(for example, regular network devices on FreeBSD 4.3 and 4.4, and Endace
-DAG devices), so \-1 is returned for those devices.
+do not support those calls (for example, regular network devices on
+FreeBSD 4.3 and 4.4, and Endace DAG devices), so \-1 is returned for
+those devices.  In that case, those calls must be given a timeout less
+than or equal to the timeout returned by
+.B pcap_get_required_select_timeout()
+for the device for which
+.B pcap_get_selectable_fd()
+returned \-1, the device must be put in non-blocking mode with a call to
+.BR pcap_setnonblock() ,
+and an attempt must always be made to read packets from the device
+when the call returns.  If
+.B pcap_get_required_select_timeout()
+returns
+.BR NULL ,
+it is not possible to wait for packets to arrive on the device in an
+event loop.
 .PP
-Note that a descriptor on which a read can be done without blocking may,
+Note that a device on which a read can be done without blocking may,
 on some platforms, not have any packets to read if the packet buffer
 timeout has expired.  A call to
 .B pcap_dispatch()
+or
+.B pcap_next_ex()
 will return 0 in this case, but will not block.
 .PP
 Note that in:
@@ -70,59 +85,55 @@ OpenBSD prior to OpenBSD 2.4;
 .IP
 Mac OS X prior to Mac OS X 10.7;
 .PP
-.B select()
+.BR select() ,
+.BR poll() ,
 and
-.B poll()
+.B kevent()
 do not work correctly on BPF devices;
 .B pcap_get_selectable_fd()
 will return a file descriptor on most of those versions (the exceptions
 being FreeBSD 4.3 and 4.4), but a simple
-.B select()
-or
-.B poll()
-will not indicate that the descriptor is readable until a full buffer's
-worth of packets is received, even if the packet timeout expires before
-then.  To work around this, an application that uses
-.B select()
+.BR select() ,
+.BR poll() ,
 or
-.B poll()
-to wait for packets to arrive must put the
+.B kevent()
+call will not indicate that the descriptor is readable until a full
+buffer's worth of packets is received, even if the packet timeout
+expires before then.  To work around this, code that uses
+those calls to wait for packets to arrive must put the
 .B pcap_t
-in non-blocking mode, and must arrange that the
-.B select()
-or
-.B poll()
+in non-blocking mode, and must arrange that the call
 have a timeout less than or equal to the packet buffer timeout,
 and must try to read packets after that timeout expires, regardless of
-whether
-.B select()
-or
-.B poll()
-indicated that the file descriptor for the
+whether the call indicated that the file descriptor for the
 .B pcap_t
 is ready to be read or not.  (That workaround will not work in FreeBSD
-4.3 and later; however, in FreeBSD 4.6 and later,
-.B select()
-and
-.B poll()
+4.3 and later; however, in FreeBSD 4.6 and later, those calls
 work correctly on BPF devices, so the workaround isn't necessary,
 although it does no harm.)
 .PP
 Note also that
 .B poll()
+and
+.B kevent()
 doesn't work on character special files, including BPF devices, in Mac
 OS X 10.4 and 10.5, so, while
 .B select()
 can be used on the descriptor returned by
 .BR pcap_get_selectable_fd() ,
 .B poll()
-cannot be used on it those versions of Mac OS X.  Kqueues also don't
-work on that descriptor.
+and
+.B kevent()
+cannot be used on it those versions of Mac OS X.
 .BR poll() ,
-but not kqueues, work on that descriptor in Mac OS X releases prior to
+but not
+.BR kevent() ,
+works on that descriptor in Mac OS X releases prior to
 10.4;
 .B poll()
-and kqueues work on that descriptor in Mac OS X 10.6 and later.
+and
+.B kevent()
+work on that descriptor in Mac OS X 10.6 and later.
 .PP
 .B pcap_get_selectable_fd()
 is not available on Windows.
@@ -130,4 +141,5 @@ is not available on Windows.
 A selectable file descriptor is returned if one exists; otherwise, \-1
 is returned.
 .SH SEE ALSO
-pcap(3PCAP), select(2), poll(2)
+pcap(3PCAP), pcap_get_required_select_timeout(3PCAP),
+pcap_setnonblock(3PCAP), select(2), poll(2), epoll(2), kqueue(2)