Index: E:/projects/clear/eclipse/workspace/luni/META-INF/MANIFEST.MF =================================================================== --- E:/projects/clear/eclipse/workspace/luni/META-INF/MANIFEST.MF (revision 386513) +++ E:/projects/clear/eclipse/workspace/luni/META-INF/MANIFEST.MF (working copy) @@ -21,6 +21,7 @@ java.lang.reflect, java.net, java.util, - org.apache.harmony.luni.util, - org.apache.harmony.luni.platform + org.apache.harmony.luni.net, + org.apache.harmony.luni.platform, + org.apache.harmony.luni.util Index: E:/projects/clear/eclipse/workspace/luni/.classpath =================================================================== --- E:/projects/clear/eclipse/workspace/luni/.classpath (revision 386513) +++ E:/projects/clear/eclipse/workspace/luni/.classpath (working copy) @@ -1,9 +1,14 @@ - - + + + + + - + + + Index: E:/projects/clear/eclipse/workspace/luni/src/main/java/java/net/ServerSocket.java =================================================================== --- E:/projects/clear/eclipse/workspace/luni/src/main/java/java/net/ServerSocket.java (revision 386513) +++ E:/projects/clear/eclipse/workspace/luni/src/main/java/java/net/ServerSocket.java (working copy) @@ -15,9 +15,10 @@ package java.net; - import java.io.IOException; +import org.apache.harmony.luni.net.SocketImplProvider; + import com.ibm.oti.util.Msg; /** @@ -30,452 +31,472 @@ */ public class ServerSocket { - SocketImpl impl; + SocketImpl impl; - static SocketImplFactory factory; + static SocketImplFactory factory; - private volatile boolean isCreated = false; + private volatile boolean isCreated = false; - private boolean isBound = false; + private boolean isBound = false; - private boolean isClosed = false; + private boolean isClosed = false; - /** - * Construct a ServerSocket, which is not bound to any port. The default - * number of pending connections may be backlogged. - * - * @see Socket - */ - public ServerSocket() throws IOException { - impl = factory != null ? factory.createSocketImpl() - : new PlainServerSocketImpl(); - } + /** + * Construct a ServerSocket, which is not bound to any port. The default + * number of pending connections may be backlogged. + * + * @see Socket + */ + public ServerSocket() throws IOException { + impl = factory != null ? factory.createSocketImpl() + :SocketImplProvider.getServerSocketImpl(); + } + + protected ServerSocket(SocketImpl impl){ + this.impl = impl; + } - /** - * Construct a ServerSocket, bound to the nominated port on the default - * localhost. The default number of pending connections may be backlogged. - * - * @param aport - * the port number to listen for connection requests on - * @see Socket - */ - public ServerSocket(int aport) throws IOException { - this(aport, defaultBacklog(), InetAddress.ANY); - } + /** + * Construct a ServerSocket, bound to the nominated port on the default + * localhost. The default number of pending connections may be backlogged. + * + * @param aport + * the port number to listen for connection requests on + * @see Socket + */ + public ServerSocket(int aport) throws IOException { + this(aport, defaultBacklog(), InetAddress.ANY); + } - /** - * Construct a ServerSocket, bound to the nominated port on the default - * localhost. The number of pending connections that may be backlogged is a - * specified. - * - * @param aport - * the port number to listen for connection requests on - * @param backlog - * the number of pending connection requests, before requests are - * rejected - * @see Socket - */ - public ServerSocket(int aport, int backlog) throws IOException { - this(aport, backlog, InetAddress.ANY); - } + /** + * Construct a ServerSocket, bound to the nominated port on the default + * localhost. The number of pending connections that may be backlogged is a + * specified. + * + * @param aport + * the port number to listen for connection requests on + * @param backlog + * the number of pending connection requests, before requests are + * rejected + * @see Socket + */ + public ServerSocket(int aport, int backlog) throws IOException { + this(aport, backlog, InetAddress.ANY); + } - /** - * Construct a ServerSocket, bound to the nominated local host/port. The - * number of pending connections that may be backlogged is a specified. - * - * @param aport - * the port number to listen for connection requests on - * @param localAddr - * the local machine address to bind on - * @param backlog - * the number of pending connection requests, before requests are - * rejected - * @see Socket - */ - public ServerSocket(int aport, int backlog, InetAddress localAddr) - throws IOException { - super(); - checkListen(aport); - impl = factory != null ? factory.createSocketImpl() - : new PlainServerSocketImpl(); - InetAddress addr = localAddr == null ? InetAddress.ANY : localAddr; + /** + * Construct a ServerSocket, bound to the nominated local host/port. The + * number of pending connections that may be backlogged is a specified. + * + * @param aport + * the port number to listen for connection requests on + * @param localAddr + * the local machine address to bind on + * @param backlog + * the number of pending connection requests, before requests are + * rejected + * @see Socket + */ + public ServerSocket(int aport, int backlog, InetAddress localAddr) + throws IOException { + super(); + checkListen(aport); + impl = factory != null ? factory.createSocketImpl() + : SocketImplProvider.getServerSocketImpl(); + InetAddress addr = localAddr == null ? InetAddress.ANY : localAddr; - synchronized (this) { - impl.create(true); - isCreated = true; - try { - impl.bind(addr, aport); - isBound = true; - impl.listen(backlog > 0 ? backlog : defaultBacklog()); - } catch (IOException e) { - close(); - throw e; - } - } - } + synchronized (this) { + impl.create(true); + isCreated = true; + try { + impl.bind(addr, aport); + isBound = true; + impl.listen(backlog > 0 ? backlog : defaultBacklog()); + } catch (IOException e) { + close(); + throw e; + } + } + } - /** - * Retrieve the first connection request and answer the 'host' socket that - * will conduct further communications with the requesting 'client' socket. - * - * @return Socket the 'host' socket - * @exception IOException - * if an error occurs while instantiating the 'host' socket - */ - public Socket accept() throws IOException { - checkClosedAndCreate(false); - if (!isBound()) - throw new SocketException(Msg.getString("K031f")); + /** + * Retrieve the first connection request and answer the 'host' socket that + * will conduct further communications with the requesting 'client' socket. + * + * @return Socket the 'host' socket + * @exception IOException + * if an error occurs while instantiating the 'host' socket + */ + public Socket accept() throws IOException { + checkClosedAndCreate(false); + if (!isBound()) + throw new SocketException(Msg.getString("K031f")); - // If a SOCKS proxy is being used, accept does strange things. - // Instead of returning a new Socket and allowing this ServerSocket - // to be used for another accept, it actually uses the current - // ServerSocket - // as the accepted Socket. So, closing the returned socket will close - // the - // ServerSocket as well. The ServerSocket cannot be used for a second - // accept. - if (PlainSocketImpl.usingSocks()) { - if (impl instanceof PlainSocketImpl) { - try { - SecurityManager security = System.getSecurityManager(); - if (security != null) { - security.checkAccept(getInetAddress().getHostName(), - getLocalPort()); - } - } catch (SecurityException e) { - close(); - throw e; - } + // If a SOCKS proxy is being used, accept does strange things. + // Instead of returning a new Socket and allowing this ServerSocket + // to be used for another accept, it actually uses the current + // ServerSocket + // as the accepted Socket. So, closing the returned socket will close + // the + // ServerSocket as well. The ServerSocket cannot be used for a second + // accept. + //FIXME: paulex comment this for compile +// if (IOUtil.usingSocks()) { +// if (impl instanceof PlainSocketImpl) { +// try { +// SecurityManager security = System.getSecurityManager(); +// if (security != null) { +// security.checkAccept(getInetAddress().getHostAddress(), +// getLocalPort()); +// } +// } catch (SecurityException e) { +// close(); +// throw e; +// } +// +// ((PlainSocketImpl) impl).socksAccept(); +// return new Socket(impl); +// } +// +// throw new IOException(Msg.getString("K0041")); //$NON-NLS-1$ +// } - ((PlainSocketImpl) impl).socksAccept(); - return new Socket(impl); - } + Socket aSocket = new Socket(); + try { + synchronized (this) { + implAccept(aSocket); + } + SecurityManager security = System.getSecurityManager(); + if (security != null) { + security.checkAccept(aSocket.getInetAddress().getHostAddress(), + aSocket.getPort()); + } + } catch (SecurityException e) { + aSocket.close(); + throw e; + } catch (IOException e) { + aSocket.close(); + throw e; + } + return aSocket; + } - throw new IOException(Msg.getString("K0041")); //$NON-NLS-1$ - } + /** + * Check whether the server may listen for connection requests on + * aport. Throw an exception if the port is outside the + * valid range or does not satisfy the security policy. + * + * @param aPort + * the candidate port to listen on + */ + void checkListen(int aPort) { + if (aPort < 0 || aPort > 65535) + throw new IllegalArgumentException(Msg.getString("K0325", aPort)); //$NON-NLS-1$ + SecurityManager security = System.getSecurityManager(); + if (security != null) + security.checkListen(aPort); + } - Socket aSocket = new Socket(); - try { - synchronized (this) { - implAccept(aSocket); - } - SecurityManager security = System.getSecurityManager(); - if (security != null) { - security.checkAccept(aSocket.getInetAddress().getHostName(), - aSocket.getPort()); - } - } catch (SecurityException e) { - aSocket.close(); - throw e; - } catch (IOException e) { - aSocket.close(); - throw e; - } - return aSocket; - } + /** + * Close this server socket. Any attempt to connect to this socket + * thereafter will fail. + */ + public void close() throws IOException { + isClosed = true; + impl.close(); + } - /** - * Check whether the server may listen for connection requests on - * aport. Throw an exception if the port is outside the - * valid range or does not satisfy the security policy. - * - * @param aPort - * the candidate port to listen on - */ - void checkListen(int aPort) { - if (aPort < 0 || aPort > 65535) - throw new IllegalArgumentException(Msg.getString("K0325", aPort)); //$NON-NLS-1$ - SecurityManager security = System.getSecurityManager(); - if (security != null) - security.checkListen(aPort); - } + /** + * Answer the default number of pending connections on a server socket. + * + * @return int the default number of pending connection requests + */ + static int defaultBacklog() { + return 50; + } - /** - * Close this server socket. Any attempt to connect to this socket - * thereafter will fail. - */ - public void close() throws IOException { - isClosed = true; - impl.close(); - } + /** + * Answer the local IP address for this server socket. Return null if the + * socket is not bound. This is useful on multihomed hosts. + * + * @return InetAddress the local address + */ + public InetAddress getInetAddress() { + if (!isBound()) + return null; + return impl.getInetAddress(); + } - /** - * Answer the default number of pending connections on a server socket. - * - * @return int the default number of pending connection requests - */ - static int defaultBacklog() { - return 50; - } + /** + * Answer the local port for this server socket. Return -1 if the socket is + * not bound. + * + * @return int the local port the server is listening on + */ + public int getLocalPort() { + if (!isBound()) + return -1; + return impl.getLocalPort(); + } - /** - * Answer the local IP address for this server socket. Return null if the - * socket is not bound. This is useful on multihomed hosts. - * - * @return InetAddress the local address - */ - public InetAddress getInetAddress() { - if (!isBound()) - return null; - return impl.getInetAddress(); - } + /** + * Answer the time-out period of this server socket. This is the time the + * server will wait listening for connections, before exiting. + * + * @return int the listening timeout + * @exception SocketException + * thrown if option cannot be retrieved + */ + public synchronized int getSoTimeout() throws IOException { + // TODO Bug-Reporter:check changed! checkClosedAndCreate(true); + if (!isCreated) { + synchronized (this) { + if (!isCreated) { - /** - * Answer the local port for this server socket. Return -1 if the socket is - * not bound. - * - * @return int the local port the server is listening on - */ - public int getLocalPort() { - if (!isBound()) - return -1; - return impl.getLocalPort(); - } + try { + impl.create(true); + } catch (SocketException e) { + throw e; + } catch (IOException e) { + throw new SocketException(e.toString()); + } + isCreated = true; + } + } + } + return ((Integer) impl.getOption(SocketOptions.SO_TIMEOUT)).intValue(); + } - /** - * Answer the time-out period of this server socket. This is the time the - * server will wait listening for connections, before exiting. - * - * @return int the listening timeout - * @exception SocketException - * thrown if option cannot be retrieved - */ - public synchronized int getSoTimeout() throws IOException { - checkClosedAndCreate(true); - return ((Integer) impl.getOption(SocketOptions.SO_TIMEOUT)).intValue(); - } + /** + * Invoke the server socket implementation to accept a connection on the + * newly created aSocket. + * + * @param aSocket + * the concrete socketImpl to accept the connection request on + * @exception IOException + * thrown if connection cannot be accepted + */ + protected final void implAccept(Socket aSocket) throws IOException { + impl.accept(aSocket.impl); + aSocket.accepted(); + } - /** - * Invoke the server socket implementation to accept a connection on the - * newly created aSocket. - * - * @param aSocket - * the concrete socketImpl to accept the connection request on - * @exception IOException - * thrown if connection cannot be accepted - */ - protected final void implAccept(Socket aSocket) throws IOException { - impl.accept(aSocket.impl); - aSocket.accepted(); - } + /** + * Set the server socket implementation factory. This method may only be + * invoked with sufficient security and only once during the application + * lifetime. + * + * @param aFactory + * the streaming socket factory to be used for further socket + * instantiations + * @exception IOException + * thrown if the factory is already set + */ + public static synchronized void setSocketFactory(SocketImplFactory aFactory) + throws IOException { + SecurityManager security = System.getSecurityManager(); + if (security != null) + security.checkSetFactory(); + if (factory == null) + factory = aFactory; + else + throw new SocketException(Msg.getString("K0042")); //$NON-NLS-1$ + } - /** - * Set the server socket implementation factory. This method may only be - * invoked with sufficient security and only once during the application - * lifetime. - * - * @param aFactory - * the streaming socket factory to be used for further socket - * instantiations - * @exception IOException - * thrown if the factory is already set - */ - public static synchronized void setSocketFactory(SocketImplFactory aFactory) - throws IOException { - SecurityManager security = System.getSecurityManager(); - if (security != null) - security.checkSetFactory(); - if (factory == null) - factory = aFactory; - else - throw new SocketException(Msg.getString("K0042")); //$NON-NLS-1$ - } + /** + * Set the listen time-out period for this server socket. + * + * @param timeout + * the time to wait for a connection request + * @exception SocketException + * thrown if an error occurs during setting the option + */ + public synchronized void setSoTimeout(int timeout) throws SocketException { + checkClosedAndCreate(true); + if (timeout >= 0) { + impl.setOption(SocketOptions.SO_TIMEOUT, new Integer(timeout)); + } else { + throw new IllegalArgumentException(Msg.getString("K0036")); //$NON-NLS-1$ + } + } - /** - * Set the listen time-out period for this server socket. - * - * @param timeout - * the time to wait for a connection request - * @exception SocketException - * thrown if an error occurs during setting the option - */ - public synchronized void setSoTimeout(int timeout) throws SocketException { - checkClosedAndCreate(true); - if (timeout >= 0) { - impl.setOption(SocketOptions.SO_TIMEOUT, new Integer(timeout)); - } else { - throw new IllegalArgumentException(Msg.getString("K0036")); //$NON-NLS-1$ - } - } + /** + * Answers a string containing a concise, human-readable description of the + * server socket. The port field is reported a zero, as there + * is no connection formed to the server. + * + * @return String the description + */ + public String toString() { + StringBuffer result = new StringBuffer(64); + result.append("ServerSocket["); //$NON-NLS-1$ + if (!isBound()) + return result.append("unbound]").toString(); //$NON-NLS-1$ + return result.append("addr="). //$NON-NLS-1$ + append(getInetAddress()).append(",port=0,localport="). //$NON-NLS-1$ + append(getLocalPort()).append("]"). //$NON-NLS-1$ + toString(); + } - /** - * Answers a string containing a concise, human-readable description of the - * server socket. The port field is reported a zero, as there - * is no connection formed to the server. - * - * @return String the description - */ - public String toString() { - StringBuffer result = new StringBuffer(64); - result.append("ServerSocket["); //$NON-NLS-1$ - if (!isBound()) - return result.append("unbound]").toString(); //$NON-NLS-1$ - return result.append("addr="). //$NON-NLS-1$ - append(getInetAddress()).append(",port=0,localport="). //$NON-NLS-1$ - append(getLocalPort()).append("]"). //$NON-NLS-1$ - toString(); - } + /** + * Bind the ServerSocket to the nominated local host/port. The default + * number of pending connections may be backlogged. + * + * @param localAddr + * the local machine address and port to bind on + * + * @exception IllegalArgumentException + * if the SocketAddress is not supported + * @exception IOException + * if the socket is already bound, or a problem occurs during + * the bind + */ + public void bind(SocketAddress localAddr) throws IOException { + bind(localAddr, defaultBacklog()); + } - /** - * Bind the ServerSocket to the nominated local host/port. The default - * number of pending connections may be backlogged. - * - * @param localAddr - * the local machine address and port to bind on - * - * @exception IllegalArgumentException - * if the SocketAddress is not supported - * @exception IOException - * if the socket is already bound, or a problem occurs during - * the bind - */ - public void bind(SocketAddress localAddr) throws IOException { - bind(localAddr, defaultBacklog()); - } + /** + * Bind the ServerSocket to the nominated local host/port. The number of + * pending connections that may be backlogged is a specified. + * + * @param localAddr + * the local machine address and port to bind on + * @param backlog + * the number of pending connection requests, before requests are + * rejected + * + * @exception IllegalArgumentException + * if the SocketAddress is not supported + * @exception IOException + * if the socket is already bound, or a problem occurs during + * the bind + */ + public void bind(SocketAddress localAddr, int backlog) throws IOException { + checkClosedAndCreate(true); + if (isBound()) + throw new BindException(Msg.getString("K0315")); //$NON-NLS-1$ + int port = 0; + InetAddress addr = InetAddress.ANY; + if (localAddr != null) { + if (!(localAddr instanceof InetSocketAddress)) + throw new IllegalArgumentException(Msg.getString( + "K0316", localAddr.getClass())); //$NON-NLS-1$ + InetSocketAddress inetAddr = (InetSocketAddress) localAddr; + if ((addr = inetAddr.getAddress()) == null) + throw new SocketException(Msg.getString( + "K0317", inetAddr.getHostName())); //$NON-NLS-1$ + port = inetAddr.getPort(); + } + SecurityManager security = System.getSecurityManager(); + if (security != null) + security.checkListen(port); - /** - * Bind the ServerSocket to the nominated local host/port. The number of - * pending connections that may be backlogged is a specified. - * - * @param localAddr - * the local machine address and port to bind on - * @param backlog - * the number of pending connection requests, before requests are - * rejected - * - * @exception IllegalArgumentException - * if the SocketAddress is not supported - * @exception IOException - * if the socket is already bound, or a problem occurs during - * the bind - */ - public void bind(SocketAddress localAddr, int backlog) throws IOException { - checkClosedAndCreate(true); - if (isBound()) - throw new BindException(Msg.getString("K0315")); //$NON-NLS-1$ - int port = 0; - InetAddress addr = InetAddress.ANY; - if (localAddr != null) { - if (!(localAddr instanceof InetSocketAddress)) - throw new IllegalArgumentException(Msg.getString( - "K0316", localAddr.getClass())); //$NON-NLS-1$ - InetSocketAddress inetAddr = (InetSocketAddress) localAddr; - if ((addr = inetAddr.getAddress()) == null) - throw new SocketException(Msg.getString( - "K0317", inetAddr.getHostName())); //$NON-NLS-1$ - port = inetAddr.getPort(); - } - SecurityManager security = System.getSecurityManager(); - if (security != null) - security.checkListen(port); + synchronized (this) { + try { + impl.bind(addr, port); + isBound = true; + impl.listen(backlog > 0 ? backlog : defaultBacklog()); + } catch (IOException e) { + close(); + throw e; + } + } + } - synchronized (this) { - try { - impl.bind(addr, port); - isBound = true; - impl.listen(backlog > 0 ? backlog : defaultBacklog()); - } catch (IOException e) { - close(); - throw e; - } - } - } + /** + * Answer the local SocketAddress for this server socket, or null if the + * socket is not bound. This is useful on multihomed hosts. + */ + public SocketAddress getLocalSocketAddress() { + if (!isBound()) + return null; + return new InetSocketAddress(getInetAddress(), getLocalPort()); + } - /** - * Answer the local SocketAddress for this server socket, or null if the - * socket is not bound. This is useful on multihomed hosts. - */ - public SocketAddress getLocalSocketAddress() { - if (!isBound()) - return null; - return new InetSocketAddress(getInetAddress(), getLocalPort()); - } + /** + * Return if the server socket is bound to a local address and port. + */ + public boolean isBound() { + return isBound; + } - /** - * Return if the server socket is bound to a local address and port. - */ - public boolean isBound() { - return isBound; - } + /** + * Return if the server socket is closed. + */ + public boolean isClosed() { + return isClosed; + } - /** - * Return if the server socket is closed. - */ - public boolean isClosed() { - return isClosed; - } + /** + * Check if the socket is closed, and throw an exception. + */ + private void checkClosedAndCreate(boolean create) throws SocketException { + if (isClosed()) + throw new SocketException(Msg.getString("K003d")); - /** - * Check if the socket is closed, and throw an exception. - */ - private void checkClosedAndCreate(boolean create) throws SocketException { - if (isClosed()) - throw new SocketException(Msg.getString("K003d")); + if (!create || isCreated) + return; - if (!create || isCreated) - return; + synchronized (this) { + if (isCreated) + return; + try { + impl.create(true); + } catch (SocketException e) { + throw e; + } catch (IOException e) { + throw new SocketException(e.toString()); + } + isCreated = true; + } + } - synchronized (this) { - if (isCreated) - return; - try { - impl.create(true); - } catch (SocketException e) { - throw e; - } catch (IOException e) { - throw new SocketException(e.toString()); - } - isCreated = true; - } - } + /** + * Set the SO_REUSEADDR socket option. + * + * @param reuse + * the socket SO_REUSEADDR option setting + */ + public void setReuseAddress(boolean reuse) throws SocketException { + checkClosedAndCreate(true); + impl.setOption(SocketOptions.SO_REUSEADDR, reuse ? Boolean.TRUE + : Boolean.FALSE); + } - /** - * Set the SO_REUSEADDR socket option. - * - * @param reuse - * the socket SO_REUSEADDR option setting - */ - public void setReuseAddress(boolean reuse) throws SocketException { - checkClosedAndCreate(true); - impl.setOption(SocketOptions.SO_REUSEADDR, reuse ? Boolean.TRUE - : Boolean.FALSE); - } + /** + * Get the state of the SO_REUSEADDR socket option. + */ + public boolean getReuseAddress() throws SocketException { + checkClosedAndCreate(true); + return ((Boolean) impl.getOption(SocketOptions.SO_REUSEADDR)) + .booleanValue(); + } - /** - * Get the state of the SO_REUSEADDR socket option. - */ - public boolean getReuseAddress() throws SocketException { - checkClosedAndCreate(true); - return ((Boolean) impl.getOption(SocketOptions.SO_REUSEADDR)) - .booleanValue(); - } + /** + * Set the socket receive buffer size. + * + * @param size + * the buffer size, in bytes + * + * @exception java.net.SocketException + * If an error occurs while setting the size or the size is + * invalid. + */ + public void setReceiveBufferSize(int size) throws SocketException { + checkClosedAndCreate(true); + if (size >= 1) + impl.setOption(SocketOptions.SO_RCVBUF, new Integer(size)); + else + throw new IllegalArgumentException(Msg.getString("K0035")); //$NON-NLS-1$ + } - /** - * Set the socket receive buffer size. - * - * @param size - * the buffer size, in bytes - * - * @exception java.net.SocketException - * If an error occurs while setting the size or the size is - * invalid. - */ - public void setReceiveBufferSize(int size) throws SocketException { - checkClosedAndCreate(true); - if (size >= 1) - impl.setOption(SocketOptions.SO_RCVBUF, new Integer(size)); - else - throw new IllegalArgumentException(Msg.getString("K0035")); //$NON-NLS-1$ - } - - /** - * Answer the socket receive buffer size (SO_RCVBUF). - * - * @return int socket receive buffer size - */ - public int getReceiveBufferSize() throws SocketException { - checkClosedAndCreate(true); - return ((Integer) impl.getOption(SocketOptions.SO_RCVBUF)).intValue(); - } + /** + * Answer the socket receive buffer size (SO_RCVBUF). + * + * @return int socket receive buffer size + */ + public int getReceiveBufferSize() throws SocketException { + checkClosedAndCreate(true); + return ((Integer) impl.getOption(SocketOptions.SO_RCVBUF)).intValue(); + } } Index: E:/projects/clear/eclipse/workspace/luni/src/main/java/java/net/DatagramSocketImpl.java =================================================================== --- E:/projects/clear/eclipse/workspace/luni/src/main/java/java/net/DatagramSocketImpl.java (revision 386513) +++ E:/projects/clear/eclipse/workspace/luni/src/main/java/java/net/DatagramSocketImpl.java (working copy) @@ -19,6 +19,10 @@ import java.io.FileDescriptor; import java.io.IOException; +import org.apache.harmony.luni.net.NetUtil; +import org.apache.harmony.luni.platform.INetworkSystem; +import org.apache.harmony.luni.platform.Platform; + /** * The abstract superclass of datagram & multicast socket implementatations. */ @@ -79,8 +83,9 @@ * * @return InetAddress the local address to which the socket is bound. */ - abstract InetAddress getLocalAddress(); - + InetAddress getLocalAddress() { + return Platform.getNetworkSystem().getSocketLocalAddress(fd, NetUtil.preferIPv6Addresses()); + } /** * Answer the local port. If the socket was bound to any available port, as * flagged by a localPort value of -1, query the IP stack. Index: E:/projects/clear/eclipse/workspace/luni/src/main/java/org/apache/harmony/luni/net/PlainDatagramSocketImpl.java =================================================================== --- E:/projects/clear/eclipse/workspace/luni/src/main/java/org/apache/harmony/luni/net/PlainDatagramSocketImpl.java (revision 0) +++ E:/projects/clear/eclipse/workspace/luni/src/main/java/org/apache/harmony/luni/net/PlainDatagramSocketImpl.java (revision 0) @@ -0,0 +1,737 @@ +/* Copyright 1998, 2006 The Apache Software Foundation or its licensors, as applicable + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.harmony.luni.net; + +import java.io.FileDescriptor; +import java.io.IOException; +import java.io.InterruptedIOException; +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.DatagramSocketImpl; +import java.net.Inet4Address; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.NetworkInterface; +import java.net.Socket; +import java.net.SocketAddress; +import java.net.SocketException; +import java.net.SocketOptions; +import java.net.SocketTimeoutException; +import java.net.UnknownHostException; +import java.security.AccessController; + +import org.apache.harmony.luni.platform.INetworkSystem; +import org.apache.harmony.luni.platform.Platform; + +import com.ibm.oti.util.Msg; +import com.ibm.oti.util.PriviAction; + +/** + * The default, concrete instance of datagram sockets. This class does not + * support security checks. Alternative types of DatagramSocketImpl's may be + * used by setting the impl.prefix system property. + */ + +class PlainDatagramSocketImpl extends DatagramSocketImpl { + + static final int MULTICAST_IF = 1; + + static final int MULTICAST_TTL = 2; + + static final int TCP_NODELAY = 4; + + static final int FLAG_SHUTDOWN = 8; + + private final static int SO_BROADCAST = 32; + + final static int IP_MULTICAST_ADD = 19; + + final static int IP_MULTICAST_DROP = 20; + + final static int IP_MULTICAST_TTL = 17; + + private boolean bindToDevice; + + private byte[] ipaddress = { 0, 0, 0, 0 }; + + private int ttl = 1; + + private INetworkSystem netImpl = Platform.getNetworkSystem(); + + private volatile boolean isNativeConnected = false; + + public int receiveTimeout = 0; + + public boolean streaming = true; + + public boolean shutdownInput = false; + + // for datagram and multicast sockets we have to set + // REUSEADDR and REUSEPORT when REUSEADDR is set + // for other types of sockets we need to just set REUSEADDR + // therefore we have this other option which sets + // both if supported by the platform. + // this cannot be in SOCKET_OPTIONS because since it + // is a public interface it ends up being public even + // if it is not declared public + static final int REUSEADDR_AND_REUSEPORT = 10001; + + // used to keep address to which the socket was connected to at the + // native level + private InetAddress connectedAddress = null; + + private int connectedPort = -1; + + // used to store the trafficClass value which is simply returned + // as the value that was set. We also need it to pass it to methods + // that specify an address packets are going to be sent to + private int trafficClass = 0; + + // Fill in the JNI id caches + // private static native void oneTimeInitialization(boolean + // jcl_IPv6_support); + // + // static { + // oneTimeInitialization(true); + // } + + + public PlainDatagramSocketImpl(FileDescriptor fd, int localPort) { + super(); + this.fd = fd; + this.localPort = localPort; + } + + public PlainDatagramSocketImpl(){ + super(); + } + + /** + * Bind the datagram socket to the nominated localhost/port. Sockets must be + * bound prior to attempting to send or receive data. + * + * @param port + * the port on the localhost to bind + * @param addr + * the address on the multihomed localhost to bind + * + * @exception SocketException + * if an error occured during bind, such as if the port was + * already bound + */ + public void bind(int port, InetAddress addr) throws SocketException { + String prop = (String) AccessController.doPrivileged(new PriviAction( + "bindToDevice")); + boolean useBindToDevice = prop != null + && prop.toLowerCase().equals("true"); + bindToDevice = netImpl.bind2(fd, port, useBindToDevice, addr); + if (0 != port) { + localPort = port; + } else { + localPort = netImpl.getSocketLocalPort(fd, + NetUtil.preferIPv6Addresses()); + } + + try { + // Ignore failures + setOption(SO_BROADCAST, Boolean.TRUE); + } catch (IOException e) { + } + } + + /** + * Close the socket. + */ + public void close() { + synchronized (fd) { + if (fd.valid()) { + try { + netImpl.socketClose(fd); + } catch (IOException e) { + // TODO do nothing? + } + fd = new FileDescriptor(); + } + } + } + + /** + * Allocate the socket descriptor in the IP stack. + */ + public void create() throws SocketException { + netImpl.createDatagramSocket(fd, NetUtil.preferIPv4Stack()); + } + + protected void finalize() { + close(); + } + + /** + * Answer the nominated socket option. As the timeouts are not set as + * options in the IP stack, the field value is returned. + * + * @return Object the nominated socket option value + */ + public Object getOption(int optID) throws SocketException { + if (optID == SocketOptions.SO_TIMEOUT) { + return new Integer(receiveTimeout); + } else if (optID == SocketOptions.IP_TOS) { + return new Integer(trafficClass); + } else { + // Call the native first so there will be + // an exception if the socket if closed. + Object result = netImpl.getSocketOption(fd, optID); + if (optID == SocketOptions.IP_MULTICAST_IF + && (netImpl.getSocketFlags() & MULTICAST_IF) != 0) { + try { + return Inet4Address.getByAddress(ipaddress); + } catch (UnknownHostException e) { + return null; + } + } + return result; + } + } + + public int getTimeToLive() throws IOException { + // Call the native first so there will be an exception if the socket if + // closed. + int result = (((Byte) getOption(IP_MULTICAST_TTL)).byteValue()) & 0xFF; + if ((netImpl.getSocketFlags() & MULTICAST_TTL) != 0) { + return ttl; + } + return result; + } + + public byte getTTL() throws IOException { + // Call the native first so there will be an exception if the socket if + // closed. + byte result = ((Byte) getOption(IP_MULTICAST_TTL)).byteValue(); + if ((netImpl.getSocketFlags() & MULTICAST_TTL) != 0) { + return (byte) ttl; + } + return result; + } + + /** + * Add this socket to the multicast group. A socket must joint a group + * before data may be received. A socket may be a member of multiple groups + * but may join any group once. + * + * @param addr + * the multicast group to be joined + * @exception java.io.IOException + * may be thrown while joining a group + */ + public void join(InetAddress addr) throws IOException { + setOption(IP_MULTICAST_ADD, new GenericIPMreq(addr)); + } + + /** + * Add this socket to the multicast group. A socket must join a group before + * data may be received. A socket may be a member of multiple groups but may + * join any group once. + * + * @param addr + * the multicast group to be joined + * @param netInterface + * the network interface on which the addresses should be dropped + * @exception java.io.IOException + * may be thrown while joining a group + */ + public void joinGroup(SocketAddress addr, NetworkInterface netInterface) + throws IOException { + if (addr instanceof InetSocketAddress) { + InetAddress groupAddr = ((InetSocketAddress) addr).getAddress(); + setOption(IP_MULTICAST_ADD, new GenericIPMreq(groupAddr, + netInterface)); + } + } + + /** + * Remove the socket from the multicast group. + * + * @param addr + * the multicast group to be left + * @exception java.io.IOException + * May be thrown while leaving the group + */ + public void leave(InetAddress addr) throws IOException { + setOption(IP_MULTICAST_DROP, new GenericIPMreq(addr)); + } + + /** + * Remove the socket from the multicast group. + * + * @param addr + * the multicast group to be left + * @param netInterface + * the network interface on which the addresses should be dropped + * @exception java.io.IOException + * May be thrown while leaving the group + */ + public void leaveGroup(SocketAddress addr, NetworkInterface netInterface) + throws IOException { + if (addr instanceof InetSocketAddress) { + InetAddress groupAddr = ((InetSocketAddress) addr).getAddress(); + setOption(IP_MULTICAST_DROP, new GenericIPMreq(groupAddr, + netInterface)); + } + } + + // /** + // * Connect the socket to a port and address + // * + // * @param aFD + // * the FileDescriptor to associate with the socket + // * @param port + // * the port to connect to + // * @param trafficClass + // * the traffic Class to be used then the connection is made + // * @param inetAddress + // * address to connect to. + // * + // * @exception SocketException + // * if the connect fails + // */ + // protected static native void connectDatagramImpl2(FileDescriptor aFD, + // int port, int trafficClass, InetAddress inetAddress) + // throws SocketException; + // + // /** + // * Disconnect the socket to a port and address + // * + // * @param aFD + // * the FileDescriptor to associate with the socket + // * + // * @exception SocketException + // * if the disconnect fails + // */ + // protected static native void disconnectDatagramImpl(FileDescriptor aFD) + // throws SocketException; + // + // /** + // * Allocate a datagram socket in the IP stack. The socket is associated + // with + // * the aFD. + // * + // * @param aFD + // * the FileDescriptor to associate with the socket + // * @param preferIPv4Stack + // * IP stack preference if underlying platform is V4/V6 + // * @exception SocketException + // * upon an allocation error + // */ + // protected static native void createDatagramSocketImpl(FileDescriptor aFD, + // boolean preferIPv4Stack) throws SocketException; + // + // /** + // * Bind the socket to the port/localhost in the IP stack. + // * + // * @param aFD + // * the socket descriptor + // * @param port + // * the option selector + // * @param bindToDevice + // * bind the socket to the specified interface + // * @param inetAddress + // * address to connect to. + // * @exception SocketException + // * thrown if bind operation fails + // */ + // protected static native boolean socketBindImpl2(FileDescriptor aFD, + // int port, boolean bindToDevice, InetAddress inetAddress) + // throws SocketException; + // + // /** + // * Peek on the socket, update sender address and answer the + // * sender port. + // * + // * @param aFD + // * the socket FileDescriptor + // * @param sender + // * an InetAddress, to be updated with the sender's address + // * @param receiveTimeout + // * the maximum length of time the socket should block, reading + // * @return int the sender port + // * + // * @exception IOException + // * upon an read error or timeout + // */ + // protected static native int peekDatagramImpl(FileDescriptor aFD, + // InetAddress sender, int receiveTimeout) throws IOException; + // + // /** + // * Recieve data on the socket into the specified buffer. The packet fields + // * data & length are passed in addition to + // * packet to eliminate the JNI field access calls. + // * + // * @param aFD + // * the socket FileDescriptor + // * @param packet + // * the DatagramPacket to receive into + // * @param data + // * the data buffer of the packet + // * @param offset + // * the offset in the data buffer + // * @param length + // * the length of the data buffer in the packet + // * @param receiveTimeout + // * the maximum length of time the socket should block, reading + // * @param peek + // * indicates to peek at the data + // * @exception IOException + // * upon an read error or timeout + // */ + // protected static native int receiveDatagramImpl2(FileDescriptor aFD, + // DatagramPacket packet, byte[] data, int offset, int length, + // int receiveTimeout, boolean peek) throws IOException; + // + // /** + // * Recieve data on the connected socket into the specified buffer. The + // * packet fields data & length are passed in + // * addition to packet to eliminate the JNI field access + // * calls. + // * + // * @param aFD + // * the socket FileDescriptor + // * @param packet + // * the DatagramPacket to receive into + // * @param data + // * the data buffer of the packet + // * @param offset + // * the offset in the data buffer + // * @param length + // * the length of the data buffer in the packet + // * @param receiveTimeout + // * the maximum length of time the socket should block, reading + // * @param peek + // * indicates to peek at the data + // * @exception IOException + // * upon an read error or timeout + // */ + // protected static native int recvConnectedDatagramImpl(FileDescriptor aFD, + // DatagramPacket packet, byte[] data, int offset, int length, + // int receiveTimeout, boolean peek) throws IOException; + // + // /** + // * Send the data to the nominated target address + // * and port. These values are derived from the + // * DatagramPacket to reduce the field calls within JNI. + // * + // * @param fd + // * the socket FileDescriptor + // * @param data + // * the data buffer of the packet + // * @param offset + // * the offset in the data buffer + // * @param length + // * the length of the data buffer in the packet + // * @param port + // * the target host port + // * @param trafficClass + // * the traffic class to be used when the datagram is sent + // * @param inetAddress + // * address to connect to. + // * + // * @exception IOException + // * upon an read error or timeout + // */ + // protected static native int sendDatagramImpl2(FileDescriptor fd, + // byte[] data, int offset, int length, int port, + // boolean bindToDevice, int trafficClass, InetAddress inetAddress) + // throws IOException; + // + // /** + // * Send the data to the address and port to which the was + // * connnected and port. + // * + // * @param fd + // * the socket FileDescriptor + // * @param data + // * the data buffer of the packet + // * @param offset + // * the offset in the data buffer + // * @param length + // * the length of the data buffer in the packet + // * @param bindToDevice + // * not used, current kept in case needed as was the case for + // * sendDatagramImpl + // * @exception IOException + // * upon an read error or timeout + // */ + // protected static native int sendConnectedDatagramImpl(FileDescriptor fd, + // byte[] data, int offset, int length, boolean bindToDevice) + // throws IOException; + + protected int peek(InetAddress sender) throws IOException { + if (isNativeConnected) { + // in this case we know the port and address from which the data + // must have be been received as the socket is connected. However, + // we still need to do the receive in order to know that there was + // data received. We use a short buffer as we don't actually need + // the packet, only the knowledge that it is there + byte[] storageArray = new byte[10]; + DatagramPacket pack = new DatagramPacket(storageArray, + storageArray.length); + netImpl.recvConnectedDatagram(fd, pack, pack.getData(), pack + .getOffset(), pack.getLength(), receiveTimeout, true); // peek + // to set the sender ,we now use a native function + // sender.ipaddress = connectedAddress.getAddress(); + netImpl.setInetAddress(sender, connectedAddress.getAddress()); + return connectedPort; + } + return netImpl.peekDatagram(fd, sender, receiveTimeout); + } + + /** + * Answer the data that may be read at this socket. Any data larger than the + * packet buffer length will be discarded. The read will block until either + * data is is read or, if the timeout is defined, the operation times out. + * + * @exception IOException + * if an error or timeout occurs during a read + */ + public void receive(DatagramPacket pack) throws java.io.IOException { + try { + if (isNativeConnected) { + // do not peek + netImpl.recvConnectedDatagram(fd, pack, pack.getData(), + pack.getOffset(), pack.getLength(), receiveTimeout, + false); + updatePacketRecvAddress(pack); + } else { + // receiveDatagramImpl2 + netImpl.receiveDatagram(fd, pack, pack.getData(), pack + .getOffset(), pack.getLength(), receiveTimeout, false); + } + } catch (InterruptedIOException e) { + throw new SocketTimeoutException(e.getMessage()); + } + } + + /** + * Send the data on this socket. + * + * @exception IOException + * if an error occurs during the write + */ + public void send(DatagramPacket packet) throws IOException { + + if (isNativeConnected) { + netImpl.sendConnectedDatagram(fd, packet.getData(), packet + .getOffset(), packet.getLength(), bindToDevice); + } else { + // sendDatagramImpl2 + netImpl.sendDatagram(fd, packet.getData(), packet.getOffset(), + packet.getLength(), packet.getPort(), bindToDevice, + trafficClass, packet.getAddress()); + } + } + + /** + * Set the nominated socket option. As the timeouts are not set as options + * in the IP stack, the value is stored in an instance field. + * + * @exception SocketException + * thrown if the option value is unsupported or invalid + */ + public void setOption(int optID, Object val) throws SocketException { + // for datagram sockets on some platforms we have to set both the + // REUSEADDR AND REUSEPORT so for REUSEADDR set this option option + // which tells the VM to set the two values as appropriate for the + // platform + if (optID == SocketOptions.SO_REUSEADDR) { + optID = REUSEADDR_AND_REUSEPORT; + } + + if (optID == SocketOptions.SO_TIMEOUT) { + receiveTimeout = ((Integer) val).intValue(); + } else { + int flags = netImpl.getSocketFlags(); + try { + netImpl.setSocketOption(fd, optID | (flags << 16), val); + } catch (SocketException e) { + // we don't throw an exception for IP_TOS even if the platform + // won't let us set the requested value + if (optID != SocketOptions.IP_TOS) { + throw e; + } + } + if (optID == SocketOptions.IP_MULTICAST_IF + && (flags & MULTICAST_IF) != 0) { + InetAddress inet = (InetAddress) val; + if (bytesToInt(inet.getAddress(), 0) == 0 + || inet.isLoopbackAddress()) { + ipaddress = ((InetAddress) val).getAddress(); + } else { + InetAddress local = null; + try { + local = InetAddress.getLocalHost(); + } catch (UnknownHostException e) { + throw new SocketException("getLocalHost(): " + + e.toString()); + } + if (inet.equals(local)) { + ipaddress = ((InetAddress) val).getAddress(); + } else { + throw new SocketException(val + " != getLocalHost(): " + + local); + } + } + } + // save this value as it is acutally used differently for IPv4 and + // IPv6 so we cannot get the value using the getOption. The option + // is actually only set for IPv4 and a masked version of the value + // will be set as only a subset of the values are allowed on the + // socket. Therefore we need to retain it to return the value that + // was set. We also need the value to be passed into a number of + // natives so that it can be used properly with IPv6 + if (optID == SocketOptions.IP_TOS) { + trafficClass = ((Integer) val).intValue(); + } + } + } + + public void setTimeToLive(int ttl) throws java.io.IOException { + setOption(IP_MULTICAST_TTL, new Byte((byte) (ttl & 0xFF))); + if ((netImpl.getSocketFlags() & MULTICAST_TTL) != 0) { + this.ttl = ttl; + } + } + + public void setTTL(byte ttl) throws java.io.IOException { + setOption(IP_MULTICAST_TTL, new Byte(ttl)); + if ((netImpl.getSocketFlags() & MULTICAST_TTL) != 0) { + this.ttl = ttl; + } + } + + /** + * Connect the socket to the specified remote address and port. + * + * @param inetAddr + * the remote address + * @param port + * the remote port + * + * @exception SocketException + * possibly thrown, if the datagram socket cannot be + * connected to the specified remote address and port + */ + public void connect(InetAddress inetAddr, int port) throws SocketException { + + // connectDatagram impl2 + netImpl.connectDatagram(fd, port, trafficClass, inetAddr); + + // if we get here then we are connected at the native level + try { + connectedAddress = InetAddress.getByAddress(inetAddr.getAddress()); + } catch (UnknownHostException e) { + // this is never expected to happen as we should not have gotten + // here if the address is not resolvable + throw new SocketException(Msg.getString( + "K0317", inetAddr.getHostName())); //$NON-NLS-1$ + } + connectedPort = port; + isNativeConnected = true; + } + + /** + * Disconnect the socket from the remote address and port. + */ + public void disconnect() { + try { + netImpl.disconnectDatagram(fd); + } catch (Exception e) { + // there is currently no way to return an error so just eat any + // exception + } + connectedPort = -1; + connectedAddress = null; + isNativeConnected = false; + } + + /** + * Receive data into the supplied datagram packet by peeking. The data is + * not removed and will be received by another peekData() or receive() call. + * + * This call will block until either data is received or, if a timeout is + * set, the timeout expires. + * + * @param pack + * the DatagramPacket used to store the data + * + * @return the port the packet was received from + * + * @exception IOException + * if an error occurs + */ + public int peekData(DatagramPacket pack) throws IOException { + try { + if (isNativeConnected) { + netImpl.recvConnectedDatagram(fd, pack, pack.getData(), + pack.getOffset(), pack.getLength(), receiveTimeout, + true); // peek + updatePacketRecvAddress(pack); + } else { + // receiveDatagram 2 + netImpl.receiveDatagram(fd, pack, pack.getData(), pack + .getOffset(), pack.getLength(), receiveTimeout, true); // peek + } + } catch (InterruptedIOException e) { + throw new SocketTimeoutException(e.getMessage()); + } + return pack.getPort(); + } + + /** + * Set the received address and port in the packet. We do this when the + * Datagram socket is connected at the native level and the + * recvConnnectedDatagramImpl does not update the packet with address from + * which the packet was received + * + * @param packet + * the packet to be updated + */ + private void updatePacketRecvAddress(DatagramPacket packet) { + packet.setAddress(connectedAddress); + packet.setPort(connectedPort); + } + + static void intToBytes(int value, byte bytes[], int start) { + // Shift the int so the current byte is right-most + // Use a byte mask of 255 to single out the last byte. + bytes[start] = (byte) ((value >> 24) & 255); + bytes[start + 1] = (byte) ((value >> 16) & 255); + bytes[start + 2] = (byte) ((value >> 8) & 255); + bytes[start + 3] = (byte) (value & 255); + } + + static int bytesToInt(byte bytes[], int start) { + // First mask the byte with 255, as when a negative + // signed byte converts to an integer, it has bits + // on in the first 3 bytes, we are only concerned + // about the right-most 8 bits. + // Then shift the rightmost byte to align with its + // position in the integer. + int value = ((bytes[start + 3] & 255)) + | ((bytes[start + 2] & 255) << 8) + | ((bytes[start + 1] & 255) << 16) + | ((bytes[start] & 255) << 24); + return value; + } +} Index: E:/projects/clear/eclipse/workspace/luni/src/main/java/org/apache/harmony/luni/net/PlainSocketImpl2.java =================================================================== --- E:/projects/clear/eclipse/workspace/luni/src/main/java/org/apache/harmony/luni/net/PlainSocketImpl2.java (revision 0) +++ E:/projects/clear/eclipse/workspace/luni/src/main/java/org/apache/harmony/luni/net/PlainSocketImpl2.java (revision 0) @@ -0,0 +1,161 @@ +/* Copyright 1998, 2006 The Apache Software Foundation or its licensors, as applicable + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.harmony.luni.net; + +import java.io.FileDescriptor; +import java.io.IOException; +import java.net.InetAddress; +import java.net.SocketException; + +import org.apache.harmony.luni.net.NetUtil; +import org.apache.harmony.luni.net.PlainSocketImpl; + +/** + * This class was added so we can create sockets without options that were + * needed for server sockets. It just overrides create so that we call new + * natives which only set the options required for plain sockets. In order to + * preserve behaviour of older versions the create PlainSocketImpl was left as + * is and this new class was added. For newer versions an instance of this class + * is used, for earlier versions the original PlainSocketImpl is used. + */ +class PlainSocketImpl2 extends PlainSocketImpl { + + public PlainSocketImpl2(FileDescriptor fd, int localport, InetAddress addr, int port) { + super(); + super.fd = fd; + super.localport = localport; + super.address = addr; + super.port = port; + } + + public PlainSocketImpl2(){ + super(); + } + + /** + * Answer the result of attempting to create a stream socket in the IP + * stack. This version does not set certain options which were required for + * server sockets and which the initial vesrion ended up setting for both + * socket and serverSockets as the same method was used to create a socket + * for both. We have added a new method so that we can preserve the behavior + * of earlier versions + * + * @param aFD + * the socket FileDescriptor + * @exception SocketException + * if an error occurs while creating the socket + */ + // static native void createStreamSocketImpl2(FileDescriptor aFD, + // boolean preferIPv4Stack) throws SocketException; + // + // /** + // * Connect the underlying socket to the nominated remotehost/port. + // * + // * @param aFD + // * the socket FileDescriptor + // * @param aport + // * the remote machine port to connect to + // * @param trafficClass + // * the traffic class to be used when connecting + // * @param inetAddress + // * the address to connect to + // * @exception SocketException + // * if an error occurs while connecting + // */ + // static native void connectStreamSocketImpl2(FileDescriptor aFD, int + // aport, + // int trafficClass, InetAddress inetAddress) throws IOException; + // + // /** + // * Connect the underlying socket to the nominated remotehost/port. + // * + // * @param aFD + // * the socket FileDescriptor + // * @param aport + // * the remote machine port to connect to + // * @param timeout + // * timeout after which SocketTimeoutException will be thrown + // * @param trafficClass + // * the traffic class to be used when connecting + // * @param inetAddress + // * the address to connect to + // * @exception SocketException + // * if an error occurs while connecting + // * @exception SocketTimeoutException + // * if a timeout occurs while trying to connect + // */ + // static native void connectStreamWithTimeoutSocketImpl2(FileDescriptor + // aFD, + // int aport, int timeout, int trafficClass, InetAddress inetAddress) + // throws IOException; + /** + * Creates a new unconnected socket. If streaming is true, create a stream + * socket, else a datagram socket. The deprecated datagram usage is not + * supported and will throw an exception. + * + * @param isStreaming + * true, if the socket is type streaming + * @exception SocketException + * if an error occurs while creating the socket + */ + protected void create(boolean isStreaming) throws IOException { + streaming = isStreaming; + if (isStreaming) { + netImpl.createSocket(fd, NetUtil.preferIPv4Stack()); + } else { + netImpl.createDatagramSocket(fd, NetUtil.preferIPv4Stack()); + } + } + + /** + * Send the data to the nominated target address + * and port. These values are derived from the + * DatagramPacket to reduce the field calls within JNI. + * + * @param fd + * the socket FileDescriptor + * @param data + * the data buffer of the packet + * @param length + * the length of the data buffer in the packet + * @param port + * the target host port + * @param inetAddress + * the address to send the datagram on + * + * @exception IOException + * upon an read error or timeout + */ + // static native int sendDatagramImpl2(FileDescriptor fd, byte[] data, + // int offset, int length, int port, InetAddress inetAddress) + // throws IOException; + // + // /** + // * Bind the socket to the port/localhost in the IP stack. + // * + // * @param aFD + // * the socket descriptor + // * @param port + // * the option selector + // * @param inetAddress + // * the address to be used + // * + // * @throws SocketException + // * if bind operation fails + // */ + // static native void socketBindImpl2(FileDescriptor aFD, int port, + // InetAddress inetAddress) throws SocketException; +} Index: E:/projects/clear/eclipse/workspace/luni/src/main/java/org/apache/harmony/luni/net/SocketInputStream.java =================================================================== --- E:/projects/clear/eclipse/workspace/luni/src/main/java/org/apache/harmony/luni/net/SocketInputStream.java (revision 0) +++ E:/projects/clear/eclipse/workspace/luni/src/main/java/org/apache/harmony/luni/net/SocketInputStream.java (revision 0) @@ -0,0 +1,169 @@ +/* Copyright 1998, 2006 The Apache Software Foundation or its licensors, as applicable + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.harmony.luni.net; + +import java.io.IOException; +import java.io.InputStream; +import java.net.Socket; +import java.net.SocketImpl; + +import org.apache.harmony.luni.net.PlainSocketImpl; + +import com.ibm.oti.util.Msg; + +/** + * The SocketInputStream supports the streamed reading of bytes from a socket. + * Multiple streams may be opened on a socket, so care should be taken to manage + * opened streams and coordinate read operations between threads. + */ +class SocketInputStream extends InputStream { + + private static final String ERRCODE_OFFSETCOUNT_OUTOFBOUND = "K002f"; //$NON-NLS-1$ + + private static final String ERRCODE_OFFSET_OUTOFBOUND = "K002e"; //$NON-NLS-1$ + + private static final String ERRCODE_BUFFER_NULL = "K0047"; //$NON-NLS-1$ + + PlainSocketImpl socket; + + /** + * Constructs a SocketInputStream for the socket. Read + * operations are forwarded to the socket. + * + * @param socket + * the socket to be read + * @see Socket + */ + public SocketInputStream(SocketImpl socket) { + super(); + this.socket = (PlainSocketImpl) socket; + } + + /** + * Answer the number of bytes that may be read without blocking. Zero + * indicates a read operation would block. This call itself does not block, + * but may throw an IOException. + * + * @return int the number of bytes that may be read without blocking + * @exception IOException + * thrown if an error occurs during the test + */ + public int available() throws IOException { + return socket.available(); + } + + /** + * Close the stream and the underlying socket. + * + * @exception IOException + * thrown if an error occurs during the close + */ + public void close() throws IOException { + socket.close(); + super.close(); + } + + /** + * Read a single byte from the socket, answering the value as an + * int. This call may block indefinitely, depending upon + * whether data is available and whether the read timeout option has been + * set on the socket. A value of -1 indicates 'end-of-file'. + * + * @return int the value read + * @exception IOException + * thrown if an error occurs during the read + */ + public int read() throws IOException { + byte[] buffer = new byte[1]; + int result = socket.read(buffer, 0, 1); + return (-1 == result) ? result : buffer[0] & 0xFF; + } + + /** + * Read a buffer.length number of bytes from the socket, into the + * buffer. This call may block indefinitely, depending upon + * whether data is available and whether the read timeout option has been + * set on the socket. The number of bytes actually read is returned; a value + * of -1 indicates 'end-of-file'. + * + * @param buffer + * the buffer to read into + * @return int the number of bytes actually read + * @exception IOException + * thrown if an error occurs during the read + */ + public int read(byte[] buffer) throws IOException { + return read(buffer, 0, buffer.length); + } + + /** + * Read a count number of bytes from the socket, into the + * buffer at an offset. This call may block + * indefinitely, depending upon whether data is available and whether the + * read timeout option has been set on the socket. The number of bytes + * actually read is returned; a value of -1 indicates 'end-of-file'. + * + * @param buffer + * the buffer to read into + * @param offset + * the offset into the buffer to start filling + * @param count + * the maximum number of bytes to read + * @return int the number of bytes actually read + * @exception IOException, + * ArrayIndexOutOfBoundsException thrown if the argument + * bounds are incorrect or an error occurs during the read + */ + public int read(byte[] buffer, int offset, int count) throws IOException { + if (null == buffer) { + throw new IOException(Msg.getString(ERRCODE_BUFFER_NULL)); + } + + if (0 == count) { + return 0; + } + + if (0 > offset || offset >= buffer.length) { + throw new ArrayIndexOutOfBoundsException(Msg + .getString(ERRCODE_OFFSET_OUTOFBOUND)); + } + if (0 > count || offset + count > buffer.length) { + throw new ArrayIndexOutOfBoundsException(Msg + .getString(ERRCODE_OFFSETCOUNT_OUTOFBOUND)); + } + + return socket.read(buffer, offset, count); + } + + /** + * Skips n number of bytes in this InputStream. Subsequent + * read()'s will not return these bytes unless + * reset() is used. This method may perform multiple reads to + * read n bytes. This implementation reads n + * bytes into a temporary buffer. + * + * @param n + * the number of bytes to skip. + * @return the number of bytes actually skipped. + * + * @exception java.io.IOException + * If the stream is already closed or another IOException + * occurs. + */ + public long skip(long n) throws IOException { + return (0 == n) ? 0 : super.skip(n); + } +} Index: E:/projects/clear/eclipse/workspace/luni/src/main/java/org/apache/harmony/luni/net/NetUtil.java =================================================================== --- E:/projects/clear/eclipse/workspace/luni/src/main/java/org/apache/harmony/luni/net/NetUtil.java (revision 0) +++ E:/projects/clear/eclipse/workspace/luni/src/main/java/org/apache/harmony/luni/net/NetUtil.java (revision 0) @@ -0,0 +1,63 @@ +/* Copyright 1998, 2006 The Apache Software Foundation or its licensors, as applicable + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.harmony.luni.net; + +import java.security.AccessController; + +import com.ibm.oti.util.PriviAction; + +public class NetUtil { + + /* + * FIXME: enhance performance to cache the values + */ + + /** + * Answer whether to use a SOCKS proxy. + * + * @return boolean + */ + public static boolean usingSocks() { + String proxySet = (String) AccessController + .doPrivileged(new PriviAction("socksProxySet")); + if (proxySet != null) { + return proxySet.toLowerCase().equals("true"); + } + return AccessController.doPrivileged(new PriviAction("socksProxyHost")) != null; + } + + /** + * Answer whether to prefer IPV6 address + * + * @return boolean + */ + public static boolean preferIPv6Addresses() { + String result = (String) AccessController.doPrivileged(new PriviAction( + "java.net.preferIPv6Addresses")); + return "true".equals(result); + } + + /** + * Answer whether to prefer IPV4 stack + * + * @return boolean + */ + public static boolean preferIPv4Stack() { + String result = (String) AccessController.doPrivileged(new PriviAction( + "java.net.preferIPv4Stack")); + return "true".equals(result); + } + +} Index: E:/projects/clear/eclipse/workspace/luni/src/main/java/org/apache/harmony/luni/net/PlainMulticastSocketImpl.java =================================================================== --- E:/projects/clear/eclipse/workspace/luni/src/main/java/org/apache/harmony/luni/net/PlainMulticastSocketImpl.java (revision 0) +++ E:/projects/clear/eclipse/workspace/luni/src/main/java/org/apache/harmony/luni/net/PlainMulticastSocketImpl.java (revision 0) @@ -0,0 +1,54 @@ +/* Copyright 1998, 2006 The Apache Software Foundation or its licensors, as applicable + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.harmony.luni.net; + +import java.io.FileDescriptor; +import java.net.SocketException; + +import org.apache.harmony.luni.platform.Platform; + + +/** + * This class was added so we can create sockets with options that are needed + * for server sockets. It just overrides create so that we call new natives + * which only set the options required for server sockets. In order to preserve + * behaviour of older versions the create PlainSocketImpl was left as is and + * this new class was added. For newer versions an instance of this class is + * used, for earlier versions the original PlainSocketImpl is used. + */ +class PlainMulticastSocketImpl extends PlainDatagramSocketImpl { + + // /** + // * Answer the result of attempting to create a multicast socket in the IP + // * stack. Any special options required for server sockets will be set by + // * this method. + // * + // * @param aFD + // * the socket FileDescriptor + // * @exception SocketException + // * if an error occurs while creating the socket + // */ + // static native void createMulticastSocketImpl(FileDescriptor aFD, + // boolean preferIPv4Stack) throws SocketException; + + /** + * Allocate the socket descriptor in the IP stack. + */ + public void create() throws SocketException { + Platform.getNetworkSystem() + .createMulticastSocket(fd, NetUtil.preferIPv4Stack()); + } +} Index: E:/projects/clear/eclipse/workspace/luni/src/main/java/org/apache/harmony/luni/net/PlainServerSocketImpl.java =================================================================== --- E:/projects/clear/eclipse/workspace/luni/src/main/java/org/apache/harmony/luni/net/PlainServerSocketImpl.java (revision 0) +++ E:/projects/clear/eclipse/workspace/luni/src/main/java/org/apache/harmony/luni/net/PlainServerSocketImpl.java (revision 0) @@ -0,0 +1,78 @@ +/* Copyright 1998, 2006 The Apache Software Foundation or its licensors, as applicable + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.harmony.luni.net; + +import java.io.FileDescriptor; +import java.net.SocketException; + +import org.apache.harmony.luni.net.NetUtil; +import org.apache.harmony.luni.net.PlainSocketImpl; + +/** + * This class was added so we can create sockets with options that are needed + * for server sockets. It just overrides create so that we call new natives + * which only set the options required for server sockets. In order to preserve + * behaviour of older versions the create PlainSocketImpl was left as is and + * this new class was added. For newer versions an instance of this class is + * used, for earlier versions the original PlainSocketImpl is used. + */ +class PlainServerSocketImpl extends PlainSocketImpl { + + public PlainServerSocketImpl(){ + super(); + } + + public PlainServerSocketImpl(FileDescriptor fd){ + super(); + this.fd = fd; + } + + /** + * Answer the result of attempting to create a server stream socket in the + * IP stack. Any special options required for server sockets will be set by + * this method. + * + * @param aFD + * the socket FileDescriptor + * @exception SocketException + * if an error occurs while creating the socket + */ + // static native void createServerStreamSocketImpl(FileDescriptor aFD, + // boolean preferIPv4Stack) throws SocketException; + /** + * Creates a new unconnected socket. If streaming is true, create a stream + * socket, else a datagram socket. The deprecated datagram usage is not + * supported and will throw an exception. + * + * @param isStreaming + * true, if the socket is type streaming + * @exception SocketException + * if an error occurs while creating the socket + */ + protected void create(boolean isStreaming) throws SocketException { + streaming = isStreaming; + // if (isStreaming) { + // createServerStreamSocketImpl(fd, Socket.preferIPv4Stack()); + // } else { + // createDatagramSocketImpl(fd, Socket.preferIPv4Stack()); + // } + if (isStreaming) { + netImpl.createServerStreamSocket(fd, NetUtil.preferIPv4Stack()); + } else { + netImpl.createDatagramSocket(fd, NetUtil.preferIPv4Stack()); + } + } +} Index: E:/projects/clear/eclipse/workspace/luni/src/main/java/org/apache/harmony/luni/net/SocketImplProvider.java =================================================================== --- E:/projects/clear/eclipse/workspace/luni/src/main/java/org/apache/harmony/luni/net/SocketImplProvider.java (revision 0) +++ E:/projects/clear/eclipse/workspace/luni/src/main/java/org/apache/harmony/luni/net/SocketImplProvider.java (revision 0) @@ -0,0 +1,57 @@ +/* Copyright 2006 The Apache Software Foundation or its licensors, as applicable + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.harmony.luni.net; + +import java.io.FileDescriptor; +import java.net.DatagramSocketImpl; +import java.net.InetAddress; +import java.net.SocketImpl; + +import org.apache.harmony.luni.net.PlainDatagramSocketImpl; +import org.apache.harmony.luni.net.PlainMulticastSocketImpl; +import org.apache.harmony.luni.net.PlainServerSocketImpl; +import org.apache.harmony.luni.net.PlainSocketImpl2; + +public class SocketImplProvider { + + public static SocketImpl getSocketImpl(){ + return new PlainSocketImpl2(); + } + + public static SocketImpl getSocketImpl(FileDescriptor fd, int localport, InetAddress addr, int port){ + return new PlainSocketImpl2(fd, localport, addr, port); + } + + public static SocketImpl getServerSocketImpl(){ + return new PlainServerSocketImpl(); + } + + public static SocketImpl getServerSocketImpl(FileDescriptor fd){ + return new PlainServerSocketImpl(fd); + } + + public static DatagramSocketImpl getDatagramSocketImpl(){ + return new PlainDatagramSocketImpl(); + } + + public static DatagramSocketImpl getMulticastSocketImpl(){ + return new PlainMulticastSocketImpl(); + } + + public static DatagramSocketImpl getDatagramSocketImpl(FileDescriptor fd, int localPort) { + return new PlainDatagramSocketImpl(fd, localPort); + } + +} Index: E:/projects/clear/eclipse/workspace/luni/src/main/java/org/apache/harmony/luni/net/SocketOutputStream.java =================================================================== --- E:/projects/clear/eclipse/workspace/luni/src/main/java/org/apache/harmony/luni/net/SocketOutputStream.java (revision 0) +++ E:/projects/clear/eclipse/workspace/luni/src/main/java/org/apache/harmony/luni/net/SocketOutputStream.java (revision 0) @@ -0,0 +1,116 @@ +/* Copyright 1998, 2006 The Apache Software Foundation or its licensors, as applicable + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.harmony.luni.net; + +import java.io.IOException; +import java.io.OutputStream; +import java.net.Socket; +import java.net.SocketImpl; + +import org.apache.harmony.luni.net.PlainSocketImpl; + +class SocketOutputStream extends OutputStream { + + private static final String ERRCODE_BUFFER_NULL = "K0047"; //$NON-NLS-1$ + + private static final String ERRCODE_OFFSET_OUTOFBOUND = "K002f"; //$NON-NLS-1$ + + PlainSocketImpl socket; + + /** + * Constructs a SocketOutputStream for the socket. Write + * operations are forwarded to the socket. + * + * @param socket + * the socket to be written + * @see Socket + */ + + public SocketOutputStream(SocketImpl socket) { + super(); + this.socket = (PlainSocketImpl) socket; + } + + /** + * Close the stream and the underlying socket. + * + * @exception IOException + * thrown if an error occurs during the close + */ + + public void close() throws IOException { + socket.close(); + super.close(); + } + + /** + * Write the buffer to the socket. + * + * @param buffer + * the buffer to write + * @exception IOException + * thrown if an error occurs during the write + */ + public void write(byte[] buffer) throws IOException { + socket.write(buffer, 0, buffer.length); + } + + /** + * Write the count number of bytes from the + * buffer to the socket, starting at offset. + * + * @param buffer + * the buffer to write + * @param offset + * the offset in buffer to start writing + * @param count + * the number of bytes to write + * @exception IOException, + * IndexOutOfBoundsException thrown if an error occurs during + * the write + */ + public void write(byte[] buffer, int offset, int count) throws IOException { + // avoid int overflow + if (buffer != null) { + if (0 <= offset && offset <= buffer.length && 0 <= count + && count <= buffer.length - offset) { + socket.write(buffer, offset, count); + } else { + throw new ArrayIndexOutOfBoundsException(com.ibm.oti.util.Msg + .getString(ERRCODE_OFFSET_OUTOFBOUND)); + } + } else { + throw new NullPointerException(com.ibm.oti.util.Msg + .getString(ERRCODE_BUFFER_NULL)); + } + } + + /** + * Write a single byte, the lowest-order byte from an int to + * the socket. + * + * @param oneByte + * the value to write + * @exception IOException + * thrown if an error occurs during the write + */ + public void write(int oneByte) throws IOException { + byte[] buffer = new byte[1]; + buffer[0] = (byte) (oneByte & 0xFF); + + socket.write(buffer, 0, 1); + } +} Index: E:/projects/clear/eclipse/workspace/luni/src/main/java/org/apache/harmony/luni/net/GenericIPMreq.java =================================================================== --- E:/projects/clear/eclipse/workspace/luni/src/main/java/org/apache/harmony/luni/net/GenericIPMreq.java (revision 0) +++ E:/projects/clear/eclipse/workspace/luni/src/main/java/org/apache/harmony/luni/net/GenericIPMreq.java (revision 0) @@ -0,0 +1,107 @@ +/* Copyright 1998, 2006 The Apache Software Foundation or its licensors, as applicable + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.harmony.luni.net; + + +import java.net.Inet4Address; +import java.net.Inet6Address; +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.util.Enumeration; + +/** + * This class provides is used to pass the information required in an ip_mreq or + * ip6_mreq structure to java natives. We don't have accessor methods as it is + * more straight forward in the natives to simply access the fields directly + */ +final class GenericIPMreq { + + // private members + private InetAddress multiaddr; + + private InetAddress interfaceAddr; + + private boolean isIPV6Address; + + private int interfaceIdx; + + /** + * This constructor is used to create an instance of the object + * + * @param addr + * multicast address to join/leave + * + */ + GenericIPMreq(InetAddress addr) { + multiaddr = addr; + interfaceAddr = null; + interfaceIdx = 0; + init(); + } + + /** + * This constructor is used to create an instance of the object + * + * @param addr + * multicast address to join/leave + * @param netInterface + * the NetworkInterface object identifying the interface on which + * to join/leave + * + */ + GenericIPMreq(InetAddress addr, NetworkInterface netInterface) { + multiaddr = addr; + if (null != netInterface) { + // TODO check if necessary + //interfaceIdx = netInterface.getIndex(); + + // here we need to get the first IPV4 address as we only use it if + // we + // are settting the interface for an IPV4 multicast socket. For + // adds/drops on + // IPV6 addresses we use the index within the networkInterface + interfaceAddr = null; + Enumeration theAddresses = netInterface.getInetAddresses(); + if ((addr instanceof Inet4Address) && (theAddresses != null)) { + boolean found = false; + while ((theAddresses.hasMoreElements()) && (found != true)) { + InetAddress theAddress = (InetAddress) theAddresses + .nextElement(); + if (theAddress instanceof Inet4Address) { + interfaceAddr = theAddress; + found = true; + } + } + } + } else { + // network interface is null so we just want to defer the decision + // to + // the system + interfaceIdx = 0; + interfaceAddr = null; + } + init(); + } + + /** + * This method does any required initialization for the constructors + */ + private void init() { + // set the flag indicating if the multicast address is an IPV6 address + // or not + isIPV6Address = ((multiaddr != null) && (multiaddr instanceof Inet6Address)); + } +} Index: E:/projects/clear/eclipse/workspace/luni/src/main/java/org/apache/harmony/luni/net/Socks4Message.java =================================================================== --- E:/projects/clear/eclipse/workspace/luni/src/main/java/org/apache/harmony/luni/net/Socks4Message.java (revision 0) +++ E:/projects/clear/eclipse/workspace/luni/src/main/java/org/apache/harmony/luni/net/Socks4Message.java (revision 0) @@ -0,0 +1,251 @@ +/* Copyright 1998, 2006 The Apache Software Foundation or its licensors, as applicable + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.harmony.luni.net; + +import java.io.UnsupportedEncodingException; + +class Socks4Message { + protected byte[] buffer; + + final static private int SOCKS_VERSION = 4; + + final static public int COMMAND_CONNECT = 1; + + final static public int COMMAND_BIND = 2; + + final static public int RETURN_SUCCESS = 90; + + final static public int RETURN_FAILURE = 91; + + final static public int RETURN_CANNOT_CONNECT_TO_IDENTD = 92; + + final static public int RETURN_DIFFERENT_USER_IDS = 93; + + final static protected int INDEX_VERSION = 0; + + final static private int INDEX_COMMAND = 1; + + final static private int INDEX_PORT = 2; + + final static private int INDEX_IP = 4; + + final static private int INDEX_USER_ID = 8; + + final static private int BUFFER_LENGTH = 256; + + final static public int REPLY_LENGTH = 8; + + final static private int MAX_USER_ID_LENGTH = BUFFER_LENGTH - INDEX_USER_ID; + + public Socks4Message() { + super(); + buffer = new byte[BUFFER_LENGTH]; + setVersionNumber(SOCKS_VERSION); + } + + /** + * Get the request's command or result. + */ + public int getCommandOrResult() { + return buffer[INDEX_COMMAND]; + } + + /** + * Set the request's command or result. + */ + public void setCommandOrResult(int command) { + buffer[INDEX_COMMAND] = (byte) command; + } + + /** + * Answer the request's port number. + */ + public int getPort() { + return getInt16(INDEX_PORT); + } + + /** + * Set the request's port number. + */ + public void setPort(int port) { + setInt16(INDEX_PORT, port); + } + + /* + * Answer the IP address of the request as an integer. + */ + public int getIP() { + return getInt32(INDEX_IP); + } + + /** + * Set the IP address. This expects an array of four bytes in host order. + */ + public void setIP(byte[] ip) { + buffer[INDEX_IP] = ip[0]; + buffer[INDEX_IP + 1] = ip[1]; + buffer[INDEX_IP + 2] = ip[2]; + buffer[INDEX_IP + 3] = ip[3]; + } + + /** + * Answer the user id for authentication. + */ + public String getUserId() { + return getString(INDEX_USER_ID, MAX_USER_ID_LENGTH); + } + + /** + * Set the user id for authentication. + */ + public void setUserId(String id) { + setString(INDEX_USER_ID, MAX_USER_ID_LENGTH, id); + } + + /** + */ + public String toString() { + StringBuffer buf = new StringBuffer(""); + buf.append("Version: "); + buf.append(Integer.toHexString(getVersionNumber())); + buf.append(" Command: "); + buf.append(Integer.toHexString(getCommandOrResult())); + buf.append(" Port: "); + buf.append(getPort()); + buf.append(" IP: "); + buf.append(Integer.toHexString(getIP())); + buf.append(" User ID: "); + buf.append(getUserId()); + return buf.toString(); + } + + /** + * Answer the total number of bytes used for the request. This method + * searches for the end of the user id, then searches for the end of the + * password and returns the final index as the requests length. + */ + public int getLength() { + int index = 0; + + // Look for the end of the user id. + for (index = INDEX_USER_ID; buffer[index] != 0; index++) { + /* + * Finds the end of the user id by searching for the null + * termination of the user id string. + */ + } + + // Increment the index to include the NULL character in the length; + index++; + return index; + } + + /** + * Answer an error string corresponding to the given error value. + */ + public String getErrorString(int error) { + switch (error) { + case RETURN_FAILURE: + return com.ibm.oti.util.Msg.getString("K00cd"); + case RETURN_CANNOT_CONNECT_TO_IDENTD: + return com.ibm.oti.util.Msg.getString("K00ce"); + case RETURN_DIFFERENT_USER_IDS: + return com.ibm.oti.util.Msg.getString("K00cf"); + default: + return com.ibm.oti.util.Msg.getString("K00d0"); + } + } + + /** + * Answer the message's byte buffer. + */ + public byte[] getBytes() { + return buffer; + } + + /** + * Get a 16 bit integer from the buffer at the offset given. + */ + private int getInt16(int offset) { + return (((buffer[offset] & 0xFF) << 8) + (buffer[offset + 1] & 0xFF)); + } + + /** + * Get a 32 bit integer from the buffer at the offset given. + */ + private int getInt32(int offset) { + return ((buffer[offset + 3] & 0xFF) + + ((buffer[offset + 2] & 0xFF) << 8) + + ((buffer[offset + 1] & 0xFF) << 16) + ((buffer[offset + 0] & 0xFF) << 24)); + } + + /** + * Get a String from the buffer at the offset given. The method reads until + * it encounters a null value or reaches the maxLength given. + */ + private String getString(int offset, int maxLength) { + int index = offset; + int lastIndex = index + maxLength; + String result; + + while (index < lastIndex && (buffer[index] != 0)) { + index++; + } + try { + result = new String(buffer, offset, index - offset, "ISO8859_1"); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e.toString()); + } + return result; + } + + /** + * Answer the SOCKS version number. Should always be 4. + */ + private int getVersionNumber() { + return buffer[INDEX_VERSION]; + } + + /** + * Put a 16 bit integer into the buffer at the offset given. + */ + private void setInt16(int offset, int value) { + buffer[offset] = (byte) (value >>> 8 & 0xFF); + buffer[offset + 1] = (byte) (value & 0xFF); + } + + /** + * Put a string into the buffer at the offset given. + */ + private void setString(int offset, int maxLength, String theString) { + byte[] stringBytes; + try { + stringBytes = theString.getBytes("ISO8859_1"); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e.toString()); + } + int length = Math.min(stringBytes.length, maxLength); + System.arraycopy(stringBytes, 0, buffer, offset, length); + buffer[offset + length] = 0; + } + + /** + * Set the SOCKS version number. This should always be 4. + */ + private void setVersionNumber(int number) { + buffer[INDEX_VERSION] = (byte) number; + } +} Index: E:/projects/clear/eclipse/workspace/luni/src/main/java/org/apache/harmony/luni/net/PlainSocketImpl.java =================================================================== --- E:/projects/clear/eclipse/workspace/luni/src/main/java/org/apache/harmony/luni/net/PlainSocketImpl.java (revision 0) +++ E:/projects/clear/eclipse/workspace/luni/src/main/java/org/apache/harmony/luni/net/PlainSocketImpl.java (revision 0) @@ -0,0 +1,663 @@ +/* Copyright 1998, 2006 The Apache Software Foundation or its licensors, as applicable + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.harmony.luni.net; + +import java.io.FileDescriptor; +import java.io.IOException; +import java.io.InputStream; +import java.io.InterruptedIOException; +import java.io.OutputStream; +import java.net.ConnectException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.SocketAddress; +import java.net.SocketException; +import java.net.SocketImpl; +import java.net.SocketOptions; +import java.net.SocketTimeoutException; +import java.net.UnknownHostException; +import java.security.AccessController; + +import org.apache.harmony.luni.net.NetUtil; +import org.apache.harmony.luni.net.PlainSocketImpl; +import org.apache.harmony.luni.net.SocketInputStream; +import org.apache.harmony.luni.net.SocketOutputStream; +import org.apache.harmony.luni.net.Socks4Message; +import org.apache.harmony.luni.platform.INetworkSystem; +import org.apache.harmony.luni.platform.Platform; + +import com.ibm.oti.util.Msg; +import com.ibm.oti.util.PriviAction; + +/** + * A concrete connected-socket implementation. + */ +class PlainSocketImpl extends SocketImpl { + + // Const copy from socket + + static final int MULTICAST_IF = 1; + + static final int MULTICAST_TTL = 2; + + static final int TCP_NODELAY = 4; + + static final int FLAG_SHUTDOWN = 8; + + // For SOCKS support. A SOCKS bind() uses the last + // host connected to in its request. + static private InetAddress lastConnectedAddress; + + static private int lastConnectedPort; + + private boolean tcpNoDelay = true; + + private Object connectLock = new Object(); + + // used to store the trafficClass value which is simply returned + // as the value that was set. We also need it to pass it to methods + // that specify an address packets are going to be sent to + private int trafficClass = 0; + + protected INetworkSystem netImpl = Platform.getNetworkSystem(); + + public int receiveTimeout = 0; + + public boolean streaming = true; + + public boolean shutdownInput = false; + + /** + * Accepts a connection on the provided socket, by calling the IP stack. + * + * @param newImpl + * the socket to accept connections on + * @exception SocketException + * if an error occurs while accepting + */ + protected void accept(SocketImpl newImpl) throws IOException { + if (NetUtil.usingSocks()) { + ((PlainSocketImpl) newImpl).socksBind(); + ((PlainSocketImpl) newImpl).socksAccept(); + return; + } + + try { + netImpl.acceptStreamSocket(fd, newImpl, ((PlainSocketImpl) newImpl) + .getFD(), receiveTimeout); + } catch (InterruptedIOException e) { + throw new SocketTimeoutException(e.getMessage()); + } + ((PlainSocketImpl) newImpl).setLocalport(getLocalPort()); + } + + /** + * Answer the number of bytes that may be read from this socket without + * blocking. This call does not block. + * + * @return int the number of bytes that may be read without blocking + * @exception SocketException + * if an error occurs while peeking + */ + + protected synchronized int available() throws IOException { + // we need to check if the input has been shutdown. If so + // we should return that there is no data to be read + if (shutdownInput == true) { + return 0; + } + return netImpl.availableStream(fd); + } + + /** + * Binds this socket to the specified local host/port. Binding to the 0 port + * implies binding to any available port. By not making the assignment to + * the instVar, the getLocalPort method will lazily go to the stack and + * query for the assigned port + * + * @param anAddr + * the local machine address to bind the socket to + * @param aPort + * the port on the local machine to bind the socket to + * @exception IOException + * if an error occurs while binding + */ + protected void bind(InetAddress anAddr, int aPort) throws IOException { + if (NetUtil.usingSocks()) { + socksBind(); + return; + } + netImpl.bind(fd, aPort, anAddr); + // PlainSocketImpl2.socketBindImpl2(fd, aPort, anAddr); + address = anAddr; + if (0 != aPort) { + localport = aPort; + } else { + localport = netImpl.getSocketLocalPort(fd, + NetUtil.preferIPv6Addresses()); + } + } + + /** + * Close the socket. Usage thereafter is invalid. + * + * @exception IOException + * if an error occurs while closing + */ + protected void close() throws IOException { + synchronized (fd) { + if (fd.valid()) { + if ((netImpl.getSocketFlags() & FLAG_SHUTDOWN) != 0) { + try { + shutdownOutput(); + } catch (Exception e) { + } + } + netImpl.socketClose(fd); + fd = new FileDescriptor(); + } + } + } + + /** + * Connects this socket to the specified remote host/port. This method + * assumes the sender has verified the host with the security policy. + * + * @param aHost + * the remote host to connect to + * @param aPort + * the remote port to connect to + * @exception IOException + * if an error occurs while connecting + */ + protected void connect(String aHost, int aPort) throws IOException { + // InetAddress anAddr = InetAddress.getHostByNameImpl(aHost, + // preferIPv6Addresses()); + InetAddress anAddr = netImpl.getHostByName(aHost, + NetUtil.preferIPv6Addresses()); + connect(anAddr, aPort); + } + + /** + * Connects this socket to the specified remote host address/port. + * + * @param anAddr + * the remote host address to connect to + * @param aPort + * the remote port to connect to + * @exception IOException + * if an error occurs while connecting + */ + protected void connect(InetAddress anAddr, int aPort) throws IOException { + connect(anAddr, aPort, 0); + } + + /** + * Connects this socket to the specified remote host address/port. + * + * @param anAddr + * the remote host address to connect to + * @param aPort + * the remote port to connect to + * @param timeout + * a timeout where supported. 0 means no timeout + * @exception IOException + * if an error occurs while connecting + */ + private void connect(InetAddress anAddr, int aPort, int timeout) + throws IOException { + InetAddress address = anAddr.isAnyLocalAddress() ? InetAddress + .getByName("localhost") : anAddr; + + try { + if (streaming) { + if (NetUtil.usingSocks()) { + socksConnect(anAddr, aPort, 0); + } else { + if (timeout == 0) { + // PlainSocketImpl2.connectStreamSocketImpl2(fd, aPort, + // trafficClass, address); + netImpl.connect(fd, trafficClass, anAddr, aPort); + } else { + // PlainSocketImpl2.connectStreamWithTimeoutSocketImpl2( + // fd, aPort, timeout, trafficClass, address); + netImpl.connectStreamWithTimeoutSocket(fd, aPort, + timeout, trafficClass, anAddr); + } + } + } + } catch (ConnectException e) { + throw new ConnectException(anAddr + ":" + aPort + " - " + + e.getMessage()); + } + super.address = anAddr; + super.port = aPort; + } + + /** + * Creates a new unconnected socket. If streaming is true, create a stream + * socket, else a datagram socket. The deprecated datagram usage is not + * supported and will throw an exception. + * + * @param streaming + * true, if the socket is type streaming + * @exception SocketException + * if an error occurs while creating the socket + */ + protected void create(boolean streaming) throws IOException { + this.streaming = streaming; + // if (streaming) { + // createStreamSocketImpl(fd, Socket.preferIPv4Stack()); + // } else { + // createDatagramSocketImpl(fd, Socket.preferIPv4Stack()); + // } + + if (streaming) { + netImpl.createStreamSocket(fd, NetUtil.preferIPv4Stack()); + } else { + netImpl.createDatagramSocket(fd, NetUtil.preferIPv4Stack()); + } + } + + protected void finalize() throws IOException { + close(); + } + + /** + * Answer the socket input stream. + * + * @return InputStream an InputStream on the socket + * @exception IOException + * thrown if an error occurs while accessing the stream + */ + protected synchronized InputStream getInputStream() throws IOException { + if (!fd.valid()) { + throw new SocketException(Msg.getString("K003d")); + } + + return new SocketInputStream(this); + } + + /** + * Answer the nominated socket option. Receive timeouts are maintained in + * Java, rather than in the JNI code. + * + * @param optID + * the socket option to retrieve + * @return Object the option value + * @exception SocketException + * thrown if an error occurs while accessing the option + */ + public Object getOption(int optID) throws SocketException { + if (optID == SocketOptions.SO_TIMEOUT) { + return new Integer(receiveTimeout); + } else if (optID == SocketOptions.IP_TOS) { + return new Integer(trafficClass); + } else { + // Call the native first so there will be + // an exception if the socket if closed. + Object result = netImpl.getSocketOption(fd, optID); + if (optID == SocketOptions.TCP_NODELAY + && (netImpl.getSocketFlags() & TCP_NODELAY) != 0) { + return new Boolean(tcpNoDelay); + } + return result; + } + } + + /** + * Answer the socket output stream. + * + * @return OutputStream an OutputStream on the socket + * @exception IOException + * thrown if an error occurs while accessing the stream + */ + protected synchronized OutputStream getOutputStream() throws IOException { + if (!fd.valid()) { + throw new SocketException(Msg.getString("K003d")); + } + return new SocketOutputStream(this); + } + + /** + * Listen for connection requests on this stream socket. Incoming connection + * requests are queued, up to the limit nominated by backlog. Additional + * requests are rejected. listen() may only be invoked on stream sockets. + * + * @param backlog + * the max number of outstanding connection requests + * @exception IOException + * thrown if an error occurs while listening + */ + protected void listen(int backlog) throws IOException { + if (NetUtil.usingSocks()) { + // Do nothing for a SOCKS connection. The listen occurs on the + // server during the bind. + return; + } + // listenStreamSocketImpl(fd, backlog); + netImpl.listenStreamSocket(fd, backlog); + } + + /** + * Set the nominated socket option. Receive timeouts are maintained in Java, + * rather than in the JNI code. + * + * @param optID + * the socket option to set + * @param val + * the option value + * @exception SocketException + * thrown if an error occurs while setting the option + */ + public void setOption(int optID, Object val) throws SocketException { + if (optID == SocketOptions.SO_TIMEOUT) { + receiveTimeout = ((Integer) val).intValue(); + } else { + try { + netImpl.setSocketOption(fd, optID, val); + if (optID == SocketOptions.TCP_NODELAY + && (netImpl.getSocketFlags() & TCP_NODELAY) != 0) { + tcpNoDelay = ((Boolean) val).booleanValue(); + } + } catch (SocketException e) { + + // we don't through an exception for IP_TOS even if the platform + // won't let us set the requested value + if (optID != SocketOptions.IP_TOS) { + throw e; + } + } + + // save this value as it is acutally used differently for IPv4 and + // IPv6 so we cannot get the value using the getOption. The option + // is actually only set for IPv4 and a masked version of the value + // will be set as only a subset of the values are allowed on the + // socket. Therefore we need to retain it to return the value that + // was set. We also need the value to be passed into a number of + // natives so that it can be used properly with IPv6 + if (optID == SocketOptions.IP_TOS) { + trafficClass = ((Integer) val).intValue(); + } + } + } + + /** + * Get the SOCKS proxy server port. + */ + private int socksGetServerPort() { + int portValue = -1; + + String proxyPort = (String) AccessController + .doPrivileged(new PriviAction("socksProxyPort")); + + if (proxyPort != null) { + portValue = Integer.parseInt(proxyPort); + } + if (portValue < 0) { + portValue = 1080; + } + + return portValue; + } + + /** + * Get the InetAddress of the SOCKS proxy server. + */ + private InetAddress socksGetServerAddress() throws UnknownHostException { + String proxyName = (String) AccessController + .doPrivileged(new PriviAction("socksProxyHost")); + + InetAddress anAddr = netImpl.getHostByName(proxyName, + NetUtil.preferIPv6Addresses()); + return anAddr; + } + + /** + * Connect using a SOCKS server. + */ + private void socksConnect(InetAddress applicationServerAddress, + int applicationServerPort, int timeout) throws IOException { + try { + if (timeout == 0) { + // PlainSocketImpl2.connectStreamSocketImpl2(fd, + // socksGetServerPort(), trafficClass, + // socksGetServerAddress()); + netImpl.connect(fd, trafficClass, socksGetServerAddress(), + socksGetServerPort()); + } else { + // PlainSocketImpl2.connectStreamWithTimeoutSocketImpl2(fd, + // socksGetServerPort(), timeout, trafficClass, + // socksGetServerAddress()); + netImpl.connectStreamWithTimeoutSocket(fd, + socksGetServerPort(), timeout, trafficClass, + socksGetServerAddress()); + } + + } catch (Exception e) { + throw new SocketException(Msg.getString("K003e", e)); + } + + socksRequestConnection(applicationServerAddress, applicationServerPort); + + lastConnectedAddress = applicationServerAddress; + lastConnectedPort = applicationServerPort; + } + + /** + * Request a SOCKS connection to the application server given. If the + * request fails to complete successfully, an exception is thrown. + */ + private void socksRequestConnection(InetAddress applicationServerAddress, + int applicationServerPort) throws IOException { + socksSendRequest(Socks4Message.COMMAND_CONNECT, + applicationServerAddress, applicationServerPort); + Socks4Message reply = socksReadReply(); + if (reply.getCommandOrResult() != Socks4Message.RETURN_SUCCESS) { + throw new IOException(reply.getErrorString(reply + .getCommandOrResult())); + } + } + + /** + * Perform an accept for a SOCKS bind. + */ + public void socksAccept() throws IOException { + Socks4Message reply = socksReadReply(); + if (reply.getCommandOrResult() != Socks4Message.RETURN_SUCCESS) { + throw new IOException(reply.getErrorString(reply + .getCommandOrResult())); + } + } + + /** + * Shutdown the input portion of the socket. + */ + protected void shutdownInput() throws IOException { + shutdownInput = true; + // shutdownInputImpl(fd); + netImpl.shutdownInput(fd); + } + + /** + * Shutdown the output portion of the socket. + */ + protected void shutdownOutput() throws IOException { + // shutdownOutputImpl(fd); + netImpl.shutdownOutput(fd); + } + + /** + * Bind using a SOCKS server. + */ + private void socksBind() throws IOException { + try { + // PlainSocketImpl2.connectStreamSocketImpl2(fd, + // socksGetServerPort(), + // trafficClass, socksGetServerAddress()); + netImpl.connect(fd, trafficClass, socksGetServerAddress(), + socksGetServerPort()); + } catch (Exception e) { + throw new IOException(Msg.getString("K003f", e)); + } + + // There must be a connection to an application host for the bind to + // work. + if (lastConnectedAddress == null) { + throw new SocketException(Msg.getString("K0040")); + } + + // Use the last connected address and port in the bind request. + socksSendRequest(Socks4Message.COMMAND_BIND, lastConnectedAddress, + lastConnectedPort); + Socks4Message reply = socksReadReply(); + + if (reply.getCommandOrResult() != Socks4Message.RETURN_SUCCESS) { + throw new IOException(reply.getErrorString(reply + .getCommandOrResult())); + } + + // A peculiarity of socks 4 - if the address returned is 0, use the + // original socks server address. + if (reply.getIP() == 0) { + address = socksGetServerAddress(); + } else { + // IPv6 support not yet required as + // currently the Socks4Message.getIP() only returns int, + // so only works with IPv4 4byte addresses + byte[] replyBytes = new byte[4]; + intToBytes(reply.getIP(), replyBytes, 0); + address = InetAddress.getByAddress(replyBytes); + } + localport = reply.getPort(); + } + + /** + * Send a SOCKS V4 request. + */ + private void socksSendRequest(int command, InetAddress address, int port) + throws IOException { + Socks4Message request = new Socks4Message(); + request.setCommandOrResult(command); + request.setPort(port); + request.setIP(address.getAddress()); + request.setUserId("default"); + + getOutputStream().write(request.getBytes(), 0, request.getLength()); + } + + /** + * Read a SOCKS V4 reply. + */ + private Socks4Message socksReadReply() throws IOException { + Socks4Message reply = new Socks4Message(); + int bytesRead = 0; + while (bytesRead < Socks4Message.REPLY_LENGTH) { + bytesRead += getInputStream().read(reply.getBytes(), bytesRead, + Socks4Message.REPLY_LENGTH - bytesRead); + } + return reply; + } + + /** + * Connect the socket to the host/port specified by the SocketAddress with a + * specified timeout. + * + * + * @param remoteAddr + * the remote machine address and port to connect to + * @param timeout + * the millisecond timeout value, the connect will block + * indefinitely for a zero value. + * + * @exception IOException + * if a problem occurs during the connect + */ + protected void connect(SocketAddress remoteAddr, int timeout) + throws IOException { + InetSocketAddress inetAddr = (InetSocketAddress) remoteAddr; + connect(inetAddr.getAddress(), inetAddr.getPort(), timeout); + } + + /** + * Answer if the socket supports urgent data. + */ + protected boolean supportsUrgentData() { + // return !streaming || SocketImpl.supportsUrgentDataImpl(fd); + return !streaming || netImpl.supportsUrgentData(fd); + } + + /** + * Send the single byte of urgent data on the socket. + * + * @param value + * the byte of urgent data + * + * @exception IOException + * when an error occurs sending urgent data + */ + protected void sendUrgentData(int value) throws IOException { + // SocketImpl.sendUrgentDataImpl(fd, (byte) value); + netImpl.sendUrgentData(fd, (byte) value); + } + + FileDescriptor getFD() { + return fd; + } + + private void setLocalport(int localport) { + this.localport = localport; + } + + int read(byte[] buffer, int offset, int count) throws IOException { + if (shutdownInput) { + return -1; + } + try { + // int read = receiveStreamImpl(fd, buffer, offset, count, + // receiveTimeout); + int read = netImpl.receiveStream(fd, buffer, offset, count, + receiveTimeout); + if (read == -1) { + shutdownInput = true; + } + return read; + } catch (InterruptedIOException e) { + throw new SocketTimeoutException(e.getMessage()); + } + } + + int write(byte[] buffer, int offset, int count) throws IOException { + if (!streaming) { + // PlainSocketImpl2.sendDatagramImpl2(fd, buffer, offset, count, + // port, + // address); + netImpl + .sendDatagram2(fd, buffer, offset, count, port, address); + } + // return sendStreamImpl(fd, buffer, offset, count); + return netImpl.sendStream(fd, buffer, offset, count); + } + + static void intToBytes(int value, byte bytes[], int start) { + // Shift the int so the current byte is right-most + // Use a byte mask of 255 to single out the last byte. + bytes[start] = (byte) ((value >> 24) & 255); + bytes[start + 1] = (byte) ((value >> 16) & 255); + bytes[start + 2] = (byte) ((value >> 8) & 255); + bytes[start + 3] = (byte) (value & 255); + } +}