summaryrefslogtreecommitdiff
path: root/vm/reference/gnu/java/net/VMPlainSocketImpl.java
diff options
context:
space:
mode:
Diffstat (limited to 'vm/reference/gnu/java/net/VMPlainSocketImpl.java')
-rw-r--r--vm/reference/gnu/java/net/VMPlainSocketImpl.java505
1 files changed, 298 insertions, 207 deletions
diff --git a/vm/reference/gnu/java/net/VMPlainSocketImpl.java b/vm/reference/gnu/java/net/VMPlainSocketImpl.java
index 76be558dc..126294c7f 100644
--- a/vm/reference/gnu/java/net/VMPlainSocketImpl.java
+++ b/vm/reference/gnu/java/net/VMPlainSocketImpl.java
@@ -38,8 +38,11 @@ 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.NetworkInterface;
import java.net.SocketAddress;
import java.net.SocketException;
import java.net.SocketImpl;
@@ -47,6 +50,8 @@ import java.net.SocketOptions;
import java.net.UnknownHostException;
import gnu.classpath.Configuration;
+import gnu.java.nio.VMChannel;
+import gnu.java.nio.VMChannel.State;
/**
* The VM interface for {@link gnu.java.net.PlainSocketImpl}.
@@ -56,6 +61,8 @@ import gnu.classpath.Configuration;
*/
public final class VMPlainSocketImpl
{
+ private final State nfd;
+
/**
* Static initializer to load native library.
*/
@@ -66,249 +73,333 @@ public final class VMPlainSocketImpl
System.loadLibrary("javanet");
}
}
+
+ public VMPlainSocketImpl()
+ {
+ // 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;
+ }
- /**
- * 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)
+ public void setOption(int optionId, Object optionValue)
+ throws SocketException
+ {
+ int value;
+ if (optionValue instanceof Integer)
+ value = ((Integer) optionValue).intValue();
+ else if (optionValue instanceof Boolean)
+ value = ((Boolean) optionValue).booleanValue() ? 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;
/**
- * 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
+ * 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.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
*/
- static native void create(PlainSocketImpl socket) throws IOException;
-
+ 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.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;
+
/**
- * Connects to the remote address and port specified as arguments.
+ * Binds this socket to the given local address and port.
*
- * @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
+ * @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.
*/
- static native void connect(PlainSocketImpl socket, InetAddress addr,
- int port) throws IOException;
-
+ 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");
+ }
+
/**
- * 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
+ * Native bind function for IPv4 addresses. The addr array must be
+ * exactly four bytes long.
+ *
+ * VMs without native support need not implement this.
*
- * @exception IOException If an error occurs
+ * @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
*/
- static native void bind(PlainSocketImpl socket, InetAddress addr, int port)
+ private static native void bind(int fd, byte[] 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
+ * Native bind function for IPv6 addresses. The addr array must be
+ * exactly sixteen bytes long.
*
- * @exception IOException if an error occurs
- */
- static native void listen(PlainSocketImpl socket, int queueLen)
- throws IOException;
-
- /**
- * Accepts a new connection on this socket.
+ * VMs without native support need not implement this.
*
- * @param socket the socket object
- * @param impl the socket object to accept this connection.
+ * @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
*/
- static native void accept(PlainSocketImpl socket, SocketImpl impl)
+ private static native void bind6(int fd, byte[] addr, int port)
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
+ * Listen on this socket for incoming connections.
*
- * @throws IOException if an error occurs
+ * @param backlog The backlog of connections.
+ * @throws IOException If listening fails.
+ * @see gnu.java.nio.VMChannel#accept()
*/
- static native void close(PlainSocketImpl socket) throws IOException;
-
+ public void listen(int backlog) throws IOException
+ {
+ listen(nfd.getNativeFD(), backlog);
+ }
+
/**
- * 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
+ * Native listen function. VMs without native support need not implement
+ * this.
*
- * @return the actual number of bytes read or -1 if end of stream.
- *
- * @throws IOException if an error occurs
+ * @param fd The file descriptor integer.
+ * @param backlog The listen backlog size.
+ * @throws IOException
*/
- static native int read(PlainSocketImpl socket, byte[] buf, int offset,
- int len) throws IOException;
+ private static native void listen(int fd, int backlog) 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 void join(InetAddress group) throws IOException
{
- byte[] buf = new byte[1];
- if (read(socket, buf, 0, 1) > 0)
- return buf[0] & 0xFF;
+ if (group instanceof Inet4Address)
+ join(nfd.getNativeFD(), group.getAddress());
+ else if (group instanceof Inet6Address)
+ join6(nfd.getNativeFD(), group.getAddress());
else
- return -1;
+ 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;
- /**
- * 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.
- *
- * @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
- */
- 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)
+ public void joinGroup(InetSocketAddress addr, NetworkInterface netif)
throws IOException
{
- write(socket, new byte[]{ (byte) data }, 0, 1);
+ 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");
}
-
- /**
- * 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)
+
+ 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
{
- 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);
- }
- finally
- {
- if (oldTimeoutObj != null)
- setOption(socket, SocketOptions.SO_TIMEOUT, oldTimeoutObj);
- }
+ 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.
+
/**
- * Send one byte of urgent data over the socket.
- *
- * @param socket the socket object
- * @param data the byte to send
+ * 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.
*/
- static void sendUrgendData(PlainSocketImpl socket, int data)
+ public final class State
{
- throw new InternalError ("PlainSocketImpl::sendUrgentData not implemented");
+ 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();
+ }
+ }
}
-}
+} \ No newline at end of file