Improve handling of async close during connect and other cleanups niosocketimpl-branch
authoralanb
Sat, 23 Mar 2019 15:11:51 +0000
branchniosocketimpl-branch
changeset 57281 c08d024d6bf9
parent 57280 a458758d1a63
child 57293 67c102efba4b
Improve handling of async close during connect and other cleanups
src/java.base/share/classes/sun/nio/ch/NioSocketImpl.java
src/java.base/share/classes/sun/nio/ch/SocketChannelImpl.java
test/jdk/java/net/Socket/AsyncShutdown.java
test/jdk/java/net/Socket/ConnectionReset.java
test/jdk/java/net/Socket/Timeouts.java
test/jdk/java/net/Socket/UdpSocket.java
test/jdk/java/net/SocketImpl/SocketImplCombinations.java
--- a/src/java.base/share/classes/sun/nio/ch/NioSocketImpl.java	Fri Mar 22 14:13:04 2019 +0000
+++ b/src/java.base/share/classes/sun/nio/ch/NioSocketImpl.java	Sat Mar 23 15:11:51 2019 +0000
@@ -522,37 +522,36 @@
     }
 
     /**
-     * Waits for a connection attempt to finish with a timeout.
+     * Waits for a connection attempt to finish with a timeout
      * @throws SocketTimeoutException if the connect timeout elapses
      */
-    private boolean timedFinishConnect(FileDescriptor fd, int millis) throws IOException {
+    private void timedFinishConnect(FileDescriptor fd, int millis) throws IOException {
         long nanos = NANOSECONDS.convert(millis, TimeUnit.MILLISECONDS);
         long remainingNanos = nanos;
         long startNanos = System.nanoTime();
-        boolean connected;
+        boolean polled;
         do {
             park(fd, Net.POLLOUT, remainingNanos);
-            connected = Net.pollConnectNow(fd);
-            if (!connected) {
+            polled = Net.pollConnectNow(fd);
+            if (!polled) {
                 remainingNanos = nanos - (System.nanoTime() - startNanos);
                 if (remainingNanos <= 0) {
                     throw new SocketTimeoutException("Connect timed out");
                 }
             }
-        } while (!connected && isOpen());
-        return connected;
+        } while (!polled && isOpen());
     }
 
     /**
      * Attempts to establish a connection to the given socket address with a
      * timeout. Closes the socket if connection cannot be established.
-     * @throws IllegalArgumentException if the address is not an InetSocketAddress
-     * @throws UnknownHostException if the InetSocketAddress is not resolved
-     * @throws IOException if the connection cannot be established
+     * @throws IOException if the address is not a resolved InetSocketAdress or
+     *         the connection cannot be established
      */
     private void implConnect(SocketAddress remote, int millis) throws IOException {
+        // SocketImpl connect only specifies IOException
         if (!(remote instanceof InetSocketAddress))
-            throw new IllegalArgumentException("Unsupported address type");
+            throw new IOException("Unsupported address type");
         InetSocketAddress isa = (InetSocketAddress) remote;
         if (isa.isUnresolved()) {
             throw new UnknownHostException(isa.getHostName());
@@ -572,18 +571,24 @@
                 try {
                     configureNonBlockingIfNeeded(fd, millis);
                     int n = Net.connect(fd, address, port);
-                    if (n > 0 && isOpen()) {
-                        connected = true;
-                    } else if (IOStatus.okayToRetry(n) && isOpen()) {
-                        if (millis > 0) {
-                            // finish connect with timeout
-                            connected = timedFinishConnect(fd, millis);
-                        } else {
-                            // finish connect, no timeout
-                            do {
-                                park(fd, Net.POLLOUT);
-                                connected = Net.pollConnectNow(fd);
-                            } while (!connected && isOpen());
+                    if (isOpen()) {
+                        if (n > 0) {
+                            // connection established
+                            connected = true;
+                        } else if (IOStatus.okayToRetry(n)) {
+                            // not established or interrupted
+                            if (millis > 0) {
+                                // finish connect with timeout
+                                timedFinishConnect(fd, millis);
+                            } else {
+                                // finish connect, no timeout
+                                boolean polled;
+                                do {
+                                    park(fd, Net.POLLOUT);
+                                    polled = Net.pollConnectNow(fd);
+                                } while (!polled && isOpen());
+                            }
+                            connected = isOpen();
                         }
                     }
                 } finally {
@@ -886,18 +891,39 @@
             Thread.currentThread().interrupt();
     }
 
+    // the socket options supported by client and server sockets
+    private static volatile Set<SocketOption<?>> clientSocketOptions;
+    private static volatile Set<SocketOption<?>> serverSocketOptions;
+
     @Override
     protected Set<SocketOption<?>> supportedOptions() {
-        Set<SocketOption<?>> options = new HashSet<>();
-        options.addAll(super.supportedOptions());
-        if (server) {
-            options.addAll(ExtendedSocketOptions.serverSocketOptions());
-        } else {
-            options.addAll(ExtendedSocketOptions.clientSocketOptions());
+        Set<SocketOption<?>> options = (server) ? serverSocketOptions : clientSocketOptions;
+        if (options == null) {
+            options = new HashSet<>();
+            options.add(StandardSocketOptions.SO_RCVBUF);
+            options.add(StandardSocketOptions.SO_REUSEADDR);
+            if (server) {
+                // IP_TOS added for server socket to maintain compatibility
+                options.add(StandardSocketOptions.IP_TOS);
+                options.addAll(ExtendedSocketOptions.serverSocketOptions());
+            } else {
+                options.add(StandardSocketOptions.IP_TOS);
+                options.add(StandardSocketOptions.SO_KEEPALIVE);
+                options.add(StandardSocketOptions.SO_SNDBUF);
+                options.add(StandardSocketOptions.SO_LINGER);
+                options.add(StandardSocketOptions.TCP_NODELAY);
+                options.addAll(ExtendedSocketOptions.clientSocketOptions());
+            }
+            if (Net.isReusePortAvailable())
+                options.add(StandardSocketOptions.SO_REUSEPORT);
+            options = Collections.unmodifiableSet(options);
+            if (server) {
+                serverSocketOptions = options;
+            } else {
+                clientSocketOptions = options;
+            }
         }
-        if (Net.isReusePortAvailable())
-            options.add(StandardSocketOptions.SO_REUSEPORT);
-        return Collections.unmodifiableSet(options);
+        return options;
     }
 
     @Override
--- a/src/java.base/share/classes/sun/nio/ch/SocketChannelImpl.java	Fri Mar 22 14:13:04 2019 +0000
+++ b/src/java.base/share/classes/sun/nio/ch/SocketChannelImpl.java	Sat Mar 23 15:11:51 2019 +0000
@@ -792,13 +792,15 @@
                     boolean connected = false;
                     try {
                         beginFinishConnect(blocking);
+                        boolean polled;
                         if (blocking) {
                             do {
-                                connected = Net.pollConnect(fd, -1);
-                            } while (!connected && isOpen());
+                                polled = Net.pollConnect(fd, -1);
+                            } while (!polled && isOpen());
                         } else {
-                            connected = Net.pollConnect(fd, 0);
+                            polled = Net.pollConnect(fd, 0);
                         }
+                        connected = polled && isOpen();
                     } finally {
                         endFinishConnect(blocking, connected);
                     }
--- a/test/jdk/java/net/Socket/AsyncShutdown.java	Fri Mar 22 14:13:04 2019 +0000
+++ b/test/jdk/java/net/Socket/AsyncShutdown.java	Sat Mar 23 15:11:51 2019 +0000
@@ -25,7 +25,6 @@
  * @test
  * @requires (os.family == "linux" | os.family == "mac")
  * @run testng AsyncShutdown
- * @run testng/othervm -Djdk.net.usePlainSocketImpl AsyncShutdown
  * @summary Test shutdownInput/shutdownOutput with threads blocked in read/write
  */
 
--- a/test/jdk/java/net/Socket/ConnectionReset.java	Fri Mar 22 14:13:04 2019 +0000
+++ b/test/jdk/java/net/Socket/ConnectionReset.java	Sat Mar 23 15:11:51 2019 +0000
@@ -25,7 +25,6 @@
  * @test
  * @requires os.family != "solaris"
  * @run testng ConnectionReset
- * @run testng/othervm -Djdk.net.usePlainSocketImpl ConnectionReset
  * @summary Test behavior of read and available when a connection is reset
  */
 
--- a/test/jdk/java/net/Socket/Timeouts.java	Fri Mar 22 14:13:04 2019 +0000
+++ b/test/jdk/java/net/Socket/Timeouts.java	Sat Mar 23 15:11:51 2019 +0000
@@ -26,7 +26,6 @@
  * @library /test/lib
  * @build jdk.test.lib.Utils
  * @run testng Timeouts
- * @run testng/othervm -Djdk.net.usePlainSocketImpl Timeouts
  * @summary Test Socket timeouts
  */
 
--- a/test/jdk/java/net/Socket/UdpSocket.java	Fri Mar 22 14:13:04 2019 +0000
+++ b/test/jdk/java/net/Socket/UdpSocket.java	Sat Mar 23 15:11:51 2019 +0000
@@ -24,7 +24,6 @@
 /**
  * @test
  * @run main UdpSocket
- * @run main/othervm -Djdk.net.usePlainSocketImpl UdpSocket
  * @summary Basic test for a Socket to a UDP socket
  */
 
--- a/test/jdk/java/net/SocketImpl/SocketImplCombinations.java	Fri Mar 22 14:13:04 2019 +0000
+++ b/test/jdk/java/net/SocketImpl/SocketImplCombinations.java	Sat Mar 23 15:11:51 2019 +0000
@@ -26,7 +26,6 @@
  * @bug 8220493
  * @modules java.base/java.net:+open java.base/sun.nio.ch:+open
  * @run testng/othervm SocketImplCombinations
- * @run testng/othervm -Djdk.net.usePlainSocketImpl SocketImplCombinations
  * @summary Test Socket and ServerSocket with combinations of SocketImpls
  */
 
@@ -383,7 +382,7 @@
             expectThrows(IOException.class, ss::accept);
         }
     }
-    
+
     public void testServerSocketAccept5b() throws IOException {
         var socket = new Socket((SocketImpl) null) { };
         assertTrue(getSocketImpl(socket) == null);