mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-26 14:24:46 +02:00
8343791: Socket.connect API should document whether the socket will be closed when hostname resolution fails or another error occurs
Reviewed-by: dfuchs, alanb
This commit is contained in:
parent
4ac2e477b9
commit
3eb5461578
5 changed files with 226 additions and 42 deletions
|
@ -454,6 +454,7 @@ public class Socket implements java.io.Closeable {
|
|||
throws IOException
|
||||
{
|
||||
Objects.requireNonNull(address);
|
||||
assert address instanceof InetSocketAddress;
|
||||
|
||||
// create the SocketImpl and the underlying socket
|
||||
SocketImpl impl = createImpl();
|
||||
|
@ -463,16 +464,13 @@ public class Socket implements java.io.Closeable {
|
|||
this.state = SOCKET_CREATED;
|
||||
|
||||
try {
|
||||
if (localAddr != null)
|
||||
if (localAddr != null) {
|
||||
bind(localAddr);
|
||||
connect(address);
|
||||
} catch (IOException | IllegalArgumentException e) {
|
||||
try {
|
||||
close();
|
||||
} catch (IOException ce) {
|
||||
e.addSuppressed(ce);
|
||||
}
|
||||
throw e;
|
||||
connect(address);
|
||||
} catch (Throwable throwable) {
|
||||
closeSuppressingExceptions(throwable);
|
||||
throw throwable;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -571,6 +569,10 @@ public class Socket implements java.io.Closeable {
|
|||
/**
|
||||
* Connects this socket to the server.
|
||||
*
|
||||
* <p> If the endpoint is an unresolved {@link InetSocketAddress}, or the
|
||||
* connection cannot be established, then the socket is closed, and an
|
||||
* {@link IOException} is thrown.
|
||||
*
|
||||
* <p> This method is {@linkplain Thread#interrupt() interruptible} in the
|
||||
* following circumstances:
|
||||
* <ol>
|
||||
|
@ -589,6 +591,8 @@ public class Socket implements java.io.Closeable {
|
|||
* @param endpoint the {@code SocketAddress}
|
||||
* @throws IOException if an error occurs during the connection, the socket
|
||||
* is already connected or the socket is closed
|
||||
* @throws UnknownHostException if the endpoint is an unresolved
|
||||
* {@link InetSocketAddress}
|
||||
* @throws java.nio.channels.IllegalBlockingModeException
|
||||
* if this socket has an associated channel,
|
||||
* and the channel is in non-blocking mode
|
||||
|
@ -605,6 +609,11 @@ public class Socket implements java.io.Closeable {
|
|||
* A timeout of zero is interpreted as an infinite timeout. The connection
|
||||
* will then block until established or an error occurs.
|
||||
*
|
||||
* <p> If the endpoint is an unresolved {@link InetSocketAddress}, the
|
||||
* connection cannot be established, or the timeout expires before the
|
||||
* connection is established, then the socket is closed, and an
|
||||
* {@link IOException} is thrown.
|
||||
*
|
||||
* <p> This method is {@linkplain Thread#interrupt() interruptible} in the
|
||||
* following circumstances:
|
||||
* <ol>
|
||||
|
@ -625,6 +634,8 @@ public class Socket implements java.io.Closeable {
|
|||
* @throws IOException if an error occurs during the connection, the socket
|
||||
* is already connected or the socket is closed
|
||||
* @throws SocketTimeoutException if timeout expires before connecting
|
||||
* @throws UnknownHostException if the endpoint is an unresolved
|
||||
* {@link InetSocketAddress}
|
||||
* @throws java.nio.channels.IllegalBlockingModeException
|
||||
* if this socket has an associated channel,
|
||||
* and the channel is in non-blocking mode
|
||||
|
@ -644,26 +655,25 @@ public class Socket implements java.io.Closeable {
|
|||
if (isClosed(s))
|
||||
throw new SocketException("Socket is closed");
|
||||
if (isConnected(s))
|
||||
throw new SocketException("already connected");
|
||||
throw new SocketException("Already connected");
|
||||
|
||||
if (!(endpoint instanceof InetSocketAddress epoint))
|
||||
throw new IllegalArgumentException("Unsupported address type");
|
||||
|
||||
if (epoint.isUnresolved()) {
|
||||
var uhe = new UnknownHostException(epoint.getHostName());
|
||||
closeSuppressingExceptions(uhe);
|
||||
throw uhe;
|
||||
}
|
||||
|
||||
InetAddress addr = epoint.getAddress();
|
||||
int port = epoint.getPort();
|
||||
checkAddress(addr, "connect");
|
||||
|
||||
try {
|
||||
getImpl().connect(epoint, timeout);
|
||||
} catch (SocketTimeoutException e) {
|
||||
throw e;
|
||||
} catch (InterruptedIOException e) {
|
||||
Thread thread = Thread.currentThread();
|
||||
if (thread.isVirtual() && thread.isInterrupted()) {
|
||||
close();
|
||||
throw new SocketException("Closed by interrupt");
|
||||
}
|
||||
throw e;
|
||||
} catch (IOException error) {
|
||||
closeSuppressingExceptions(error);
|
||||
throw error;
|
||||
}
|
||||
|
||||
// connect will bind the socket if not previously bound
|
||||
|
@ -1589,6 +1599,14 @@ public class Socket implements java.io.Closeable {
|
|||
return ((Boolean) (getImpl().getOption(SocketOptions.SO_REUSEADDR))).booleanValue();
|
||||
}
|
||||
|
||||
private void closeSuppressingExceptions(Throwable parentException) {
|
||||
try {
|
||||
close();
|
||||
} catch (IOException exception) {
|
||||
parentException.addSuppressed(exception);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes this socket.
|
||||
* <p>
|
||||
|
|
|
@ -40,6 +40,7 @@ import java.net.StandardProtocolFamily;
|
|||
import java.net.StandardSocketOptions;
|
||||
import java.net.UnknownHostException;
|
||||
import java.nio.channels.AlreadyBoundException;
|
||||
import java.nio.channels.AlreadyConnectedException;
|
||||
import java.nio.channels.ClosedChannelException;
|
||||
import java.nio.channels.NotYetBoundException;
|
||||
import java.nio.channels.NotYetConnectedException;
|
||||
|
@ -166,6 +167,8 @@ public class Net {
|
|||
nx = newSocketException("Socket is not connected");
|
||||
else if (x instanceof AlreadyBoundException)
|
||||
nx = newSocketException("Already bound");
|
||||
else if (x instanceof AlreadyConnectedException)
|
||||
nx = newSocketException("Already connected");
|
||||
else if (x instanceof NotYetBoundException)
|
||||
nx = newSocketException("Socket is not bound yet");
|
||||
else if (x instanceof UnsupportedAddressTypeException)
|
||||
|
@ -190,32 +193,12 @@ public class Net {
|
|||
return new SocketException(msg);
|
||||
}
|
||||
|
||||
static void translateException(Exception x,
|
||||
boolean unknownHostForUnresolved)
|
||||
throws IOException
|
||||
{
|
||||
static void translateException(Exception x) throws IOException {
|
||||
if (x instanceof IOException ioe)
|
||||
throw ioe;
|
||||
// Throw UnknownHostException from here since it cannot
|
||||
// be thrown as a SocketException
|
||||
if (unknownHostForUnresolved &&
|
||||
(x instanceof UnresolvedAddressException))
|
||||
{
|
||||
throw new UnknownHostException();
|
||||
}
|
||||
translateToSocketException(x);
|
||||
}
|
||||
|
||||
static void translateException(Exception x)
|
||||
throws IOException
|
||||
{
|
||||
translateException(x, false);
|
||||
}
|
||||
|
||||
private static InetSocketAddress getLoopbackAddress(int port) {
|
||||
return new InetSocketAddress(InetAddress.getLoopbackAddress(), port);
|
||||
}
|
||||
|
||||
private static final InetAddress ANY_LOCAL_INET4ADDRESS;
|
||||
private static final InetAddress ANY_LOCAL_INET6ADDRESS;
|
||||
private static final InetAddress INET4_LOOPBACK_ADDRESS;
|
||||
|
|
|
@ -599,8 +599,11 @@ public final class NioSocketImpl extends SocketImpl implements PlatformSocketImp
|
|||
}
|
||||
} catch (IOException ioe) {
|
||||
close();
|
||||
if (ioe instanceof InterruptedIOException) {
|
||||
if (ioe instanceof SocketTimeoutException) {
|
||||
throw ioe;
|
||||
} else if (ioe instanceof InterruptedIOException) {
|
||||
assert Thread.currentThread().isVirtual();
|
||||
throw new SocketException("Closed by interrupt");
|
||||
} else {
|
||||
throw SocketExceptions.of(ioe, isa);
|
||||
}
|
||||
|
|
|
@ -35,6 +35,7 @@ import java.net.SocketAddress;
|
|||
import java.net.SocketException;
|
||||
import java.net.SocketOption;
|
||||
import java.net.StandardSocketOptions;
|
||||
import java.net.UnknownHostException;
|
||||
import java.nio.channels.SocketChannel;
|
||||
import java.util.Set;
|
||||
|
||||
|
@ -85,6 +86,14 @@ class SocketAdaptor
|
|||
public void connect(SocketAddress remote, int timeout) throws IOException {
|
||||
if (remote == null)
|
||||
throw new IllegalArgumentException("connect: The address can't be null");
|
||||
if (remote instanceof InetSocketAddress isa && isa.isUnresolved()) {
|
||||
if (!sc.isOpen())
|
||||
throw new SocketException("Socket is closed");
|
||||
if (sc.isConnected())
|
||||
throw new SocketException("Already connected");
|
||||
close();
|
||||
throw new UnknownHostException(remote.toString());
|
||||
}
|
||||
if (timeout < 0)
|
||||
throw new IllegalArgumentException("connect: timeout can't be negative");
|
||||
try {
|
||||
|
@ -95,7 +104,7 @@ class SocketAdaptor
|
|||
sc.blockingConnect(remote, Long.MAX_VALUE);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Net.translateException(e, true);
|
||||
Net.translateException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue