8221252: (sc) SocketChannel and its socket adaptor need to handle connection reset
authoralanb
Fri, 22 Mar 2019 11:35:35 +0000
changeset 54246 f04e3492fd88
parent 54245 96c45aa61056
child 54247 3e7fccdb6181
child 57278 bf925a3ee68a
8221252: (sc) SocketChannel and its socket adaptor need to handle connection reset Reviewed-by: bpb
src/java.base/share/classes/sun/nio/ch/IOStatus.java
src/java.base/share/classes/sun/nio/ch/Net.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/classes/sun/nio/ch/UnixAsynchronousSocketChannelImpl.java
src/java.base/unix/native/libnio/ch/Net.c
src/java.base/unix/native/libnio/ch/SocketDispatcher.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
test/jdk/java/nio/channels/SocketChannel/ConnectionReset.java
--- a/src/java.base/share/classes/sun/nio/ch/IOStatus.java	Fri Mar 22 13:42:45 2019 +0530
+++ b/src/java.base/share/classes/sun/nio/ch/IOStatus.java	Fri Mar 22 11:35:35 2019 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 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
@@ -81,4 +81,12 @@
         return ((n > EOF) || (n < UNSUPPORTED_CASE));
     }
 
+    /**
+     * Returns true if the error code is UNAVAILABLE or INTERRUPTED, the
+     * error codes to indicate that an I/O operation can be retried.
+     */
+    static boolean okayToRetry(long n) {
+        return (n == IOStatus.UNAVAILABLE) || (n == IOStatus.INTERRUPTED);
+    }
+
 }
--- a/src/java.base/share/classes/sun/nio/ch/Net.java	Fri Mar 22 13:42:45 2019 +0530
+++ b/src/java.base/share/classes/sun/nio/ch/Net.java	Fri Mar 22 11:35:35 2019 +0000
@@ -310,6 +310,12 @@
     static final ExtendedSocketOptions extendedOptions =
             ExtendedSocketOptions.getInstance();
 
+    static void setSocketOption(FileDescriptor fd, SocketOption<?> name, Object value)
+        throws IOException
+    {
+        setSocketOption(fd, Net.UNSPEC, name, value);
+    }
+
     static void setSocketOption(FileDescriptor fd, ProtocolFamily family,
                                 SocketOption<?> name, Object value)
         throws IOException
@@ -372,8 +378,13 @@
         setIntOption0(fd, mayNeedConversion, key.level(), key.name(), arg, isIPv6);
     }
 
-    static Object getSocketOption(FileDescriptor fd, ProtocolFamily family,
-                                  SocketOption<?> name)
+    static Object getSocketOption(FileDescriptor fd, SocketOption<?> name)
+        throws IOException
+    {
+        return getSocketOption(fd, Net.UNSPEC, name);
+    }
+
+    static Object getSocketOption(FileDescriptor fd, ProtocolFamily family, SocketOption<?> name)
         throws IOException
     {
         Class<?> type = name.type();
@@ -426,8 +437,7 @@
         return socket(UNSPEC, stream);
     }
 
-    static FileDescriptor socket(ProtocolFamily family, boolean stream)
-        throws IOException {
+    static FileDescriptor socket(ProtocolFamily family, boolean stream) throws IOException {
         boolean preferIPv6 = isIPv6Available() &&
             (family != StandardProtocolFamily.INET);
         return IOUtil.newFD(socket0(preferIPv6, stream, false, fastLoopback));
@@ -525,21 +535,44 @@
                                              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);
+    }
+
+    /**
      * Polls a connecting socket to test if the connection has been established.
      *
      * @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;
 
     /**
+     * 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);
+    }
+
+    /**
      * Return the number of bytes in the socket input buffer.
      */
     static native int available(FileDescriptor fd) throws IOException;
--- a/src/java.base/share/classes/sun/nio/ch/SocketAdaptor.java	Fri Mar 22 13:42:45 2019 +0530
+++ b/src/java.base/share/classes/sun/nio/ch/SocketAdaptor.java	Fri Mar 22 11:35:35 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	Fri Mar 22 13:42:45 2019 +0530
+++ b/src/java.base/share/classes/sun/nio/ch/SocketChannelImpl.java	Fri Mar 22 11:35:35 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;
@@ -52,6 +53,7 @@
 import java.util.Set;
 import java.util.concurrent.locks.ReentrantLock;
 
+import sun.net.ConnectionResetException;
 import sun.net.NetHooks;
 import sun.net.ext.ExtendedSocketOptions;
 import sun.net.util.SocketExceptions;
@@ -85,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
@@ -230,7 +235,7 @@
             }
 
             // no options that require special handling
-            Net.setSocketOption(fd, Net.UNSPEC, name, value);
+            Net.setSocketOption(fd, name, value);
             return this;
         }
     }
@@ -260,7 +265,7 @@
             }
 
             // no options that require special handling
-            return (T) Net.getSocketOption(fd, Net.UNSPEC, name);
+            return (T) Net.getSocketOption(fd, name);
         }
     }
 
@@ -334,6 +339,10 @@
         }
     }
 
+    private void throwConnectionReset() throws SocketException {
+        throw new SocketException("Connection reset");
+    }
+
     @Override
     public int read(ByteBuffer buf) throws IOException {
         Objects.requireNonNull(buf);
@@ -345,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;
@@ -356,6 +369,9 @@
                 } else {
                     n = IOUtil.read(fd, buf, -1, nd);
                 }
+            } catch (ConnectionResetException e) {
+                connectionReset = true;
+                throwConnectionReset();
             } finally {
                 endRead(blocking, n > 0);
                 if (n <= 0 && isInputClosed)
@@ -380,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;
@@ -391,6 +411,9 @@
                 } else {
                     n = IOUtil.read(fd, dsts, offset, length, nd);
                 }
+            } catch (ConnectionResetException e) {
+                connectionReset = true;
+                throwConnectionReset();
             } finally {
                 endRead(blocking, n > 0);
                 if (n <= 0 && isInputClosed)
@@ -769,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);
                     }
@@ -1007,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	Fri Mar 22 13:42:45 2019 +0530
+++ b/src/java.base/unix/classes/sun/nio/ch/SocketDispatcher.java	Fri Mar 22 11:35:35 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
@@ -34,13 +34,28 @@
  */
 
 class SocketDispatcher extends NativeDispatcher {
+    SocketDispatcher() { }
 
+    /**
+     * Reads up to len bytes from a socket with special handling for "connection
+     * reset".
+     *
+     * @throws sun.net.ConnectionResetException if connection reset is detected
+     * @throws IOException if another I/O error occurs
+     */
     int read(FileDescriptor fd, long address, int len) throws IOException {
-        return FileDispatcherImpl.read0(fd, address, len);
+        return read0(fd, address, len);
     }
 
+    /**
+     * Scattering read from a socket into len buffers with special handling for
+     * "connection reset".
+     *
+     * @throws sun.net.ConnectionResetException if connection reset is detected
+     * @throws IOException if another I/O error occurs
+     */
     long readv(FileDescriptor fd, long address, int len) throws IOException {
-        return FileDispatcherImpl.readv0(fd, address, len);
+        return readv0(fd, address, len);
     }
 
     int write(FileDescriptor fd, long address, int len) throws IOException {
@@ -58,4 +73,16 @@
     void preClose(FileDescriptor fd) throws IOException {
         FileDispatcherImpl.preClose0(fd);
     }
+
+    // -- Native methods --
+
+    private static native int read0(FileDescriptor fd, long address, int len)
+        throws IOException;
+
+    private static native long readv0(FileDescriptor fd, long address, int len)
+        throws IOException;
+
+    static {
+        IOUtil.load();
+    }
 }
--- a/src/java.base/unix/classes/sun/nio/ch/UnixAsynchronousSocketChannelImpl.java	Fri Mar 22 13:42:45 2019 +0530
+++ b/src/java.base/unix/classes/sun/nio/ch/UnixAsynchronousSocketChannelImpl.java	Fri Mar 22 11:35:35 2019 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 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
@@ -31,6 +31,8 @@
 import java.util.concurrent.*;
 import java.io.IOException;
 import java.io.FileDescriptor;
+
+import sun.net.ConnectionResetException;
 import sun.net.NetHooks;
 import sun.net.util.SocketExceptions;
 import sun.security.action.GetPropertyAction;
@@ -415,6 +417,8 @@
             enableReading();
             if (x instanceof ClosedChannelException)
                 x = new AsynchronousCloseException();
+            if (x instanceof ConnectionResetException)
+                x = new IOException(x.getMessage());
             exc = x;
         } finally {
             // restart poll in case of concurrent write
@@ -546,6 +550,8 @@
         } catch (Throwable x) {
             if (x instanceof ClosedChannelException)
                 x = new AsynchronousCloseException();
+            if (x instanceof ConnectionResetException)
+                x = new IOException(x.getMessage());
             exc = x;
         } finally {
             if (!pending)
--- a/src/java.base/unix/native/libnio/ch/Net.c	Fri Mar 22 13:42:45 2019 +0530
+++ b/src/java.base/unix/native/libnio/ch/Net.c	Fri Mar 22 11:35:35 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);
@@ -828,23 +828,22 @@
         errno = 0;
         result = getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &n);
         if (result < 0) {
-            return handleSocketError(env, errno);
+            handleSocketError(env, errno);
+            return JNI_FALSE;
         } else if (error) {
-            return handleSocketError(env, error);
+            handleSocketError(env, error);
+            return JNI_FALSE;
         } else if ((poller.revents & POLLHUP) != 0) {
-            return handleSocketError(env, ENOTCONN);
+            handleSocketError(env, ENOTCONN);
+            return JNI_FALSE;
         }
         // 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;
     }
 }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/unix/native/libnio/ch/SocketDispatcher.c	Fri Mar 22 11:35:35 2019 +0000
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 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
+ * 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/types.h>
+ #include <sys/uio.h>
+ #include <unistd.h>
+
+ #include "jni.h"
+ #include "jni_util.h"
+ #include "jlong.h"
+ #include "nio.h"
+ #include "nio_util.h"
+ #include "sun_nio_ch_SocketDispatcher.h"
+
+ JNIEXPORT jint JNICALL
+ Java_sun_nio_ch_SocketDispatcher_read0(JNIEnv *env, jclass clazz,
+                                        jobject fdo, jlong address, jint len)
+ {
+     jint fd = fdval(env, fdo);
+     void *buf = (void *)jlong_to_ptr(address);
+     jint n = read(fd, buf, len);
+     if ((n == -1) && (errno == ECONNRESET || errno == EPIPE)) {
+         JNU_ThrowByName(env, "sun/net/ConnectionResetException", "Connection reset");
+         return IOS_THROWN;
+     } else {
+         return convertReturnVal(env, n, JNI_TRUE);
+     }
+ }
+
+ JNIEXPORT jlong JNICALL
+ Java_sun_nio_ch_SocketDispatcher_readv0(JNIEnv *env, jclass clazz,
+                                         jobject fdo, jlong address, jint len)
+ {
+     jint fd = fdval(env, fdo);
+     struct iovec *iov = (struct iovec *)jlong_to_ptr(address);
+     jlong n = readv(fd, iov, len);
+     if ((n == -1) && (errno == ECONNRESET || errno == EPIPE)) {
+         JNU_ThrowByName(env, "sun/net/ConnectionResetException", "Connection reset");
+         return IOS_THROWN;
+     } else {
+         return convertLongReturnVal(env, n, JNI_TRUE);
+     }
+ }
--- a/src/java.base/windows/classes/sun/nio/ch/SocketDispatcher.java	Fri Mar 22 13:42:45 2019 +0530
+++ b/src/java.base/windows/classes/sun/nio/ch/SocketDispatcher.java	Fri Mar 22 11:35:35 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,19 +25,16 @@
 
 package sun.nio.ch;
 
-import java.io.*;
+import java.io.FileDescriptor;
+import java.io.IOException;
 
 /**
  * Allows different platforms to call different native methods
  * for read and write operations.
  */
 
-class SocketDispatcher extends NativeDispatcher
-{
-
-    static {
-        IOUtil.load();
-    }
+class SocketDispatcher extends NativeDispatcher {
+    SocketDispatcher() { }
 
     int read(FileDescriptor fd, long address, int len) throws IOException {
         return read0(fd, address, len);
@@ -63,7 +60,8 @@
         close0(fd);
     }
 
-    //-- Native methods
+    // -- Native methods --
+
     static native int read0(FileDescriptor fd, long address, int len)
         throws IOException;
 
@@ -79,4 +77,8 @@
     static native void preClose0(FileDescriptor fd) throws IOException;
 
     static native void close0(FileDescriptor fd) throws IOException;
+
+    static {
+        IOUtil.load();
+    }
 }
--- a/src/java.base/windows/native/libnio/ch/Net.c	Fri Mar 22 13:42:45 2019 +0530
+++ b/src/java.base/windows/native/libnio/ch/Net.c	Fri Mar 22 11:35:35 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	Fri Mar 22 13:42:45 2019 +0530
+++ b/src/java.base/windows/native/libnio/ch/SocketDispatcher.c	Fri Mar 22 11:35:35 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
@@ -72,7 +72,11 @@
         if (theErr == WSAEWOULDBLOCK) {
             return IOS_UNAVAILABLE;
         }
-        JNU_ThrowIOExceptionWithLastError(env, "Read failed");
+        if (theErr == WSAECONNRESET) {
+            JNU_ThrowByName(env, "sun/net/ConnectionResetException", "Connection reset");
+        } else {
+            JNU_ThrowIOExceptionWithLastError(env, "Read failed");
+        }
         return IOS_THROWN;
     }
 
@@ -128,7 +132,11 @@
         if (theErr == WSAEWOULDBLOCK) {
             return IOS_UNAVAILABLE;
         }
-        JNU_ThrowIOExceptionWithLastError(env, "Vector read failed");
+        if (theErr == WSAECONNRESET) {
+            JNU_ThrowByName(env, "sun/net/ConnectionResetException", "Connection reset");
+        } else {
+            JNU_ThrowIOExceptionWithLastError(env, "Vector read failed");
+        }
         return IOS_THROWN;
     }
 
@@ -174,7 +182,11 @@
                if (theErr == WSAEWOULDBLOCK) {
                    return IOS_UNAVAILABLE;
                }
-               JNU_ThrowIOExceptionWithLastError(env, "Write failed");
+               if (theErr == WSAECONNRESET) {
+                   JNU_ThrowIOException(env, "Connection reset by peer");
+               } else {
+                   JNU_ThrowIOExceptionWithLastError(env, "Write failed");
+               }
                return IOS_THROWN;
             }
         }
@@ -256,7 +268,11 @@
         if (theErr == WSAEWOULDBLOCK) {
             return IOS_UNAVAILABLE;
         }
-        JNU_ThrowIOExceptionWithLastError(env, "Vector write failed");
+        if (theErr == WSAECONNRESET) {
+            JNU_ThrowIOException(env, "Connection reset by peer");
+        } else {
+            JNU_ThrowIOExceptionWithLastError(env, "Vector write failed");
+        }
         return IOS_THROWN;
     }
 
--- a/src/jdk.sctp/unix/classes/sun/nio/ch/sctp/SctpChannelImpl.java	Fri Mar 22 13:42:45 2019 +0530
+++ b/src/jdk.sctp/unix/classes/sun/nio/ch/sctp/SctpChannelImpl.java	Fri Mar 22 11:35:35 2019 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 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
@@ -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()) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/nio/channels/SocketChannel/ConnectionReset.java	Fri Mar 22 11:35:35 2019 +0000
@@ -0,0 +1,248 @@
+/*
+ * Copyright (c) 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
+ * 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
+ * @requires os.family != "solaris"
+ * @run testng ConnectionReset
+ * @summary Test behavior of SocketChannel.read and the Socket adaptor read
+ *          and available methods when a connection is reset
+ */
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.nio.ByteBuffer;
+import java.nio.channels.SocketChannel;
+import java.lang.reflect.Method;
+
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+@Test
+public class ConnectionReset {
+
+    static final int REPEAT_COUNT = 5;
+
+    /**
+     * Tests SocketChannel.read when the connection is reset and there are no
+     * bytes to read.
+     */
+    public void testSocketChannelReadNoData() throws IOException {
+        System.out.println("testSocketChannelReadNoData");
+        withResetConnection(null, sc -> {
+            ByteBuffer bb = ByteBuffer.allocate(100);
+            for (int i=0; i<REPEAT_COUNT; i++) {
+                try {
+                    sc.read(bb);
+                    assertTrue(false);
+                } catch (IOException ioe) {
+                    System.out.format("read => %s (expected)%n", ioe);
+                }
+            }
+        });
+    }
+
+    /**
+     * Tests SocketChannel.read when the connection is reset and there are bytes
+     * to read.
+     */
+    public void testSocketChannelReadData() throws IOException {
+        System.out.println("testSocketChannelReadData");
+        byte[] data = { 1, 2, 3 };
+        withResetConnection(data, sc -> {
+            int remaining = data.length;
+            ByteBuffer bb = ByteBuffer.allocate(remaining + 100);
+            for (int i=0; i<REPEAT_COUNT; i++) {
+                try {
+                    int bytesRead = sc.read(bb);
+                    if (bytesRead == -1) {
+                        System.out.println("read => EOF");
+                    } else {
+                        System.out.println("read => " + bytesRead + " byte(s)");
+                    }
+                    assertTrue(bytesRead > 0);
+                    remaining -= bytesRead;
+                    assertTrue(remaining >= 0);
+                } catch (IOException ioe) {
+                    System.out.format("read => %s%n", ioe);
+                    remaining = 0;
+                }
+            }
+        });
+    }
+
+
+    /**
+     * Tests available before Socket read when the connection is reset and there
+     * are no bytes to read.
+     */
+    public void testAvailableBeforeSocketReadNoData() throws IOException {
+        System.out.println("testAvailableBeforeSocketReadNoData");
+        withResetConnection(null, sc -> {
+            Socket s = sc.socket();
+            InputStream in = s.getInputStream();
+            for (int i=0; i<REPEAT_COUNT; i++) {
+                int bytesAvailable = in.available();
+                System.out.format("available => %d%n", bytesAvailable);
+                assertTrue(bytesAvailable == 0);
+                try {
+                    int bytesRead = in.read();
+                    if (bytesRead == -1) {
+                        System.out.println("read => EOF");
+                    } else {
+                        System.out.println("read => 1 byte");
+                    }
+                    assertTrue(false);
+                } catch (IOException ioe) {
+                    System.out.format("read => %s (expected)%n", ioe);
+                }
+            }
+        });
+    }
+
+    /**
+     * Tests available before Socket read when the connection is reset and there
+     * are bytes to read.
+     */
+    public void testAvailableBeforeSocketReadData() throws IOException {
+        System.out.println("testAvailableBeforeSocketReadData");
+        byte[] data = { 1, 2, 3 };
+        withResetConnection(data, sc -> {
+            Socket s = sc.socket();
+            InputStream in = s.getInputStream();
+            int remaining = data.length;
+            for (int i=0; i<REPEAT_COUNT; i++) {
+                int bytesAvailable = in.available();
+                System.out.format("available => %d%n", bytesAvailable);
+                assertTrue(bytesAvailable <= remaining);
+                try {
+                    int bytesRead = in.read();
+                    if (bytesRead == -1) {
+                        System.out.println("read => EOF");
+                        assertTrue(false);
+                    } else {
+                        System.out.println("read => 1 byte");
+                        assertTrue(remaining > 0);
+                        remaining--;
+                    }
+                } catch (IOException ioe) {
+                    System.out.format("read => %s%n", ioe);
+                    remaining = 0;
+                }
+            }
+        });
+    }
+
+    /**
+     * Tests Socket read before available when the connection is reset and there
+     * are no bytes to read.
+     */
+    public void testSocketReadNoDataBeforeAvailable() throws IOException {
+        System.out.println("testSocketReadNoDataBeforeAvailable");
+        withResetConnection(null, sc -> {
+            Socket s = sc.socket();
+            InputStream in = s.getInputStream();
+            for (int i=0; i<REPEAT_COUNT; i++) {
+                try {
+                    int bytesRead = in.read();
+                    if (bytesRead == -1) {
+                        System.out.println("read => EOF");
+                    } else {
+                        System.out.println("read => 1 byte");
+                    }
+                    assertTrue(false);
+                } catch (IOException ioe) {
+                    System.out.format("read => %s (expected)%n", ioe);
+                }
+                int bytesAvailable = in.available();
+                System.out.format("available => %d%n", bytesAvailable);
+                assertTrue(bytesAvailable == 0);
+            }
+        });
+    }
+
+    /**
+     * Tests Socket read before available when the connection is reset and there
+     * are bytes to read.
+     */
+    public void testSocketReadDataBeforeAvailable() throws IOException {
+        System.out.println("testSocketReadDataBeforeAvailable");
+        byte[] data = { 1, 2, 3 };
+        withResetConnection(data, sc -> {
+            Socket s = sc.socket();
+            InputStream in = s.getInputStream();
+            int remaining = data.length;
+            for (int i=0; i<REPEAT_COUNT; i++) {
+                try {
+                    int bytesRead = in.read();
+                    if (bytesRead == -1) {
+                        System.out.println("read => EOF");
+                        assertTrue(false);
+                    } else {
+                        System.out.println("read => 1 byte");
+                        assertTrue(remaining > 0);
+                        remaining--;
+                    }
+                } catch (IOException ioe) {
+                    System.out.format("read => %s%n", ioe);
+                    remaining = 0;
+                }
+                int bytesAvailable = in.available();
+                System.out.format("available => %d%n", bytesAvailable);
+                assertTrue(bytesAvailable <= remaining);
+            }
+        });
+    }
+
+    interface ThrowingConsumer<T> {
+        void accept(T t) throws IOException;
+    }
+
+    /**
+     * Invokes a consumer with a SocketChannel connected to a peer that has closed
+     * the connection with a "connection reset". The peer sends the given data
+     * bytes before closing (when data is not null).
+     */
+    static void withResetConnection(byte[] data, ThrowingConsumer<SocketChannel> consumer)
+        throws IOException
+    {
+        var loopback = InetAddress.getLoopbackAddress();
+        try (var listener = new ServerSocket()) {
+            listener.bind(new InetSocketAddress(loopback, 0));
+            try (var sc = SocketChannel.open()) {
+                sc.connect(listener.getLocalSocketAddress());
+                try (Socket peer = listener.accept()) {
+                    if (data != null) {
+                        peer.getOutputStream().write(data);
+                    }
+                    peer.setSoLinger(true, 0);
+                }
+                consumer.accept(sc);
+            }
+        }
+    }
+}