mirror of
https://github.com/2003scape/deep-c-rsc.git
synced 2024-03-22 05:49:51 -04:00
751 lines
22 KiB
Java
751 lines
22 KiB
Java
/* 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 fd
|
|
* @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() { }
|
|
}
|
|
}
|