pcap.jdk7.internal.DefaultPollSelector Maven / Gradle / Ivy
/*
* Copyright (c) 2020-2021 Pcap Project
* SPDX-License-Identifier: MIT OR Apache-2.0
*/
package pcap.jdk7.internal;
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Platform;
import com.sun.jna.Structure;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import pcap.spi.Selectable;
import pcap.spi.Selection;
import pcap.spi.Selector;
import pcap.spi.Timeout;
import pcap.spi.exception.NoSuchSelectableException;
import pcap.spi.exception.TimeoutException;
import pcap.spi.util.Consumer;
class DefaultPollSelector extends AbstractSelector {
static final int POLLIN = 1;
static final int POLLOUT = 4;
static final int EINTR = 4;
pollfd[] pfds = new pollfd[0];
DefaultPollSelector() {
super.isClosed = false;
}
static int toJavaEvent(int epollOps, int javaIOps) {
int ops = 0;
if (epollOps == POLLIN) {
ops |= javaIOps & (Selection.OPERATION_READ);
}
if (epollOps == POLLOUT) {
ops |= javaIOps & (Selection.OPERATION_WRITE);
}
return ops;
}
static short toPollEvent(int ops) {
short eventOps = 0;
if ((ops & (Selection.OPERATION_READ)) != 0) {
eventOps |= POLLIN;
}
if ((ops & (Selection.OPERATION_WRITE)) != 0) {
eventOps |= POLLOUT;
}
return eventOps;
}
boolean doWhile(int rc, int lastError) {
return rc < 0 && EINTR == lastError;
}
Iterable toIterableSelectable(int rc, int timeout) throws TimeoutException {
if (rc < 0 || rc > registered.size()) {
return Collections.EMPTY_LIST;
}
if (rc == 0) {
throw new TimeoutException(String.format("Timeout: %d.", timeout));
}
final SelectableList selected = new SelectableList();
for (int i = 0; i < registered.size(); i++) {
pfds[i].read();
final DefaultSelection selection = registered.get(pfds[i].fd);
selection.setReadyOperation(toJavaEvent(pfds[i].revents, selection.interestOperations()));
if (selection.isReadable()) {
selected.add(selection.selectable());
}
}
return selected;
}
private pollfd[] add(DefaultSelection selection, int size) {
try {
int fd = NativeMappings.PLATFORM_DEPENDENT.pcap_get_selectable_fd(selection.pcap.pointer);
pollfd[] newPfds = (pollfd[]) (new pollfd().toArray(size));
newPfds[pfds.length].fd = fd;
newPfds[pfds.length].events = POLLIN;
newPfds[pfds.length].revents = 0;
newPfds[pfds.length].write();
selection.pcap.selector = this;
selection.pollFDsIndex = pfds.length;
registered.put(fd, selection);
return newPfds;
} catch (NullPointerException | UnsatisfiedLinkError e) {
return pfds;
}
}
@Override
public Selector register(Selectable pcap) throws IllegalArgumentException, IllegalStateException {
register(pcap, Selection.OPERATION_READ, null);
return this;
}
@Override
Selection register(Selectable selectable, int interestOperations, Object attachment)
throws IllegalArgumentException, IllegalStateException {
DefaultSelection selection = validateRegister(selectable, attachment);
if (!registered.isEmpty()) {
// register new pcap
pollfd[] newPfds = add(selection, pfds.length + 1);
for (int i = 0; i < pfds.length; i++) {
newPfds[i].fd = pfds[i].fd;
newPfds[i].events = pfds[i].events;
newPfds[i].revents = pfds[i].revents;
newPfds[i].write();
}
this.pfds = newPfds;
} else {
this.pfds = add(selection, 1);
}
selection.interestOperations(interestOperations);
selection.attach(attachment);
return selection;
}
@Override
void interestOperations(DefaultSelection selection, int interestOperations) {
if (pfds[selection.pollFDsIndex] != null) {
pfds[selection.pollFDsIndex].events = toPollEvent(interestOperations);
pfds[selection.pollFDsIndex].write();
}
}
@Override
public Iterable select(Timeout timeout)
throws TimeoutException, NoSuchSelectableException, IllegalStateException,
IllegalArgumentException {
validateSelect(timeout);
int ts = (int) timeout.microSecond() / 1000;
int rc;
do {
rc = LibC.INSTANCE.poll(pfds, registered.size(), ts);
} while (doWhile(rc, Native.getLastError()));
return toIterableSelectable(rc, ts);
}
@Override
public int select(Consumer consumer, Timeout timeout)
throws TimeoutException, NoSuchSelectableException, IllegalStateException,
IllegalArgumentException {
validateSelect(timeout);
int ts = (int) timeout.microSecond() / 1000;
int rc;
do {
rc = LibC.INSTANCE.poll(pfds, registered.size(), ts);
} while (doWhile(rc, Native.getLastError()));
return consume(rc, timeout, consumer);
}
int consume(int rc, Timeout timeout, Consumer consumer) throws TimeoutException {
if (rc < 0) {
return rc;
}
if (rc == 0) {
throw new TimeoutException(String.format("Timeout: %s,", timeout));
}
for (int i = 0; i < registered.size(); i++) {
pfds[i].read();
final DefaultSelection selection = registered.get(pfds[i].fd);
selection.setReadyOperation(toJavaEvent(pfds[i].revents, selection.interestOperations()));
consumer.accept(selection);
}
return rc;
}
@Override
protected void cancel(DefaultPcap pcap) {
try {
int fd = NativeMappings.PLATFORM_DEPENDENT.pcap_get_selectable_fd(pcap.pointer);
for (int i = 0; i < registered.size(); i++) {
if (pfds[i].fd == fd) {
if (pfds.length > 1) {
pollfd[] newPfds = (pollfd[]) (new pollfd().toArray(pfds.length - 1));
int index = 0;
for (int j = 0; j < pfds.length; j++) {
if (j != i) {
newPfds[index].fd = pfds[index].fd;
newPfds[index].events = pfds[index].events;
newPfds[index].revents = pfds[index].revents;
index++;
} else {
registered.remove(fd);
}
}
} else {
registered.remove(fd);
}
break;
}
}
} catch (NullPointerException | UnsatisfiedLinkError e) {
//
}
}
@Override
public void close() throws Exception {
Iterator iterator = registered.values().iterator();
while (iterator.hasNext()) {
iterator.next().pcap.selector = null;
iterator.remove();
}
isClosed = true;
}
interface LibC extends Library {
LibC INSTANCE = Native.load(Platform.C_LIBRARY_NAME, LibC.class);
int poll(pollfd[] fds, int nfds, int timeout);
}
public static class pollfd extends Structure {
public int fd;
public short events;
public short revents;
public pollfd() {
// public constructor
}
@Override
protected List getFieldOrder() {
return Arrays.asList( //
"fd", //
"events", //
"revents" //
);
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
pollfd pollfd = (pollfd) o;
return fd == pollfd.fd;
}
@Override
public int hashCode() {
return Objects.hash(fd);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy