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