Merged gcj-eclipse branch to trunk.
From-SVN: r120621
This commit is contained in:
@@ -90,7 +90,7 @@ final class VMMemoryMXBeanImpl
|
||||
* information when memory is allocated and deallocated. The
|
||||
* format of the output is left up to the virtual machine.
|
||||
*
|
||||
* @return true if verbose class loading output is on.
|
||||
* @return true if verbose memory usage output is on.
|
||||
*/
|
||||
static native boolean isVerbose();
|
||||
|
||||
@@ -101,7 +101,7 @@ final class VMMemoryMXBeanImpl
|
||||
* may be called by multiple threads concurrently, but there
|
||||
* is only one global setting of verbosity that is affected.
|
||||
*
|
||||
* @param verbose the new setting for verbose class loading
|
||||
* @param verbose the new setting for verbose memory usage
|
||||
* output.
|
||||
*/
|
||||
static native void setVerbose(boolean verbose);
|
||||
|
||||
@@ -38,15 +38,16 @@ exception statement from your version. */
|
||||
package gnu.java.net;
|
||||
|
||||
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.NetworkInterface;
|
||||
import java.net.SocketException;
|
||||
import java.net.SocketImpl;
|
||||
import java.net.SocketOptions;
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
import gnu.classpath.Configuration;
|
||||
import gnu.java.nio.VMChannel;
|
||||
|
||||
/**
|
||||
* The VM interface for {@link gnu.java.net.PlainSocketImpl}.
|
||||
@@ -56,6 +57,12 @@ import gnu.classpath.Configuration;
|
||||
*/
|
||||
public final class VMPlainSocketImpl
|
||||
{
|
||||
/** Option id for time to live
|
||||
*/
|
||||
private static final int CP_IP_TTL = 0x1E61;
|
||||
|
||||
private final State nfd;
|
||||
|
||||
/**
|
||||
* Static initializer to load native library.
|
||||
*/
|
||||
@@ -66,249 +73,440 @@ public final class VMPlainSocketImpl
|
||||
System.loadLibrary("javanet");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the specified option on a socket to the passed in object.
|
||||
* The optionId parameter is one of the defined constants in
|
||||
* the SocketImpl interface.
|
||||
*
|
||||
* @param socket the socket object
|
||||
* @param optionId the identifier of the option
|
||||
* @param value the value to set the option to
|
||||
*
|
||||
* @throws SocketException if an error occurs
|
||||
*/
|
||||
static native void setOption(PlainSocketImpl socket, int optionId, Object value)
|
||||
throws SocketException;
|
||||
|
||||
/**
|
||||
* Returns the current setting of the specified option. The optionId
|
||||
* is one of the defined constants in this interface.
|
||||
*
|
||||
* @param socket the socket object
|
||||
* @param optionId the option identifier
|
||||
*
|
||||
* @return the current value of the option
|
||||
*
|
||||
* @throws SocketException ff an error occurs
|
||||
*/
|
||||
static native Object getOption(PlainSocketImpl socket, int optionId)
|
||||
throws SocketException;
|
||||
|
||||
/**
|
||||
* Creates a new socket that is not bound to any local address/port and
|
||||
* is not connected to any remote address/port.
|
||||
*
|
||||
* @param socket the socket object
|
||||
*
|
||||
* @throws IOException if something goes wrong while creating the socket
|
||||
*/
|
||||
static native void create(PlainSocketImpl socket) throws IOException;
|
||||
|
||||
/**
|
||||
* Connects to the remote address and port specified as arguments.
|
||||
*
|
||||
* @param socket the socket object
|
||||
* @param addr the remote address to connect to
|
||||
* @param port the remote port to connect to
|
||||
*
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
static native void connect(PlainSocketImpl socket, InetAddress addr,
|
||||
int port) throws IOException;
|
||||
|
||||
/**
|
||||
* Binds to the specified port on the specified addr. Note that this addr
|
||||
* must represent a local IP address. **** How bind to INADDR_ANY? ****
|
||||
*
|
||||
* @param socket the socket object
|
||||
* @param addr the address to bind to
|
||||
* @param port the port number to bind to
|
||||
*
|
||||
* @exception IOException If an error occurs
|
||||
*/
|
||||
static native void bind(PlainSocketImpl socket, InetAddress addr, int port)
|
||||
throws IOException;
|
||||
|
||||
/**
|
||||
* Starts listening for connections on a socket. The queueLen parameter
|
||||
* is how many pending connections will queue up waiting to be serviced
|
||||
* before being accepted. If the queue of pending requests exceeds this
|
||||
* number, additional connections will be refused.
|
||||
*
|
||||
* @param socket the socket object
|
||||
* @param queueLen the length of the pending connection queue
|
||||
*
|
||||
* @exception IOException if an error occurs
|
||||
*/
|
||||
static native void listen(PlainSocketImpl socket, int queueLen)
|
||||
throws IOException;
|
||||
|
||||
/**
|
||||
* Accepts a new connection on this socket.
|
||||
*
|
||||
* @param socket the socket object
|
||||
* @param impl the socket object to accept this connection.
|
||||
*/
|
||||
static native void accept(PlainSocketImpl socket, SocketImpl impl)
|
||||
throws IOException;
|
||||
|
||||
/**
|
||||
* Returns the number of bytes that the caller can read from this socket
|
||||
* without blocking.
|
||||
*
|
||||
* @param socket the socket object
|
||||
*
|
||||
* @return the number of readable bytes before blocking
|
||||
*
|
||||
* @throws IOException If an error occurs
|
||||
*/
|
||||
static native int available(PlainSocketImpl socket) throws IOException;
|
||||
|
||||
/**
|
||||
* Closes the socket. This will cause any InputStream or OutputStream
|
||||
* objects for this Socket to be closed as well.
|
||||
*
|
||||
* <p>
|
||||
* Note that if the SO_LINGER option is set on this socket, then the
|
||||
* operation could block.
|
||||
* </p>
|
||||
*
|
||||
* @param socket the socket object
|
||||
*
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
static native void close(PlainSocketImpl socket) throws IOException;
|
||||
|
||||
/**
|
||||
* Internal method used by SocketInputStream for reading data from
|
||||
* the connection. Reads up to len bytes of data into the buffer
|
||||
* buf starting at offset bytes into the buffer.
|
||||
*
|
||||
* @param socket the socket object
|
||||
*
|
||||
* @return the actual number of bytes read or -1 if end of stream.
|
||||
*
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
static native int read(PlainSocketImpl socket, byte[] buf, int offset,
|
||||
int len) throws IOException;
|
||||
|
||||
/**
|
||||
* Internal method used by SocketInputStream for reading data from
|
||||
* the connection. Reads and returns one byte of data.
|
||||
*
|
||||
* @param socket the socket object
|
||||
*
|
||||
* @return read byte or -1 if end of stream.
|
||||
*
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
static int read(PlainSocketImpl socket) throws IOException
|
||||
|
||||
public VMPlainSocketImpl()
|
||||
{
|
||||
byte[] buf = new byte[1];
|
||||
if (read(socket, buf, 0, 1) > 0)
|
||||
return buf[0] & 0xFF;
|
||||
else
|
||||
return -1;
|
||||
// XXX consider adding security check here.
|
||||
nfd = new State();
|
||||
}
|
||||
|
||||
public VMPlainSocketImpl(VMChannel channel) throws IOException
|
||||
{
|
||||
this();
|
||||
nfd.setChannelFD(channel.getState());
|
||||
}
|
||||
|
||||
public State getState()
|
||||
{
|
||||
return nfd;
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal method used by SocketOuputStream for writing data to
|
||||
* the connection. Writes up to len bytes of data from the buffer
|
||||
* <code>buf</code> starting at <cod>offset</code> bytes into the buffer.
|
||||
/** This method exists to hide the CP_IP_TTL value from
|
||||
* higher levels.
|
||||
*
|
||||
* @param socket the socket object
|
||||
* @param buf the buffer to write to the stream
|
||||
* @param offset the start offset in the buffer
|
||||
* @param len the number of bytes to write
|
||||
*
|
||||
* @throws IOException if an error occurs
|
||||
* Always think of JNode ... :)
|
||||
*/
|
||||
static native void write(PlainSocketImpl socket, byte[] buf, int offset,
|
||||
int len) throws IOException;
|
||||
|
||||
/**
|
||||
* Internal method used by SocketOuputStream for writing data to
|
||||
* the connection. Writes exactly one byte to the socket.
|
||||
*
|
||||
* @param socket the socket object
|
||||
* @param data the byte to write to the socket
|
||||
*
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
static void write(PlainSocketImpl socket, int data)
|
||||
throws IOException
|
||||
public void setTimeToLive(int ttl)
|
||||
throws SocketException
|
||||
{
|
||||
write(socket, new byte[]{ (byte) data }, 0, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the input stream for this socket to the end of the stream. Any
|
||||
* attempts to read more bytes from the stream will return an EOF.
|
||||
*
|
||||
* @param socket the socket object
|
||||
*
|
||||
* @throws IOException if I/O errors occur
|
||||
*/
|
||||
static native void shutdownInput(PlainSocketImpl socket) throws IOException;
|
||||
|
||||
/**
|
||||
* Disables the output stream for this socket. Any attempt to write more
|
||||
* data to the socket will throw an IOException.
|
||||
*
|
||||
* @param socket the socket object
|
||||
*
|
||||
* @throws IOException if I/O errors occur
|
||||
*/
|
||||
static native void shutdownOutput(PlainSocketImpl socket) throws IOException;
|
||||
|
||||
/**
|
||||
* Connects to the remote socket address with a specified timeout.
|
||||
*
|
||||
* @param socket the socket object
|
||||
* @param address the remote address to connect to
|
||||
* @param timeout the timeout to use for this connect, 0 means infinite.
|
||||
*
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
static synchronized void connect(PlainSocketImpl socket,
|
||||
SocketAddress address, int timeout)
|
||||
throws IOException
|
||||
{
|
||||
InetSocketAddress sockAddr = (InetSocketAddress) address;
|
||||
InetAddress addr = sockAddr.getAddress();
|
||||
|
||||
if (addr == null)
|
||||
throw new UnknownHostException(sockAddr.getHostName());
|
||||
|
||||
int port = sockAddr.getPort();
|
||||
|
||||
if (timeout < 0)
|
||||
throw new IllegalArgumentException("negative timeout");
|
||||
|
||||
Object oldTimeoutObj = null;
|
||||
try
|
||||
{
|
||||
oldTimeoutObj = getOption(socket, SocketOptions.SO_TIMEOUT);
|
||||
setOption(socket, SocketOptions.SO_TIMEOUT, new Integer(timeout));
|
||||
connect(socket, addr, port);
|
||||
setOption(nfd.getNativeFD(), CP_IP_TTL, ttl);
|
||||
}
|
||||
finally
|
||||
catch (IOException ioe)
|
||||
{
|
||||
if (oldTimeoutObj != null)
|
||||
setOption(socket, SocketOptions.SO_TIMEOUT, oldTimeoutObj);
|
||||
SocketException se = new SocketException();
|
||||
se.initCause(ioe);
|
||||
throw se;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send one byte of urgent data over the socket.
|
||||
*
|
||||
* @param socket the socket object
|
||||
* @param data the byte to send
|
||||
*/
|
||||
static void sendUrgendData(PlainSocketImpl socket, int data)
|
||||
public int getTimeToLive()
|
||||
throws SocketException
|
||||
{
|
||||
throw new InternalError ("PlainSocketImpl::sendUrgentData not implemented");
|
||||
try
|
||||
{
|
||||
return getOption(nfd.getNativeFD(), CP_IP_TTL);
|
||||
}
|
||||
catch (IOException ioe)
|
||||
{
|
||||
SocketException se = new SocketException();
|
||||
se.initCause(ioe);
|
||||
throw se;
|
||||
}
|
||||
}
|
||||
|
||||
public void setOption(int optionId, Object optionValue)
|
||||
throws SocketException
|
||||
{
|
||||
int value;
|
||||
if (optionValue instanceof Integer)
|
||||
value = ((Integer) optionValue).intValue();
|
||||
else if (optionValue instanceof Boolean)
|
||||
// Switching off the linger behavior is done by setting
|
||||
// the value to -1. This is how the Java API interprets
|
||||
// it.
|
||||
value = ((Boolean) optionValue).booleanValue()
|
||||
? 1
|
||||
: (optionId == SocketOptions.SO_LINGER)
|
||||
? -1
|
||||
: 0;
|
||||
else
|
||||
throw new IllegalArgumentException("option value type "
|
||||
+ optionValue.getClass().getName());
|
||||
|
||||
try
|
||||
{
|
||||
setOption(nfd.getNativeFD(), optionId, value);
|
||||
}
|
||||
catch (IOException ioe)
|
||||
{
|
||||
SocketException se = new SocketException();
|
||||
se.initCause(ioe);
|
||||
throw se;
|
||||
}
|
||||
}
|
||||
|
||||
private static native void setOption(int fd, int id, int value)
|
||||
throws SocketException;
|
||||
|
||||
public void setMulticastInterface(int optionId, InetAddress addr)
|
||||
throws SocketException
|
||||
{
|
||||
try
|
||||
{
|
||||
if (addr instanceof Inet4Address)
|
||||
setMulticastInterface(nfd.getNativeFD(), optionId, (Inet4Address) addr);
|
||||
else if (addr instanceof Inet6Address)
|
||||
{
|
||||
NetworkInterface iface = NetworkInterface.getByInetAddress(addr);
|
||||
setMulticastInterface6(nfd.getNativeFD(), optionId, iface.getName());
|
||||
}
|
||||
else
|
||||
throw new SocketException("Unknown address format: " + addr);
|
||||
}
|
||||
catch (SocketException se)
|
||||
{
|
||||
throw se;
|
||||
}
|
||||
catch (IOException ioe)
|
||||
{
|
||||
SocketException se = new SocketException();
|
||||
se.initCause(ioe);
|
||||
throw se;
|
||||
}
|
||||
}
|
||||
|
||||
private static native void setMulticastInterface(int fd,
|
||||
int optionId,
|
||||
Inet4Address addr);
|
||||
|
||||
private static native void setMulticastInterface6(int fd,
|
||||
int optionId,
|
||||
String ifName);
|
||||
|
||||
/**
|
||||
* Get a socket option. This implementation is only required to support
|
||||
* socket options that are boolean values, which include:
|
||||
*
|
||||
* SocketOptions.IP_MULTICAST_LOOP
|
||||
* SocketOptions.SO_BROADCAST
|
||||
* SocketOptions.SO_KEEPALIVE
|
||||
* SocketOptions.SO_OOBINLINE
|
||||
* SocketOptions.SO_REUSEADDR
|
||||
* SocketOptions.TCP_NODELAY
|
||||
*
|
||||
* and socket options that are integer values, which include:
|
||||
*
|
||||
* SocketOptions.IP_TOS
|
||||
* SocketOptions.SO_LINGER
|
||||
* SocketOptions.SO_RCVBUF
|
||||
* SocketOptions.SO_SNDBUF
|
||||
* SocketOptions.SO_TIMEOUT
|
||||
*
|
||||
* @param optionId The option ID to fetch.
|
||||
* @return A {@link Boolean} or {@link Integer} containing the socket
|
||||
* option.
|
||||
* @throws SocketException
|
||||
*/
|
||||
public Object getOption(int optionId) throws SocketException
|
||||
{
|
||||
int value;
|
||||
try
|
||||
{
|
||||
value = getOption(nfd.getNativeFD(), optionId);
|
||||
}
|
||||
catch (IOException ioe)
|
||||
{
|
||||
SocketException se = new SocketException();
|
||||
se.initCause(ioe);
|
||||
throw se;
|
||||
}
|
||||
|
||||
switch (optionId)
|
||||
{
|
||||
case SocketOptions.IP_MULTICAST_LOOP:
|
||||
case SocketOptions.SO_BROADCAST:
|
||||
case SocketOptions.SO_KEEPALIVE:
|
||||
case SocketOptions.SO_OOBINLINE:
|
||||
case SocketOptions.SO_REUSEADDR:
|
||||
case SocketOptions.TCP_NODELAY:
|
||||
return Boolean.valueOf(value != 0);
|
||||
|
||||
case SocketOptions.IP_TOS:
|
||||
case SocketOptions.SO_LINGER:
|
||||
case SocketOptions.SO_RCVBUF:
|
||||
case SocketOptions.SO_SNDBUF:
|
||||
case SocketOptions.SO_TIMEOUT:
|
||||
return new Integer(value);
|
||||
|
||||
default:
|
||||
throw new SocketException("getting option " + optionId +
|
||||
" not supported here");
|
||||
}
|
||||
}
|
||||
|
||||
private static native int getOption(int fd, int id) throws SocketException;
|
||||
|
||||
/**
|
||||
* Returns an Inet4Address or Inet6Address instance belonging to the
|
||||
* interface which is set as the multicast interface.
|
||||
*
|
||||
* The optionId is provided to make it possible that the native
|
||||
* implementation may do something different depending on whether
|
||||
* the value is SocketOptions.IP_MULTICAST_IF or
|
||||
* SocketOptions.IP_MULTICAST_IF2.
|
||||
*/
|
||||
public InetAddress getMulticastInterface(int optionId)
|
||||
throws SocketException
|
||||
{
|
||||
try
|
||||
{
|
||||
return getMulticastInterface(nfd.getNativeFD(), optionId);
|
||||
}
|
||||
catch (IOException ioe)
|
||||
{
|
||||
SocketException se = new SocketException();
|
||||
se.initCause(ioe);
|
||||
throw se;
|
||||
}
|
||||
}
|
||||
|
||||
private static native InetAddress getMulticastInterface(int fd,
|
||||
int optionId);
|
||||
|
||||
/**
|
||||
* Binds this socket to the given local address and port.
|
||||
*
|
||||
* @param address The address to bind to; the InetAddress is either
|
||||
* an IPv4 or IPv6 address.
|
||||
* @throws IOException If binding fails; for example, if the port
|
||||
* in the given InetSocketAddress is privileged, and the current
|
||||
* process has insufficient privileges.
|
||||
*/
|
||||
public void bind(InetSocketAddress address) throws IOException
|
||||
{
|
||||
InetAddress addr = address.getAddress();
|
||||
if (addr instanceof Inet4Address)
|
||||
{
|
||||
bind (nfd.getNativeFD(), addr.getAddress(), address.getPort());
|
||||
}
|
||||
else if (addr instanceof Inet6Address)
|
||||
bind6 (nfd.getNativeFD(), addr.getAddress(), address.getPort());
|
||||
else
|
||||
throw new SocketException ("unsupported address type");
|
||||
}
|
||||
|
||||
/**
|
||||
* Native bind function for IPv4 addresses. The addr array must be
|
||||
* exactly four bytes long.
|
||||
*
|
||||
* VMs without native support need not implement this.
|
||||
*
|
||||
* @param fd The native file descriptor integer.
|
||||
* @param addr The IPv4 address, in network byte order.
|
||||
* @param port The port to bind to.
|
||||
* @throws IOException
|
||||
*/
|
||||
private static native void bind(int fd, byte[] addr, int port)
|
||||
throws IOException;
|
||||
|
||||
/**
|
||||
* Native bind function for IPv6 addresses. The addr array must be
|
||||
* exactly sixteen bytes long.
|
||||
*
|
||||
* VMs without native support need not implement this.
|
||||
*
|
||||
* @param fd The native file descriptor integer.
|
||||
* @param addr The IPv6 address, in network byte order.
|
||||
* @param port The port to bind to.
|
||||
* @throws IOException
|
||||
*/
|
||||
private static native void bind6(int fd, byte[] addr, int port)
|
||||
throws IOException;
|
||||
|
||||
/**
|
||||
* Listen on this socket for incoming connections.
|
||||
*
|
||||
* @param backlog The backlog of connections.
|
||||
* @throws IOException If listening fails.
|
||||
* @see gnu.java.nio.VMChannel#accept()
|
||||
*/
|
||||
public void listen(int backlog) throws IOException
|
||||
{
|
||||
listen(nfd.getNativeFD(), backlog);
|
||||
}
|
||||
|
||||
/**
|
||||
* Native listen function. VMs without native support need not implement
|
||||
* this.
|
||||
*
|
||||
* @param fd The file descriptor integer.
|
||||
* @param backlog The listen backlog size.
|
||||
* @throws IOException
|
||||
*/
|
||||
private static native void listen(int fd, int backlog) throws IOException;
|
||||
|
||||
public void join(InetAddress group) throws IOException
|
||||
{
|
||||
if (group instanceof Inet4Address)
|
||||
join(nfd.getNativeFD(), group.getAddress());
|
||||
else if (group instanceof Inet6Address)
|
||||
join6(nfd.getNativeFD(), group.getAddress());
|
||||
else
|
||||
throw new IllegalArgumentException("unknown address type");
|
||||
}
|
||||
|
||||
private static native void join(int fd, byte[] addr) throws IOException;
|
||||
|
||||
private static native void join6(int fd, byte[] addr) throws IOException;
|
||||
|
||||
public void leave(InetAddress group) throws IOException
|
||||
{
|
||||
if (group instanceof Inet4Address)
|
||||
leave(nfd.getNativeFD(), group.getAddress());
|
||||
else if (group instanceof Inet6Address)
|
||||
leave6(nfd.getNativeFD(), group.getAddress());
|
||||
else
|
||||
throw new IllegalArgumentException("unknown address type");
|
||||
}
|
||||
|
||||
private static native void leave(int fd, byte[] addr) throws IOException;
|
||||
|
||||
private static native void leave6(int fd, byte[] addr) throws IOException;
|
||||
|
||||
public void joinGroup(InetSocketAddress addr, NetworkInterface netif)
|
||||
throws IOException
|
||||
{
|
||||
InetAddress address = addr.getAddress();
|
||||
|
||||
if (address instanceof Inet4Address)
|
||||
joinGroup(nfd.getNativeFD(), address.getAddress(),
|
||||
netif != null ? netif.getName() : null);
|
||||
else if (address instanceof Inet6Address)
|
||||
joinGroup6(nfd.getNativeFD(), address.getAddress(),
|
||||
netif != null ? netif.getName() : null);
|
||||
else
|
||||
throw new IllegalArgumentException("unknown address type");
|
||||
}
|
||||
|
||||
private static native void joinGroup(int fd, byte[] addr, String ifname)
|
||||
throws IOException;
|
||||
|
||||
private static native void joinGroup6(int fd, byte[] addr, String ifname)
|
||||
throws IOException;
|
||||
|
||||
public void leaveGroup(InetSocketAddress addr, NetworkInterface netif)
|
||||
throws IOException
|
||||
{
|
||||
InetAddress address = addr.getAddress();
|
||||
if (address instanceof Inet4Address)
|
||||
leaveGroup(nfd.getNativeFD(), address.getAddress(),
|
||||
netif != null ? netif.getName() : null);
|
||||
else if (address instanceof Inet6Address)
|
||||
leaveGroup6(nfd.getNativeFD(), address.getAddress(),
|
||||
netif != null ? netif.getName() : null);
|
||||
else
|
||||
throw new IllegalArgumentException("unknown address type");
|
||||
}
|
||||
|
||||
private static native void leaveGroup(int fd, byte[] addr, String ifname)
|
||||
throws IOException;
|
||||
|
||||
private static native void leaveGroup6(int fd, byte[] addr, String ifname)
|
||||
throws IOException;
|
||||
|
||||
|
||||
public void shutdownInput() throws IOException
|
||||
{
|
||||
shutdownInput(nfd.getNativeFD());
|
||||
}
|
||||
|
||||
private static native void shutdownInput(int native_fd) throws IOException;
|
||||
|
||||
public void shutdownOutput() throws IOException
|
||||
{
|
||||
shutdownOutput(nfd.getNativeFD());
|
||||
}
|
||||
|
||||
private static native void shutdownOutput(int native_fd) throws IOException;
|
||||
|
||||
public void sendUrgentData(int data) throws IOException
|
||||
{
|
||||
sendUrgentData(nfd.getNativeFD(), data);
|
||||
}
|
||||
|
||||
private static native void sendUrgentData(int natfive_fd, int data) throws IOException;
|
||||
|
||||
public void close() throws IOException
|
||||
{
|
||||
nfd.close();
|
||||
}
|
||||
|
||||
// Inner classes.
|
||||
|
||||
/**
|
||||
* Our wrapper for the native file descriptor. In this implementation,
|
||||
* it is a simple wrapper around {@link VMChannel.State}, to simplify
|
||||
* management of the native state.
|
||||
*/
|
||||
public final class State
|
||||
{
|
||||
private VMChannel.State channelFd;
|
||||
|
||||
State()
|
||||
{
|
||||
channelFd = null;
|
||||
}
|
||||
|
||||
public boolean isValid()
|
||||
{
|
||||
if (channelFd != null)
|
||||
return channelFd.isValid();
|
||||
return false;
|
||||
}
|
||||
|
||||
public int getNativeFD() throws IOException
|
||||
{
|
||||
return channelFd.getNativeFD();
|
||||
}
|
||||
|
||||
public void setChannelFD(final VMChannel.State nfd) throws IOException
|
||||
{
|
||||
if (this.channelFd != null && this.channelFd.isValid())
|
||||
throw new IOException("file descriptor already initialized");
|
||||
this.channelFd = nfd;
|
||||
}
|
||||
|
||||
public void close() throws IOException
|
||||
{
|
||||
if (channelFd == null)
|
||||
throw new IOException("invalid file descriptor");
|
||||
channelFd.close();
|
||||
}
|
||||
|
||||
protected void finalize() throws Throwable
|
||||
{
|
||||
try
|
||||
{
|
||||
if (isValid())
|
||||
close();
|
||||
}
|
||||
finally
|
||||
{
|
||||
super.finalize();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -39,13 +39,16 @@ exception statement from your version. */
|
||||
package gnu.java.nio;
|
||||
|
||||
import gnu.classpath.Configuration;
|
||||
import gnu.java.net.PlainSocketImpl;
|
||||
import gnu.java.nio.PipeImpl.SinkChannelImpl;
|
||||
import gnu.java.nio.PipeImpl.SourceChannelImpl;
|
||||
import gnu.java.nio.channels.FileChannelImpl;
|
||||
|
||||
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
|
||||
@@ -54,33 +57,43 @@ import java.nio.ByteBuffer;
|
||||
* @author Michael Barker <mike@middlesoft.co.uk>
|
||||
*
|
||||
*/
|
||||
public class VMChannel
|
||||
public final class VMChannel
|
||||
{
|
||||
private final int fd;
|
||||
/**
|
||||
* Our reference implementation uses an integer to store the native
|
||||
* file descriptor. Implementations without such support
|
||||
*/
|
||||
private final State nfd;
|
||||
|
||||
private VMChannel(int fd)
|
||||
private Kind kind;
|
||||
|
||||
public VMChannel()
|
||||
{
|
||||
this.fd = fd;
|
||||
// XXX consider adding security check here, so only Classpath
|
||||
// code may create instances.
|
||||
this.nfd = new State();
|
||||
kind = Kind.OTHER;
|
||||
}
|
||||
|
||||
public static VMChannel getVMChannel(PlainSocketImpl socket)
|
||||
/**
|
||||
* 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
|
||||
{
|
||||
return new VMChannel(socket.getNativeFD());
|
||||
this();
|
||||
this.nfd.setNativeFD(native_fd);
|
||||
}
|
||||
|
||||
public static VMChannel getVMChannel(SourceChannelImpl source)
|
||||
public State getState()
|
||||
{
|
||||
return new VMChannel(source.getNativeFD());
|
||||
}
|
||||
|
||||
public static VMChannel getVMChannel(SinkChannelImpl sink)
|
||||
{
|
||||
return new VMChannel(sink.getNativeFD());
|
||||
}
|
||||
|
||||
public static VMChannel getVMChannel(FileChannelImpl file)
|
||||
{
|
||||
return new VMChannel(file.getNativeFD());
|
||||
return nfd;
|
||||
}
|
||||
|
||||
static
|
||||
@@ -93,81 +106,151 @@ public class VMChannel
|
||||
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 fd
|
||||
* @param blocking
|
||||
* @param blocking The blocking flag to set.
|
||||
*/
|
||||
public native void setBlocking(int fd, boolean blocking);
|
||||
|
||||
public void setBlocking(boolean blocking)
|
||||
public void setBlocking(boolean blocking) throws IOException
|
||||
{
|
||||
setBlocking(fd, blocking);
|
||||
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.
|
||||
* Assumes that the buffer is a DirectBuffer.
|
||||
*
|
||||
* @param fd Native file descriptor to read from.
|
||||
* @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.
|
||||
*/
|
||||
native int read(int fd, ByteBuffer dst)
|
||||
throws IOException;
|
||||
|
||||
public int read(ByteBuffer dst)
|
||||
throws IOException
|
||||
{
|
||||
return read(fd, dst);
|
||||
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 fd Native file descriptor to read from.
|
||||
* @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.
|
||||
*/
|
||||
native long readScattering(int fd, ByteBuffer[] dsts, int offset, int length)
|
||||
throws IOException;
|
||||
|
||||
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(fd, dsts, offset, 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 fd
|
||||
* @param src
|
||||
* @param src The source buffer.
|
||||
* @return Number of bytes written.
|
||||
* @throws IOException
|
||||
*/
|
||||
native int write(int fd, ByteBuffer src)
|
||||
throws IOException;
|
||||
|
||||
public int write(ByteBuffer src)
|
||||
throws IOException
|
||||
public int write(ByteBuffer src) throws IOException
|
||||
{
|
||||
return write(fd, src);
|
||||
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
|
||||
@@ -180,18 +263,488 @@ public class VMChannel
|
||||
* @return Number of bytes written.
|
||||
* @throws IOException
|
||||
*/
|
||||
native long writeGathering(int fd, ByteBuffer[] srcs, int offset, int length)
|
||||
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");
|
||||
|
||||
return writeGathering(fd, srcs, offset, 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() { }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,7 +38,6 @@ exception statement from your version. */
|
||||
package gnu.java.nio;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.channels.spi.SelectorProvider;
|
||||
import gnu.classpath.Configuration;
|
||||
|
||||
/**
|
||||
@@ -58,7 +57,24 @@ final class VMPipe
|
||||
System.loadLibrary ("javanio");
|
||||
}
|
||||
}
|
||||
|
||||
static native void init(PipeImpl self, SelectorProvider provider)
|
||||
throws IOException;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user