# HG changeset patch # User alanb # Date 1553090090 0 # Node ID 07b6be5d915012bae840da6e4fa4b0791454f2e3 # Parent 3519688a4e4d0e2af50ac5491ce79988633456e1 More cleanup of connection reset diff -r 3519688a4e4d -r 07b6be5d9150 src/java.base/share/classes/java/net/ServerSocket.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); } diff -r 3519688a4e4d -r 07b6be5d9150 src/java.base/share/classes/java/net/Socket.java --- 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); } diff -r 3519688a4e4d -r 07b6be5d9150 src/java.base/share/classes/sun/nio/ch/Net.java --- 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); } diff -r 3519688a4e4d -r 07b6be5d9150 src/java.base/share/classes/sun/nio/ch/NioSocketImpl.java --- 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(); } } diff -r 3519688a4e4d -r 07b6be5d9150 src/java.base/share/classes/sun/nio/ch/SocketAdaptor.java --- 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; diff -r 3519688a4e4d -r 07b6be5d9150 src/java.base/share/classes/sun/nio/ch/SocketChannelImpl.java --- 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) { diff -r 3519688a4e4d -r 07b6be5d9150 src/java.base/unix/classes/sun/nio/ch/SocketDispatcher.java --- 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 diff -r 3519688a4e4d -r 07b6be5d9150 src/java.base/unix/native/libnio/ch/Net.c --- 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; } } diff -r 3519688a4e4d -r 07b6be5d9150 src/java.base/windows/classes/sun/nio/ch/SocketDispatcher.java --- 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 diff -r 3519688a4e4d -r 07b6be5d9150 src/java.base/windows/native/libnio/ch/Net.c --- 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; } } diff -r 3519688a4e4d -r 07b6be5d9150 src/java.base/windows/native/libnio/ch/SocketDispatcher.c --- 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"); } diff -r 3519688a4e4d -r 07b6be5d9150 src/jdk.sctp/unix/classes/sun/nio/ch/sctp/SctpChannelImpl.java --- 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()) {