8060170: Support SIO_LOOPBACK_FAST_PATH option on Windows
authoralanb
Sun, 19 Oct 2014 11:52:53 +0100
changeset 27178 885f4428b501
parent 27177 3717db2c3bfe
child 27179 eb37413280cb
8060170: Support SIO_LOOPBACK_FAST_PATH option on Windows Reviewed-by: alanb Contributed-by: kirk.shoop@microsoft.com, v-valkop@microsoft.com
jdk/make/mapfiles/libnet/mapfile-vers
jdk/src/java.base/share/classes/sun/nio/ch/Net.java
jdk/src/java.base/share/native/libnet/net_util.h
jdk/src/java.base/unix/native/libnet/net_util_md.c
jdk/src/java.base/unix/native/libnio/ch/Net.c
jdk/src/java.base/windows/native/libnet/net_util_md.c
jdk/src/java.base/windows/native/libnio/ch/Net.c
jdk/test/java/nio/channels/AsynchronousSocketChannel/StressLoopback.java
--- a/jdk/make/mapfiles/libnet/mapfile-vers	Fri Oct 17 10:59:32 2014 +0100
+++ b/jdk/make/mapfiles/libnet/mapfile-vers	Sun Oct 19 11:52:53 2014 +0100
@@ -110,6 +110,8 @@
 		NET_Bind;
 		NET_MapSocketOption;
 		NET_Wait;
+		NET_EnableFastTcpLoopback;
+		NET_ThrowNew;
                 ipv6_available;
                 initInetAddressIDs;
 
--- a/jdk/src/java.base/share/classes/sun/nio/ch/Net.java	Fri Oct 17 10:59:32 2014 +0100
+++ b/jdk/src/java.base/share/classes/sun/nio/ch/Net.java	Sun Oct 19 11:52:53 2014 +0100
@@ -50,30 +50,8 @@
     // set to true if exclusive binding is on for Windows
     private static final boolean exclusiveBind;
 
-    static {
-        int availLevel = isExclusiveBindAvailable();
-        if (availLevel >= 0) {
-            String exclBindProp =
-                java.security.AccessController.doPrivileged(
-                    new PrivilegedAction<String>() {
-                        @Override
-                        public String run() {
-                            return System.getProperty(
-                                    "sun.net.useExclusiveBind");
-                        }
-                    });
-            if (exclBindProp != null) {
-                exclusiveBind = exclBindProp.length() == 0 ?
-                        true : Boolean.parseBoolean(exclBindProp);
-            } else if (availLevel == 1) {
-                exclusiveBind = true;
-            } else {
-                exclusiveBind = false;
-            }
-        } else {
-            exclusiveBind = false;
-        }
-    }
+    // set to true if the fast tcp loopback should be enabled on Windows
+    private static final boolean fastLoopback;
 
     // -- Miscellaneous utilities --
 
@@ -391,6 +369,23 @@
         }
     }
 
+    public static boolean isFastTcpLoopbackRequested() {
+        String loopbackProp = java.security.AccessController.doPrivileged(
+            new PrivilegedAction<String>() {
+                @Override
+                public String run() {
+                    return System.getProperty("jdk.net.useFastTcpLoopback");
+                }
+            });
+        boolean enable;
+        if ("".equals(loopbackProp)) {
+            enable = true;
+        } else {
+            enable = Boolean.parseBoolean(loopbackProp);
+        }
+        return enable;
+    }
+
     // -- Socket operations --
 
     private static native boolean isIPv6Available0();
@@ -413,15 +408,16 @@
         throws IOException {
         boolean preferIPv6 = isIPv6Available() &&
             (family != StandardProtocolFamily.INET);
-        return IOUtil.newFD(socket0(preferIPv6, stream, false));
+        return IOUtil.newFD(socket0(preferIPv6, stream, false, fastLoopback));
     }
 
     static FileDescriptor serverSocket(boolean stream) {
-        return IOUtil.newFD(socket0(isIPv6Available(), stream, true));
+        return IOUtil.newFD(socket0(isIPv6Available(), stream, true, fastLoopback));
     }
 
     // Due to oddities SO_REUSEADDR on windows reuse is ignored
-    private static native int socket0(boolean preferIPv6, boolean stream, boolean reuse);
+    private static native int socket0(boolean preferIPv6, boolean stream, boolean reuse,
+                                      boolean fastLoopback);
 
     public static void bind(FileDescriptor fd, InetAddress addr, int port)
         throws IOException
@@ -634,4 +630,30 @@
         POLLCONN   = pollconnValue();
     }
 
+    static {
+        int availLevel = isExclusiveBindAvailable();
+        if (availLevel >= 0) {
+            String exclBindProp =
+                java.security.AccessController.doPrivileged(
+                    new PrivilegedAction<String>() {
+                        @Override
+                        public String run() {
+                            return System.getProperty(
+                                    "sun.net.useExclusiveBind");
+                        }
+                    });
+            if (exclBindProp != null) {
+                exclusiveBind = exclBindProp.length() == 0 ?
+                        true : Boolean.parseBoolean(exclBindProp);
+            } else if (availLevel == 1) {
+                exclusiveBind = true;
+            } else {
+                exclusiveBind = false;
+            }
+        } else {
+            exclusiveBind = false;
+        }
+
+        fastLoopback = isFastTcpLoopbackRequested();
+    }
 }
--- a/jdk/src/java.base/share/native/libnet/net_util.h	Fri Oct 17 10:59:32 2014 +0100
+++ b/jdk/src/java.base/share/native/libnet/net_util.h	Sun Oct 19 11:52:53 2014 +0100
@@ -184,9 +184,13 @@
 JNIEXPORT int JNICALL
 NET_MapSocketOptionV6(jint cmd, int *level, int *optname);
 
+JNIEXPORT jint JNICALL
+NET_EnableFastTcpLoopback(int fd);
+
 int getScopeID (struct sockaddr *);
 
 int cmpScopeID (unsigned int, struct sockaddr *);
 
 unsigned short in_cksum(unsigned short *addr, int len);
+
 #endif /* NET_UTILS_H */
--- a/jdk/src/java.base/unix/native/libnet/net_util_md.c	Fri Oct 17 10:59:32 2014 +0100
+++ b/jdk/src/java.base/unix/native/libnet/net_util_md.c	Sun Oct 19 11:52:53 2014 +0100
@@ -790,6 +790,11 @@
 #endif
 }
 
+JNIEXPORT jint JNICALL
+NET_EnableFastTcpLoopback(int fd) {
+    return 0;
+}
+
 /* In the case of an IPv4 Inetaddress this method will return an
  * IPv4 mapped address where IPv6 is available and v4MappedAddress is TRUE.
  * Otherwise it will return a sockaddr_in structure for an IPv4 InetAddress.
--- a/jdk/src/java.base/unix/native/libnio/ch/Net.c	Fri Oct 17 10:59:32 2014 +0100
+++ b/jdk/src/java.base/unix/native/libnio/ch/Net.c	Sun Oct 19 11:52:53 2014 +0100
@@ -188,7 +188,7 @@
 
 JNIEXPORT int JNICALL
 Java_sun_nio_ch_Net_socket0(JNIEnv *env, jclass cl, jboolean preferIPv6,
-                            jboolean stream, jboolean reuse)
+                            jboolean stream, jboolean reuse, jboolean ignored)
 {
     int fd;
     int type = (stream ? SOCK_STREAM : SOCK_DGRAM);
--- a/jdk/src/java.base/windows/native/libnet/net_util_md.c	Fri Oct 17 10:59:32 2014 +0100
+++ b/jdk/src/java.base/windows/native/libnet/net_util_md.c	Sun Oct 19 11:52:53 2014 +0100
@@ -29,6 +29,9 @@
 #include "net_util.h"
 #include "jni.h"
 
+// Taken from mstcpip.h in Windows SDK 8.0 or newer.
+#define SIO_LOOPBACK_FAST_PATH              _WSAIOW(IOC_VENDOR,16)
+
 #ifndef IPTOS_TOS_MASK
 #define IPTOS_TOS_MASK 0x1e
 #endif
@@ -844,6 +847,25 @@
     }
 }
 
+/**
+ * Enables SIO_LOOPBACK_FAST_PATH
+ */
+JNIEXPORT jint JNICALL
+NET_EnableFastTcpLoopback(int fd) {
+    int enabled = 1;
+    DWORD result_byte_count = -1;
+    int result = WSAIoctl(fd,
+                          SIO_LOOPBACK_FAST_PATH,
+                          &enabled,
+                          sizeof(enabled),
+                          NULL,
+                          0,
+                          &result_byte_count,
+                          NULL,
+                          NULL);
+    return result == SOCKET_ERROR ? WSAGetLastError() : 0;
+}
+
 /* If address types is IPv6, then IPv6 must be available. Otherwise
  * no address can be generated. In the case of an IPv4 Inetaddress this
  * method will return an IPv4 mapped address where IPv6 is available and
--- a/jdk/src/java.base/windows/native/libnio/ch/Net.c	Fri Oct 17 10:59:32 2014 +0100
+++ b/jdk/src/java.base/windows/native/libnio/ch/Net.c	Sun Oct 19 11:52:53 2014 +0100
@@ -127,7 +127,7 @@
 
 JNIEXPORT jint JNICALL
 Java_sun_nio_ch_Net_socket0(JNIEnv *env, jclass cl, jboolean preferIPv6,
-                            jboolean stream, jboolean reuse)
+                            jboolean stream, jboolean reuse, jboolean fastLoopback)
 {
     SOCKET s;
     int domain = (preferIPv6) ? AF_INET6 : AF_INET;
@@ -152,6 +152,20 @@
         NET_ThrowNew(env, WSAGetLastError(), "socket");
     }
 
+    if (stream && fastLoopback) {
+        static int loopback_available = 1;
+        if (loopback_available) {
+            int rv = NET_EnableFastTcpLoopback((jint)s);
+            if (rv) {
+                if (rv == WSAEOPNOTSUPP) {
+                    loopback_available = 0;
+                } else {
+                    NET_ThrowNew(env, rv, "fastLoopback");
+                }
+            }
+        }
+    }
+
     return (jint)s;
 }
 
--- a/jdk/test/java/nio/channels/AsynchronousSocketChannel/StressLoopback.java	Fri Oct 17 10:59:32 2014 +0100
+++ b/jdk/test/java/nio/channels/AsynchronousSocketChannel/StressLoopback.java	Sun Oct 19 11:52:53 2014 +0100
@@ -24,6 +24,8 @@
 /* @test
  * @bug 6834246 6842687
  * @summary Stress test connections through the loopback interface
+ * @run main StressLoopback
+ * @run main/othervm -Djdk.net.useFastTcpLoopback StressLoopback
  */
 
 import java.nio.ByteBuffer;