mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 06:45:07 +02:00
8221252: (sc) SocketChannel and its socket adaptor need to handle connection reset
Reviewed-by: bpb
This commit is contained in:
parent
cc590f5765
commit
3a4d5db248
13 changed files with 507 additions and 88 deletions
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue