8221252: (sc) SocketChannel and its socket adaptor need to handle connection reset

Reviewed-by: bpb
This commit is contained in:
Alan Bateman 2019-03-22 11:35:35 +00:00
parent cc590f5765
commit 3a4d5db248
13 changed files with 507 additions and 88 deletions

View file

@ -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 @@ public final class IOStatus {
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);
}
}

View file

@ -310,6 +310,12 @@ public class Net {
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 @@ public class Net {
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 @@ public class Net {
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,20 +535,43 @@ public class Net {
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.
*/

View file

@ -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 @@ class SocketAdaptor
}
}
}
@Override
public int available() throws IOException {
return sc.available();
}
}
private InputStream socketInputStream = null;

View file

@ -32,6 +32,7 @@ import java.net.InetSocketAddress;
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.Objects;
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 @@ class SocketChannelImpl
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 @@ class SocketChannelImpl
}
// no options that require special handling
Net.setSocketOption(fd, Net.UNSPEC, name, value);
Net.setSocketOption(fd, name, value);
return this;
}
}
@ -260,7 +265,7 @@ class SocketChannelImpl
}
// no options that require special handling
return (T) Net.getSocketOption(fd, Net.UNSPEC, name);
return (T) Net.getSocketOption(fd, name);
}
}
@ -334,6 +339,10 @@ class SocketChannelImpl
}
}
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 @@ class SocketChannelImpl
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 @@ class SocketChannelImpl
} 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 @@ class SocketChannelImpl
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 @@ class SocketChannelImpl
} 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 @@ class SocketChannelImpl
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);
}
@ -1006,6 +1027,20 @@ class SocketChannelImpl
}
}
/**
* 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
*/