From: Joan Lledó <[email protected]>

---
 pcap-hurd.c | 139 ++++++++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 124 insertions(+), 15 deletions(-)

diff --git a/pcap-hurd.c b/pcap-hurd.c
index 134a109b..fde0256b 100644
--- a/pcap-hurd.c
+++ b/pcap-hurd.c
@@ -7,16 +7,18 @@
 
 #include <fcntl.h>
 #include <hurd.h>
-#include <mach.h>
 #include <time.h>
 #include <errno.h>
+#include <pthread.h>
 #include <stdio.h>
 #include <stddef.h>
 #include <stdlib.h>
 #include <string.h>
+#include <unistd.h>
 #include <device/device.h>
 #include <device/device_types.h>
 #include <device/net_status.h>
+#include <hurd/ports.h>
 #include <net/if_ether.h>
 
 #include "pcap-int.h"
@@ -26,6 +28,8 @@ struct pcap_hurd {
        device_t mach_dev;
        mach_port_t rcv_port;
        int filtering_in_kernel;
+       pthread_t pipe_thread_id;
+       int pipefd[2];
 };
 
 /* Accept all packets. */
@@ -126,11 +130,11 @@ pcap_read_hurd(pcap_t *p, int cnt _U_, pcap_handler 
callback, u_char *user)
        struct pcap_hurd *ph;
        struct pcap_pkthdr h;
        struct timespec ts;
-       int wirelen, caplen;
+       int wirelen, caplen, rpipe, ret;
        u_char *pkt;
-       kern_return_t kr;
 
        ph = p->priv;
+       rpipe = ph->pipefd[0];
        msg = (struct net_rcv_msg *)p->buffer;
 
 retry:
@@ -139,19 +143,16 @@ retry:
                return PCAP_ERROR_BREAK;
        }
 
-       kr = mach_msg(&msg->msg_hdr, MACH_RCV_MSG | MACH_RCV_INTERRUPT, 0,
-                     p->bufsize, ph->rcv_port, MACH_MSG_TIMEOUT_NONE,
-                     MACH_PORT_NULL);
-       clock_gettime(CLOCK_REALTIME, &ts);
-
-       if (kr) {
-               if (kr == MACH_RCV_INTERRUPTED)
-                       goto retry;
-
-               pcapint_fmt_errmsg_for_kern_return_t(p->errbuf, 
PCAP_ERRBUF_SIZE, kr,
-                   "mach_msg");
+       ret = read(rpipe, &msg->msg_hdr, p->bufsize);
+       if (ret < 0) {
+               pcapint_fmt_errmsg_for_kern_return_t(p->errbuf,
+                       PCAP_ERRBUF_SIZE, errno, "read");
                return PCAP_ERROR;
        }
+       if (ret == 0)
+               /* Pipe closed, 0 packets read */
+               return 0;
+       clock_gettime(CLOCK_REALTIME, &ts);
 
        ph->stat.ps_recv++;
 
@@ -212,7 +213,7 @@ pcap_inject_hurd(pcap_t *p, const void *buf, int size)
        if (kr) {
                pcapint_fmt_errmsg_for_kern_return_t(p->errbuf, 
PCAP_ERRBUF_SIZE, kr,
                    "device_write");
-               return -1;
+               return PCAP_ERROR;
        }
 
        return count;
@@ -232,9 +233,34 @@ static void
 pcap_cleanup_hurd(pcap_t *p)
 {
        struct pcap_hurd *ph;
+       int err;
 
        ph = p->priv;
 
+       /* Cancel the thread */
+       if (ph->pipe_thread_id != 0) {
+               pthread_cancel(ph->pipe_thread_id);
+
+               err = pthread_join(ph->pipe_thread_id, NULL);
+               if (err != 0) {
+                       pcapint_fmt_errmsg_for_errno(p->errbuf,
+                               PCAP_ERRBUF_SIZE, err, "pthread_join");
+               }
+               ph->pipe_thread_id = 0;
+       }
+
+       /* Close the pipe ends */
+       if (ph->pipefd[1] != -1) {
+               close(ph->pipefd[1]);
+               ph->pipefd[1] = -1;
+       }
+
+       if (ph->pipefd[0] != -1) {
+               close(ph->pipefd[0]);
+               ph->pipefd[0] = -1;
+       }
+
+       /* Release remaining resources */
        if (ph->rcv_port != MACH_PORT_NULL) {
                mach_port_deallocate(mach_task_self(), ph->rcv_port);
                ph->rcv_port = MACH_PORT_NULL;
@@ -242,12 +268,83 @@ pcap_cleanup_hurd(pcap_t *p)
 
        if (ph->mach_dev != MACH_PORT_NULL) {
                device_close(ph->mach_dev);
+               mach_port_deallocate(mach_task_self(), ph->mach_dev);
                ph->mach_dev = MACH_PORT_NULL;
        }
 
        pcapint_cleanup_live_common(p);
 }
 
+static void*
+pipe_write_thread(void *arg) {
+       pcap_t *p;
+       struct pcap_hurd *ph;
+       int wpipe, ret;
+       struct net_rcv_msg msg;
+       u_int msgsize;
+       kern_return_t kr;
+       mach_msg_timeout_t timeout_ms;
+       sigset_t set;
+
+       pthread_setname_np (pthread_self(), "pcap_hurd_pipe_thread");
+
+       /* Block SIGPIPE for this thread */
+       sigemptyset(&set);
+       sigaddset(&set, SIGPIPE);
+       pthread_sigmask(SIG_BLOCK, &set, NULL);
+
+       p = (pcap_t *)arg;
+       ph = p->priv;
+       wpipe = ph->pipefd[1];
+       msgsize = sizeof(struct net_rcv_msg);
+       timeout_ms = 100;
+
+       while (1) {
+               kr = mach_msg(&msg.msg_hdr,
+                       MACH_RCV_MSG | MACH_RCV_INTERRUPT| MACH_RCV_TIMEOUT,
+                       0, msgsize, ph->rcv_port, timeout_ms,
+                       MACH_PORT_NULL);
+
+               if (kr) {
+                       if (kr == MACH_RCV_TIMED_OUT || kr == 
MACH_RCV_INTERRUPTED) {
+                               pthread_testcancel();
+                               continue;
+                       }
+
+                       pcapint_fmt_errmsg_for_kern_return_t(p->errbuf,
+                               PCAP_ERRBUF_SIZE, kr, "mach_msg");
+
+                       return NULL;
+               }
+
+               ret = write(wpipe, &msg, msgsize);
+               if (ret < 0) {
+                       pcapint_fmt_errmsg_for_errno(p->errbuf,
+                               PCAP_ERRBUF_SIZE, errno, "write");
+                       return NULL;
+               }
+       }
+
+       return NULL;
+}
+
+static int
+init_pipe(pcap_t *p) {
+       int err;
+       struct pcap_hurd *ph;
+
+       ph = p->priv;
+       err = pipe(ph->pipefd);
+       if (err < 0)
+               return errno;
+
+       err = pthread_create(&ph->pipe_thread_id, NULL, pipe_write_thread, p);
+       if (err != 0)
+               return err;
+
+       return 0;
+}
+
 static int
 pcap_activate_hurd(pcap_t *p)
 {
@@ -310,6 +407,15 @@ pcap_activate_hurd(pcap_t *p)
                goto error;
        }
 
+       ret = init_pipe(p);
+       if (ret != 0) {
+               pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
+                       ret, "init_pipe");
+               goto error;
+       }
+
+       p->selectable_fd = ph->pipefd[0];
+
        /*
         * XXX Ethernet only currently
         *
@@ -332,6 +438,7 @@ pcap_activate_hurd(pcap_t *p)
        p->inject_op = pcap_inject_hurd;
        p->setfilter_op = pcap_setfilter_hurd;
        p->stats_op = pcap_stats_hurd;
+       p->cleanup_op = pcap_cleanup_hurd;
 
        return 0;
 
@@ -353,6 +460,8 @@ pcapint_create_interface(const char *device _U_, char *ebuf)
        ph = p->priv;
        ph->mach_dev = MACH_PORT_NULL;
        ph->rcv_port = MACH_PORT_NULL;
+       ph->pipefd[0] = -1;
+       ph->pipefd[1] = -1;
        p->activate_op = pcap_activate_hurd;
        return p;
 }
-- 
2.50.1


Reply via email to