aboutsummaryrefslogtreecommitdiff
path: root/pcap-linux.c
diff options
context:
space:
mode:
Diffstat (limited to 'pcap-linux.c')
-rw-r--r--pcap-linux.c68
1 files changed, 58 insertions, 10 deletions
diff --git a/pcap-linux.c b/pcap-linux.c
index dd21e5c3..f37d74e1 100644
--- a/pcap-linux.c
+++ b/pcap-linux.c
@@ -137,6 +137,9 @@
#include <net/if_arp.h>
#include <poll.h>
#include <dirent.h>
+#ifdef HAVE_SYS_EVENTFD_H
+#include <sys/eventfd.h>
+#endif
#include "pcap-int.h"
#include "pcap/sll.h"
@@ -326,6 +329,10 @@ struct pcap_linux {
unsigned char *current_packet; /* Current packet within the TPACKET_V3 block. Move to next block if NULL. */
int packets_left; /* Unhandled packets left within the block from previous call to pcap_read_linux_mmap_v3 in case of TPACKET_V3. */
#endif
+#ifdef HAVE_SYS_EVENTFD_H
+ int poll_breakloop_fd; /* fd to an eventfd to break from blocking operations */
+#endif
+
};
/*
@@ -538,6 +545,11 @@ pcap_create_interface(const char *device, char *ebuf)
handle->tstamp_precision_list[1] = PCAP_TSTAMP_PRECISION_NANO;
#endif /* defined(SIOCGSTAMPNS) && defined(SO_TIMESTAMPNS) */
+#ifdef HAVE_SYS_EVENTFD_H
+ struct pcap_linux *handlep = handle->priv;
+ handlep->poll_breakloop_fd = eventfd(0, EFD_NONBLOCK);
+#endif
+
return handle;
}
@@ -1374,6 +1386,10 @@ static void pcap_cleanup_linux( pcap_t *handle )
free(handlep->device);
handlep->device = NULL;
}
+
+#ifdef HAVE_SYS_EVENTFD_H
+ close(handlep->poll_breakloop_fd);
+#endif
pcap_cleanup_live_common(handle);
}
@@ -1465,6 +1481,17 @@ set_poll_timeout(struct pcap_linux *handlep)
}
}
+#ifdef HAVE_SYS_EVENTFD_H
+static void pcap_breakloop_linux(pcap_t *handle)
+{
+ pcap_breakloop_common(handle);
+ struct pcap_linux *handlep = handle->priv;
+
+ uint64_t value = 1;
+ write(handlep->poll_breakloop_fd, &value, sizeof(value));
+}
+#endif
+
/*
* Get a handle for a live capture from the given device. You can
* pass NULL as device to get all packages (without link level
@@ -1520,6 +1547,9 @@ pcap_activate_linux(pcap_t *handle)
handle->cleanup_op = pcap_cleanup_linux;
handle->read_op = pcap_read_linux;
handle->stats_op = pcap_stats_linux;
+#ifdef HAVE_SYS_EVENTFD_H
+ handle->breakloop_op = pcap_breakloop_linux;
+#endif
/*
* The "any" device is a special device which causes us not
@@ -4933,11 +4963,16 @@ static int pcap_wait_for_frames_mmap(pcap_t *handle)
{
struct pcap_linux *handlep = handle->priv;
char c;
- struct pollfd pollinfo;
int ret;
-
- pollinfo.fd = handle->fd;
- pollinfo.events = POLLIN;
+#ifdef HAVE_SYS_EVENTFD_H
+ struct pollfd pollinfo[2];
+ pollinfo[1].fd = handlep->poll_breakloop_fd;
+ pollinfo[1].events = POLLIN;
+#else
+ struct pollfd pollinfo[1];
+#endif
+ pollinfo[0].fd = handle->fd;
+ pollinfo[0].events = POLLIN;
do {
/*
@@ -4948,26 +4983,31 @@ static int pcap_wait_for_frames_mmap(pcap_t *handle)
* The timeout is 0 in non-blocking mode, so poll()
* returns immediately.
*/
- ret = poll(&pollinfo, 1, handlep->poll_timeout);
+
+#ifdef HAVE_SYS_EVENTFD_H
+ ret = poll(pollinfo, 2, handlep->poll_timeout);
+#else
+ ret = poll(pollinfo, 1, handlep->poll_timeout);
+#endif
if (ret < 0 && errno != EINTR) {
pcap_fmt_errmsg_for_errno(handle->errbuf,
PCAP_ERRBUF_SIZE, errno,
"can't poll on packet socket");
return PCAP_ERROR;
- } else if (ret > 0 &&
- (pollinfo.revents & (POLLHUP|POLLRDHUP|POLLERR|POLLNVAL))) {
+ } else if (ret > 0 && pollinfo[0].revents &&
+ (pollinfo[0].revents & (POLLHUP|POLLRDHUP|POLLERR|POLLNVAL))) {
/*
* There's some indication other than
* "you can read on this descriptor" on
* the descriptor.
*/
- if (pollinfo.revents & (POLLHUP | POLLRDHUP)) {
+ if (pollinfo[0].revents & (POLLHUP | POLLRDHUP)) {
pcap_snprintf(handle->errbuf,
PCAP_ERRBUF_SIZE,
"Hangup on packet socket");
return PCAP_ERROR;
}
- if (pollinfo.revents & POLLERR) {
+ if (pollinfo[0].revents & POLLERR) {
/*
* A recv() will give us the actual error code.
*
@@ -4996,13 +5036,21 @@ static int pcap_wait_for_frames_mmap(pcap_t *handle)
}
return PCAP_ERROR;
}
- if (pollinfo.revents & POLLNVAL) {
+ if (pollinfo[0].revents & POLLNVAL) {
pcap_snprintf(handle->errbuf,
PCAP_ERRBUF_SIZE,
"Invalid polling request on packet socket");
return PCAP_ERROR;
}
}
+
+#ifdef HAVE_SYS_EVENTFD_H
+ if (pollinfo[1].revents & POLLIN) {
+ uint64_t value;
+ read(handlep->poll_breakloop_fd, &value, sizeof(value));
+ }
+#endif
+
/* check for break loop condition on interrupted syscall*/
if (handle->break_loop) {
handle->break_loop = 0;