]> The Tcpdump Group git mirrors - libpcap/commitdiff
Support setting non-blocking mode before activating.
authorGuy Harris <[email protected]>
Sun, 26 Feb 2017 01:10:42 +0000 (17:10 -0800)
committerGuy Harris <[email protected]>
Sun, 26 Feb 2017 01:10:42 +0000 (17:10 -0800)
We just set a flag and attempt to set non-blocking mode after
activating.

If a module can't support non-blocking mode, it should set the set
non-blocking operator in the create routine, so a pre-activation call
will fail the same way a post-activation call fails.

While we're at it:

Have the get non-blocking and set non-blocking modes not take an error
buffer as an argument; they have the error buffer in the pcap_t to set.
pcap_getnonblock() and pcap_setnonblock() just copy the error from there
to the argument passed in.

Make sure we set the cleanup op pointer when appropriate.

12 files changed:
pcap-bpf.c
pcap-dag.c
pcap-dbus.c
pcap-dos.c
pcap-int.h
pcap-linux.c
pcap-septel.c
pcap-snf.c
pcap-tc.c
pcap-win32.c
pcap.c
savefile.c

index d4f5523864da1d67097613ae2c1f5d3b39bf9105..5e3fe31a31cde5c99f664d324a224669e59a3015 100644 (file)
@@ -252,7 +252,7 @@ static int pcap_set_datalink_bpf(pcap_t *p, int dlt);
  * blocking mode.
  */
 static int
-pcap_getnonblock_bpf(pcap_t *p, char *errbuf)
+pcap_getnonblock_bpf(pcap_t *p)
 {
 #ifdef HAVE_ZEROCOPY_BPF
        struct pcap_bpf *pb = p->priv;
@@ -260,11 +260,11 @@ pcap_getnonblock_bpf(pcap_t *p, char *errbuf)
        if (pb->zerocopy)
                return (pb->nonblock);
 #endif
-       return (pcap_getnonblock_fd(p, errbuf));
+       return (pcap_getnonblock_fd(p));
 }
 
 static int
-pcap_setnonblock_bpf(pcap_t *p, int nonblock, char *errbuf)
+pcap_setnonblock_bpf(pcap_t *p, int nonblock)
 {
 #ifdef HAVE_ZEROCOPY_BPF
        struct pcap_bpf *pb = p->priv;
@@ -274,7 +274,7 @@ pcap_setnonblock_bpf(pcap_t *p, int nonblock, char *errbuf)
                return (0);
        }
 #endif
-       return (pcap_setnonblock_fd(p, nonblock, errbuf));
+       return (pcap_setnonblock_fd(p, nonblock));
 }
 
 #ifdef HAVE_ZEROCOPY_BPF
index 6a6019b5a5e6851441a867a13ab1bea21f9ca97e..d9a03b51a1299828ca621b5b9b4f12cea1621f1d 100644 (file)
@@ -214,7 +214,7 @@ static int dag_setfilter(pcap_t *p, struct bpf_program *fp);
 static int dag_stats(pcap_t *p, struct pcap_stat *ps);
 static int dag_set_datalink(pcap_t *p, int dlt);
 static int dag_get_datalink(pcap_t *p);
-static int dag_setnonblock(pcap_t *p, int nonblock, char *errbuf);
+static int dag_setnonblock(pcap_t *p, int nonblock);
 
 static void
 delete_pcap_dag(pcap_t *p)
@@ -1129,7 +1129,7 @@ dag_set_datalink(pcap_t *p, int dlt)
 }
 
 static int
-dag_setnonblock(pcap_t *p, int nonblock, char *errbuf)
+dag_setnonblock(pcap_t *p, int nonblock)
 {
        struct pcap_dag *pd = p->priv;
        dag_size_t mindata;
@@ -1142,12 +1142,12 @@ dag_setnonblock(pcap_t *p, int nonblock, char *errbuf)
         * and have a "dag_getnonblock()" function that looks at
         * "pd->dag_flags".
         */
-       if (pcap_setnonblock_fd(p, nonblock, errbuf) < 0)
+       if (pcap_setnonblock_fd(p, nonblock) < 0)
                return (-1);
 
        if (dag_get_stream_poll64(p->fd, pd->dag_stream,
                                &mindata, &maxwait, &poll) < 0) {
-               pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "dag_get_stream_poll: %s", pcap_strerror(errno));
+               pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "dag_get_stream_poll: %s", pcap_strerror(errno));
                return -1;
        }
 
@@ -1162,7 +1162,7 @@ dag_setnonblock(pcap_t *p, int nonblock, char *errbuf)
 
        if (dag_set_stream_poll64(p->fd, pd->dag_stream,
                                mindata, &maxwait, &poll) < 0) {
-               pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "dag_set_stream_poll: %s", pcap_strerror(errno));
+               pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "dag_set_stream_poll: %s", pcap_strerror(errno));
                return -1;
        }
 
index 41f50411245b0f692c1cc770ddd8abd4df7eb5aa..ea3a390ff55c0ab8f65d7dbc0e72e6e198cefa7f 100644 (file)
@@ -211,6 +211,7 @@ dbus_activate(pcap_t *handle)
        handle->getnonblock_op = pcap_getnonblock_fd;
        handle->setnonblock_op = pcap_setnonblock_fd;
        handle->stats_op = dbus_stats;
+       handle->cleanup_op = dbus_cleanup;
 
        handle->selectable_fd = handle->fd = -1;
 
index 457db72a6a94c38690c0c5b90e1039c95ef6011c..60e9d890464f56627557351b6495e932a9f80b69 100644 (file)
@@ -197,6 +197,7 @@ static int pcap_activate_dos (pcap_t *pcap)
     if (!init_watt32(pcap, pcap->opt.device, pcap->errbuf) ||
         !first_init(pcap->opt.device, pcap->errbuf, pcap->opt.promisc))
     {
+      /* XXX - free pcap->buffer? */
       return (PCAP_ERROR);
     }
     atexit (close_driver);
@@ -206,6 +207,7 @@ static int pcap_activate_dos (pcap_t *pcap)
     pcap_snprintf (pcap->errbuf, PCAP_ERRBUF_SIZE,
                    "Cannot use different devices simultaneously "
                    "(`%s' vs. `%s')", active_dev->name, pcap->opt.device);
+    /* XXX - free pcap->buffer? */
     return (PCAP_ERROR);
   }
   handle_to_device [pcap->fd-1] = active_dev;
@@ -467,6 +469,7 @@ static void pcap_cleanup_dos (pcap_t *p)
        return;
   }
   close_driver();
+  /* XXX - call pcap_cleanup_live_common? */
 }
 
 /*
index c4791aee2a622760fd7d4898f71d0509ce2a782c..5c8c1297ba5b84c449dc2ae71c7649de9f0c1af0 100644 (file)
@@ -114,6 +114,7 @@ struct pcap_opt {
        int     promisc;
        int     rfmon;          /* monitor mode */
        int     immediate;      /* immediate mode - deliver packets as soon as they arrive */
+       int     nonblock;       /* non-blocking mode - don't wait for packets to be delivered, return "no packets available" */
        int     tstamp_type;
        int     tstamp_precision;
 };
@@ -125,8 +126,8 @@ typedef int (*inject_op_t)(pcap_t *, const void *, size_t);
 typedef int    (*setfilter_op_t)(pcap_t *, struct bpf_program *);
 typedef int    (*setdirection_op_t)(pcap_t *, pcap_direction_t);
 typedef int    (*set_datalink_op_t)(pcap_t *, int);
-typedef int    (*getnonblock_op_t)(pcap_t *, char *);
-typedef int    (*setnonblock_op_t)(pcap_t *, int, char *);
+typedef int    (*getnonblock_op_t)(pcap_t *);
+typedef int    (*setnonblock_op_t)(pcap_t *, int);
 typedef int    (*stats_op_t)(pcap_t *, struct pcap_stat *);
 #ifdef _WIN32
 typedef struct pcap_stat *(*stats_ex_op_t)(pcap_t *, int *);
@@ -378,8 +379,8 @@ int pcap_offline_read(pcap_t *, int, pcap_handler, u_char *);
  * Routines that most pcap implementations can use for non-blocking mode.
  */
 #if !defined(_WIN32) && !defined(MSDOS)
-int    pcap_getnonblock_fd(pcap_t *, char *);
-int    pcap_setnonblock_fd(pcap_t *p, int, char *);
+int    pcap_getnonblock_fd(pcap_t *);
+int    pcap_setnonblock_fd(pcap_t *p, int);
 #endif
 
 /*
index 4ba90a8007cb31401ceb897a074bbbba898a3f5b..ee8d3ee4f122be6d89fab8ba1f4eaca0eacf78ce 100644 (file)
@@ -404,8 +404,8 @@ static int pcap_read_linux_mmap_v2(pcap_t *, int, pcap_handler , u_char *);
 static int pcap_read_linux_mmap_v3(pcap_t *, int, pcap_handler , u_char *);
 #endif
 static int pcap_setfilter_linux_mmap(pcap_t *, struct bpf_program *);
-static int pcap_setnonblock_mmap(pcap_t *p, int nonblock, char *errbuf);
-static int pcap_getnonblock_mmap(pcap_t *p, char *errbuf);
+static int pcap_setnonblock_mmap(pcap_t *p, int nonblock);
+static int pcap_getnonblock_mmap(pcap_t *p);
 static void pcap_oneshot_mmap(u_char *user, const struct pcap_pkthdr *h,
     const u_char *bytes);
 #endif
@@ -4468,7 +4468,7 @@ pcap_cleanup_linux_mmap( pcap_t *handle )
 
 
 static int
-pcap_getnonblock_mmap(pcap_t *p, char *errbuf)
+pcap_getnonblock_mmap(pcap_t *p)
 {
        struct pcap_linux *handlep = p->priv;
 
@@ -4477,7 +4477,7 @@ pcap_getnonblock_mmap(pcap_t *p, char *errbuf)
 }
 
 static int
-pcap_setnonblock_mmap(pcap_t *p, int nonblock, char *errbuf)
+pcap_setnonblock_mmap(pcap_t *p, int nonblock)
 {
        struct pcap_linux *handlep = p->priv;
 
@@ -4485,7 +4485,7 @@ pcap_setnonblock_mmap(pcap_t *p, int nonblock, char *errbuf)
         * Set the file descriptor to non-blocking mode, as we use
         * it for sending packets.
         */
-       if (pcap_setnonblock_fd(p, nonblock, errbuf) == -1)
+       if (pcap_setnonblock_fd(p, nonblock) == -1)
                return -1;
 
        /*
index dc120dd5dbf7355f994d8f59d158184ddb4fa1cc..8d7b5555b885bb2514107982102ab5ed00c65110 100644 (file)
@@ -43,7 +43,7 @@
 
 static int septel_setfilter(pcap_t *p, struct bpf_program *fp);
 static int septel_stats(pcap_t *p, struct pcap_stat *ps);
-static int septel_setnonblock(pcap_t *p, int nonblock, char *errbuf);
+static int septel_setnonblock(pcap_t *p, int nonblock);
 
 /*
  * Private data for capturing on Septel devices.
@@ -237,6 +237,7 @@ pcap_t *septel_create(const char *device, char *ebuf, int *is_ours) {
                return NULL;
 
        p->activate_op = septel_activate;
+       p->setnonblock_op = septel_setnonblock; /* not supported */
        return p;
 }
 
@@ -287,9 +288,9 @@ static int septel_setfilter(pcap_t *p, struct bpf_program *fp) {
 
 
 static int
-septel_setnonblock(pcap_t *p, int nonblock, char *errbuf)
+septel_setnonblock(pcap_t *p, int nonblock)
 {
-  fprintf(errbuf, PCAP_ERRBUF_SIZE, "Non-blocking mode not supported on Septel devices");
+  fprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Non-blocking mode not supported on Septel devices");
   return (-1);
 }
 
index ca0f31785477cfc706c55068aaf12bc8ac341659..0668d0fe839d0ac29f11ac8e90e2cbbb5b5c3ddf 100644 (file)
@@ -76,7 +76,7 @@ snf_platform_cleanup(pcap_t *p)
 }
 
 static int
-snf_getnonblock(pcap_t *p, char *errbuf)
+snf_getnonblock(pcap_t *p)
 {
        struct pcap_snf *ps = p->priv;
 
@@ -84,7 +84,7 @@ snf_getnonblock(pcap_t *p, char *errbuf)
 }
 
 static int
-snf_setnonblock(pcap_t *p, int nonblock, char *errbuf)
+snf_setnonblock(pcap_t *p, int nonblock)
 {
        struct pcap_snf *ps = p->priv;
 
index 1a51a0c3bb27bd4d40901e9d51bff2050408d07e..bedb4f6eb070073725e4774bd6d3fb5a45eef2a6 100644 (file)
--- a/pcap-tc.c
+++ b/pcap-tc.c
@@ -120,8 +120,8 @@ typedef struct _TC_FUNCTIONS
 
 static pcap_if_t* TcCreatePcapIfFromPort(TC_PORT port);
 static int TcSetDatalink(pcap_t *p, int dlt);
-static int TcGetNonBlock(pcap_t *p, char *errbuf);
-static int TcSetNonBlock(pcap_t *p, int nonblock, char *errbuf);
+static int TcGetNonBlock(pcap_t *p);
+static int TcSetNonBlock(pcap_t *p, int nonblock);
 static void TcCleanup(pcap_t *p);
 static int TcInject(pcap_t *p, const void *buf, size_t size);
 static int TcRead(pcap_t *p, int cnt, pcap_handler callback, u_char *user);
@@ -765,6 +765,7 @@ TcCreate(const char *device, char *ebuf, int *is_ours)
                return NULL;
 
        p->activate_op = TcActivate;
+       p->setnonblock_op = TcSetNonBlock; /* not supported */
        return p;
 }
 
@@ -776,21 +777,17 @@ static int TcSetDatalink(pcap_t *p, int dlt)
        return 0;
 }
 
-static int TcGetNonBlock(pcap_t *p, char *errbuf)
+static int TcGetNonBlock(pcap_t *p)
 {
        pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
                    "Getting the non blocking status is not available for TurboCap ports");
-       pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
-                   "Getting the non blocking status is not available for TurboCap ports");
                return -1;
 
 }
-static int TcSetNonBlock(pcap_t *p, int nonblock, char *errbuf)
+static int TcSetNonBlock(pcap_t *p, int nonblock)
 {
        pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
                    "Setting the non blocking status is not available for TurboCap ports");
-       pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
-                   "Setting the non blocking status is not available for TurboCap ports");
                return -1;
 }
 
index 2f658e4f859fb2ed7908cdde3751fc6aae70b9cb..16cb696e2c07a9dc4203f10ea8b8bce5d27dbbd5 100644 (file)
@@ -59,8 +59,8 @@ int* _errno();
 
 static int pcap_setfilter_win32_npf(pcap_t *, struct bpf_program *);
 static int pcap_setfilter_win32_dag(pcap_t *, struct bpf_program *);
-static int pcap_getnonblock_win32(pcap_t *, char *);
-static int pcap_setnonblock_win32(pcap_t *, int, char *);
+static int pcap_getnonblock_win32(pcap_t *);
+static int pcap_setnonblock_win32(pcap_t *, int);
 
 /*dimension of the buffer in the pcap_t structure*/
 #define        WIN32_DEFAULT_USER_BUFFER_SIZE 256000
@@ -1300,7 +1300,7 @@ pcap_setfilter_win32_dag(pcap_t *p, struct bpf_program *fp) {
 }
 
 static int
-pcap_getnonblock_win32(pcap_t *p, char *errbuf)
+pcap_getnonblock_win32(pcap_t *p)
 {
        struct pcap_win *pw = p->priv;
 
@@ -1313,7 +1313,7 @@ pcap_getnonblock_win32(pcap_t *p, char *errbuf)
 }
 
 static int
-pcap_setnonblock_win32(pcap_t *p, int nonblock, char *errbuf)
+pcap_setnonblock_win32(pcap_t *p, int nonblock)
 {
        struct pcap_win *pw = p->priv;
        int newtimeout;
@@ -1338,7 +1338,7 @@ pcap_setnonblock_win32(pcap_t *p, int nonblock, char *errbuf)
        }
        if (!PacketSetReadTimeout(p->adapter, newtimeout)) {
                pcap_win32_err_to_str(GetLastError(), win_errbuf);
-               pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+               pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
                    "PacketSetReadTimeout: %s", win_errbuf);
                return (-1);
        }
diff --git a/pcap.c b/pcap.c
index f67dc016d0f3b54e16eaee2ab8993fdae0a87e4b..3cf4afa2f1b627abd72315d198220b2aabbdfdb3 100644 (file)
--- a/pcap.c
+++ b/pcap.c
@@ -1196,6 +1196,18 @@ pcap_create(const char *device, char *errbuf)
        return (p);
 }
 
+/*
+ * Set nonblocking mode on an unactivated pcap_t; this sets a flag
+ * checked by pcap_activate(), which sets the mode after calling
+ * the activate routine.
+ */
+static int
+pcap_setnonblock_unactivated(pcap_t *p, int nonblock)
+{
+       p->opt.nonblock = nonblock;
+       return (0);
+}
+
 static void
 initialize_ops(pcap_t *p)
 {
@@ -1210,7 +1222,6 @@ initialize_ops(pcap_t *p)
        p->setdirection_op = (setdirection_op_t)pcap_not_initialized;
        p->set_datalink_op = (set_datalink_op_t)pcap_not_initialized;
        p->getnonblock_op = (getnonblock_op_t)pcap_not_initialized;
-       p->setnonblock_op = (setnonblock_op_t)pcap_not_initialized;
        p->stats_op = (stats_op_t)pcap_not_initialized;
 #ifdef _WIN32
        p->stats_ex_op = (stats_ex_op_t)pcap_not_initialized_ptr;
@@ -1302,6 +1313,13 @@ pcap_create_common(char *ebuf, size_t size)
         */
        p->can_set_rfmon_op = pcap_cant_set_rfmon;
 
+       /*
+        * If pcap_setnonblock() is called on a not-yet-activated
+        * pcap_t, default to setting a flag and turning
+        * on non-blocking mode when activated.
+        */
+       p->setnonblock_op = pcap_setnonblock_unactivated;
+
        initialize_ops(p);
 
        /* put in some defaults*/
@@ -1518,9 +1536,25 @@ pcap_activate(pcap_t *p)
        if (pcap_check_activated(p))
                return (PCAP_ERROR_ACTIVATED);
        status = p->activate_op(p);
-       if (status >= 0)
+       if (status >= 0) {
+               /*
+                * If somebody requested non-blocking mode before
+                * calling pcap_activate(), turn it on now.
+                */
+               if (p->opt.nonblock) {
+                       status = p->setnonblock_op(p, 1);
+                       if (status < 0) {
+                               /*
+                                * Failed.  Undo everything done by
+                                * the activate operation.
+                                */
+                               p->cleanup_op(p);
+                               initialize_ops(p);
+                               return (status);
+                       }
+               }
                p->activated = 1;
-       else {
+       else {
                if (p->errbuf[0] == '\0') {
                        /*
                         * No error message supplied by the activate routine;
@@ -2172,14 +2206,18 @@ pcap_getnonblock(pcap_t *p, char *errbuf)
 {
        int ret;
 
-       ret = p->getnonblock_op(p, errbuf);
+       ret = p->getnonblock_op(p);
        if (ret == -1) {
                /*
-                * In case somebody depended on the bug wherein
-                * the error message was put into p->errbuf
-                * by pcap_getnonblock_fd().
+                * The get nonblock operation sets p->errbuf; this
+                * function *shouldn't* have had a separate errbuf
+                * argument, as it didn't need one, but I goofed
+                * when adding it.
+                *
+                * We copy the error message to errbuf, so callers
+                * can find it in either place.
                 */
-               strlcpy(p->errbuf, errbuf, PCAP_ERRBUF_SIZE);
+               strlcpy(errbuf, p->errbuf, PCAP_ERRBUF_SIZE);
        }
        return (ret);
 }
@@ -2190,13 +2228,13 @@ pcap_getnonblock(pcap_t *p, char *errbuf)
  */
 #if !defined(_WIN32) && !defined(MSDOS)
 int
-pcap_getnonblock_fd(pcap_t *p, char *errbuf)
+pcap_getnonblock_fd(pcap_t *p)
 {
        int fdflags;
 
        fdflags = fcntl(p->fd, F_GETFL, 0);
        if (fdflags == -1) {
-               pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "F_GETFL: %s",
+               pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "F_GETFL: %s",
                    pcap_strerror(errno));
                return (-1);
        }
@@ -2212,14 +2250,18 @@ pcap_setnonblock(pcap_t *p, int nonblock, char *errbuf)
 {
        int ret;
 
-       ret = p->setnonblock_op(p, nonblock, errbuf);
+       ret = p->setnonblock_op(p, nonblock);
        if (ret == -1) {
                /*
-                * In case somebody depended on the bug wherein
-                * the error message was put into p->errbuf
-                * by pcap_setnonblock_fd().
+                * The set nonblock operation sets p->errbuf; this
+                * function *shouldn't* have had a separate errbuf
+                * argument, as it didn't need one, but I goofed
+                * when adding it.
+                *
+                * We copy the error message to errbuf, so callers
+                * can find it in either place.
                 */
-               strlcpy(p->errbuf, errbuf, PCAP_ERRBUF_SIZE);
+               strlcpy(errbuf, p->errbuf, PCAP_ERRBUF_SIZE);
        }
        return (ret);
 }
@@ -2232,13 +2274,13 @@ pcap_setnonblock(pcap_t *p, int nonblock, char *errbuf)
  * needs to do some additional work.)
  */
 int
-pcap_setnonblock_fd(pcap_t *p, int nonblock, char *errbuf)
+pcap_setnonblock_fd(pcap_t *p, int nonblock)
 {
        int fdflags;
 
        fdflags = fcntl(p->fd, F_GETFL, 0);
        if (fdflags == -1) {
-               pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "F_GETFL: %s",
+               pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "F_GETFL: %s",
                    pcap_strerror(errno));
                return (-1);
        }
@@ -2247,7 +2289,7 @@ pcap_setnonblock_fd(pcap_t *p, int nonblock, char *errbuf)
        else
                fdflags &= ~O_NONBLOCK;
        if (fcntl(p->fd, F_SETFL, fdflags) == -1) {
-               pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "F_SETFL: %s",
+               pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "F_SETFL: %s",
                    pcap_strerror(errno));
                return (-1);
        }
index 247338c5b879ba234012691a33f024ef5d53bba6..f63b45b30f3dc0641df0aed534a0300fecb001b0 100644 (file)
@@ -92,7 +92,7 @@ static pcap_t *pcap_fopen_offline(FILE *, char *);
 #endif
 
 static int
-sf_getnonblock(pcap_t *p, char *errbuf)
+sf_getnonblock(pcap_t *p)
 {
        /*
         * This is a savefile, not a live capture file, so never say
@@ -102,7 +102,7 @@ sf_getnonblock(pcap_t *p, char *errbuf)
 }
 
 static int
-sf_setnonblock(pcap_t *p, int nonblock, char *errbuf)
+sf_setnonblock(pcap_t *p, int nonblock)
 {
        /*
         * This is a savefile, not a live capture file, so reject