More cleanup of connection reset niosocketimpl-branch
authoralanb
Wed, 20 Mar 2019 13:54:50 +0000
branchniosocketimpl-branch
changeset 57274 07b6be5d9150
parent 57270 3519688a4e4d
child 57275 222fa5ed1c91
More cleanup of connection reset
src/java.base/share/classes/java/net/ServerSocket.java
src/java.base/share/classes/java/net/Socket.java
src/java.base/share/classes/sun/nio/ch/Net.java
src/java.base/share/classes/sun/nio/ch/NioSocketImpl.java
src/java.base/share/classes/sun/nio/ch/SocketAdaptor.java
src/java.base/share/classes/sun/nio/ch/SocketChannelImpl.java
src/java.base/unix/classes/sun/nio/ch/SocketDispatcher.java
src/java.base/unix/native/libnio/ch/Net.c
src/java.base/windows/classes/sun/nio/ch/SocketDispatcher.java
src/java.base/windows/native/libnio/ch/Net.c
src/java.base/windows/native/libnio/ch/SocketDispatcher.c
src/jdk.sctp/unix/classes/sun/nio/ch/sctp/SctpChannelImpl.java
--- a/src/java.base/share/classes/java/net/ServerSocket.java	Mon Mar 18 19:59:05 2019 +0000
+++ b/src/java.base/share/classes/java/net/ServerSocket.java	Wed Mar 20 13:54:50 2019 +0000
@@ -758,7 +758,7 @@
         if (isClosed())
             throw new SocketException("Socket is closed");
         if (timeout < 0)
-            throw new IllegalArgumentException("timeout can't be negative");
+            throw new IllegalArgumentException("timeout < 0");
         getImpl().setOption(SocketOptions.SO_TIMEOUT, timeout);
     }
 
--- a/src/java.base/share/classes/java/net/Socket.java	Mon Mar 18 19:59:05 2019 +0000
+++ b/src/java.base/share/classes/java/net/Socket.java	Wed Mar 20 13:54:50 2019 +0000
@@ -1221,7 +1221,7 @@
         if (isClosed())
             throw new SocketException("Socket is closed");
         if (timeout < 0)
-          throw new IllegalArgumentException("timeout can't be negative");
+          throw new IllegalArgumentException("timeout < 0");
 
         getImpl().setOption(SocketOptions.SO_TIMEOUT, timeout);
     }
--- a/src/java.base/share/classes/sun/nio/ch/Net.java	Mon Mar 18 19:59:05 2019 +0000
+++ b/src/java.base/share/classes/sun/nio/ch/Net.java	Wed Mar 20 13:54:50 2019 +0000
@@ -535,9 +535,18 @@
                                              int level, int opt, int arg, boolean isIPv6)
         throws IOException;
 
+    /**
+     * Polls a file descriptor for events.
+     * @param timeout the timeout to wait; 0 to not wait, -1 to wait indefinitely
+     * @return the polled events or 0 if no events are polled
+     */
     static native int poll(FileDescriptor fd, int events, long timeout)
         throws IOException;
 
+    /**
+     * Performs a non-blocking poll of a file descriptor.
+     * @return the polled events or 0 if no events are polled
+     */
     static int pollNow(FileDescriptor fd, int events) throws IOException {
         return poll(fd, events, 0);
     }
@@ -548,12 +557,18 @@
      * @apiNote This method is public to allow it be used by code in jdk.sctp.
      *
      * @param timeout the timeout to wait; 0 to not wait, -1 to wait indefinitely
-     * @return 1 if connected, 0 if not connected, or IOS_INTERRUPTED
+     * @return true if connected
      */
-    public static native int pollConnect(FileDescriptor fd, long timeout)
+    public static native boolean pollConnect(FileDescriptor fd, long timeout)
         throws IOException;
 
-    static int pollConnectNow(FileDescriptor fd) throws IOException {
+    /**
+     * Performs a non-blocking poll of a connecting socket to test if the
+     * connection has been established.
+     *
+     * @return true if connected
+     */
+    static boolean pollConnectNow(FileDescriptor fd) throws IOException {
         return pollConnect(fd, 0);
     }
 
--- a/src/java.base/share/classes/sun/nio/ch/NioSocketImpl.java	Mon Mar 18 19:59:05 2019 +0000
+++ b/src/java.base/share/classes/sun/nio/ch/NioSocketImpl.java	Wed Mar 20 13:54:50 2019 +0000
@@ -525,22 +525,22 @@
      * Waits for a connection attempt to finish with a timeout.
      * @throws SocketTimeoutException if the connect timeout elapses
      */
-    private int timedFinishConnect(FileDescriptor fd, int millis) throws IOException {
+    private boolean timedFinishConnect(FileDescriptor fd, int millis) throws IOException {
         long nanos = NANOSECONDS.convert(millis, TimeUnit.MILLISECONDS);
         long remainingNanos = nanos;
         long startNanos = System.nanoTime();
-        int n;
+        boolean connected;
         do {
             park(fd, Net.POLLOUT, remainingNanos);
-            n = Net.pollConnectNow(fd);
-            if (n == 0) {
+            connected = Net.pollConnectNow(fd);
+            if (!connected) {
                 remainingNanos = nanos - (System.nanoTime() - startNanos);
                 if (remainingNanos <= 0) {
                     throw new SocketTimeoutException("Connect timed out");
                 }
             }
-        } while (n == 0 && isOpen());
-        return n;
+        } while (!connected && isOpen());
+        return connected;
     }
 
     /**
@@ -572,19 +572,20 @@
                 try {
                     configureNonBlockingIfNeeded(fd, millis);
                     int n = Net.connect(fd, address, port);
-                    if (IOStatus.okayToRetry(n) && isOpen()) {
+                    if (n > 0 && isOpen()) {
+                        connected = true;
+                    } else if (IOStatus.okayToRetry(n) && isOpen()) {
                         if (millis > 0) {
                             // finish connect with timeout
-                            n = timedFinishConnect(fd, millis);
+                            connected = timedFinishConnect(fd, millis);
                         } else {
                             // finish connect, no timeout
                             do {
                                 park(fd, Net.POLLOUT);
-                                n = Net.pollConnectNow(fd);
-                            } while (n == 0 && isOpen());
+                                connected = Net.pollConnectNow(fd);
+                            } while (!connected && isOpen());
                         }
                     }
-                    connected = (n > 0) && isOpen();
                 } finally {
                     endConnect(connected);
                 }
@@ -813,16 +814,13 @@
 
     @Override
     protected int available() throws IOException {
-        readLock.lock();
-        try {
+        synchronized (stateLock) {
             ensureOpenAndConnected();
             if (isInputClosed) {
                 return 0;
             } else {
                 return Net.available(fd);
             }
-        } finally {
-            readLock.unlock();
         }
     }
 
--- a/src/java.base/share/classes/sun/nio/ch/SocketAdaptor.java	Mon Mar 18 19:59:05 2019 +0000
+++ b/src/java.base/share/classes/sun/nio/ch/SocketAdaptor.java	Wed Mar 20 13:54:50 2019 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2019, 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
@@ -216,6 +216,11 @@
                 }
             }
         }
+
+        @Override
+        public int available() throws IOException {
+            return sc.available();
+        }
     }
 
     private InputStream socketInputStream = null;
--- a/src/java.base/share/classes/sun/nio/ch/SocketChannelImpl.java	Mon Mar 18 19:59:05 2019 +0000
+++ b/src/java.base/share/classes/sun/nio/ch/SocketChannelImpl.java	Wed Mar 20 13:54:50 2019 +0000
@@ -32,6 +32,7 @@
 import java.net.ProtocolFamily;
 import java.net.Socket;
 import java.net.SocketAddress;
+import java.net.SocketException;
 import java.net.SocketOption;
 import java.net.StandardProtocolFamily;
 import java.net.StandardSocketOptions;
@@ -86,6 +87,9 @@
     private volatile boolean isInputClosed;
     private volatile boolean isOutputClosed;
 
+    // Connection reset protected by readLock
+    private boolean connectionReset;
+
     // -- The following fields are protected by stateLock
 
     // set true when exclusive binding is on and SO_REUSEADDR is emulated
@@ -231,7 +235,7 @@
             }
 
             // no options that require special handling
-            Net.setSocketOption(fd, Net.UNSPEC, name, value);
+            Net.setSocketOption(fd, name, value);
             return this;
         }
     }
@@ -261,7 +265,7 @@
             }
 
             // no options that require special handling
-            return (T) Net.getSocketOption(fd, Net.UNSPEC, name);
+            return (T) Net.getSocketOption(fd, name);
         }
     }
 
@@ -335,6 +339,10 @@
         }
     }
 
+    private void throwConnectionReset() throws SocketException {
+        throw new SocketException("Connection reset");
+    }
+
     @Override
     public int read(ByteBuffer buf) throws IOException {
         Objects.requireNonNull(buf);
@@ -346,6 +354,10 @@
             try {
                 beginRead(blocking);
 
+                // check if connection has been reset
+                if (connectionReset)
+                    throwConnectionReset();
+
                 // check if input is shutdown
                 if (isInputClosed)
                     return IOStatus.EOF;
@@ -358,7 +370,8 @@
                     n = IOUtil.read(fd, buf, -1, nd);
                 }
             } catch (ConnectionResetException e) {
-                throw new IOException(e.getMessage());
+                connectionReset = true;
+                throwConnectionReset();
             } finally {
                 endRead(blocking, n > 0);
                 if (n <= 0 && isInputClosed)
@@ -383,6 +396,10 @@
             try {
                 beginRead(blocking);
 
+                // check if connection has been reset
+                if (connectionReset)
+                    throwConnectionReset();
+
                 // check if input is shutdown
                 if (isInputClosed)
                     return IOStatus.EOF;
@@ -395,7 +412,8 @@
                     n = IOUtil.read(fd, dsts, offset, length, nd);
                 }
             } catch (ConnectionResetException e) {
-                throw new IOException(e.getMessage());
+                connectionReset = true;
+                throwConnectionReset();
             } finally {
                 endRead(blocking, n > 0);
                 if (n <= 0 && isInputClosed)
@@ -774,15 +792,13 @@
                     boolean connected = false;
                     try {
                         beginFinishConnect(blocking);
-                        int n = 0;
                         if (blocking) {
                             do {
-                                n = Net.pollConnect(fd, -1);
-                            } while ((n == 0 || n == IOStatus.INTERRUPTED) && isOpen());
+                                connected = Net.pollConnect(fd, -1);
+                            } while (!connected && isOpen());
                         } else {
-                            n = Net.pollConnect(fd, 0);
+                            connected = Net.pollConnect(fd, 0);
                         }
-                        connected = (n > 0);
                     } finally {
                         endFinishConnect(blocking, connected);
                     }
@@ -1012,6 +1028,20 @@
     }
 
     /**
+     * Return the number of bytes in the socket input buffer.
+     */
+    int available() throws IOException {
+        synchronized (stateLock) {
+            ensureOpenAndConnected();
+            if (isInputClosed) {
+                return 0;
+            } else {
+                return Net.available(fd);
+            }
+        }
+    }
+
+    /**
      * Translates native poll revent ops into a ready operation ops
      */
     public boolean translateReadyOps(int ops, int initialOps, SelectionKeyImpl ski) {
--- a/src/java.base/unix/classes/sun/nio/ch/SocketDispatcher.java	Mon Mar 18 19:59:05 2019 +0000
+++ b/src/java.base/unix/classes/sun/nio/ch/SocketDispatcher.java	Wed Mar 20 13:54:50 2019 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2019, 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
--- a/src/java.base/unix/native/libnio/ch/Net.c	Mon Mar 18 19:59:05 2019 +0000
+++ b/src/java.base/unix/native/libnio/ch/Net.c	Wed Mar 20 13:54:50 2019 +0000
@@ -804,7 +804,7 @@
     }
 }
 
-JNIEXPORT jint JNICALL
+JNIEXPORT jboolean JNICALL
 Java_sun_nio_ch_Net_pollConnect(JNIEnv *env, jobject this, jobject fdo, jlong timeout)
 {
     jint fd = fdval(env, fdo);
@@ -835,16 +835,12 @@
             return handleSocketError(env, ENOTCONN);
         }
         // connected
-        return 1;
-    } else if (result == 0) {
-        return 0;
+        return JNI_TRUE;
+    } else if (result == 0 || errno == EINTR) {
+        return JNI_FALSE;
     } else {
-        if (errno == EINTR) {
-            return IOS_INTERRUPTED;
-        } else {
-            JNU_ThrowIOExceptionWithLastError(env, "poll failed");
-            return IOS_THROWN;
-        }
+        JNU_ThrowIOExceptionWithLastError(env, "poll failed");
+        return JNI_FALSE;
     }
 }
 
--- a/src/java.base/windows/classes/sun/nio/ch/SocketDispatcher.java	Mon Mar 18 19:59:05 2019 +0000
+++ b/src/java.base/windows/classes/sun/nio/ch/SocketDispatcher.java	Wed Mar 20 13:54:50 2019 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2019, 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
@@ -25,7 +25,8 @@
 
 package sun.nio.ch;
 
-import java.io.*;
+import java.io.FileDescriptor;
+import java.io.IOException;
 
 /**
  * Allows different platforms to call different native methods
--- a/src/java.base/windows/native/libnio/ch/Net.c	Mon Mar 18 19:59:05 2019 +0000
+++ b/src/java.base/windows/native/libnio/ch/Net.c	Wed Mar 20 13:54:50 2019 +0000
@@ -660,7 +660,7 @@
     return rv;
 }
 
-JNIEXPORT jint JNICALL
+JNIEXPORT jboolean JNICALL
 Java_sun_nio_ch_Net_pollConnect(JNIEnv* env, jclass this, jobject fdo, jlong timeout)
 {
     int optError = 0;
@@ -684,13 +684,13 @@
 
     if (result == SOCKET_ERROR) {
         handleSocketError(env, WSAGetLastError());
-        return IOS_THROWN;
+        return JNI_FALSE;
     } else if (result == 0) {
-        return 0;
+        return JNI_FALSE;
     } else {
         // connection established if writable and no error to check
         if (FD_ISSET(fd, &wr) && !FD_ISSET(fd, &ex)) {
-            return 1;
+            return JNI_TRUE;
         }
         result = getsockopt((SOCKET)fd,
                             SOL_SOCKET,
@@ -699,17 +699,13 @@
                             &n);
         if (result == SOCKET_ERROR) {
             int lastError = WSAGetLastError();
-            if (lastError == WSAEINPROGRESS) {
-                return IOS_UNAVAILABLE;
+            if (lastError != WSAEINPROGRESS) {
+                NET_ThrowNew(env, lastError, "getsockopt");
             }
-            NET_ThrowNew(env, lastError, "getsockopt");
-            return IOS_THROWN;
+        } else if (optError != NO_ERROR) {
+            handleSocketError(env, optError);
         }
-        if (optError != NO_ERROR) {
-            handleSocketError(env, optError);
-            return IOS_THROWN;
-        }
-        return 0;
+        return JNI_FALSE;
     }
 }
 
--- a/src/java.base/windows/native/libnio/ch/SocketDispatcher.c	Mon Mar 18 19:59:05 2019 +0000
+++ b/src/java.base/windows/native/libnio/ch/SocketDispatcher.c	Wed Mar 20 13:54:50 2019 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2019, 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
@@ -73,7 +73,7 @@
             return IOS_UNAVAILABLE;
         }
         if (theErr == WSAECONNRESET) {
-            JNU_ThrowIOException(env, "Connection reset by peer");
+            JNU_ThrowByName(env, "sun/net/ConnectionResetException", "Connection reset");
         } else {
             JNU_ThrowIOExceptionWithLastError(env, "Read failed");
         }
@@ -133,7 +133,7 @@
             return IOS_UNAVAILABLE;
         }
         if (theErr == WSAECONNRESET) {
-            JNU_ThrowIOException(env, "Connection reset by peer");
+            JNU_ThrowByName(env, "sun/net/ConnectionResetException", "Connection reset");
         } else {
             JNU_ThrowIOExceptionWithLastError(env, "Vector read failed");
         }
--- a/src/jdk.sctp/unix/classes/sun/nio/ch/sctp/SctpChannelImpl.java	Mon Mar 18 19:59:05 2019 +0000
+++ b/src/jdk.sctp/unix/classes/sun/nio/ch/sctp/SctpChannelImpl.java	Wed Mar 20 13:54:50 2019 +0000
@@ -465,7 +465,7 @@
                     if (state != ChannelState.PENDING)
                         throw new NoConnectionPendingException();
                 }
-                int n = 0;
+                boolean connected = false;
                 try {
                     try {
                         begin();
@@ -477,26 +477,11 @@
                                 receiverThread = NativeThread.current();
                             }
                             if (!isBlocking()) {
-                                for (;;) {
-                                    n = Net.pollConnect(fd, 0);
-                                    if (  (n == IOStatus.INTERRUPTED)
-                                          && isOpen())
-                                        continue;
-                                    break;
-                                }
+                                connected = Net.pollConnect(fd, 0);
                             } else {
-                                for (;;) {
-                                    n = Net.pollConnect(fd, -1);
-                                    if (n == 0) {
-                                        // Loop in case of
-                                        // spurious notifications
-                                        continue;
-                                    }
-                                    if (  (n == IOStatus.INTERRUPTED)
-                                          && isOpen())
-                                        continue;
-                                    break;
-                                }
+                                do {
+                                    connected = Net.pollConnect(fd, -1);
+                                } while (!connected && isOpen());
                             }
                         }
                     } finally {
@@ -504,16 +489,10 @@
                             receiverThread = 0;
                             if (state == ChannelState.KILLPENDING) {
                                 kill();
-                                /* poll()/getsockopt() does not report
-                                 * error (throws exception, with n = 0)
-                                 * on Linux platform after dup2 and
-                                 * signal-wakeup. Force n to 0 so the
-                                 * end() can throw appropriate exception */
-                                n = 0;
+                                connected = false;
                             }
                         }
-                        end((n > 0) || (n == IOStatus.UNAVAILABLE));
-                        assert IOStatus.check(n);
+                        end(connected);
                     }
                 } catch (IOException x) {
                     /* If an exception was thrown, close the channel after
@@ -523,7 +502,7 @@
                     throw x;
                 }
 
-                if (n > 0) {
+                if (connected) {
                     synchronized (stateLock) {
                         state = ChannelState.CONNECTED;
                         if (!isBound()) {