pax_global_header00006660000000000000000000000064145000142500014501gustar00rootroot0000000000000052 comment=6b243df155f239b1ed7b1714ca757d9c1ddf810a jnr-enxio-jnr-enxio-0.32.16/000077500000000000000000000000001450001425000154725ustar00rootroot00000000000000jnr-enxio-jnr-enxio-0.32.16/.github/000077500000000000000000000000001450001425000170325ustar00rootroot00000000000000jnr-enxio-jnr-enxio-0.32.16/.github/workflows/000077500000000000000000000000001450001425000210675ustar00rootroot00000000000000jnr-enxio-jnr-enxio-0.32.16/.github/workflows/ci.yml000066400000000000000000000014321450001425000222050ustar00rootroot00000000000000# This workflow will build a Java project with Maven # For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven name: Java CI with Maven on: push: branches: [ master ] pull_request: branches: [ master ] jobs: jdk8: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Set up JDK 8 uses: actions/setup-java@v1.4.3 with: java-version: 8 - name: Build with Maven run: mvn -B package --file pom.xml jdk11: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Set up JDK 11 uses: actions/setup-java@v1.4.3 with: java-version: 11 - name: Build with Maven run: mvn -B package --file pom.xml jnr-enxio-jnr-enxio-0.32.16/.gitignore000066400000000000000000000001241450001425000174570ustar00rootroot00000000000000build target nbproject/private dist *.orig$ *.rej$ *.class$ *~ .idea *.iml /.redcar/jnr-enxio-jnr-enxio-0.32.16/LICENSE000066400000000000000000000010361450001425000164770ustar00rootroot00000000000000 Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.jnr-enxio-jnr-enxio-0.32.16/README.md000066400000000000000000000002561450001425000167540ustar00rootroot00000000000000jnr-enxio ========= Native I/O access for java Check out the [examples](https://github.com/jnr/jnr-enxio/tree/master/src/test/java/jnr/enxio/example) for more information. jnr-enxio-jnr-enxio-0.32.16/pom.xml000066400000000000000000000112611450001425000170100ustar00rootroot00000000000000 4.0.0 org.sonatype.oss oss-parent 7 com.github.jnr jnr-enxio jar 0.32.16 jnr-enxio Native I/O access for java http://github.com/jnr/jnr-enxio The Apache Software License, Version 2.0 http://www.apache.org/licenses/LICENSE-2.0.txt repo scm:git:git@github.com:jnr/jnr-enxio.git scm:git:git@github.com:jnr/jnr-enxio.git git@github.com:jnr/jnr-enxio.git wmeissner Wayne Meissner wmeissner@gmail.com UTF-8 8 8 junit junit 4.13.1 test com.github.jnr jnr-constants 0.10.4 com.github.jnr jnr-ffi 2.2.15 org.apache.felix maven-bundle-plugin 2.3.7 <_nouses>true *,jnr.ffi.mapper,jnr.ffi.provider.converters,com.kenai.jffi jnr.enxio bundle-manifest process-classes manifest org.apache.maven.plugins maven-jar-plugin 2.3.1 ${project.build.outputDirectory}/META-INF/MANIFEST.MF org.jnrproject.enxio org.apache.maven.plugins maven-source-plugin 2.2.1 attach-sources jar-no-fork org.apache.maven.plugins maven-javadoc-plugin 3.2.0 attach-javadocs jar org.apache.maven.plugins maven-compiler-plugin 3.8.1 java9 maven-surefire-plugin 3.0.0-M5 --add-opens java.base/java.io=ALL-UNNAMED [9,) 8 jnr-enxio-jnr-enxio-0.32.16/src/000077500000000000000000000000001450001425000162615ustar00rootroot00000000000000jnr-enxio-jnr-enxio-0.32.16/src/main/000077500000000000000000000000001450001425000172055ustar00rootroot00000000000000jnr-enxio-jnr-enxio-0.32.16/src/main/java/000077500000000000000000000000001450001425000201265ustar00rootroot00000000000000jnr-enxio-jnr-enxio-0.32.16/src/main/java/jnr/000077500000000000000000000000001450001425000207175ustar00rootroot00000000000000jnr-enxio-jnr-enxio-0.32.16/src/main/java/jnr/enxio/000077500000000000000000000000001450001425000220415ustar00rootroot00000000000000jnr-enxio-jnr-enxio-0.32.16/src/main/java/jnr/enxio/channels/000077500000000000000000000000001450001425000236345ustar00rootroot00000000000000jnr-enxio-jnr-enxio-0.32.16/src/main/java/jnr/enxio/channels/KQSelectionKey.java000066400000000000000000000035271450001425000273400ustar00rootroot00000000000000/* * Copyright (C) 2008 Wayne Meissner * * This file is part of the JNR project. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jnr.enxio.channels; import java.nio.channels.SelectableChannel; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.spi.AbstractSelectionKey; class KQSelectionKey extends AbstractSelectionKey { private final KQSelector selector; private final NativeSelectableChannel channel; private int interestOps = 0; private int readyOps = 0; public KQSelectionKey(KQSelector selector, NativeSelectableChannel channel, int ops) { this.selector = selector; this.channel = channel; this.interestOps = ops; } int getFD() { return channel.getFD(); } @Override public SelectableChannel channel() { return (SelectableChannel) channel; } @Override public Selector selector() { return selector; } @Override public int interestOps() { return interestOps; } @Override public SelectionKey interestOps(int ops) { interestOps = ops; selector.interestOps(this, ops); return this; } @Override public int readyOps() { return readyOps; } void readyOps(int readyOps) { this.readyOps = readyOps; } } jnr-enxio-jnr-enxio-0.32.16/src/main/java/jnr/enxio/channels/KQSelector.java000066400000000000000000000336061450001425000265230ustar00rootroot00000000000000/* * Copyright (C) 2008 Wayne Meissner * * This file is part of the JNR project. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jnr.enxio.channels; import jnr.constants.platform.Errno; import jnr.ffi.Memory; import jnr.ffi.Pointer; import jnr.ffi.StructLayout; import jnr.ffi.TypeAlias; import jnr.ffi.provider.jffi.NativeRuntime; import jnr.ffi.Platform; import java.io.IOException; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.spi.AbstractSelectableChannel; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; /** * An implementation of a {@link java.nio.channels.Selector} that uses the BSD (including MacOS) * kqueue(2) mechanism */ class KQSelector extends java.nio.channels.spi.AbstractSelector { private static final boolean DEBUG = false; private static final int MAX_EVENTS = 100; private static final int EVFILT_READ = -1; private static final int EVFILT_WRITE = -2; private static final int EV_ADD = 0x0001; private static final int EV_DELETE = 0x0002; private static final int EV_ENABLE = 0x0004; private static final int EV_DISABLE = 0x0008; private static final int EV_CLEAR = 0x0020; private int kqfd = -1; private final jnr.ffi.Runtime runtime = NativeRuntime.getSystemRuntime(); private final Pointer changebuf; private final Pointer eventbuf; private final EventIO io = EventIO.getInstance(); private final int[] pipefd = { -1, -1 }; private final Object regLock = new Object(); private final Map descriptors = new ConcurrentHashMap(); private final Set selected = new LinkedHashSet(); private final Native.Timespec ZERO_TIMESPEC = new Native.Timespec(0, 0); public KQSelector(NativeSelectorProvider provider) { super(provider); changebuf = Memory.allocateDirect(runtime, MAX_EVENTS * io.size()); eventbuf = Memory.allocateDirect(runtime, MAX_EVENTS * io.size()); Native.libc().pipe(pipefd); kqfd = Native.libc().kqueue(); io.put(changebuf, 0, pipefd[0], EVFILT_READ, EV_ADD); Native.libc().kevent(kqfd, changebuf, 1, null, 0, ZERO_TIMESPEC); } private static class Descriptor { private final int fd; private final Set keys = new HashSet(); private boolean write = false, read = false; public Descriptor(int fd) { this.fd = fd; } } @Override protected void implCloseSelector() throws IOException { if (kqfd != -1) { Native.close(kqfd); } if (pipefd[0] != -1) { Native.close(pipefd[0]); } if (pipefd[1] != -1) { Native.close(pipefd[1]); } pipefd[0] = pipefd[1] = kqfd = -1; // deregister all keys for (Map.Entry entry : descriptors.entrySet()) { for (KQSelectionKey k : entry.getValue().keys) { deregister(k); } } } @Override protected SelectionKey register(AbstractSelectableChannel ch, int ops, Object att) { KQSelectionKey k = new KQSelectionKey(this, (NativeSelectableChannel) ch, ops); synchronized (regLock) { Descriptor d = new Descriptor(k.getFD()); descriptors.put(k.getFD(), d); d.keys.add(k); handleChangedKey(d); } k.attach(att); return k; } @Override public Set keys() { Set keys = new HashSet(); for (Descriptor fd : descriptors.values()) { keys.addAll(fd.keys); } return Collections.unmodifiableSet(keys); } @Override public Set selectedKeys() { return selected; } @Override public int selectNow() throws IOException { return poll(0); } @Override public int select(long timeout) throws IOException { return poll(timeout); } @Override public int select() throws IOException { return poll(-1); } private int poll(long timeout) { int nchanged = handleCancelledKeys(); Native.Timespec ts = null; if (timeout >= 0) { long sec = TimeUnit.MILLISECONDS.toSeconds(timeout); long nsec = TimeUnit.MILLISECONDS.toNanos(timeout % 1000); ts = new Native.Timespec(sec, nsec); } if (DEBUG) System.err.printf("nchanged=%d\n", nchanged); int nready = 0; try { begin(); do { nready = Native.libc().kevent(kqfd, changebuf, nchanged, eventbuf, MAX_EVENTS, ts); } while (nready < 0 && Errno.EINTR.equals(Errno.valueOf(Native.getRuntime().getLastError()))); if (DEBUG) System.err.println("kevent returned " + nready + " events ready"); } finally { end(); } int updatedKeyCount = 0; synchronized (regLock) { for (int i = 0; i < nready; ++i) { int fd = io.getFD(eventbuf, i); Descriptor d = descriptors.get(fd); if (d != null) { int filt = io.getFilter(eventbuf, i); if (DEBUG) System.err.printf("fd=%d filt=0x%x\n", d.fd, filt); for (KQSelectionKey k : d.keys) { int iops = k.interestOps(); int ops = 0; if (filt == EVFILT_READ) { ops |= iops & (SelectionKey.OP_ACCEPT | SelectionKey.OP_READ); } if (filt == EVFILT_WRITE) { ops |= iops & (SelectionKey.OP_CONNECT | SelectionKey.OP_WRITE); } ++updatedKeyCount; k.readyOps(ops); if (!selected.contains(k)) { selected.add(k); } } } else if (fd == pipefd[0]) { if (DEBUG) System.err.println("Waking up"); wakeupReceived(); } } } return updatedKeyCount; } private int handleCancelledKeys() { Set cancelled = cancelledKeys(); synchronized (cancelled) { int nchanged = 0; synchronized (regLock) { for (SelectionKey k : cancelled) { KQSelectionKey kqs = (KQSelectionKey) k; deregister(kqs); synchronized (selected) { selected.remove(kqs); } Descriptor d = descriptors.get(kqs.getFD()); if (d != null) d.keys.remove(kqs); if (d == null || d.keys.isEmpty()) { io.put(changebuf, nchanged++, kqs.getFD(), EVFILT_READ, EV_DELETE); io.put(changebuf, nchanged++, kqs.getFD(), EVFILT_WRITE, EV_DELETE); descriptors.remove(kqs.getFD()); } if (nchanged >= MAX_EVENTS) { Native.libc().kevent(kqfd, changebuf, nchanged, null, 0, ZERO_TIMESPEC); nchanged = 0; } } } cancelled.clear(); return nchanged; } } private void handleChangedKey(Descriptor changed) { synchronized (regLock) { int _nchanged = 0; int writers = 0, readers = 0; for (KQSelectionKey k : changed.keys) { if ((k.interestOps() & (SelectionKey.OP_ACCEPT | SelectionKey.OP_READ)) != 0) { ++readers; } if ((k.interestOps() & (SelectionKey.OP_CONNECT | SelectionKey.OP_WRITE)) != 0) { ++writers; } } for (Integer filt : new Integer[] { EVFILT_READ, EVFILT_WRITE }) { int flags = 0; // // If no one is interested in events on the fd, disable it // if (filt == EVFILT_READ) { if (readers > 0 && !changed.read) { flags = EV_ADD |EV_ENABLE | EV_CLEAR; changed.read = true; } else if (readers == 0 && changed.read) { flags = EV_DISABLE; changed.read = false; } } if (filt == EVFILT_WRITE) { if (writers > 0 && !changed.write) { flags = EV_ADD | EV_ENABLE | EV_CLEAR; changed.write = true; } else if (writers == 0 && changed.write) { flags = EV_DISABLE; changed.write = false; } } if (DEBUG) System.err.printf("Updating fd %d filt=0x%x flags=0x%x\n", changed.fd, filt, flags); if (flags != 0) { io.put(changebuf, _nchanged++, changed.fd, filt, flags); } } Native.libc().kevent(kqfd, changebuf, _nchanged, null, 0, ZERO_TIMESPEC); } } private void wakeupReceived() { Native.libc().read(pipefd[0], new byte[1], 1); } @Override public Selector wakeup() { Native.libc().write(pipefd[1], new byte[1], 1); return this; } void interestOps(KQSelectionKey k, int ops) { synchronized (regLock) { handleChangedKey(descriptors.get(k.getFD())); } } private static final class EventIO { private static final EventIO INSTANCE = new EventIO(); private final EventLayout layout; private final jnr.ffi.Type uintptr_t; private EventIO() { boolean is_freebsd_12_or_later = false; if(Platform.getNativePlatform().getOS() == Platform.OS.FREEBSD) { String version = System.getProperty("os.version"); if(version != null) { int tr_i = -1; for(char c : new char[] { ' ', '_', '-', '+', '.' }) { int i = version.indexOf(c); if(i >= 0 && (tr_i == -1 || tr_i > i)) tr_i = i; } if(tr_i >= 0) version = version.substring(0, tr_i); try { int freebsd_major_version = Integer.parseInt(version); if(freebsd_major_version > 11) is_freebsd_12_or_later = true; } catch(NumberFormatException e) { if(DEBUG) e.printStackTrace(); } } } if(is_freebsd_12_or_later) { layout = new FreeBSD12EventLayout(NativeRuntime.getSystemRuntime()); } else { layout = new LegacyEventLayout(NativeRuntime.getSystemRuntime()); } uintptr_t = layout.getRuntime().findType(TypeAlias.uintptr_t); } public static EventIO getInstance() { return EventIO.INSTANCE; } public final void put(Pointer buf, int index, int fd, int filt, int flags) { buf.putInt(uintptr_t, (index * layout.size()) + layout.ident.offset(), fd); buf.putShort((index * layout.size()) + layout.filter.offset(), (short) filt); buf.putShort((index * layout.size()) + layout.flags.offset(), (short)flags); } public final int size() { return layout.size(); } int getFD(Pointer ptr, int index) { return (int) ptr.getInt(uintptr_t, (index * layout.size()) + layout.ident.offset()); } public final void putFilter(Pointer buf, int index, int filter) { buf.putShort((index * layout.size()) + layout.filter.offset(), (short) filter); } public final int getFilter(Pointer buf, int index) { return buf.getShort((index * layout.size()) + layout.filter.offset()); } public final void putFlags(Pointer buf, int index, int flags) { buf.putShort((index * layout.size()) + layout.flags.offset(), (short) flags); } } private static abstract class EventLayout extends StructLayout { private EventLayout(jnr.ffi.Runtime runtime) { super(runtime); } public final uintptr_t ident = new uintptr_t(); public final int16_t filter = new int16_t(); public final u_int16_t flags = new u_int16_t(); public final u_int32_t fflags = new u_int32_t(); } private static class LegacyEventLayout extends EventLayout { private LegacyEventLayout(jnr.ffi.Runtime runtime) { super(runtime); } public final intptr_t data = new intptr_t(); public final Pointer udata = new Pointer(); } private static class FreeBSD12EventLayout extends EventLayout { private FreeBSD12EventLayout(jnr.ffi.Runtime runtime) { super(runtime); } public final int64_t data = new int64_t(); public final Pointer udata = new Pointer(); public final u_int64_t[] ext = array(new u_int64_t[4]); } } jnr-enxio-jnr-enxio-0.32.16/src/main/java/jnr/enxio/channels/Native.java000066400000000000000000000141241450001425000257270ustar00rootroot00000000000000/* * Copyright (C) 2008 Wayne Meissner * * This file is part of the JNR project. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jnr.enxio.channels; import jnr.constants.platform.Errno; import jnr.enxio.channels.WinLibCAdapter.LibMSVCRT; import jnr.ffi.*; import jnr.ffi.Platform.OS; import jnr.ffi.Runtime; import jnr.ffi.annotations.IgnoreError; import jnr.ffi.annotations.In; import jnr.ffi.annotations.Out; import jnr.ffi.annotations.Transient; import jnr.ffi.types.size_t; import jnr.ffi.types.ssize_t; import jnr.ffi.Platform; import java.io.IOException; import java.nio.ByteBuffer; public final class Native { public static interface LibC { public static final int F_GETFL = jnr.constants.platform.Fcntl.F_GETFL.intValue(); public static final int F_SETFL = jnr.constants.platform.Fcntl.F_SETFL.intValue(); public static final int O_NONBLOCK = jnr.constants.platform.OpenFlags.O_NONBLOCK.intValue(); public int close(int fd); public @ssize_t int read(int fd, @Out ByteBuffer data, @size_t long size); public @ssize_t int read(int fd, @Out byte[] data, @size_t long size); public @ssize_t int write(int fd, @In ByteBuffer data, @size_t long size); public @ssize_t int write(int fd, @In byte[] data, @size_t long size); public int fcntl(int fd, int cmd, int data); public int poll(@In @Out ByteBuffer pfds, int nfds, int timeout); public int poll(@In @Out Pointer pfds, int nfds, int timeout); public int kqueue(); public int kevent(int kq, @In ByteBuffer changebuf, int nchanges, @Out ByteBuffer eventbuf, int nevents, @In @Transient Timespec timeout); public int kevent(int kq, @In Pointer changebuf, int nchanges, @Out Pointer eventbuf, int nevents, @In @Transient Timespec timeout); public int pipe(@Out int[] fds); public int shutdown(int s, int how); @IgnoreError String strerror(int error); } private static final class SingletonHolder { static final LibC libc; static final jnr.ffi.Runtime runtime; static { Platform platform = Platform.getNativePlatform(); LibraryLoader loader = LibraryLoader.create(LibC.class); loader.library(platform.getStandardCLibraryName()); if (platform.getOS() == OS.SOLARIS) { loader.library("socket"); } LibC straight = loader.load(); if (platform.getOS() == OS.WINDOWS) { LibMSVCRT mslib = LibraryLoader.create(LibMSVCRT.class).load(platform.getStandardCLibraryName()); libc = new WinLibCAdapter(mslib); } else { libc = straight; } runtime = Runtime.getRuntime(libc); } } static LibC libc() { return SingletonHolder.libc; } static jnr.ffi.Runtime getRuntime() { return SingletonHolder.runtime; } public static int close(int fd) throws IOException { int rc; do { rc = libc().close(fd); } while (rc < 0 && Errno.EINTR.equals(getLastError())); if (rc < 0) { String message = String.format("Error closing fd %d: %s", fd, getLastErrorString()); throw new NativeException(message, getLastError()); } else { return rc; } } public static int read(int fd, ByteBuffer dst) throws IOException { if (dst == null) { throw new NullPointerException("Destination buffer cannot be null"); } if (dst.isReadOnly()) { throw new IllegalArgumentException("Read-only buffer"); } int n; do { n = libc().read(fd, dst, dst.remaining()); } while (n < 0 && Errno.EINTR.equals(getLastError())); if (n > 0) { dst.position(dst.position() + n); } return n; } public static int write(int fd, ByteBuffer src) throws IOException { if (src == null) { throw new NullPointerException("Source buffer cannot be null"); } int n; do { n = libc().write(fd, src, src.remaining()); } while (n < 0 && Errno.EINTR.equals(getLastError())); if (n > 0) { src.position(src.position() + n); } return n; } public static void setBlocking(int fd, boolean block) { int flags = libc().fcntl(fd, LibC.F_GETFL, 0); if (block) { flags &= ~LibC.O_NONBLOCK; } else { flags |= LibC.O_NONBLOCK; } libc().fcntl(fd, LibC.F_SETFL, flags); } public static int shutdown(int fd, int how) { return libc().shutdown(fd, how); } public static String getLastErrorString() { return libc().strerror(LastError.getLastError(getRuntime())); } public static Errno getLastError() { return Errno.valueOf(LastError.getLastError(getRuntime())); } public static final class Timespec extends Struct { public final SignedLong tv_sec = new SignedLong(); public final SignedLong tv_nsec = new SignedLong(); public Timespec() { super(Native.getRuntime()); } public Timespec(Runtime runtime) { super(runtime); } public Timespec(long sec, long nsec) { super(Native.getRuntime()); tv_sec.set(sec); tv_nsec.set(nsec); } } } jnr-enxio-jnr-enxio-0.32.16/src/main/java/jnr/enxio/channels/NativeDeviceChannel.java000066400000000000000000000056611450001425000303460ustar00rootroot00000000000000/* * Copyright (C) 2008 Wayne Meissner * * This file is part of the JNR project. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jnr.enxio.channels; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.ByteChannel; import java.nio.channels.SelectionKey; import java.nio.channels.spi.AbstractSelectableChannel; import java.nio.channels.spi.SelectorProvider; public class NativeDeviceChannel extends AbstractSelectableChannel implements ByteChannel, NativeSelectableChannel { private final int fd; private final int validOps; private final boolean isFile; public NativeDeviceChannel(int fd) { this(fd, false); } public NativeDeviceChannel(int fd, boolean isFile) { this(selectorProvider(isFile), fd, SelectionKey.OP_READ | SelectionKey.OP_WRITE, isFile); } public NativeDeviceChannel(SelectorProvider provider, int fd, int ops, boolean isFile) { super(provider); this.fd = fd; this.validOps = ops; this.isFile = isFile; } private static SelectorProvider selectorProvider(boolean isFile) { return (isFile) ? NativeFileSelectorProvider.getInstance() : NativeSelectorProvider.getInstance(); } @Override protected void implCloseSelectableChannel() throws IOException { int n = Native.close(fd); if (n < 0) { throw new IOException(Native.getLastErrorString()); } } @Override protected void implConfigureBlocking(boolean block) throws IOException { Native.setBlocking(fd, block); } @Override public final int validOps() { return validOps; } public final int getFD() { return fd; } public int read(ByteBuffer dst) throws IOException { int n = Native.read(fd, dst); switch (n) { case 0: return -1; case -1: switch (Native.getLastError()) { case EAGAIN: case EWOULDBLOCK: return 0; default: throw new IOException(Native.getLastErrorString()); } default: return n; } } public int write(ByteBuffer src) throws IOException { int n = Native.write(fd, src); if (n < 0) { throw new IOException(Native.getLastErrorString()); } return n; } } jnr-enxio-jnr-enxio-0.32.16/src/main/java/jnr/enxio/channels/NativeException.java000066400000000000000000000005441450001425000276070ustar00rootroot00000000000000package jnr.enxio.channels; import jnr.constants.platform.Errno; import java.io.IOException; public class NativeException extends IOException { private final Errno errno; public NativeException(String message, Errno errno) { super(message); this.errno = errno; } public Errno getErrno() { return errno; } } jnr-enxio-jnr-enxio-0.32.16/src/main/java/jnr/enxio/channels/NativeFileSelectorProvider.java000066400000000000000000000042771450001425000317530ustar00rootroot00000000000000/* * Copyright (C) 2008 Wayne Meissner * * This file is part of the JNR project. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jnr.enxio.channels; import jnr.ffi.Platform; import java.io.IOException; import java.nio.channels.DatagramChannel; import java.nio.channels.Pipe; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; import java.nio.channels.spi.AbstractSelector; import java.nio.channels.spi.SelectorProvider; public final class NativeFileSelectorProvider extends SelectorProvider { private static final class SingletonHolder { static NativeFileSelectorProvider INSTANCE = new NativeFileSelectorProvider(); } public static final SelectorProvider getInstance() { return SingletonHolder.INSTANCE; } @Override public DatagramChannel openDatagramChannel() throws IOException { throw new UnsupportedOperationException("Not supported yet."); } public DatagramChannel openDatagramChannel(java.net.ProtocolFamily family) throws IOException { throw new UnsupportedOperationException("Not supported yet."); } @Override public Pipe openPipe() throws IOException { throw new UnsupportedOperationException("Not supported yet."); } @Override public AbstractSelector openSelector() throws IOException { return new PollSelector(this); } @Override public ServerSocketChannel openServerSocketChannel() throws IOException { throw new UnsupportedOperationException("Not supported yet."); } @Override public SocketChannel openSocketChannel() throws IOException { throw new UnsupportedOperationException("Not supported yet."); } } jnr-enxio-jnr-enxio-0.32.16/src/main/java/jnr/enxio/channels/NativeSelectableChannel.java000066400000000000000000000014401450001425000312010ustar00rootroot00000000000000/* * Copyright (C) 2008 Wayne Meissner * * This file is part of the JNR project. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jnr.enxio.channels; import java.nio.channels.Channel; public interface NativeSelectableChannel extends Channel { public int getFD(); } jnr-enxio-jnr-enxio-0.32.16/src/main/java/jnr/enxio/channels/NativeSelectorProvider.java000066400000000000000000000043601450001425000311440ustar00rootroot00000000000000/* * Copyright (C) 2008 Wayne Meissner * * This file is part of the JNR project. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jnr.enxio.channels; import jnr.ffi.Platform; import java.io.IOException; import java.nio.channels.DatagramChannel; import java.nio.channels.Pipe; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; import java.nio.channels.spi.AbstractSelector; import java.nio.channels.spi.SelectorProvider; public final class NativeSelectorProvider extends SelectorProvider { private static final class SingletonHolder { static NativeSelectorProvider INSTANCE = new NativeSelectorProvider(); } public static final SelectorProvider getInstance() { return SingletonHolder.INSTANCE; } @Override public DatagramChannel openDatagramChannel() throws IOException { throw new UnsupportedOperationException("Not supported yet."); } public DatagramChannel openDatagramChannel(java.net.ProtocolFamily family) throws IOException { throw new UnsupportedOperationException("Not supported yet."); } @Override public Pipe openPipe() throws IOException { throw new UnsupportedOperationException("Not supported yet."); } @Override public AbstractSelector openSelector() throws IOException { return Platform.getNativePlatform().isBSD() ? new KQSelector(this) : new PollSelector(this); } @Override public ServerSocketChannel openServerSocketChannel() throws IOException { throw new UnsupportedOperationException("Not supported yet."); } @Override public SocketChannel openSocketChannel() throws IOException { throw new UnsupportedOperationException("Not supported yet."); } } jnr-enxio-jnr-enxio-0.32.16/src/main/java/jnr/enxio/channels/NativeServerSocketChannel.java000066400000000000000000000033011450001425000315530ustar00rootroot00000000000000/* * Copyright (C) 2008 Wayne Meissner * * This file is part of the JNR project. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jnr.enxio.channels; import java.io.IOException; import java.nio.channels.SelectionKey; import java.nio.channels.spi.AbstractSelectableChannel; import java.nio.channels.spi.SelectorProvider; public class NativeServerSocketChannel extends AbstractSelectableChannel implements NativeSelectableChannel { private final int fd; private final int validOps; public NativeServerSocketChannel(int fd) { this(NativeSelectorProvider.getInstance(), fd, SelectionKey.OP_ACCEPT | SelectionKey.OP_READ); } public NativeServerSocketChannel(SelectorProvider provider, int fd, int ops) { super(provider); this.fd = fd; this.validOps = ops; } @Override protected void implCloseSelectableChannel() throws IOException { Native.close(fd); } @Override protected void implConfigureBlocking(boolean block) throws IOException { Native.setBlocking(fd, block); } @Override public final int validOps() { return validOps; } public final int getFD() { return fd; } } jnr-enxio-jnr-enxio-0.32.16/src/main/java/jnr/enxio/channels/NativeSocketChannel.java000066400000000000000000000065361450001425000304010ustar00rootroot00000000000000/* * Copyright (C) 2008 Wayne Meissner * * This file is part of the JNR project. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jnr.enxio.channels; import jnr.constants.platform.Shutdown; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.ByteChannel; import java.nio.channels.SelectionKey; import java.nio.channels.spi.AbstractSelectableChannel; import java.nio.channels.spi.SelectorProvider; public class NativeSocketChannel extends AbstractSelectableChannel implements ByteChannel, NativeSelectableChannel { private final int fd; private final int validOps; public NativeSocketChannel(int fd) { this(NativeSelectorProvider.getInstance(), fd, SelectionKey.OP_READ | SelectionKey.OP_WRITE); } public NativeSocketChannel(int fd, int ops) { this(NativeSelectorProvider.getInstance(), fd, ops); } NativeSocketChannel(SelectorProvider provider, int fd, int ops) { super(provider); this.fd = fd; this.validOps = ops; } @Override protected void implCloseSelectableChannel() throws IOException { Native.close(fd); } @Override protected void implConfigureBlocking(boolean block) throws IOException { Native.setBlocking(fd, block); } @Override public final int validOps() { return validOps; } public final int getFD() { return fd; } public int read(ByteBuffer dst) throws IOException { int n = Native.read(fd, dst); switch (n) { case 0: return -1; case -1: switch (Native.getLastError()) { case EAGAIN: case EWOULDBLOCK: return 0; default: throw new IOException(Native.getLastErrorString()); } default: return n; } } public int write(ByteBuffer src) throws IOException { int n = Native.write(fd, src); if (n < 0) { switch (Native.getLastError()) { case EAGAIN: case EWOULDBLOCK: return 0; default: throw new IOException(Native.getLastErrorString()); } } return n; } public void shutdownInput() throws IOException { int n = Native.shutdown(fd, SHUT_RD); if (n < 0) { throw new IOException(Native.getLastErrorString()); } } public void shutdownOutput() throws IOException { int n = Native.shutdown(fd, SHUT_WR); if (n < 0) { throw new IOException(Native.getLastErrorString()); } } private final static int SHUT_RD = Shutdown.SHUT_RD.intValue(); private final static int SHUT_WR = Shutdown.SHUT_WR.intValue(); } jnr-enxio-jnr-enxio-0.32.16/src/main/java/jnr/enxio/channels/PollSelectionKey.java000066400000000000000000000036401450001425000277270ustar00rootroot00000000000000/* * This file is part of the JNR project. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jnr.enxio.channels; import java.nio.channels.SelectableChannel; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.spi.AbstractSelectionKey; class PollSelectionKey extends AbstractSelectionKey { private final PollSelector selector; private final NativeSelectableChannel channel; private int interestOps = 0; private int readyOps = 0; private int index = -1; public PollSelectionKey(PollSelector selector, NativeSelectableChannel channel) { this.selector = selector; this.channel = channel; } void setIndex(int index) { this.index = index; } int getIndex() { return index; } int getFD() { return channel.getFD(); } @Override public SelectableChannel channel() { return (SelectableChannel) channel; } @Override public Selector selector() { return selector; } @Override public int interestOps() { return interestOps; } @Override public SelectionKey interestOps(int ops) { interestOps = ops; selector.interestOps(this, ops); return this; } @Override public int readyOps() { return readyOps; } void readyOps(int readyOps) { this.readyOps = readyOps; } } jnr-enxio-jnr-enxio-0.32.16/src/main/java/jnr/enxio/channels/PollSelector.java000066400000000000000000000210451450001425000271100ustar00rootroot00000000000000/* * This file is part of the JNR project. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jnr.enxio.channels; import jnr.constants.platform.Errno; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.spi.AbstractSelectableChannel; import java.nio.channels.spi.SelectorProvider; import java.util.*; import java.util.concurrent.ConcurrentHashMap; /** * An implementation of a {@link java.nio.channels.Selector} that uses good old * poll(2) */ class PollSelector extends java.nio.channels.spi.AbstractSelector { private static final int POLLFD_SIZE = 8; private static final int FD_OFFSET = 0; private static final int EVENTS_OFFSET = 4; private static final int REVENTS_OFFSET = 6; static final int POLLIN = 0x1; static final int POLLOUT = 0x4; static final int POLLERR = 0x8; static final int POLLHUP = 0x10; private PollSelectionKey[] keyArray = new PollSelectionKey[0]; private ByteBuffer pollData = null; private int nfds; private final int[] pipefd = { -1, -1 }; private final Object regLock = new Object(); private final Map keys = new ConcurrentHashMap(); private final Set selected = new HashSet(); public PollSelector(SelectorProvider provider) { super(provider); Native.libc().pipe(pipefd); // Register the wakeup pipe as the first element in the pollfd array pollData = ByteBuffer.allocateDirect(8).order(ByteOrder.nativeOrder()); putPollFD(0, pipefd[0]); putPollEvents(0, POLLIN); nfds = 1; keyArray = new PollSelectionKey[1]; } private void putPollFD(int idx, int fd) { pollData.putInt((idx * POLLFD_SIZE) + FD_OFFSET, fd); } private void putPollEvents(int idx, int events) { pollData.putShort((idx * POLLFD_SIZE) + EVENTS_OFFSET, (short) events); } private int getPollFD(int idx) { return pollData.getInt((idx * POLLFD_SIZE) + FD_OFFSET); } private short getPollEvents(int idx) { return pollData.getShort((idx * POLLFD_SIZE) + EVENTS_OFFSET); } private short getPollRevents(int idx) { return pollData.getShort((idx * POLLFD_SIZE) + REVENTS_OFFSET); } private void putPollRevents(int idx, int events) { pollData.putShort((idx * POLLFD_SIZE) + REVENTS_OFFSET, (short) events); } @Override protected void implCloseSelector() throws IOException { if (pipefd[0] != -1) { Native.close(pipefd[0]); } if (pipefd[1] != -1) { Native.close(pipefd[1]); } // remove all keys for (SelectionKey key : keys.keySet()) { remove((PollSelectionKey)key); } } @Override protected SelectionKey register(AbstractSelectableChannel ch, int ops, Object att) { PollSelectionKey key = new PollSelectionKey(this, (NativeSelectableChannel) ch); add(key); key.attach(att); key.interestOps(ops); return key; } @Override public Set keys() { return new HashSet(Arrays.asList(keyArray).subList(1, nfds)); } @Override public Set selectedKeys() { return selected; } void interestOps(PollSelectionKey k, int ops) { short events = 0; if ((ops & (SelectionKey.OP_ACCEPT | SelectionKey.OP_READ)) != 0) { events |= POLLIN; } if ((ops & (SelectionKey.OP_WRITE | SelectionKey.OP_CONNECT)) != 0) { events |= POLLOUT; } putPollEvents(k.getIndex(), events); } private void add(PollSelectionKey k) { synchronized (regLock) { ++nfds; if (keyArray.length < nfds) { PollSelectionKey[] newArray = new PollSelectionKey[nfds + (nfds / 2)]; System.arraycopy(keyArray, 0, newArray, 0, nfds - 1); keyArray = newArray; ByteBuffer newBuffer = ByteBuffer.allocateDirect(newArray.length * 8); if (pollData != null) { newBuffer.put(pollData); } newBuffer.position(0); pollData = newBuffer.order(ByteOrder.nativeOrder()); } k.setIndex(nfds - 1); keyArray[nfds - 1] = k; putPollFD(k.getIndex(), k.getFD()); putPollEvents(k.getIndex(), 0); keys.put(k, true); } } private void remove(PollSelectionKey k) { int idx = k.getIndex(); synchronized (regLock) { // // If not the last key, swap last one into the removed key's position // if (idx < (nfds - 1)) { PollSelectionKey last = keyArray[nfds - 1]; keyArray[idx] = last; // Copy the data for the last key into place putPollFD(idx, getPollFD(last.getIndex())); putPollEvents(idx, getPollEvents(last.getIndex())); last.setIndex(idx); } else { putPollFD(idx, -1); putPollEvents(idx, 0); } keyArray[nfds - 1] = null; --nfds; synchronized (selected) { selected.remove(k); } keys.remove(k); } deregister(k); } @Override public int selectNow() throws IOException { return poll(0); } @Override public int select(long timeout) throws IOException { return poll(timeout > 0 ? timeout : -1); } @Override public int select() throws IOException { return poll(-1); } private int poll(long timeout) throws IOException { // // Remove any cancelled keys // Set cancelled = cancelledKeys(); synchronized (cancelled) { for (SelectionKey k : cancelled) { remove((PollSelectionKey) k); } cancelled.clear(); } int nready = 0; try { begin(); do { nready = Native.libc().poll(pollData, nfds, (int) timeout); } while (nready < 0 && Errno.EINTR.equals(Errno.valueOf(Native.getRuntime().getLastError()))); } finally { end(); } if (nready < 1) { return nready; } if ((getPollRevents(0) & POLLIN) != 0) { wakeupReceived(); } int updatedKeyCount = 0; for (SelectionKey k : keys.keySet()) { PollSelectionKey pk = (PollSelectionKey) k; int revents = getPollRevents(pk.getIndex()); if (revents != 0) { putPollRevents(pk.getIndex(), 0); int iops = k.interestOps(); int ops = 0; if ((revents & POLLIN) != 0) { ops |= iops & (SelectionKey.OP_ACCEPT | SelectionKey.OP_READ); } if ((revents & POLLOUT) != 0) { ops |= iops & (SelectionKey.OP_CONNECT | SelectionKey.OP_WRITE); } // If an error occurred, enable all interested ops and let the // event handling code deal with it if ((revents & (POLLHUP | POLLERR)) != 0) { ops = iops; } ((PollSelectionKey) k).readyOps(ops); ++updatedKeyCount; if (!selected.contains(k)) { selected.add(k); } } } return updatedKeyCount; } private void wakeupReceived() throws IOException { Native.read(pipefd[0], ByteBuffer.allocate(1)); } @Override public Selector wakeup() { try { Native.write(pipefd[1], ByteBuffer.allocate(1)); } catch (IOException ioe) { throw new RuntimeException(ioe); } return this; } } jnr-enxio-jnr-enxio-0.32.16/src/main/java/jnr/enxio/channels/WinLibCAdapter.java000066400000000000000000000107751450001425000273010ustar00rootroot00000000000000/* * This file is part of the JNR project. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jnr.enxio.channels; import java.nio.ByteBuffer; import jnr.enxio.channels.Native.LibC; import jnr.enxio.channels.Native.Timespec; import jnr.ffi.Pointer; import jnr.ffi.Runtime; import jnr.ffi.annotations.IgnoreError; import jnr.ffi.annotations.In; import jnr.ffi.annotations.Out; import jnr.ffi.provider.LoadedLibrary; import jnr.ffi.types.size_t; import jnr.ffi.types.ssize_t; /** * MSVCRT.DLL only supports some LibC functions, but the symbols are different. * This adapter maps the MSVCRT.DLL names to standard LibC names */ public final class WinLibCAdapter implements LibC, LoadedLibrary { public static interface LibMSVCRT { public int _close(int fd); public @ssize_t int _read(int fd, @Out ByteBuffer data, @size_t long size); public @ssize_t int _read(int fd, @Out byte[] data, @size_t long size); public @ssize_t int _write(int fd, @In ByteBuffer data, @size_t long size); public @ssize_t int _write(int fd, @In byte[] data, @size_t long size); public int _pipe(@Out int[] fds); @IgnoreError String _strerror(int error); // These functions don't exist: //public int shutdown(int s, int how); //public int fcntl(int fd, int cmd, int data); //public int poll(@In @Out ByteBuffer pfds, int nfds, int timeout); //public int poll(@In @Out Pointer pfds, int nfds, int timeout); //public int kqueue(); //public int kevent(int kq, @In ByteBuffer changebuf, int nchanges, // @Out ByteBuffer eventbuf, int nevents, // @In @Transient Timespec timeout); //public int kevent(int kq, // @In Pointer changebuf, int nchanges, // @Out Pointer eventbuf, int nevents, // @In @Transient Timespec timeout); } private LibMSVCRT win; public WinLibCAdapter(LibMSVCRT winlibc) { this.win = winlibc; } @Override public int close(int fd) { return win._close(fd); } @Override public int read(int fd, ByteBuffer data, long size) { return win._read(fd, data, size); } @Override public int read(int fd, byte[] data, long size) { return win._read(fd, data, size); } @Override public int write(int fd, ByteBuffer data, long size) { return win._write(fd, data, size); } @Override public int write(int fd, byte[] data, long size) { return win._write(fd, data, size); } @Override public int pipe(int[] fds) { return win._pipe(fds); } @Override public String strerror(int error) { return win._strerror(error); } @Override public Runtime getRuntime() { return Runtime.getRuntime(win); } // Unsupported Operations. Some may be implementable, others like fcntl may not be. @Override public int fcntl(int fd, int cmd, int data) { throw new UnsupportedOperationException("fcntl isn't supported on Windows"); } @Override public int poll(ByteBuffer pfds, int nfds, int timeout) { throw new UnsupportedOperationException("poll isn't supported on Windows"); } @Override public int poll(Pointer pfds, int nfds, int timeout) { throw new UnsupportedOperationException("poll isn't supported on Windows"); } @Override public int kqueue() { throw new UnsupportedOperationException("kqueue isn't supported on Windows"); } @Override public int kevent(int kq, ByteBuffer changebuf, int nchanges, ByteBuffer eventbuf, int nevents, Timespec timeout) { throw new UnsupportedOperationException("kevent isn't supported on Windows"); } @Override public int kevent(int kq, Pointer changebuf, int nchanges, Pointer eventbuf, int nevents, Timespec timeout) { throw new UnsupportedOperationException("kevent isn't supported on Windows"); } @Override public int shutdown(int s, int how) { throw new UnsupportedOperationException("shutdown isn't supported on Windows"); } }jnr-enxio-jnr-enxio-0.32.16/src/test/000077500000000000000000000000001450001425000172405ustar00rootroot00000000000000jnr-enxio-jnr-enxio-0.32.16/src/test/java/000077500000000000000000000000001450001425000201615ustar00rootroot00000000000000jnr-enxio-jnr-enxio-0.32.16/src/test/java/jnr/000077500000000000000000000000001450001425000207525ustar00rootroot00000000000000jnr-enxio-jnr-enxio-0.32.16/src/test/java/jnr/enxio/000077500000000000000000000000001450001425000220745ustar00rootroot00000000000000jnr-enxio-jnr-enxio-0.32.16/src/test/java/jnr/enxio/channels/000077500000000000000000000000001450001425000236675ustar00rootroot00000000000000jnr-enxio-jnr-enxio-0.32.16/src/test/java/jnr/enxio/channels/NativeTest.java000066400000000000000000000014141450001425000266200ustar00rootroot00000000000000package jnr.enxio.channels; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import java.io.FileDescriptor; import java.io.FileOutputStream; import java.lang.reflect.Field; public class NativeTest { @Rule public ExpectedException expectedEx = ExpectedException.none(); @Test public void closeThrowsOnNativeError() throws Exception { FileOutputStream fos = new FileOutputStream("/dev/null"); FileDescriptor descriptor = fos.getFD(); Field fdField = descriptor.getClass().getDeclaredField("fd"); fdField.setAccessible(true); int fd = (int)(Integer)fdField.get(descriptor); Native.close(fd); expectedEx.expect(NativeException.class); Native.close(fd); } } jnr-enxio-jnr-enxio-0.32.16/src/test/java/jnr/enxio/example/000077500000000000000000000000001450001425000235275ustar00rootroot00000000000000jnr-enxio-jnr-enxio-0.32.16/src/test/java/jnr/enxio/example/TCPServer.java000066400000000000000000000201451450001425000262110ustar00rootroot00000000000000/* * Copyright (C) 2008 Wayne Meissner * * This file is part of the JNR project. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jnr.enxio.example; import jnr.enxio.channels.NativeSelectableChannel; import jnr.enxio.channels.NativeSelectorProvider; import jnr.enxio.channels.NativeServerSocketChannel; import jnr.enxio.channels.NativeSocketChannel; import jnr.ffi.*; import jnr.ffi.annotations.In; import jnr.ffi.annotations.Out; import jnr.ffi.types.size_t; import jnr.ffi.types.ssize_t; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.SelectableChannel; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; /** * * @author wayne */ public class TCPServer { static final String[] libnames = Platform.getNativePlatform().getOS() == Platform.OS.SOLARIS ? new String[] { "socket", "nsl", "c" } : new String[] { Platform.getNativePlatform().getStandardCLibraryName() }; static final LibC libc = Library.loadLibrary(LibC.class, libnames); static final jnr.ffi.Runtime runtime = jnr.ffi.Runtime.getSystemRuntime(); public static class SockAddr extends Struct { public SockAddr() { super(runtime); } } static class BSDSockAddrIN extends SockAddr { public final Unsigned8 sin_len = new Unsigned8(); public final Unsigned8 sin_family = new Unsigned8(); public final Unsigned16 sin_port = new Unsigned16(); public final Unsigned32 sin_addr = new Unsigned32(); public final Padding sin_zero = new Padding(NativeType.SCHAR, 8); } static class SockAddrIN extends SockAddr { public final Unsigned16 sin_family = new Unsigned16(); public final Unsigned16 sin_port = new Unsigned16(); public final Unsigned32 sin_addr = new Unsigned32(); public final Padding sin_zero = new Padding(NativeType.SCHAR, 8); } public static interface LibC { static final int AF_INET = jnr.constants.platform.AddressFamily.AF_INET.intValue(); static final int SOCK_STREAM = jnr.constants.platform.Sock.SOCK_STREAM.intValue(); int socket(int domain, int type, int protocol); int close(int fd); int listen(int fd, int backlog); int bind(int fd, SockAddr addr, int len); int accept(int fd, @Out SockAddr addr, int[] len); @ssize_t int read(int fd, @Out ByteBuffer data, @size_t int len); @ssize_t int read(int fd, @Out byte[] data, @size_t int len); @ssize_t int write(int fd, @In ByteBuffer data, @size_t int len); String strerror(int error); } static short htons(short val) { return Short.reverseBytes(val); } static NativeServerSocketChannel serverSocket(int port) { int fd = libc.socket(LibC.AF_INET, LibC.SOCK_STREAM, 0); System.out.println("fd=" + fd); SockAddr addr; if (Platform.getNativePlatform().isBSD()) { BSDSockAddrIN sin = new BSDSockAddrIN(); sin.sin_family.set((byte) LibC.AF_INET); sin.sin_port.set(htons((short) port)); addr = sin; } else { SockAddrIN sin = new SockAddrIN(); sin.sin_family.set(htons((short) LibC.AF_INET)); sin.sin_port.set(htons((short) port)); addr = sin; } System.out.println("sizeof addr=" + Struct.size(addr)); if (libc.bind(fd, addr, Struct.size(addr)) < 0) { System.err.println("bind failed: " + libc.strerror(LastError.getLastError(runtime))); System.exit(1); } if (libc.listen(fd, 5) < 0) { System.err.println("listen failed: " + libc.strerror(LastError.getLastError(runtime))); System.exit(1); } System.out.println("bind+listen succeeded"); return new NativeServerSocketChannel(fd); } private static abstract class IO { protected final SelectableChannel channel; protected final Selector selector; public IO(Selector selector, SelectableChannel ch) { this.selector = selector; this.channel = ch; } public abstract void read(); public abstract void write(); } private static class Accepter extends IO { public Accepter(Selector selector, NativeServerSocketChannel ch) { super(selector, ch); } public void read() { SockAddrIN sin = new SockAddrIN(); int[] addrSize = { Struct.size(sin) }; int clientfd = libc.accept(((NativeSelectableChannel) channel).getFD(), sin, addrSize); System.out.println("client fd = " + clientfd); NativeSocketChannel ch = new NativeSocketChannel(clientfd); try { ch.configureBlocking(false); ch.register(selector, SelectionKey.OP_READ, new Client(selector, ch)); selector.wakeup(); } catch (IOException ex) {} } public void write() { SelectionKey k = channel.keyFor(selector); k.interestOps(SelectionKey.OP_ACCEPT); } } private static class Client extends IO { private final ByteBuffer buf = ByteBuffer.allocateDirect(1024); public Client(Selector selector, NativeSocketChannel ch) { super(selector, ch); } public void read() { int n = libc.read(((NativeSelectableChannel) channel).getFD(), buf, buf.remaining()); System.out.println("Read " + n + " bytes from client"); if (n <= 0) { SelectionKey k = channel.keyFor(selector); k.cancel(); libc.close(((NativeSelectableChannel) channel).getFD()); return; } buf.position(n); buf.flip(); channel.keyFor(selector).interestOps(SelectionKey.OP_WRITE); } public void write() { while (buf.hasRemaining()) { int n = libc.write(((NativeSelectableChannel) channel).getFD(), buf, buf.remaining()); System.out.println("write returned " + n); if (n > 0) { buf.position(buf.position() + n); } if (n == 0) { return; } if (n < 0) { channel.keyFor(selector).cancel(); libc.close(((NativeSelectableChannel) channel).getFD()); return; } } System.out.println("outbuf empty"); buf.clear(); channel.keyFor(selector).interestOps(SelectionKey.OP_READ); } } public static void main(String[] args) { short baseport = 2000; try { Selector selector = NativeSelectorProvider.getInstance().openSelector(); for (int i = 0; i < 2; ++i) { NativeServerSocketChannel ch = serverSocket(baseport + i); ch.configureBlocking(false); ch.register(selector, SelectionKey.OP_ACCEPT, new Accepter(selector, ch)); } while (true) { selector.select(); for (SelectionKey k : selector.selectedKeys()) { if ((k.readyOps() & (SelectionKey.OP_READ | SelectionKey.OP_ACCEPT)) != 0) { ((IO) k.attachment()).read(); } if ((k.readyOps() & (SelectionKey.OP_WRITE | SelectionKey.OP_CONNECT)) != 0) { ((IO) k.attachment()).write(); } } } } catch (IOException ex) { } } }