mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-28 07:14:30 +02:00
8278326: Socket close is not thread safe and other cleanup
Reviewed-by: jpai
This commit is contained in:
parent
036c80844e
commit
4b573343a6
5 changed files with 835 additions and 232 deletions
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1995, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1995, 2023, 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
|
||||
|
@ -78,18 +78,23 @@ import sun.net.PlatformSocketImpl;
|
|||
* @since 1.0
|
||||
*/
|
||||
public class ServerSocket implements java.io.Closeable {
|
||||
/**
|
||||
* The underlying SocketImpl
|
||||
*/
|
||||
// the underlying SocketImpl
|
||||
private final SocketImpl impl;
|
||||
|
||||
/**
|
||||
* Various states of this socket, need stateLock to change.
|
||||
*/
|
||||
// various states
|
||||
private volatile boolean created; // impl.create(boolean) called
|
||||
private volatile boolean bound;
|
||||
private volatile boolean closed;
|
||||
private final Object stateLock = new Object();
|
||||
|
||||
// used to coordinate creating and closing underlying socket
|
||||
private final Object socketLock = new Object();
|
||||
|
||||
/**
|
||||
* Creates a server socket with the given {@code SocketImpl}.
|
||||
*/
|
||||
private ServerSocket(Void unused, SocketImpl impl) {
|
||||
this.impl = Objects.requireNonNull(impl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a server socket with a user-specified {@code SocketImpl}.
|
||||
|
@ -104,9 +109,7 @@ public class ServerSocket implements java.io.Closeable {
|
|||
* @since 12
|
||||
*/
|
||||
protected ServerSocket(SocketImpl impl) {
|
||||
Objects.requireNonNull(impl);
|
||||
checkPermission();
|
||||
this.impl = impl;
|
||||
this(checkPermission(), impl);
|
||||
}
|
||||
|
||||
private static Void checkPermission() {
|
||||
|
@ -280,16 +283,26 @@ public class ServerSocket implements java.io.Closeable {
|
|||
}
|
||||
|
||||
/**
|
||||
* Get the {@code SocketImpl} attached to this socket, creating
|
||||
* it if necessary.
|
||||
*
|
||||
* @return the {@code SocketImpl} attached to that ServerSocket.
|
||||
* @throws SocketException if creation fails.
|
||||
* @since 1.4
|
||||
* Create a SocketImpl for a server socket. The SocketImpl is created
|
||||
* without an underlying socket.
|
||||
*/
|
||||
private static SocketImpl createImpl() {
|
||||
SocketImplFactory factory = ServerSocket.factory;
|
||||
if (factory != null) {
|
||||
return factory.createSocketImpl();
|
||||
} else {
|
||||
return SocketImpl.createPlatformSocketImpl(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@code SocketImpl} for this ServerSocket, creating the
|
||||
* underlying socket if required.
|
||||
* @throws SocketException if creating the underlying socket fails
|
||||
*/
|
||||
private SocketImpl getImpl() throws SocketException {
|
||||
if (!created) {
|
||||
synchronized (stateLock) {
|
||||
synchronized (socketLock) {
|
||||
if (!created) {
|
||||
if (closed) {
|
||||
throw new SocketException("Socket is closed");
|
||||
|
@ -308,18 +321,6 @@ public class ServerSocket implements java.io.Closeable {
|
|||
return impl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a SocketImpl for a server socket.
|
||||
*/
|
||||
private static SocketImpl createImpl() {
|
||||
SocketImplFactory factory = ServerSocket.factory;
|
||||
if (factory != null) {
|
||||
return factory.createSocketImpl();
|
||||
} else {
|
||||
return SocketImpl.createPlatformSocketImpl(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Binds the {@code ServerSocket} to a specific address
|
||||
|
@ -385,15 +386,11 @@ public class ServerSocket implements java.io.Closeable {
|
|||
if (security != null)
|
||||
security.checkListen(epoint.getPort());
|
||||
|
||||
synchronized (stateLock) {
|
||||
if (closed)
|
||||
throw new SocketException("Socket is closed");
|
||||
if (bound)
|
||||
throw new SocketException("Already bound");
|
||||
getImpl().bind(epoint.getAddress(), epoint.getPort());
|
||||
getImpl().listen(backlog);
|
||||
bound = true;
|
||||
}
|
||||
// SocketImpl bind+listen throw if already bound or closed
|
||||
SocketImpl impl = getImpl();
|
||||
impl.bind(epoint.getAddress(), epoint.getPort());
|
||||
impl.listen(backlog);
|
||||
bound = true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -581,19 +578,24 @@ public class ServerSocket implements java.io.Closeable {
|
|||
* @revised 1.4
|
||||
*/
|
||||
protected final void implAccept(Socket s) throws IOException {
|
||||
SocketImpl si = s.impl;
|
||||
SocketImpl si = s.impl();
|
||||
|
||||
// Socket has no SocketImpl
|
||||
if (si == null) {
|
||||
si = implAccept();
|
||||
s.setImpl(si);
|
||||
s.postAccept();
|
||||
try {
|
||||
s.setConnectedImpl(si);
|
||||
} catch (SocketException e) {
|
||||
// s has been closed so newly accepted connection needs to be closed
|
||||
si.closeQuietly();
|
||||
throw e;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Socket has a SOCKS or HTTP SocketImpl, need delegate
|
||||
if (si instanceof DelegatingSocketImpl) {
|
||||
si = ((DelegatingSocketImpl) si).delegate();
|
||||
if (si instanceof DelegatingSocketImpl dsi) {
|
||||
si = dsi.delegate();
|
||||
assert si instanceof PlatformSocketImpl;
|
||||
}
|
||||
|
||||
|
@ -609,17 +611,23 @@ public class ServerSocket implements java.io.Closeable {
|
|||
if (impl instanceof PlatformSocketImpl) {
|
||||
SocketImpl psi = platformImplAccept();
|
||||
si.copyOptionsTo(psi);
|
||||
s.setImpl(psi);
|
||||
si.closeQuietly();
|
||||
try {
|
||||
s.setConnectedImpl(psi);
|
||||
} catch (SocketException e) {
|
||||
// s has been closed so newly accepted connection needs to be closed
|
||||
psi.closeQuietly();
|
||||
throw e;
|
||||
}
|
||||
} else {
|
||||
s.impl = null; // temporarily break connection to impl
|
||||
s.setImpl(null); // temporarily break connection to impl
|
||||
try {
|
||||
customImplAccept(si);
|
||||
} finally {
|
||||
s.impl = si; // restore connection to impl
|
||||
s.setImpl(si); // restore connection to impl
|
||||
}
|
||||
s.setConnected();
|
||||
}
|
||||
s.postAccept();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -736,7 +744,7 @@ public class ServerSocket implements java.io.Closeable {
|
|||
* @revised 1.4
|
||||
*/
|
||||
public void close() throws IOException {
|
||||
synchronized (stateLock) {
|
||||
synchronized (socketLock) {
|
||||
if (!closed) {
|
||||
closed = true;
|
||||
|
||||
|
@ -830,8 +838,8 @@ public class ServerSocket implements java.io.Closeable {
|
|||
throw new SocketException("Socket is closed");
|
||||
Object o = getImpl().getOption(SocketOptions.SO_TIMEOUT);
|
||||
/* extra type safety */
|
||||
if (o instanceof Integer) {
|
||||
return ((Integer) o).intValue();
|
||||
if (o instanceof Integer i) {
|
||||
return i.intValue();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
@ -1010,10 +1018,9 @@ public class ServerSocket implements java.io.Closeable {
|
|||
* @since 1.4
|
||||
* @see #getReceiveBufferSize
|
||||
*/
|
||||
public void setReceiveBufferSize (int size) throws SocketException {
|
||||
if (!(size > 0)) {
|
||||
public void setReceiveBufferSize(int size) throws SocketException {
|
||||
if (size <= 0)
|
||||
throw new IllegalArgumentException("negative receive size");
|
||||
}
|
||||
if (isClosed())
|
||||
throw new SocketException("Socket is closed");
|
||||
getImpl().setOption(SocketOptions.SO_RCVBUF, size);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue