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
	}