diff options
Diffstat (limited to 'libjava/classpath/vm/reference/gnu/java/nio')
3 files changed, 888 insertions, 0 deletions
diff --git a/libjava/classpath/vm/reference/gnu/java/nio/VMChannel.java b/libjava/classpath/vm/reference/gnu/java/nio/VMChannel.java new file mode 100644 index 000000000..4494ff13c --- /dev/null +++ b/libjava/classpath/vm/reference/gnu/java/nio/VMChannel.java @@ -0,0 +1,749 @@ +/* VMChannel.java -- Native interface suppling channel operations. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.nio; + +import gnu.classpath.Configuration; + +import java.io.IOException; +import java.net.Inet4Address; +import java.net.Inet6Address; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.SocketAddress; +import java.net.SocketException; +import java.nio.ByteBuffer; +import java.nio.MappedByteBuffer; + +/** + * Native interface to support configuring of channel to run in a non-blocking + * manner and support scatter/gather io operations. + * + * @author Michael Barker <mike@middlesoft.co.uk> + * + */ +public final class VMChannel +{ + /** + * Our reference implementation uses an integer to store the native + * file descriptor. Implementations without such support + */ + private final State nfd; + + private Kind kind; + + public VMChannel() + { + // XXX consider adding security check here, so only Classpath + // code may create instances. + this.nfd = new State(); + kind = Kind.OTHER; + } + + /** + * This constructor is used by the POSIX reference implementation; + * other virtual machines need not support it. + * + * <strong>Important:</strong> do not call this in library code that is + * not specific to Classpath's reference implementation. + * + * @param native_fd The native file descriptor integer. + * @throws IOException + */ + VMChannel(final int native_fd) throws IOException + { + this(); + this.nfd.setNativeFD(native_fd); + } + + public State getState() + { + return nfd; + } + + static + { + // load the shared library needed for native methods. + if (Configuration.INIT_LOAD_LIBRARY) + { + System.loadLibrary ("javanio"); + } + initIDs(); + } + + public static VMChannel getStdin() throws IOException + { + return new VMChannel(stdin_fd()); + } + + public static VMChannel getStdout() throws IOException + { + return new VMChannel(stdout_fd()); + } + + public static VMChannel getStderr() throws IOException + { + return new VMChannel(stderr_fd()); + } + + private static native int stdin_fd(); + private static native int stdout_fd(); + private static native int stderr_fd(); + + /** + * Set the file descriptor to have the required blocking + * setting. + * + * @param blocking The blocking flag to set. + */ + public void setBlocking(boolean blocking) throws IOException + { + setBlocking(nfd.getNativeFD(), blocking); + } + + private static native void setBlocking(int fd, boolean blocking) + throws IOException; + + public int available() throws IOException + { + return available(nfd.getNativeFD()); + } + + private static native int available(int native_fd) throws IOException; + + /** + * Reads a byte buffer directly using the supplied file descriptor. + * + * @param dst Direct Byte Buffer to read to. + * @return Number of bytes read. + * @throws IOException If an error occurs or dst is not a direct buffers. + */ + public int read(ByteBuffer dst) + throws IOException + { + return read(nfd.getNativeFD(), dst); + } + + private static native int read(int fd, ByteBuffer dst) throws IOException; + + /** + * Read a single byte. + * + * @return The byte read, or -1 on end of file. + * @throws IOException + */ + public int read() throws IOException + { + return read(nfd.getNativeFD()); + } + + private static native int read(int fd) throws IOException; + + /** + * Reads into byte buffers directly using the supplied file descriptor. + * Assumes that the buffer list contains DirectBuffers. Will perform a + * scattering read. + * + * @param dsts An array direct byte buffers. + * @param offset Index of the first buffer to read to. + * @param length The number of buffers to read to. + * @return Number of bytes read. + * @throws IOException If an error occurs or the dsts are not direct buffers. + */ + public long readScattering(ByteBuffer[] dsts, int offset, int length) + throws IOException + { + if (offset + length > dsts.length) + throw new IndexOutOfBoundsException("offset + length > dsts.length"); + + return readScattering(nfd.getNativeFD(), dsts, offset, length); + } + + private static native long readScattering(int fd, ByteBuffer[] dsts, + int offset, int length) + throws IOException; + + /** + * Receive a datagram on this channel, returning the host address + * that sent the datagram. + * + * @param dst Where to store the datagram. + * @return The host address that sent the datagram. + * @throws IOException + */ + public SocketAddress receive(ByteBuffer dst) throws IOException + { + if (kind != Kind.SOCK_DGRAM) + throw new SocketException("not a datagram socket"); + ByteBuffer hostPort = ByteBuffer.allocateDirect(18); + int hostlen = receive(nfd.getNativeFD(), dst, hostPort); + if (hostlen == 0) + return null; + if (hostlen == 4) // IPv4 + { + byte[] addr = new byte[4]; + hostPort.get(addr); + int port = hostPort.getShort() & 0xFFFF; + return new InetSocketAddress(Inet4Address.getByAddress(addr), port); + } + if (hostlen == 16) // IPv6 + { + byte[] addr = new byte[16]; + hostPort.get(addr); + int port = hostPort.getShort() & 0xFFFF; + return new InetSocketAddress(Inet6Address.getByAddress(addr), port); + } + + throw new SocketException("host address received with invalid length: " + + hostlen); + } + + private static native int receive (int fd, ByteBuffer dst, ByteBuffer address) + throws IOException; + + /** + * Writes from a direct byte bufer using the supplied file descriptor. + * Assumes the buffer is a DirectBuffer. + * + * @param src The source buffer. + * @return Number of bytes written. + * @throws IOException + */ + public int write(ByteBuffer src) throws IOException + { + return write(nfd.getNativeFD(), src); + } + + private native int write(int fd, ByteBuffer src) throws IOException; + + /** + * Writes from byte buffers directly using the supplied file descriptor. + * Assumes the that buffer list constains DirectBuffers. Will perform + * as gathering write. + * + * @param srcs + * @param offset + * @param length + * @return Number of bytes written. + * @throws IOException + */ + public long writeGathering(ByteBuffer[] srcs, int offset, int length) + throws IOException + { + if (offset + length > srcs.length) + throw new IndexOutOfBoundsException("offset + length > srcs.length"); + + // A gathering write is limited to 16 buffers; when writing, ensure + // that we have at least one buffer with something in it in the 16 + // buffer window starting at offset. + while (!srcs[offset].hasRemaining() && offset < srcs.length) + offset++; + + // There are no buffers with anything to write. + if (offset == srcs.length) + return 0; + + // If we advanced `offset' so far that we don't have `length' + // buffers left, reset length to only the remaining buffers. + if (length > srcs.length - offset) + length = srcs.length - offset; + + return writeGathering(nfd.getNativeFD(), srcs, offset, length); + } + + private native long writeGathering(int fd, ByteBuffer[] srcs, + int offset, int length) + throws IOException; + + /** + * Send a datagram to the given address. + * + * @param src The source buffer. + * @param dst The destination address. + * @return The number of bytes written. + * @throws IOException + */ + public int send(ByteBuffer src, InetSocketAddress dst) + throws IOException + { + InetAddress addr = dst.getAddress(); + if (addr == null) + throw new NullPointerException(); + if (addr instanceof Inet4Address) + return send(nfd.getNativeFD(), src, addr.getAddress(), dst.getPort()); + else if (addr instanceof Inet6Address) + return send6(nfd.getNativeFD(), src, addr.getAddress(), dst.getPort()); + else + throw new SocketException("unrecognized inet address type"); + } + + // Send to an IPv4 address. + private static native int send(int fd, ByteBuffer src, byte[] addr, int port) + throws IOException; + + // Send to an IPv6 address. + private static native int send6(int fd, ByteBuffer src, byte[] addr, int port) + throws IOException; + + /** + * Write a single byte. + * + * @param b The byte to write. + * @throws IOException + */ + public void write(int b) throws IOException + { + write(nfd.getNativeFD(), b); + } + + private static native void write(int fd, int b) throws IOException; + + private native static void initIDs(); + + // Network (socket) specific methods. + + /** + * Create a new socket. This method will initialize the native file + * descriptor state of this instance. + * + * @param stream Whether or not to create a streaming socket, or a datagram + * socket. + * @throws IOException If creating a new socket fails, or if this + * channel already has its native descriptor initialized. + */ + public void initSocket(boolean stream) throws IOException + { + if (nfd.isValid()) + throw new IOException("native FD already initialized"); + if (stream) + kind = Kind.SOCK_STREAM; + else + kind = Kind.SOCK_DGRAM; + nfd.setNativeFD(socket(stream)); + } + + /** + * Create a new socket, returning the native file descriptor. + * + * @param stream Set to true for streaming sockets; false for datagrams. + * @return The native file descriptor. + * @throws IOException If creating the socket fails. + */ + private static native int socket(boolean stream) throws IOException; + + /** + * Connect the underlying socket file descriptor to the remote host. + * + * @param saddr The address to connect to. + * @param timeout The connect timeout to use for blocking connects. + * @return True if the connection succeeded; false if the file descriptor + * is in non-blocking mode and the connection did not immediately + * succeed. + * @throws IOException If an error occurs while connecting. + */ + public boolean connect(InetSocketAddress saddr, int timeout) + throws SocketException + { + int fd; + + InetAddress addr = saddr.getAddress(); + + // Translates an IOException into a SocketException to conform + // to the throws clause. + try + { + fd = nfd.getNativeFD(); + } + catch (IOException ioe) + { + throw new SocketException(ioe.getMessage()); + } + + if (addr instanceof Inet4Address) + return connect(fd, addr.getAddress(), saddr.getPort(), + timeout); + if (addr instanceof Inet6Address) + return connect6(fd, addr.getAddress(), saddr.getPort(), + timeout); + throw new SocketException("unsupported internet address"); + } + + private static native boolean connect(int fd, byte[] addr, int port, int timeout) + throws SocketException; + + private static native boolean connect6(int fd, byte[] addr, int port, int timeout) + throws SocketException; + + /** + * Disconnect this channel, if it is a datagram socket. Disconnecting + * a datagram channel will disassociate it from any address, so the + * socket will remain open, but can send and receive datagrams from + * any address. + * + * @throws IOException If disconnecting this channel fails, or if this + * channel is not a datagram channel. + */ + public void disconnect() throws IOException + { + if (kind != Kind.SOCK_DGRAM) + throw new IOException("can only disconnect datagram channels"); + disconnect(nfd.getNativeFD()); + } + + private static native void disconnect(int fd) throws IOException; + + public InetSocketAddress getLocalAddress() throws IOException + { + if (!nfd.isValid()) + return null; + ByteBuffer name = ByteBuffer.allocateDirect(18); + int namelen = getsockname(nfd.getNativeFD(), name); + if (namelen == 0) // not bound + return null; // XXX return some wildcard? + if (namelen == 4) + { + byte[] addr = new byte[4]; + name.get(addr); + int port = name.getShort() & 0xFFFF; + return new InetSocketAddress(Inet4Address.getByAddress(addr), port); + } + if (namelen == 16) + { + byte[] addr = new byte[16]; + name.get(addr); + int port = name.getShort() & 0xFFFF; + return new InetSocketAddress(Inet6Address.getByAddress(addr), port); + } + throw new SocketException("invalid address length"); + } + + private static native int getsockname(int fd, ByteBuffer name) + throws IOException; + + /** + * Returns the socket address of the remote peer this channel is connected + * to, or null if this channel is not yet connected. + * + * @return The peer address. + * @throws IOException + */ + public InetSocketAddress getPeerAddress() throws IOException + { + if (!nfd.isValid()) + return null; + ByteBuffer name = ByteBuffer.allocateDirect(18); + int namelen = getpeername (nfd.getNativeFD(), name); + if (namelen == 0) // not connected yet + return null; + if (namelen == 4) // IPv4 + { + byte[] addr = new byte[4]; + name.get(addr); + int port = name.getShort() & 0xFFFF; + return new InetSocketAddress(Inet4Address.getByAddress(addr), port); + } + else if (namelen == 16) // IPv6 + { + byte[] addr = new byte[16]; + name.get(addr); + int port = name.getShort() & 0xFFFF; + return new InetSocketAddress(Inet6Address.getByAddress(addr), port); + } + throw new SocketException("invalid address length"); + } + + /* + * The format here is the peer address, followed by the port number. + * The returned value is the length of the peer address; thus, there + * will be LEN + 2 valid bytes put into NAME. + */ + private static native int getpeername(int fd, ByteBuffer name) + throws IOException; + + /** + * Accept an incoming connection, returning a new VMChannel, or null + * if the channel is nonblocking and no connection is pending. + * + * @return The accepted connection, or null. + * @throws IOException If an IO error occurs. + */ + public VMChannel accept() throws IOException + { + int new_fd = accept(nfd.getNativeFD()); + if (new_fd == -1) // non-blocking accept had no pending connection + return null; + return new VMChannel(new_fd); + } + + private static native int accept(int native_fd) throws IOException; + + // File-specific methods. + + /** + * Open a file at PATH, initializing the native state to operate on + * that open file. + * + * @param path The absolute file path. + * @throws IOException If the file cannot be opened, or if this + * channel was previously initialized. + */ + public void openFile(String path, int mode) throws IOException + { + if (nfd.isValid() || nfd.isClosed()) + throw new IOException("can't reinitialize this channel"); + int fd = open(path, mode); + nfd.setNativeFD(fd); + kind = Kind.FILE; + } + + private static native int open(String path, int mode) throws IOException; + + public long position() throws IOException + { + if (kind != Kind.FILE) + throw new IOException("not a file"); + return position(nfd.getNativeFD()); + } + + private static native long position(int fd) throws IOException; + + public void seek(long pos) throws IOException + { + if (kind != Kind.FILE) + throw new IOException("not a file"); + seek(nfd.getNativeFD(), pos); + } + + private static native void seek(int fd, long pos) throws IOException; + + public void truncate(long length) throws IOException + { + if (kind != Kind.FILE) + throw new IOException("not a file"); + truncate(nfd.getNativeFD(), length); + } + + private static native void truncate(int fd, long len) throws IOException; + + public boolean lock(long pos, long len, boolean shared, boolean wait) + throws IOException + { + if (kind != Kind.FILE) + throw new IOException("not a file"); + return lock(nfd.getNativeFD(), pos, len, shared, wait); + } + + private static native boolean lock(int fd, long pos, long len, + boolean shared, boolean wait) + throws IOException; + + public void unlock(long pos, long len) throws IOException + { + if (kind != Kind.FILE) + throw new IOException("not a file"); + unlock(nfd.getNativeFD(), pos, len); + } + + private static native void unlock(int fd, long pos, long len) throws IOException; + + public long size() throws IOException + { + if (kind != Kind.FILE) + throw new IOException("not a file"); + return size(nfd.getNativeFD()); + } + + private static native long size(int fd) throws IOException; + + public MappedByteBuffer map(char mode, long position, int size) + throws IOException + { + if (kind != Kind.FILE) + throw new IOException("not a file"); + return map(nfd.getNativeFD(), mode, position, size); + } + + private static native MappedByteBuffer map(int fd, char mode, + long position, int size) + throws IOException; + + public boolean flush(boolean metadata) throws IOException + { + if (kind != Kind.FILE) + throw new IOException("not a file"); + return flush(nfd.getNativeFD(), metadata); + } + + private static native boolean flush(int fd, boolean metadata) throws IOException; + + // Close. + + /** + * Close this socket. The socket is also automatically closed when this + * object is finalized. + * + * @throws IOException If closing the socket fails, or if this object has + * no open socket. + */ + public void close() throws IOException + { + nfd.close(); + } + + static native void close(int native_fd) throws IOException; + + /** + * <p>Provides a simple mean for the JNI code to find out whether the + * current thread was interrupted by a call to Thread.interrupt().</p> + * + * @return + */ + static boolean isThreadInterrupted() + { + return Thread.currentThread().isInterrupted(); + } + + // Inner classes. + + /** + * A wrapper for a native file descriptor integer. This tracks the state + * of an open file descriptor, and ensures that + * + * This class need not be fully supported by virtual machines; if a + * virtual machine does not use integer file descriptors, or does and + * wishes to hide that, then the methods of this class may be stubbed out. + * + * System-specific classes that depend on access to native file descriptor + * integers SHOULD declare this fact. + */ + public final class State + { + private int native_fd; + private boolean valid; + private boolean closed; + + State() + { + native_fd = -1; + valid = false; + closed = false; + } + + public boolean isValid() + { + return valid; + } + + public boolean isClosed() + { + return closed; + } + + public int getNativeFD() throws IOException + { + if (!valid) + throw new IOException("invalid file descriptor"); + return native_fd; + } + + void setNativeFD(final int native_fd) throws IOException + { + if (valid) + throw new IOException("file descriptor already initialized"); + this.native_fd = native_fd; + valid = true; + } + + public void close() throws IOException + { + if (!valid) + throw new IOException("invalid file descriptor"); + try + { + VMChannel.close(native_fd); + } + finally + { + valid = false; + closed = true; + } + } + + public String toString() + { + if (closed) + return "<<closed>>"; + if (!valid) + return "<<invalid>>"; + return String.valueOf(native_fd); + } + + protected void finalize() throws Throwable + { + try + { + if (valid) + close(); + } + finally + { + super.finalize(); + } + } + } + + /** + * An enumeration of possible kinds of channel. + */ + static class Kind // XXX enum + { + /** A streaming (TCP) socket. */ + static final Kind SOCK_STREAM = new Kind(); + + /** A datagram (UDP) socket. */ + static final Kind SOCK_DGRAM = new Kind(); + + /** A file. */ + static final Kind FILE = new Kind(); + + /** Something else; not a socket or file. */ + static final Kind OTHER = new Kind(); + + private Kind() { } + } +} diff --git a/libjava/classpath/vm/reference/gnu/java/nio/VMPipe.java b/libjava/classpath/vm/reference/gnu/java/nio/VMPipe.java new file mode 100644 index 000000000..a36970452 --- /dev/null +++ b/libjava/classpath/vm/reference/gnu/java/nio/VMPipe.java @@ -0,0 +1,80 @@ +/* VMPipe.java -- Reference implementation for VM hooks used by PipeImpl + Copyright (C) 2004 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.nio; + +import java.io.IOException; +import gnu.classpath.Configuration; + +/** + * This class contains the native methods for gnu.java.nio.PipeImpl + * As such, it needs help from the VM. + * + * @author Patrik Reali + */ +final class VMPipe +{ + + static + { + // load the shared library needed for native methods. + if (Configuration.INIT_LOAD_LIBRARY) + { + System.loadLibrary ("javanio"); + } + } + + /** + * Create a pipe, consisting of a readable VMChannel and a writable + * VMChannel. The readable channel is returned is the first element + * of the array, and the writable in the second. + * + * @return A pair of VMChannels; the first readable, the second + * writable. + * @throws IOException If the pipe cannot be created. + */ + static VMChannel[] pipe() throws IOException + { + VMChannel[] pipe = new VMChannel[2]; + int[] fds = pipe0(); + pipe[0] = new VMChannel(fds[0]); + pipe[1] = new VMChannel(fds[1]); + return pipe; + } + + private static native int[] pipe0() throws IOException; +} diff --git a/libjava/classpath/vm/reference/gnu/java/nio/VMSelector.java b/libjava/classpath/vm/reference/gnu/java/nio/VMSelector.java new file mode 100644 index 000000000..4d37c2c1c --- /dev/null +++ b/libjava/classpath/vm/reference/gnu/java/nio/VMSelector.java @@ -0,0 +1,59 @@ +/* VMSelector.java -- + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.nio; + +import gnu.classpath.Configuration; +import java.io.IOException; + +public final class VMSelector +{ + static + { + // load the shared library needed for native methods. + if (Configuration.INIT_LOAD_LIBRARY) + { + System.loadLibrary ("javanio"); + } + } + + // A timeout value of 0 means block forever. + static native int select (int[] read, int[] write, + int[] except, long timeout) + throws IOException; + +} |