diff options
author | jfrijters <jfrijters> | 2015-06-26 17:41:57 +0300 |
---|---|---|
committer | jfrijters <jfrijters> | 2015-06-26 17:41:57 +0300 |
commit | b2ddeb8b1671ebd911e664751a7a1851fd86e03f (patch) | |
tree | 5527576c40a2225c8bba67d6bcbb7788e94d58d6 | |
parent | 7a84420150a75ebe065388c56a03a7e6dcfb833e (diff) |
Unforked java/net/SocketInputStream.java and java/net/SocketOutputStream.java.
-rw-r--r-- | openjdk/FORKED | 2 | ||||
-rw-r--r-- | openjdk/allsources.lst | 4 | ||||
-rw-r--r-- | openjdk/java/net/SocketInputStream.java | 332 | ||||
-rw-r--r-- | openjdk/java/net/SocketOutputStream.java | 254 | ||||
-rw-r--r-- | runtime/IKVM.Runtime.8.csproj | 1 | ||||
-rw-r--r-- | runtime/openjdk/java.net.SocketInputStream.cs | 216 | ||||
-rw-r--r-- | runtime/runtime.build | 1 |
7 files changed, 220 insertions, 590 deletions
diff --git a/openjdk/FORKED b/openjdk/FORKED index f46f6c78..f5b8f344 100644 --- a/openjdk/FORKED +++ b/openjdk/FORKED @@ -40,8 +40,6 @@ jdk/src/share/classes/java/lang/String.java=java/lang/StringHelper.java jdk/src/share/classes/java/lang/System.java=java/lang/System.java jdk/src/share/classes/java/lang/Thread.java=java/lang/Thread.java jdk/src/share/classes/java/lang/Throwable.java=java/lang/ThrowableHelper.java -jdk/src/share/classes/java/net/SocketInputStream.java=java/net/SocketInputStream.java -jdk/src/share/classes/java/net/SocketOutputStream.java=java/net/SocketOutputStream.java jdk/src/share/classes/java/nio/Bits.java=java/nio/Bits.java jdk/src/share/classes/java/security/AccessController.java=java/security/AccessController.java jdk/src/share/classes/java/security/ProtectionDomain.java=java/security/ProtectionDomain.java diff --git a/openjdk/allsources.lst b/openjdk/allsources.lst index 7105481e..b566ebd7 100644 --- a/openjdk/allsources.lst +++ b/openjdk/allsources.lst @@ -113,8 +113,6 @@ java/net/DualStackPlainSocketImpl.java java/net/DualStackPlainSocketImpl_c.java java/net/net_util_md.java java/net/PlainSocketImpl.java -java/net/SocketInputStream.java -java/net/SocketOutputStream.java java/net/SocketUtil.java java/net/TwoStacksPlainDatagramSocketImpl.java java/net/TwoStacksPlainDatagramSocketImpl_c.java @@ -10371,8 +10369,10 @@ sun/security/jgss/wrapper/SunNativeProvider.java @OPENJDK@/jdk/src/share/classes/java/net/SocketException.java @OPENJDK@/jdk/src/share/classes/java/net/SocketImpl.java @OPENJDK@/jdk/src/share/classes/java/net/SocketImplFactory.java +@OPENJDK@/jdk/src/share/classes/java/net/SocketInputStream.java @OPENJDK@/jdk/src/share/classes/java/net/SocketOption.java @OPENJDK@/jdk/src/share/classes/java/net/SocketOptions.java +@OPENJDK@/jdk/src/share/classes/java/net/SocketOutputStream.java @OPENJDK@/jdk/src/share/classes/java/net/SocketPermission.java @OPENJDK@/jdk/src/share/classes/java/net/SocketSecrets.java @OPENJDK@/jdk/src/share/classes/java/net/SocketTimeoutException.java diff --git a/openjdk/java/net/SocketInputStream.java b/openjdk/java/net/SocketInputStream.java deleted file mode 100644 index 161947cc..00000000 --- a/openjdk/java/net/SocketInputStream.java +++ /dev/null @@ -1,332 +0,0 @@ -/* - * Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package java.net; - -import java.io.FileDescriptor; -import java.io.FileInputStream; -import java.io.IOException; -import java.nio.channels.FileChannel; -import static ikvm.internal.Winsock.*; -import static java.net.net_util_md.*; - -import sun.misc.IoTrace; -import sun.net.ConnectionResetException; - -/** - * This stream extends FileInputStream to implement a - * SocketInputStream. Note that this class should <b>NOT</b> be - * public. - * - * @author Jonathan Payne - * @author Arthur van Hoff - */ -class SocketInputStream extends FileInputStream -{ - - private boolean eof; - private AbstractPlainSocketImpl impl = null; - private byte temp[]; - private Socket socket = null; - - /** - * Creates a new SocketInputStream. Can only be called - * by a Socket. This method needs to hang on to the owner Socket so - * that the fd will not be closed. - * @param impl the implemented socket input stream - */ - SocketInputStream(AbstractPlainSocketImpl impl) throws IOException { - super(impl.getFileDescriptor()); - this.impl = impl; - socket = impl.getSocket(); - } - - /** - * Returns the unique {@link java.nio.channels.FileChannel FileChannel} - * object associated with this file input stream.</p> - * - * The <code>getChannel</code> method of <code>SocketInputStream</code> - * returns <code>null</code> since it is a socket based stream.</p> - * - * @return the file channel associated with this file input stream - * - * @since 1.4 - * @spec JSR-51 - */ - public final FileChannel getChannel() { - return null; - } - - /** - * Reads into an array of bytes at the specified offset using - * the received socket primitive. - * @param fd the FileDescriptor - * @param b the buffer into which the data is read - * @param off the start offset of the data - * @param len the maximum number of bytes read - * @param timeout the read timeout in ms - * @return the actual number of bytes read, -1 is - * returned when the end of the stream is reached. - * @exception IOException If an I/O error has occurred. - */ - private int socketRead0(FileDescriptor fdObj, byte bufP[], int off, int len, int timeout) throws IOException - { - // [IKVM] this method is a direct port of the native code in openjdk6-b18\jdk\src\windows\native\java\net\SocketInputStream.c - cli.System.Net.Sockets.Socket fd = null; - int nread; - - if (IS_NULL(fdObj)) { - throw new SocketException("socket closed"); - } - fd = fdObj.getSocket(); - if (fd == null) { - throw new SocketException("Socket closed"); - } - - if (timeout != 0) { - if (timeout <= 5000 || !isRcvTimeoutSupported) { - int ret = NET_Timeout (fd, timeout); - - if (ret <= 0) { - if (ret == 0) { - throw new SocketTimeoutException("Read timed out"); - } else { - // [IKVM] the OpenJDK native code is broken and always throws this exception on any failure of NET_Timeout - throw new SocketException("socket closed"); - } - } - - /*check if the socket has been closed while we were in timeout*/ - if (fdObj.getSocket() == null) { - throw new SocketException("Socket Closed"); - } - } - } - - nread = recv(fd, bufP, off, len, 0); - if (nread > 0) { - // ok - } else { - if (nread < 0) { - /* - * Recv failed. - */ - switch (WSAGetLastError()) { - case WSAEINTR: - throw new SocketException("socket closed"); - - case WSAECONNRESET: - case WSAESHUTDOWN: - /* - * Connection has been reset - Windows sometimes reports - * the reset as a shutdown error. - */ - throw new ConnectionResetException(); - - case WSAETIMEDOUT : - throw new SocketTimeoutException("Read timed out"); - - default: - throw NET_ThrowCurrent("recv failed"); - } - } - } - return nread; - } - - /** - * Reads into a byte array data from the socket. - * @param b the buffer into which the data is read - * @return the actual number of bytes read, -1 is - * returned when the end of the stream is reached. - * @exception IOException If an I/O error has occurred. - */ - public int read(byte b[]) throws IOException { - return read(b, 0, b.length); - } - - /** - * Reads into a byte array <i>b</i> at offset <i>off</i>, - * <i>length</i> bytes of data. - * @param b the buffer into which the data is read - * @param off the start offset of the data - * @param len the maximum number of bytes read - * @return the actual number of bytes read, -1 is - * returned when the end of the stream is reached. - * @exception IOException If an I/O error has occurred. - */ - public int read(byte b[], int off, int length) throws IOException { - return read(b, off, length, impl.getTimeout()); - } - - int read(byte b[], int off, int length, int timeout) throws IOException { - int n = 0; - - // EOF already encountered - if (eof) { - return -1; - } - - // connection reset - if (impl.isConnectionReset()) { - throw new SocketException("Connection reset"); - } - - // bounds check - if (length <= 0 || off < 0 || off + length > b.length) { - if (length == 0) { - return 0; - } - throw new ArrayIndexOutOfBoundsException(); - } - - boolean gotReset = false; - - Object traceContext = IoTrace.socketReadBegin(); - // acquire file descriptor and do the read - FileDescriptor fd = impl.acquireFD(); - try { - n = socketRead0(fd, b, off, length, timeout); - if (n > 0) { - return n; - } - } catch (ConnectionResetException rstExc) { - gotReset = true; - } finally { - impl.releaseFD(); - IoTrace.socketReadEnd(traceContext, impl.address, impl.port, - timeout, n > 0 ? n : 0); - } - - /* - * We receive a "connection reset" but there may be bytes still - * buffered on the socket - */ - if (gotReset) { - traceContext = IoTrace.socketReadBegin(); - impl.setConnectionResetPending(); - impl.acquireFD(); - try { - n = socketRead0(fd, b, off, length, timeout); - if (n > 0) { - return n; - } - } catch (ConnectionResetException rstExc) { - } finally { - impl.releaseFD(); - IoTrace.socketReadEnd(traceContext, impl.address, impl.port, - timeout, n > 0 ? n : 0); - } - } - - /* - * If we get here we are at EOF, the socket has been closed, - * or the connection has been reset. - */ - if (impl.isClosedOrPending()) { - throw new SocketException("Socket closed"); - } - if (impl.isConnectionResetPending()) { - impl.setConnectionReset(); - } - if (impl.isConnectionReset()) { - throw new SocketException("Connection reset"); - } - eof = true; - return -1; - } - - /** - * Reads a single byte from the socket. - */ - public int read() throws IOException { - if (eof) { - return -1; - } - temp = new byte[1]; - int n = read(temp, 0, 1); - if (n <= 0) { - return -1; - } - return temp[0] & 0xff; - } - - /** - * Skips n bytes of input. - * @param n the number of bytes to skip - * @return the actual number of bytes skipped. - * @exception IOException If an I/O error has occurred. - */ - public long skip(long numbytes) throws IOException { - if (numbytes <= 0) { - return 0; - } - long n = numbytes; - int buflen = (int) Math.min(1024, n); - byte data[] = new byte[buflen]; - while (n > 0) { - int r = read(data, 0, (int) Math.min((long) buflen, n)); - if (r < 0) { - break; - } - n -= r; - } - return numbytes - n; - } - - /** - * Returns the number of bytes that can be read without blocking. - * @return the number of immediately available bytes - */ - public int available() throws IOException { - return impl.available(); - } - - /** - * Closes the stream. - */ - private boolean closing = false; - public void close() throws IOException { - // Prevent recursion. See BugId 4484411 - if (closing) - return; - closing = true; - if (socket != null) { - if (!socket.isClosed()) - socket.close(); - } else - impl.close(); - closing = false; - } - - void setEOF(boolean eof) { - this.eof = eof; - } - - /** - * Overrides finalize, the fd is closed by the Socket. - */ - protected void finalize() {} -} diff --git a/openjdk/java/net/SocketOutputStream.java b/openjdk/java/net/SocketOutputStream.java deleted file mode 100644 index fd6e2c4f..00000000 --- a/openjdk/java/net/SocketOutputStream.java +++ /dev/null @@ -1,254 +0,0 @@ -/* - * Copyright (c) 1995, 2007, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package java.net; - -import java.io.FileDescriptor; -import java.io.FileOutputStream; -import java.io.IOException; -import java.nio.channels.FileChannel; -import static ikvm.internal.Winsock.*; -import static java.net.net_util_md.*; - -import sun.misc.IoTrace; - -/** - * This stream extends FileOutputStream to implement a - * SocketOutputStream. Note that this class should <b>NOT</b> be - * public. - * - * @author Jonathan Payne - * @author Arthur van Hoff - */ -class SocketOutputStream extends FileOutputStream -{ - private AbstractPlainSocketImpl impl = null; - private byte temp[] = new byte[1]; - private Socket socket = null; - - /** - * Creates a new SocketOutputStream. Can only be called - * by a Socket. This method needs to hang on to the owner Socket so - * that the fd will not be closed. - * @param impl the socket output stream inplemented - */ - SocketOutputStream(AbstractPlainSocketImpl impl) throws IOException { - super(impl.getFileDescriptor()); - this.impl = impl; - socket = impl.getSocket(); - } - - /** - * Returns the unique {@link java.nio.channels.FileChannel FileChannel} - * object associated with this file output stream. </p> - * - * The <code>getChannel</code> method of <code>SocketOutputStream</code> - * returns <code>null</code> since it is a socket based stream.</p> - * - * @return the file channel associated with this file output stream - * - * @since 1.4 - * @spec JSR-51 - */ - public final FileChannel getChannel() { - return null; - } - - /** - * Writes to the socket. - * @param fd the FileDescriptor - * @param b the data to be written - * @param off the start offset in the data - * @param len the number of bytes that are written - * @exception IOException If an I/O error has occurred. - */ - private void socketWrite0(FileDescriptor fdObj, byte[] data, int off, int len) throws IOException - { - // [IKVM] this method is a direct port of the native code in openjdk6-b18\jdk\src\windows\native\java\net\SocketOutputStream.c - final int MAX_BUFFER_LEN = 2048; - cli.System.Net.Sockets.Socket fd; - int buflen = 65536; // MAX_HEAP_BUFFER_LEN - int n; - - if (IS_NULL(fdObj)) { - throw new SocketException("socket closed"); - } else { - fd = fdObj.getSocket(); - } - if (IS_NULL(data)) { - throw new NullPointerException("data argument"); - } - - while(len > 0) { - int loff = 0; - int chunkLen = Math.min(buflen, len); - int llen = chunkLen; - int retry = 0; - - while(llen > 0) { - n = send(fd, data, off + loff, llen, 0); - if (n > 0) { - llen -= n; - loff += n; - continue; - } - - /* - * Due to a bug in Windows Sockets (observed on NT and Windows - * 2000) it may be necessary to retry the send. The issue is that - * on blocking sockets send/WSASend is supposed to block if there - * is insufficient buffer space available. If there are a large - * number of threads blocked on write due to congestion then it's - * possile to hit the NT/2000 bug whereby send returns WSAENOBUFS. - * The workaround we use is to retry the send. If we have a - * large buffer to send (>2k) then we retry with a maximum of - * 2k buffer. If we hit the issue with <=2k buffer then we backoff - * for 1 second and retry again. We repeat this up to a reasonable - * limit before bailing out and throwing an exception. In load - * conditions we've observed that the send will succeed after 2-3 - * attempts but this depends on network buffers associated with - * other sockets draining. - */ - if (WSAGetLastError() == WSAENOBUFS) { - if (llen > MAX_BUFFER_LEN) { - buflen = MAX_BUFFER_LEN; - chunkLen = MAX_BUFFER_LEN; - llen = MAX_BUFFER_LEN; - continue; - } - if (retry >= 30) { - throw new SocketException("No buffer space available - exhausted attempts to queue buffer"); - } - cli.System.Threading.Thread.Sleep(1000); - retry++; - continue; - } - - /* - * Send failed - can be caused by close or write error. - */ - if (WSAGetLastError() == WSAENOTSOCK) { - throw new SocketException("Socket closed"); - } else { - throw NET_ThrowCurrent("socket write error"); - } - } - len -= chunkLen; - off += chunkLen; - } - } - - /** - * Writes to the socket with appropriate locking of the - * FileDescriptor. - * @param b the data to be written - * @param off the start offset in the data - * @param len the number of bytes that are written - * @exception IOException If an I/O error has occurred. - */ - private void socketWrite(byte b[], int off, int len) throws IOException { - - if (len <= 0 || off < 0 || off + len > b.length) { - if (len == 0) { - return; - } - throw new ArrayIndexOutOfBoundsException(); - } - - Object traceContext = IoTrace.socketWriteBegin(); - int bytesWritten = 0; - FileDescriptor fd = impl.acquireFD(); - try { - socketWrite0(fd, b, off, len); - bytesWritten = len; - } catch (SocketException se) { - if (se instanceof sun.net.ConnectionResetException) { - impl.setConnectionResetPending(); - se = new SocketException("Connection reset"); - } - if (impl.isClosedOrPending()) { - throw new SocketException("Socket closed"); - } else { - throw se; - } - } finally { - impl.releaseFD(); - IoTrace.socketWriteEnd(traceContext, impl.address, impl.port, bytesWritten); - } - } - - /** - * Writes a byte to the socket. - * @param b the data to be written - * @exception IOException If an I/O error has occurred. - */ - public void write(int b) throws IOException { - temp[0] = (byte)b; - socketWrite(temp, 0, 1); - } - - /** - * Writes the contents of the buffer <i>b</i> to the socket. - * @param b the data to be written - * @exception SocketException If an I/O error has occurred. - */ - public void write(byte b[]) throws IOException { - socketWrite(b, 0, b.length); - } - - /** - * Writes <i>length</i> bytes from buffer <i>b</i> starting at - * offset <i>len</i>. - * @param b the data to be written - * @param off the start offset in the data - * @param len the number of bytes that are written - * @exception SocketException If an I/O error has occurred. - */ - public void write(byte b[], int off, int len) throws IOException { - socketWrite(b, off, len); - } - - /** - * Closes the stream. - */ - private boolean closing = false; - public void close() throws IOException { - // Prevent recursion. See BugId 4484411 - if (closing) - return; - closing = true; - if (socket != null) { - if (!socket.isClosed()) - socket.close(); - } else - impl.close(); - closing = false; - } - - /** - * Overrides finalize, the fd is closed by the Socket. - */ - protected void finalize() {} -} diff --git a/runtime/IKVM.Runtime.8.csproj b/runtime/IKVM.Runtime.8.csproj index 48c4c6cb..adee8e30 100644 --- a/runtime/IKVM.Runtime.8.csproj +++ b/runtime/IKVM.Runtime.8.csproj @@ -155,6 +155,7 @@ <Compile Include="openjdk\java.lang.invoke.cs" /> <Compile Include="openjdk\java.lang.reflect.cs" /> <Compile Include="openjdk\java.net.cs" /> + <Compile Include="openjdk\java.net.SocketInputStream.cs" /> <Compile Include="openjdk\java.nio.cs" /> <Compile Include="openjdk\java.security.cs" /> <Compile Include="openjdk\java.util.cs" /> diff --git a/runtime/openjdk/java.net.SocketInputStream.cs b/runtime/openjdk/java.net.SocketInputStream.cs new file mode 100644 index 00000000..800eb4f0 --- /dev/null +++ b/runtime/openjdk/java.net.SocketInputStream.cs @@ -0,0 +1,216 @@ +/* + * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +#if !FIRST_PASS +using Winsock = ikvm.@internal.Winsock; +using java.net; +#endif + +static class Java_java_net_SocketInputStream +{ + public static int socketRead0(object _this, java.io.FileDescriptor fd, byte[] b, int off, int len, int timeout) + { +#if FIRST_PASS + return 0; +#else + // [IKVM] this method is a direct port of the native code in openjdk6-b18\jdk\src\windows\native\java\net\SocketInputStream.c + System.Net.Sockets.Socket socket = null; + int nread; + + if (fd == null) + { + throw new SocketException("socket closed"); + } + socket = fd.getSocket(); + if (socket == null) + { + throw new SocketException("Socket closed"); + } + + if (timeout != 0) + { + if (timeout <= 5000 || !net_util_md.isRcvTimeoutSupported) + { + int ret = net_util_md.NET_Timeout(socket, timeout); + + if (ret <= 0) + { + if (ret == 0) + { + throw new SocketTimeoutException("Read timed out"); + } + else + { + // [IKVM] the OpenJDK native code is broken and always throws this exception on any failure of NET_Timeout + throw new SocketException("socket closed"); + } + } + + /*check if the socket has been closed while we were in timeout*/ + if (fd.getSocket() == null) + { + throw new SocketException("Socket Closed"); + } + } + } + + nread = Winsock.recv(socket, b, off, len, 0); + if (nread > 0) + { + // ok + } + else + { + if (nread < 0) + { + /* + * Recv failed. + */ + switch (Winsock.WSAGetLastError()) + { + case Winsock.WSAEINTR: + throw new SocketException("socket closed"); + + case Winsock.WSAECONNRESET: + case Winsock.WSAESHUTDOWN: + /* + * Connection has been reset - Windows sometimes reports + * the reset as a shutdown error. + */ + throw new sun.net.ConnectionResetException(); + + case Winsock.WSAETIMEDOUT: + throw new SocketTimeoutException("Read timed out"); + + default: + throw net_util_md.NET_ThrowCurrent("recv failed"); + } + } + } + return nread; +#endif + } + + public static void init() + { + } +} + +static class Java_java_net_SocketOutputStream +{ + public static void socketWrite0(object _this, java.io.FileDescriptor fd, byte[] data, int off, int len) + { +#if !FIRST_PASS + // [IKVM] this method is a direct port of the native code in openjdk6-b18\jdk\src\windows\native\java\net\SocketOutputStream.c + const int MAX_BUFFER_LEN = 2048; + System.Net.Sockets.Socket socket; + int buflen = 65536; // MAX_HEAP_BUFFER_LEN + int n; + + if (fd == null) + { + throw new SocketException("socket closed"); + } + else + { + socket = fd.getSocket(); + } + if (data == null) + { + throw new java.lang.NullPointerException("data argument"); + } + + while (len > 0) + { + int loff = 0; + int chunkLen = java.lang.Math.min(buflen, len); + int llen = chunkLen; + int retry = 0; + + while (llen > 0) + { + n = Winsock.send(socket, data, off + loff, llen, 0); + if (n > 0) + { + llen -= n; + loff += n; + continue; + } + + /* + * Due to a bug in Windows Sockets (observed on NT and Windows + * 2000) it may be necessary to retry the send. The issue is that + * on blocking sockets send/WSASend is supposed to block if there + * is insufficient buffer space available. If there are a large + * number of threads blocked on write due to congestion then it's + * possile to hit the NT/2000 bug whereby send returns WSAENOBUFS. + * The workaround we use is to retry the send. If we have a + * large buffer to send (>2k) then we retry with a maximum of + * 2k buffer. If we hit the issue with <=2k buffer then we backoff + * for 1 second and retry again. We repeat this up to a reasonable + * limit before bailing out and throwing an exception. In load + * conditions we've observed that the send will succeed after 2-3 + * attempts but this depends on network buffers associated with + * other sockets draining. + */ + if (Winsock.WSAGetLastError() == Winsock.WSAENOBUFS) + { + if (llen > MAX_BUFFER_LEN) + { + buflen = MAX_BUFFER_LEN; + chunkLen = MAX_BUFFER_LEN; + llen = MAX_BUFFER_LEN; + continue; + } + if (retry >= 30) + { + throw new SocketException("No buffer space available - exhausted attempts to queue buffer"); + } + System.Threading.Thread.Sleep(1000); + retry++; + continue; + } + + /* + * Send failed - can be caused by close or write error. + */ + if (Winsock.WSAGetLastError() == Winsock.WSAENOTSOCK) + { + throw new SocketException("Socket closed"); + } + else + { + throw net_util_md.NET_ThrowCurrent("socket write error"); + } + } + len -= chunkLen; + off += chunkLen; + } +#endif + } + + public static void init() + { + } +} diff --git a/runtime/runtime.build b/runtime/runtime.build index 6031b2a1..19efa747 100644 --- a/runtime/runtime.build +++ b/runtime/runtime.build @@ -190,6 +190,7 @@ <include name="openjdk/java.lang.invoke.cs" /> <include name="openjdk/java.lang.reflect.cs" /> <include name="openjdk/java.net.cs" /> + <include name="openjdk/java.net.SocketInputStream.cs" /> <include name="openjdk/java.nio.cs" /> <include name="openjdk/java.security.cs" /> <include name="openjdk/java.util.cs" /> |