Skip to content

Commit 24877ac

Browse files
author
Alan Bateman
committedDec 7, 2021
8278270: ServerSocket is not thread safe
Reviewed-by: dfuchs
1 parent e535cb3 commit 24877ac

File tree

1 file changed

+66
-65
lines changed

1 file changed

+66
-65
lines changed
 

‎src/java.base/share/classes/java/net/ServerSocket.java

+66-65
Original file line numberDiff line numberDiff line change
@@ -78,17 +78,17 @@
7878
*/
7979
public class ServerSocket implements java.io.Closeable {
8080
/**
81-
* Various states of this socket.
81+
* The underlying SocketImpl
8282
*/
83-
private boolean created = false;
84-
private boolean bound = false;
85-
private boolean closed = false;
86-
private Object closeLock = new Object();
83+
private final SocketImpl impl;
8784

8885
/**
89-
* The implementation of this Socket.
86+
* Various states of this socket, need stateLock to change.
9087
*/
91-
private SocketImpl impl;
88+
private volatile boolean created; // impl.create(boolean) called
89+
private volatile boolean bound;
90+
private volatile boolean closed;
91+
private final Object stateLock = new Object();
9292

9393
/**
9494
* Creates a server socket with a user-specified {@code SocketImpl}.
@@ -124,7 +124,7 @@ private static Void checkPermission() {
124124
* @revised 1.4
125125
*/
126126
public ServerSocket() throws IOException {
127-
setImpl();
127+
this.impl = createImpl();
128128
}
129129

130130
/**
@@ -264,18 +264,15 @@ public ServerSocket(int port, int backlog) throws IOException {
264264
* @since 1.1
265265
*/
266266
public ServerSocket(int port, int backlog, InetAddress bindAddr) throws IOException {
267-
setImpl();
268267
if (port < 0 || port > 0xFFFF)
269-
throw new IllegalArgumentException(
270-
"Port value out of range: " + port);
268+
throw new IllegalArgumentException("Port value out of range: " + port);
271269
if (backlog < 1)
272-
backlog = 50;
270+
backlog = 50;
271+
272+
this.impl = createImpl();
273273
try {
274274
bind(new InetSocketAddress(bindAddr, port), backlog);
275-
} catch(SecurityException e) {
276-
close();
277-
throw e;
278-
} catch(IOException e) {
275+
} catch (IOException | SecurityException e) {
279276
close();
280277
throw e;
281278
}
@@ -289,35 +286,36 @@ public ServerSocket(int port, int backlog, InetAddress bindAddr) throws IOExcept
289286
* @throws SocketException if creation fails.
290287
* @since 1.4
291288
*/
292-
SocketImpl getImpl() throws SocketException {
293-
if (!created)
294-
createImpl();
289+
private SocketImpl getImpl() throws SocketException {
290+
if (!created) {
291+
synchronized (stateLock) {
292+
if (!created) {
293+
if (closed) {
294+
throw new SocketException("Socket is closed");
295+
}
296+
try {
297+
impl.create(true);
298+
} catch (SocketException e) {
299+
throw e;
300+
} catch (IOException e) {
301+
throw new SocketException(e.getMessage());
302+
}
303+
created = true;
304+
}
305+
}
306+
}
295307
return impl;
296308
}
297309

298-
private void setImpl() {
310+
/**
311+
* Create a SocketImpl for a server socket.
312+
*/
313+
private static SocketImpl createImpl() {
299314
SocketImplFactory factory = ServerSocket.factory;
300315
if (factory != null) {
301-
impl = factory.createSocketImpl();
316+
return factory.createSocketImpl();
302317
} else {
303-
impl = SocketImpl.createPlatformSocketImpl(true);
304-
}
305-
}
306-
307-
/**
308-
* Creates the socket implementation.
309-
*
310-
* @throws SocketException if creation fails
311-
* @since 1.4
312-
*/
313-
void createImpl() throws SocketException {
314-
if (impl == null)
315-
setImpl();
316-
try {
317-
impl.create(true);
318-
created = true;
319-
} catch (IOException e) {
320-
throw new SocketException(e.getMessage());
318+
return SocketImpl.createPlatformSocketImpl(true);
321319
}
322320
}
323321

@@ -379,21 +377,21 @@ public void bind(SocketAddress endpoint, int backlog) throws IOException {
379377
if (epoint.isUnresolved())
380378
throw new SocketException("Unresolved address");
381379
if (backlog < 1)
382-
backlog = 50;
383-
try {
384-
@SuppressWarnings("removal")
385-
SecurityManager security = System.getSecurityManager();
386-
if (security != null)
387-
security.checkListen(epoint.getPort());
380+
backlog = 50;
381+
382+
@SuppressWarnings("removal")
383+
SecurityManager security = System.getSecurityManager();
384+
if (security != null)
385+
security.checkListen(epoint.getPort());
386+
387+
synchronized (stateLock) {
388+
if (closed)
389+
throw new SocketException("Socket is closed");
390+
if (bound)
391+
throw new SocketException("Already bound");
388392
getImpl().bind(epoint.getAddress(), epoint.getPort());
389393
getImpl().listen(backlog);
390394
bound = true;
391-
} catch(SecurityException e) {
392-
bound = false;
393-
throw e;
394-
} catch(IOException e) {
395-
bound = false;
396-
throw e;
397395
}
398396
}
399397

@@ -711,12 +709,18 @@ private void ensureCompatible(SocketImpl si) throws IOException {
711709
* @revised 1.4
712710
*/
713711
public void close() throws IOException {
714-
synchronized(closeLock) {
715-
if (isClosed())
716-
return;
717-
if (created)
718-
impl.close();
719-
closed = true;
712+
synchronized (stateLock) {
713+
if (!closed) {
714+
try {
715+
// close underlying socket if created
716+
if (created) {
717+
impl.close();
718+
}
719+
} finally {
720+
closed = true;
721+
}
722+
723+
}
720724
}
721725
}
722726

@@ -760,9 +764,7 @@ public boolean isBound() {
760764
* @since 1.4
761765
*/
762766
public boolean isClosed() {
763-
synchronized(closeLock) {
764-
return closed;
765-
}
767+
return closed;
766768
}
767769

768770
/**
@@ -783,7 +785,7 @@ public boolean isClosed() {
783785
* @since 1.1
784786
* @see #getSoTimeout()
785787
*/
786-
public synchronized void setSoTimeout(int timeout) throws SocketException {
788+
public void setSoTimeout(int timeout) throws SocketException {
787789
if (isClosed())
788790
throw new SocketException("Socket is closed");
789791
if (timeout < 0)
@@ -799,7 +801,7 @@ public synchronized void setSoTimeout(int timeout) throws SocketException {
799801
* @since 1.1
800802
* @see #setSoTimeout(int)
801803
*/
802-
public synchronized int getSoTimeout() throws IOException {
804+
public int getSoTimeout() throws IOException {
803805
if (isClosed())
804806
throw new SocketException("Socket is closed");
805807
Object o = getImpl().getOption(SocketOptions.SO_TIMEOUT);
@@ -984,7 +986,7 @@ public static synchronized void setSocketFactory(SocketImplFactory fac) throws I
984986
* @since 1.4
985987
* @see #getReceiveBufferSize
986988
*/
987-
public synchronized void setReceiveBufferSize (int size) throws SocketException {
989+
public void setReceiveBufferSize (int size) throws SocketException {
988990
if (!(size > 0)) {
989991
throw new IllegalArgumentException("negative receive size");
990992
}
@@ -1007,8 +1009,7 @@ public synchronized void setReceiveBufferSize (int size) throws SocketException
10071009
* @see #setReceiveBufferSize(int)
10081010
* @since 1.4
10091011
*/
1010-
public synchronized int getReceiveBufferSize()
1011-
throws SocketException{
1012+
public int getReceiveBufferSize() throws SocketException {
10121013
if (isClosed())
10131014
throw new SocketException("Socket is closed");
10141015
int result = 0;

0 commit comments

Comments
 (0)