mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			750 lines
		
	
	
		
			21 KiB
		
	
	
	
		
			Java
		
	
	
	
			
		
		
	
	
			750 lines
		
	
	
		
			21 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 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() { }
 | 
						|
  }
 | 
						|
}
 |