# HG changeset patch # User Nikola Grcevski # Date 1611186467 28800 # Wed Jan 20 15:47:47 2021 -0800 # Node ID 845264e53a92af5143d6f2424580015c11e51733 # Parent 71ca53c6b04269a838aa2e3a9476c019109fbb90 8250521: Configure initial RTO to use minimal retry for loopback connections on Windows Reviewed-by: alanb diff --git a/src/java.base/windows/native/libnet/net_util_md.c b/src/java.base/windows/native/libnet/net_util_md.c --- a/src/java.base/windows/native/libnet/net_util_md.c +++ b/src/java.base/windows/native/libnet/net_util_md.c @@ -785,6 +785,57 @@ return result == SOCKET_ERROR ? WSAGetLastError() : 0; } +int +IsWindows10RS3OrGreater() { + OSVERSIONINFOEXW osvi = { sizeof(osvi), 0, 0, 0, 0, {0}, 0, 0 }; + DWORDLONG const cond_mask = VerSetConditionMask( + VerSetConditionMask( + VerSetConditionMask( + 0, VER_MAJORVERSION, VER_GREATER_EQUAL), + VER_MINORVERSION, VER_GREATER_EQUAL), + VER_BUILDNUMBER, VER_GREATER_EQUAL); + + osvi.dwMajorVersion = HIBYTE(_WIN32_WINNT_WIN10); + osvi.dwMinorVersion = LOBYTE(_WIN32_WINNT_WIN10); + osvi.dwBuildNumber = 16299; // RS3 (Redstone 3) + + return VerifyVersionInfoW(&osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_BUILDNUMBER, cond_mask) != 0; +} + +/** + * Shortens the default Windows socket + * connect timeout. Recommended for usage + * on the loopback adapter only. + */ +JNIEXPORT jint JNICALL +NET_EnableFastTcpLoopbackConnect(int fd) { + TCP_INITIAL_RTO_PARAMETERS rto = { + TCP_INITIAL_RTO_UNSPECIFIED_RTT, // Use the default or overriden by the Administrator + 1 // Minimum possible value before Windows 10 RS3 + }; + + /** + * In Windows 10 RS3+ we can use the no retransmissions flag to + * completely remove the timeout delay, which is fixed to 500ms + * if Windows receives RST when the destination port is not open. + */ + if (IsWindows10RS3OrGreater()) { + rto.MaxSynRetransmissions = TCP_INITIAL_RTO_NO_SYN_RETRANSMISSIONS; + } + + DWORD result_byte_count = -1; + int result = WSAIoctl(fd, // descriptor identifying a socket + SIO_TCP_INITIAL_RTO, // dwIoControlCode + &rto, // pointer to TCP_INITIAL_RTO_PARAMETERS structure + sizeof(rto), // size, in bytes, of the input buffer + NULL, // pointer to output buffer + 0, // size of output buffer + &result_byte_count, // number of bytes returned + NULL, // OVERLAPPED structure + NULL); // completion routine + return (result == SOCKET_ERROR) ? WSAGetLastError() : 0; +} + /** * See net_util.h for documentation */ diff --git a/src/java.base/windows/native/libnet/net_util_md.h b/src/java.base/windows/native/libnet/net_util_md.h --- a/src/java.base/windows/native/libnet/net_util_md.h +++ b/src/java.base/windows/native/libnet/net_util_md.h @@ -26,6 +26,7 @@ #include #include #include +#include /* used to disable connection reset messages on Windows XP */ #ifndef SIO_UDP_CONNRESET @@ -86,10 +87,29 @@ #define GET_PORT(X) ((X)->sa.sa_family == AF_INET ? (X)->sa4.sin_port : (X)->sa6.sin6_port) +/** + * With dual socket implementation the + * IPv4 addresseses might be mapped as IPv6. + * The IPv4 loopback adapter address will + * be mapped as the following IPv6 ::ffff:127.0.0.1. + * For example, this is done by NET_InetAddressToSockaddr. + */ +#define IN6_IS_ADDR_V4MAPPED_LOOPBACK(x) ( \ + (((x)->s6_words[0] == 0) && \ + ((x)->s6_words[1] == 0) && \ + ((x)->s6_words[2] == 0) && \ + ((x)->s6_words[3] == 0) && \ + ((x)->s6_words[4] == 0) && \ + ((x)->s6_words[5] == 0xFFFF) && \ + ((x)->s6_words[6] == 0x007F) && \ + ((x)->s6_words[7] == 0x0100)) \ +) + #define IS_LOOPBACK_ADDRESS(x) ( \ ((x)->sa.sa_family == AF_INET) ? \ (ntohl((x)->sa4.sin_addr.s_addr) == INADDR_LOOPBACK) : \ - (IN6ADDR_ISLOOPBACK(x)) \ + ((IN6_IS_ADDR_LOOPBACK(&(x)->sa6.sin6_addr)) || \ + (IN6_IS_ADDR_V4MAPPED_LOOPBACK(&(x)->sa6.sin6_addr))) \ ) JNIEXPORT int JNICALL NET_SocketClose(int fd); @@ -119,6 +139,8 @@ JNIEXPORT int JNICALL NET_WinBind(int s, SOCKETADDRESS *sa, int len, jboolean exclBind); +JNIEXPORT jint JNICALL NET_EnableFastTcpLoopbackConnect(int fd); + /* XP versions of the native routines */ JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByName0_XP diff --git a/src/java.base/windows/native/libnio/ch/Net.c b/src/java.base/windows/native/libnio/ch/Net.c --- a/src/java.base/windows/native/libnio/ch/Net.c +++ b/src/java.base/windows/native/libnio/ch/Net.c @@ -194,13 +194,25 @@ { SOCKETADDRESS sa; int rv; + int so_rv; int sa_len = 0; SOCKET s = (SOCKET)fdval(env, fdo); + int type = 0, optlen = sizeof(type); if (NET_InetAddressToSockaddr(env, iao, port, &sa, &sa_len, preferIPv6) != 0) { return IOS_THROWN; } + so_rv = getsockopt(s, SOL_SOCKET, SO_TYPE, (char*)&type, &optlen); + + /** + * Windows has a very long socket connect timeout of 2 seconds. + * If it's the loopback adapter we can shorten the wait interval. + */ + if (so_rv == 0 && type == SOCK_STREAM && IS_LOOPBACK_ADDRESS(&sa)) { + NET_EnableFastTcpLoopbackConnect((jint)s); + } + rv = connect(s, &sa.sa, sa_len); if (rv != 0) { int err = WSAGetLastError(); @@ -211,9 +223,7 @@ return IOS_THROWN; } else { /* Enable WSAECONNRESET errors when a UDP socket is connected */ - int type = 0, optlen = sizeof(type); - rv = getsockopt(s, SOL_SOCKET, SO_TYPE, (char*)&type, &optlen); - if (rv == 0 && type == SOCK_DGRAM) { + if (so_rv == 0 && type == SOCK_DGRAM) { setConnectionReset(s, TRUE); } } # HG changeset patch # User Mat Carter # Date 1611186526 28800 # Wed Jan 20 15:48:46 2021 -0800 # Node ID 4599d183e80bf7ee1894d83444a641653b2758e4 # Parent 845264e53a92af5143d6f2424580015c11e51733 8255264: Support for identifying the full range of IPv4 localhost addresses on Windows Reviewed-by: alanb diff --git a/src/java.base/windows/native/libnet/net_util_md.h b/src/java.base/windows/native/libnet/net_util_md.h --- a/src/java.base/windows/native/libnet/net_util_md.h +++ b/src/java.base/windows/native/libnet/net_util_md.h @@ -90,24 +90,30 @@ /** * With dual socket implementation the * IPv4 addresseses might be mapped as IPv6. - * The IPv4 loopback adapter address will - * be mapped as the following IPv6 ::ffff:127.0.0.1. + * The IPv4 loopback adapter address ranges (127.0.0.0 through 127.255.255.255) will + * be mapped as the following IPv6 ::ffff:127.0.0.0 through ::ffff:127.255.255.255. * For example, this is done by NET_InetAddressToSockaddr. */ #define IN6_IS_ADDR_V4MAPPED_LOOPBACK(x) ( \ - (((x)->s6_words[0] == 0) && \ - ((x)->s6_words[1] == 0) && \ - ((x)->s6_words[2] == 0) && \ - ((x)->s6_words[3] == 0) && \ - ((x)->s6_words[4] == 0) && \ - ((x)->s6_words[5] == 0xFFFF) && \ - ((x)->s6_words[6] == 0x007F) && \ - ((x)->s6_words[7] == 0x0100)) \ + (((x)->s6_words[0] == 0) && \ + ((x)->s6_words[1] == 0) && \ + ((x)->s6_words[2] == 0) && \ + ((x)->s6_words[3] == 0) && \ + ((x)->s6_words[4] == 0) && \ + ((x)->s6_words[5] == 0xFFFF) && \ + (((x)->s6_words[6] & 0x00FF) == 0x007F)) \ +) + +/** + * Check for IPv4 loopback adapter address ranges (127.0.0.0 through 127.255.255.255) + */ +#define IN4_IS_ADDR_NETLONG_LOOPBACK(l) ( \ + ((l & 0xFF000000) == 0x7F000000) \ ) #define IS_LOOPBACK_ADDRESS(x) ( \ ((x)->sa.sa_family == AF_INET) ? \ - (ntohl((x)->sa4.sin_addr.s_addr) == INADDR_LOOPBACK) : \ + (IN4_IS_ADDR_NETLONG_LOOPBACK(ntohl((x)->sa4.sin_addr.s_addr))) : \ ((IN6_IS_ADDR_LOOPBACK(&(x)->sa6.sin6_addr)) || \ (IN6_IS_ADDR_V4MAPPED_LOOPBACK(&(x)->sa6.sin6_addr))) \ ) # HG changeset patch # User macarter? # Date 1611358743 28800 # Fri Jan 22 15:39:03 2021 -0800 # Node ID caeb93f79ba604df2b5d4e8c5dc35215efb418dc # Parent 4599d183e80bf7ee1894d83444a641653b2758e4 8250521: Configure initial RTO to use minimal retry for loopback connections on Windows diff --git a/src/java.base/windows/native/libnet/PlainSocketImpl.c b/src/java.base/windows/native/libnet/PlainSocketImpl.c --- a/src/java.base/windows/native/libnet/PlainSocketImpl.c +++ b/src/java.base/windows/native/libnet/PlainSocketImpl.c @@ -118,6 +118,9 @@ (JNIEnv *env, jclass clazz, jint fd, jobject iaObj, jint port) { SOCKETADDRESS sa; int rv, sa_len = 0; + int so_rv; + SOCKET s = (SOCKET)fd; + int type = 0, optlen = sizeof(type); jboolean v4MappedAddress = ipv6_available() ? JNI_TRUE : JNI_FALSE; if (NET_InetAddressToSockaddr(env, iaObj, port, &sa, @@ -125,6 +128,16 @@ return -1; } + so_rv = getsockopt(s, SOL_SOCKET, SO_TYPE, (char*)&type, &optlen); + + /** + * Windows has a very long socket connect timeout of 2 seconds. + * If it's the loopback adapter we can shorten the wait interval. + */ + if (so_rv == 0 && type == SOCK_STREAM && IS_LOOPBACK_ADDRESS(&sa)) { + NET_EnableFastTcpLoopbackConnect(fd); + } + rv = connect(fd, &sa.sa, sa_len); if (rv == SOCKET_ERROR) { int err = WSAGetLastError();