8145635: Add TCP_QUICKACK socket option
authorvtewari
Mon, 13 Nov 2017 14:03:36 +0530
changeset 47733 fbfe06b70e16
parent 47732 259dffd8dabc
child 47734 d0c784151182
child 47742 28096878fae5
child 47745 e6e6ed17abbe
8145635: Add TCP_QUICKACK socket option Reviewed-by: chegar, rriggs, clanger
make/lib/Lib-jdk.net.gmk
make/mapfiles/libextnet/mapfile-linux
make/mapfiles/libextnet/mapfile-solaris
make/mapfiles/libextnet/mapfile-vers
src/java.base/unix/classes/java/net/PlainDatagramSocketImpl.java
src/jdk.net/linux/classes/jdk/net/LinuxSocketOptions.java
src/jdk.net/linux/native/libextnet/LinuxSocketOptions.c
src/jdk.net/share/classes/jdk/net/ExtendedSocketOptions.java
src/jdk.net/share/classes/jdk/net/Sockets.java
test/jdk/jdk/net/Sockets/QuickAckTest.java
--- a/make/lib/Lib-jdk.net.gmk	Fri Nov 10 03:27:43 2017 +0000
+++ b/make/lib/Lib-jdk.net.gmk	Mon Nov 13 14:03:36 2017 +0530
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2016, 2017, 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
@@ -35,7 +35,7 @@
       SRC := $(TOPDIR)/src/jdk.net/solaris/native/libextnet, \
       OPTIMIZATION := LOW, \
       CFLAGS := $(CFLAGS_JDKLIB) -I$(SUPPORT_OUTPUTDIR)/headers/jdk.net, \
-      MAPFILE := $(TOPDIR)/make/mapfiles/libextnet/mapfile-vers, \
+      MAPFILE := $(TOPDIR)/make/mapfiles/libextnet/mapfile-solaris, \
       LDFLAGS := $(LDFLAGS_JDKLIB) \
           $(call SET_SHARED_LIBRARY_ORIGIN), \
       LIBS := -lsocket -lc -ljava, \
@@ -48,4 +48,25 @@
 endif
 
 
+ifeq ($(OPENJDK_TARGET_OS), linux)
+
+  $(eval $(call SetupNativeCompilation, BUILD_LIBEXTNET, \
+      LIBRARY := extnet, \
+      OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \
+      SRC := $(TOPDIR)/src/jdk.net/linux/native/libextnet, \
+      OPTIMIZATION := LOW, \
+      CFLAGS := $(CFLAGS_JDKLIB) -I$(SUPPORT_OUTPUTDIR)/headers/jdk.net, \
+      MAPFILE := $(TOPDIR)/make/mapfiles/libextnet/mapfile-linux, \
+      LDFLAGS := $(LDFLAGS_JDKLIB) \
+          $(call SET_SHARED_LIBRARY_ORIGIN), \
+      LIBS := -ljvm -ljava -lc, \
+      OBJECT_DIR := $(SUPPORT_OUTPUTDIR)/native/$(MODULE)/libextnet, \
+  ))
+
+  $(BUILD_LIBEXTNET): $(call FindLib, java.base, java)
+
+  TARGETS += $(BUILD_LIBEXTNET)
+endif
+
+
 ################################################################################
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/make/mapfiles/libextnet/mapfile-linux	Mon Nov 13 14:03:36 2017 +0530
@@ -0,0 +1,33 @@
+#
+# Copyright (c) 2017, 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.
+#
+
+SUNWprivate_1.1 {
+	global:
+    	Java_jdk_net_LinuxSocketOptions_setQuickAck0;
+    	Java_jdk_net_LinuxSocketOptions_getQuickAck0;
+    	Java_jdk_net_LinuxSocketOptions_quickAckSupported0;
+	local:
+	    *;
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/make/mapfiles/libextnet/mapfile-solaris	Mon Nov 13 14:03:36 2017 +0530
@@ -0,0 +1,34 @@
+#
+# Copyright (c) 2017, 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.
+#
+
+SUNWprivate_1.1 {
+	global:
+	    Java_jdk_net_SolarisSocketOptions_init;
+	    Java_jdk_net_SolarisSocketOptions_setFlowOption;
+	    Java_jdk_net_SolarisSocketOptions_getFlowOption;
+	    Java_jdk_net_SolarisSocketOptions_flowSupported;
+	local:
+	    *;
+};
--- a/make/mapfiles/libextnet/mapfile-vers	Fri Nov 10 03:27:43 2017 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,34 +0,0 @@
-#
-# Copyright (c) 2016, 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.
-#
-
-SUNWprivate_1.1 {
-	global:
-	    Java_jdk_net_SolarisSocketOptions_init;
-	    Java_jdk_net_SolarisSocketOptions_setFlowOption;
-	    Java_jdk_net_SolarisSocketOptions_getFlowOption;
-	    Java_jdk_net_SolarisSocketOptions_flowSupported;
-	local:
-	    *;
-};
--- a/src/java.base/unix/classes/java/net/PlainDatagramSocketImpl.java	Fri Nov 10 03:27:43 2017 +0000
+++ b/src/java.base/unix/classes/java/net/PlainDatagramSocketImpl.java	Mon Nov 13 14:03:36 2017 +0530
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2017, 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
@@ -85,10 +85,18 @@
 
     protected Set<SocketOption<?>> supportedOptions() {
         HashSet<SocketOption<?>> options = new HashSet<>(super.supportedOptions());
-        options.addAll(extendedOptions.options());
+        addExtSocketOptions(extendedOptions.options(), options);
         return options;
     }
 
+    private void addExtSocketOptions(Set<SocketOption<?>> extOptions,
+                                     Set<SocketOption<?>> options) {
+        // TCP_QUICKACK is applicable for TCP Sockets only.
+        extOptions.stream()
+                .filter((option) -> !option.name().equals("TCP_QUICKACK"))
+                .forEach((option) -> options.add(option));
+    }
+
     protected void socketSetOption(int opt, Object val) throws SocketException {
         if (opt == SocketOptions.SO_REUSEPORT &&
             !supportedOptions().contains(StandardSocketOptions.SO_REUSEPORT)) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.net/linux/classes/jdk/net/LinuxSocketOptions.java	Mon Nov 13 14:03:36 2017 +0530
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2017, 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 jdk.net;
+
+import java.net.SocketException;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import jdk.net.ExtendedSocketOptions.PlatformSocketOptions;
+
+class LinuxSocketOptions extends PlatformSocketOptions {
+
+    public LinuxSocketOptions() {
+    }
+
+    @Override
+    void setQuickAck(int fd, boolean on) throws SocketException {
+        setQuickAck0(fd, on);
+    }
+
+    @Override
+    boolean getQuickAck(int fd) throws SocketException {
+        return getQuickAck0(fd);
+    }
+
+    @Override
+    public boolean quickAckSupported() {
+        return quickAckSupported0();
+    }
+
+    native static private void setQuickAck0(int fd, boolean on) throws SocketException;
+
+    native static private boolean getQuickAck0(int fd) throws SocketException;
+
+    native static private boolean quickAckSupported0();
+
+    static {
+        AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
+            System.loadLibrary("extnet");
+            return null;
+        });
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.net/linux/native/libextnet/LinuxSocketOptions.c	Mon Nov 13 14:03:36 2017 +0530
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2017, 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.
+ */
+#include <sys/socket.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include <jni.h>
+#include <netinet/tcp.h>
+#include "jni_util.h"
+
+/*
+ * Class:     jdk_net_LinuxSocketOptions
+ * Method:    setQuickAck
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL Java_jdk_net_LinuxSocketOptions_setQuickAck0
+(JNIEnv *env, jobject unused, jint fd, jboolean on) {
+    int optval;
+    int rv;
+    optval = (on ? 1 : 0);
+    rv = setsockopt(fd, SOL_SOCKET, TCP_QUICKACK, &optval, sizeof (optval));
+    if (rv < 0) {
+        if (errno == ENOPROTOOPT) {
+            JNU_ThrowByName(env, "java/lang/UnsupportedOperationException",
+                            "unsupported socket option");
+        } else {
+            JNU_ThrowByNameWithLastError(env, "java/net/SocketException",
+                                        "set option TCP_QUICKACK failed");
+        }
+    }
+}
+
+/*
+ * Class:     jdk_net_LinuxSocketOptions
+ * Method:    getQuickAck
+ * Signature: (I)Z;
+ */
+JNIEXPORT jboolean JNICALL Java_jdk_net_LinuxSocketOptions_getQuickAck0
+(JNIEnv *env, jobject unused, jint fd) {
+    int on;
+    socklen_t sz = sizeof (on);
+    int rv = getsockopt(fd, SOL_SOCKET, TCP_QUICKACK, &on, &sz);
+    if (rv < 0) {
+        if (errno == ENOPROTOOPT) {
+            JNU_ThrowByName(env, "java/lang/UnsupportedOperationException",
+                            "unsupported socket option");
+        } else {
+            JNU_ThrowByNameWithLastError(env, "java/net/SocketException",
+                                        "get option TCP_QUICKACK failed");
+        }
+    }
+    return on != 0;
+}
+
+/*
+ * Class:     jdk_net_LinuxSocketOptions
+ * Method:    quickAckSupported
+ * Signature: ()Z
+ */
+JNIEXPORT jboolean JNICALL Java_jdk_net_LinuxSocketOptions_quickAckSupported0
+(JNIEnv *env, jobject unused) {
+    int one = 1;
+    int rv, s;
+    s = socket(PF_INET, SOCK_STREAM, 0);
+    if (s < 0) {
+        return JNI_FALSE;
+    }
+    rv = setsockopt(s, SOL_SOCKET, TCP_QUICKACK, (void *) &one, sizeof (one));
+    if (rv != 0 && errno == ENOPROTOOPT) {
+        rv = JNI_FALSE;
+    } else {
+        rv = JNI_TRUE;
+    }
+    close(s);
+    return rv;
+}
--- a/src/jdk.net/share/classes/jdk/net/ExtendedSocketOptions.java	Fri Nov 10 03:27:43 2017 +0000
+++ b/src/jdk.net/share/classes/jdk/net/ExtendedSocketOptions.java	Mon Nov 13 14:03:36 2017 +0530
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, 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
@@ -67,20 +67,53 @@
     public static final SocketOption<SocketFlow> SO_FLOW_SLA = new
         ExtSocketOption<SocketFlow>("SO_FLOW_SLA", SocketFlow.class);
 
+    /**
+     * Disable Delayed Acknowledgements.
+     *
+     * <p>
+     * This socket option can be used to reduce or disable delayed
+     * acknowledgments (ACKs). When {@code TCP_QUICKACK} is enabled, ACKs are
+     * sent immediately, rather than delayed if needed in accordance to normal
+     * TCP operation. This option is not permanent, it only enables a switch to
+     * or from {@code TCP_QUICKACK} mode. Subsequent operations of the TCP
+     * protocol will once again disable/enable {@code TCP_QUICKACK} mode
+     * depending on internal protocol processing and factors such as delayed ACK
+     * timeouts occurring and data transfer, therefore this option needs to be
+     * set with {@code setOption} after each operation of TCP on a given socket.
+     *
+     * <p>
+     * The value of this socket option is a {@code Boolean} that represents
+     * whether the option is enabled or disabled. The socket option is specific
+     * to stream-oriented sockets using the TCP/IP protocol. The exact semantics
+     * of this socket option are socket type and system dependent.
+     *
+     * @since 10
+     */
+    public static final SocketOption<Boolean> TCP_QUICKACK =
+            new ExtSocketOption<Boolean>("TCP_QUICKACK", Boolean.class);
 
     private static final PlatformSocketOptions platformSocketOptions =
             PlatformSocketOptions.get();
 
     private static final boolean flowSupported =
             platformSocketOptions.flowSupported();
+    private static final boolean quickAckSupported =
+            platformSocketOptions.quickAckSupported();
 
     private static final Set<SocketOption<?>> extendedOptions = options();
 
     static Set<SocketOption<?>> options() {
-        if (flowSupported)
-            return Set.of(SO_FLOW_SLA);
-        else
+        if (flowSupported) {
+            if (quickAckSupported) {
+                return Set.of(SO_FLOW_SLA, TCP_QUICKACK);
+            } else {
+                return Set.of(SO_FLOW_SLA);
+            }
+        } else if (quickAckSupported) {
+            return Set.of(TCP_QUICKACK);
+        } else {
             return Collections.<SocketOption<?>>emptySet();
+        }
     }
 
     static {
@@ -105,6 +138,8 @@
                     assert flowSupported;
                     SocketFlow flow = checkValueType(value, option.type());
                     setFlowOption(fd, flow);
+                } else if (option == TCP_QUICKACK) {
+                    setQuickAckOption(fd, (boolean) value);
                 } else {
                     throw new InternalError("Unexpected option " + option);
                 }
@@ -127,6 +162,8 @@
                     SocketFlow flow = SocketFlow.create();
                     getFlowOption(fd, flow);
                     return flow;
+                } else if (option == TCP_QUICKACK) {
+                    return getQuickAckOption(fd);
                 } else {
                     throw new InternalError("Unexpected option " + option);
                 }
@@ -156,12 +193,21 @@
     }
 
     private static void getFlowOption(FileDescriptor fd, SocketFlow f)
-        throws SocketException
-    {
+            throws SocketException {
         int status = platformSocketOptions.getFlowOption(fdAccess.get(fd), f);
         f.status(status);  // augment the given flow with the status
     }
 
+    private static void setQuickAckOption(FileDescriptor fd, boolean enable)
+            throws SocketException {
+        platformSocketOptions.setQuickAck(fdAccess.get(fd), enable);
+    }
+
+    private static Object getQuickAckOption(FileDescriptor fd)
+            throws SocketException {
+        return platformSocketOptions.getQuickAck(fdAccess.get(fd));
+    }
+
     static class PlatformSocketOptions {
 
         protected PlatformSocketOptions() {}
@@ -184,9 +230,13 @@
                             return System.getProperty("os.name");
                         }
                     });
-            if ("SunOS".equals(osname))
+            if ("SunOS".equals(osname)) {
                 return newInstance("jdk.net.SolarisSocketOptions");
-            return new PlatformSocketOptions();
+            } else if ("Linux".equals(osname)) {
+                return newInstance("jdk.net.LinuxSocketOptions");
+            } else {
+                return new PlatformSocketOptions();
+            }
         }
 
         private static final PlatformSocketOptions instance = create();
@@ -208,5 +258,17 @@
         boolean flowSupported() {
             return false;
         }
+
+        void setQuickAck(int fd, boolean on) throws SocketException {
+            throw new UnsupportedOperationException("unsupported TCP_QUICKACK option");
+        }
+
+        boolean getQuickAck(int fd) throws SocketException {
+            throw new UnsupportedOperationException("unsupported TCP_QUICKACK option");
+        }
+
+        boolean quickAckSupported() {
+            return false;
+        }
     }
 }
--- a/src/jdk.net/share/classes/jdk/net/Sockets.java	Fri Nov 10 03:27:43 2017 +0000
+++ b/src/jdk.net/share/classes/jdk/net/Sockets.java	Mon Nov 13 14:03:36 2017 +0530
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, 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
@@ -279,6 +279,9 @@
         if (flowsupported) {
             set.add(ExtendedSocketOptions.SO_FLOW_SLA);
         }
+        if (QuickAck.available) {
+            set.add(ExtendedSocketOptions.TCP_QUICKACK);
+        }
         set = Collections.unmodifiableSet(set);
         options.put(Socket.class, set);
 
@@ -290,6 +293,9 @@
         if (reuseportsupported) {
             set.add(StandardSocketOptions.SO_REUSEPORT);
         }
+        if (QuickAck.available) {
+            set.add(ExtendedSocketOptions.TCP_QUICKACK);
+        }
         set.add(StandardSocketOptions.IP_TOS);
         set = Collections.unmodifiableSet(set);
         options.put(ServerSocket.class, set);
@@ -331,4 +337,17 @@
 
         return Collections.unmodifiableMap(options);
     }
+
+    /**
+     * Tells whether TCP_QUICKACK is supported.
+     */
+    static class QuickAck {
+
+        static final boolean available;
+
+        static {
+            Set<SocketOption<?>> s = new Socket().supportedOptions();
+            available = s.contains(ExtendedSocketOptions.TCP_QUICKACK);
+        }
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/net/Sockets/QuickAckTest.java	Mon Nov 13 14:03:36 2017 +0530
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2017, 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.
+ *
+ * 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.
+ */
+
+ /*
+ * @test
+ * @bug 8145635
+ * @summary Add TCP_QUICKACK socket option
+ * @modules jdk.net
+ * @run main QuickAckTest
+ */
+import java.io.IOException;
+import java.net.DatagramSocket;
+import java.net.MulticastSocket;
+import java.net.ServerSocket;
+import java.net.Socket;
+import jdk.net.ExtendedSocketOptions;
+import jdk.net.Sockets;
+
+public class QuickAckTest {
+
+    private static final String LOCAL_HOST = "127.0.0.1";
+
+    public static void main(String args[]) throws IOException {
+
+        try (ServerSocket ss = new ServerSocket(0);
+                Socket s = new Socket(LOCAL_HOST, ss.getLocalPort());
+                DatagramSocket ds = new DatagramSocket(0);
+                MulticastSocket mc = new MulticastSocket(0)) {
+
+            if (ss.supportedOptions().contains(ExtendedSocketOptions.TCP_QUICKACK)) {
+                Sockets.setOption(ss, ExtendedSocketOptions.TCP_QUICKACK, true);
+                if (!ss.getOption(ExtendedSocketOptions.TCP_QUICKACK)) {
+                    throw new RuntimeException("Test failed, TCP_QUICKACK should"
+                            + " have been set");
+                }
+            }
+            if (s.supportedOptions().contains(ExtendedSocketOptions.TCP_QUICKACK)) {
+                Sockets.setOption(s, ExtendedSocketOptions.TCP_QUICKACK, true);
+                if (!s.getOption(ExtendedSocketOptions.TCP_QUICKACK)) {
+                    throw new RuntimeException("Test failed, TCP_QUICKACK should"
+                            + " have been set");
+                }
+            }
+            if (ds.supportedOptions().contains(ExtendedSocketOptions.TCP_QUICKACK)) {
+                throw new RuntimeException("Test failed, TCP_QUICKACK is applicable"
+                        + " for TCP Sockets only.");
+            }
+            if (mc.supportedOptions().contains(ExtendedSocketOptions.TCP_QUICKACK)) {
+                throw new RuntimeException("Test failed, TCP_QUICKACK is applicable"
+                        + " for TCP Sockets only");
+            }
+        }
+    }
+}