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 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 }