Skip to content

Commit 52a5583

Browse files
committed
8356154: Respecify java.net.Socket constructors that allow creating UDP sockets to throw IllegalArgumentException
Reviewed-by: dfuchs, alanb
1 parent 3e258cb commit 52a5583

File tree

9 files changed

+100
-135
lines changed

9 files changed

+100
-135
lines changed

src/java.base/share/classes/java/net/Socket.java

Lines changed: 19 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 1995, 2024, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 1995, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -378,27 +378,22 @@ public Socket(InetAddress address, int port, InetAddress localAddr,
378378
* In other words, it is equivalent to specifying an address of the
379379
* loopback interface. </p>
380380
* <p>
381-
* If the stream argument is {@code true}, this creates a
382-
* stream socket. If the stream argument is {@code false}, it
383-
* creates a datagram socket.
384-
* <p>
385381
* If the application has specified a {@linkplain SocketImplFactory client
386382
* socket implementation factory}, that factory's
387383
* {@linkplain SocketImplFactory#createSocketImpl() createSocketImpl}
388384
* method is called to create the actual socket implementation. Otherwise
389385
* a system-default socket implementation is created.
390-
* <p>
391-
* If a UDP socket is used, TCP/IP related socket options will not apply.
392386
*
393387
* @param host the host name, or {@code null} for the loopback address.
394388
* @param port the port number.
395-
* @param stream a {@code boolean} indicating whether this is
396-
* a stream socket or a datagram socket.
389+
* @param stream must be true, false is not allowed.
397390
* @throws IOException if an I/O error occurs when creating the socket.
398-
* @throws IllegalArgumentException if the port parameter is outside
399-
* the specified range of valid port values, which is between
400-
* 0 and 65535, inclusive.
401-
* @deprecated Use {@link DatagramSocket} instead for UDP transport.
391+
* @throws IllegalArgumentException if the stream parameter is {@code false}
392+
* or if the port parameter is outside the specified range of valid
393+
* port values, which is between 0 and 65535, inclusive.
394+
* @deprecated The {@code stream} parameter provided a way in early JDK releases
395+
* to create a {@code Socket} that used a datagram socket. This feature
396+
* no longer exists. Instead use {@link DatagramSocket} for datagram sockets.
402397
*/
403398
@Deprecated(forRemoval = true, since = "1.1")
404399
@SuppressWarnings("this-escape")
@@ -412,28 +407,23 @@ public Socket(String host, int port, boolean stream) throws IOException {
412407
* Creates a socket and connects it to the specified port number at
413408
* the specified IP address.
414409
* <p>
415-
* If the stream argument is {@code true}, this creates a
416-
* stream socket. If the stream argument is {@code false}, it
417-
* creates a datagram socket.
418-
* <p>
419410
* If the application has specified a {@linkplain SocketImplFactory client
420411
* socket implementation factory}, that factory's
421412
* {@linkplain SocketImplFactory#createSocketImpl() createSocketImpl}
422413
* method is called to create the actual socket implementation. Otherwise
423414
* a system-default socket implementation is created.
424-
* <p>
425-
* If UDP socket is used, TCP/IP related socket options will not apply.
426415
*
427416
* @param host the IP address.
428417
* @param port the port number.
429-
* @param stream if {@code true}, create a stream socket;
430-
* otherwise, create a datagram socket.
418+
* @param stream must be true, false is not allowed.
431419
* @throws IOException if an I/O error occurs when creating the socket.
432-
* @throws IllegalArgumentException if the port parameter is outside
433-
* the specified range of valid port values, which is between
434-
* 0 and 65535, inclusive.
420+
* @throws IllegalArgumentException if the stream parameter is {@code false}
421+
* or if the port parameter is outside the specified range of valid
422+
* port values, which is between 0 and 65535, inclusive.
435423
* @throws NullPointerException if {@code host} is null.
436-
* @deprecated Use {@link DatagramSocket} instead for UDP transport.
424+
* @deprecated The {@code stream} parameter provided a way in early JDK releases
425+
* to create a {@code Socket} that used a datagram socket. This feature
426+
* no longer exists. Instead use {@link DatagramSocket} for datagram sockets.
437427
*/
438428
@Deprecated(forRemoval = true, since = "1.1")
439429
@SuppressWarnings("this-escape")
@@ -454,6 +444,10 @@ private Socket(SocketAddress address, SocketAddress localAddr, boolean stream)
454444
throws IOException
455445
{
456446
Objects.requireNonNull(address);
447+
if (!stream) {
448+
throw new IllegalArgumentException(
449+
"Socket constructor does not support creation of datagram sockets");
450+
}
457451
assert address instanceof InetSocketAddress;
458452

459453
// create the SocketImpl and the underlying socket

src/java.base/share/classes/java/net/SocketImpl.java

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 1995, 2024, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 1995, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -78,15 +78,16 @@ static <S extends SocketImpl & PlatformSocketImpl> S createPlatformSocketImpl(bo
7878
public SocketImpl() { }
7979

8080
/**
81-
* Creates either a stream or a datagram socket.
81+
* Creates a stream socket.
8282
*
8383
* @apiNote
84-
* The {@link Socket} constructors to create a datagram socket
85-
* are deprecated for removal. This method will be re-specified
86-
* in a future release to not support creating datagram sockets.
84+
* The {@code stream} parameter provided a way in early JDK releases
85+
* to create a {@link Socket} that used a datagram socket.
86+
* The Socket API no longer provides a way to do this, so the
87+
* {@code create} method will always be called with a {@code stream}
88+
* value of {@code true}.
8789
*
88-
* @param stream if {@code true}, create a stream socket;
89-
* otherwise, create a datagram socket.
90+
* @param stream must be {@code true}.
9091
* @throws IOException if an I/O error occurs while creating the
9192
* socket.
9293
*/

src/java.base/share/classes/sun/nio/ch/AsynchronousServerSocketChannelImpl.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -69,7 +69,7 @@ abstract class AsynchronousServerSocketChannelImpl
6969

7070
AsynchronousServerSocketChannelImpl(AsynchronousChannelGroupImpl group) {
7171
super(group.provider());
72-
this.fd = Net.serverSocket(true);
72+
this.fd = Net.serverSocket();
7373
}
7474

7575
@Override

src/java.base/share/classes/sun/nio/ch/AsynchronousSocketChannelImpl.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ abstract class AsynchronousSocketChannelImpl
8888
throws IOException
8989
{
9090
super(group.provider());
91-
this.fd = Net.socket(true);
91+
this.fd = Net.socket();
9292
this.state = ST_UNCONNECTED;
9393
}
9494

src/java.base/share/classes/sun/nio/ch/Net.java

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -470,8 +470,8 @@ private static boolean isFastTcpLoopbackRequested() {
470470

471471
private static native boolean canUseIPv6OptionsWithIPv4LocalAddress0();
472472

473-
static FileDescriptor socket(boolean stream) throws IOException {
474-
return socket(UNSPEC, stream);
473+
static FileDescriptor socket() throws IOException {
474+
return socket(UNSPEC, true);
475475
}
476476

477477
static FileDescriptor socket(ProtocolFamily family, boolean stream) throws IOException {
@@ -480,14 +480,14 @@ static FileDescriptor socket(ProtocolFamily family, boolean stream) throws IOExc
480480
return IOUtil.newFD(socket0(preferIPv6, stream, false, FAST_LOOPBACK));
481481
}
482482

483-
static FileDescriptor serverSocket(boolean stream) {
484-
return serverSocket(UNSPEC, stream);
483+
static FileDescriptor serverSocket() {
484+
return serverSocket(UNSPEC);
485485
}
486486

487-
static FileDescriptor serverSocket(ProtocolFamily family, boolean stream) {
487+
static FileDescriptor serverSocket(ProtocolFamily family) {
488488
boolean preferIPv6 = isIPv6Available() &&
489489
(family != StandardProtocolFamily.INET);
490-
return IOUtil.newFD(socket0(preferIPv6, stream, true, FAST_LOOPBACK));
490+
return IOUtil.newFD(socket0(preferIPv6, true, true, FAST_LOOPBACK));
491491
}
492492

493493
// Due to oddities SO_REUSEADDR on Windows reuse is ignored

src/java.base/share/classes/sun/nio/ch/NioSocketImpl.java

Lines changed: 15 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -100,8 +100,6 @@ public final class NioSocketImpl extends SocketImpl implements PlatformSocketImp
100100
private static final int ST_CLOSED = 5;
101101
private volatile int state; // need stateLock to change
102102

103-
// set by SocketImpl.create, protected by stateLock
104-
private boolean stream;
105103
private Cleanable cleaner;
106104

107105
// set to true when the socket is in non-blocking mode
@@ -451,19 +449,20 @@ private void write(byte[] b, int off, int len) throws IOException {
451449
*/
452450
@Override
453451
protected void create(boolean stream) throws IOException {
452+
if (!stream) {
453+
throw new IOException("Datagram socket creation not supported");
454+
}
454455
synchronized (stateLock) {
455456
if (state != ST_NEW)
456457
throw new IOException("Already created");
457458
FileDescriptor fd;
458459
if (server) {
459-
assert stream;
460-
fd = Net.serverSocket(true);
460+
fd = Net.serverSocket();
461461
} else {
462-
fd = Net.socket(stream);
462+
fd = Net.socket();
463463
}
464-
Runnable closer = closerFor(fd, stream);
464+
Runnable closer = closerFor(fd);
465465
this.fd = fd;
466-
this.stream = stream;
467466
this.cleaner = CleanerFactory.cleaner().register(this, closer);
468467
this.state = ST_UNCONNECTED;
469468
}
@@ -653,8 +652,6 @@ protected void listen(int backlog) throws IOException {
653652
private FileDescriptor beginAccept() throws SocketException {
654653
synchronized (stateLock) {
655654
ensureOpen();
656-
if (!stream)
657-
throw new SocketException("Not a stream socket");
658655
if (localport == 0)
659656
throw new SocketException("Not bound");
660657
readerThread = NativeThread.current();
@@ -764,10 +761,9 @@ protected void accept(SocketImpl si) throws IOException {
764761
}
765762

766763
// set the fields
767-
Runnable closer = closerFor(newfd, true);
764+
Runnable closer = closerFor(newfd);
768765
synchronized (nsi.stateLock) {
769766
nsi.fd = newfd;
770-
nsi.stream = true;
771767
nsi.cleaner = CleanerFactory.cleaner().register(nsi, closer);
772768
nsi.localport = localAddress.getPort();
773769
nsi.address = isaa[0].getAddress();
@@ -1187,24 +1183,14 @@ protected void sendUrgentData(int data) throws IOException {
11871183
/**
11881184
* Returns an action to close the given file descriptor.
11891185
*/
1190-
private static Runnable closerFor(FileDescriptor fd, boolean stream) {
1191-
if (stream) {
1192-
return () -> {
1193-
try {
1194-
nd.close(fd);
1195-
} catch (IOException ioe) {
1196-
throw new UncheckedIOException(ioe);
1197-
}
1198-
};
1199-
} else {
1200-
return () -> {
1201-
try {
1202-
nd.close(fd);
1203-
} catch (IOException ioe) {
1204-
throw new UncheckedIOException(ioe);
1205-
}
1206-
};
1207-
}
1186+
private static Runnable closerFor(FileDescriptor fd) {
1187+
return () -> {
1188+
try {
1189+
nd.close(fd);
1190+
} catch (IOException ioe) {
1191+
throw new UncheckedIOException(ioe);
1192+
}
1193+
};
12081194
}
12091195

12101196
/**

src/java.base/share/classes/sun/nio/ch/ServerSocketChannelImpl.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ class ServerSocketChannelImpl
132132
if (family == UNIX) {
133133
this.fd = UnixDomainSockets.socket();
134134
} else {
135-
this.fd = Net.serverSocket(family, true);
135+
this.fd = Net.serverSocket(family);
136136
}
137137
this.fdVal = IOUtil.fdVal(fd);
138138
}
Lines changed: 36 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -21,61 +21,52 @@
2121
* questions.
2222
*/
2323

24-
/**
25-
* @test
26-
* @run testng/othervm UdpSocket
27-
* @summary Basic test for a Socket to a UDP socket
28-
*/
29-
30-
import java.io.IOException;
3124
import java.net.InetAddress;
32-
import java.net.InetSocketAddress;
3325
import java.net.Socket;
34-
import java.net.SocketAddress;
35-
import java.nio.ByteBuffer;
36-
import java.nio.channels.DatagramChannel;
37-
import java.util.Arrays;
3826

3927
import org.testng.annotations.Test;
40-
import static org.testng.Assert.*;
28+
import static org.testng.Assert.fail;
4129

42-
@Test
30+
/*
31+
* @test
32+
* @summary Basic test for the UDP sockets through the java.net.Socket constructors
33+
* @run testng UdpSocket
34+
*/
4335
public class UdpSocket {
4436

45-
private static final int MAX_RETRIES = 3;
46-
4737
/**
48-
* Test using the Socket API to send/receive datagrams
38+
* Verifies that the {@code Socket} constructors that take the {@code stream}
39+
* parameter don't allow construction of UDP sockets.
4940
*/
50-
public void testSendReceive() throws IOException {
51-
final String MESSAGE = "hello";
52-
53-
try (DatagramChannel dc = DatagramChannel.open()) {
54-
var loopback = InetAddress.getLoopbackAddress();
55-
dc.bind(new InetSocketAddress(loopback, 0));
56-
57-
int port = ((InetSocketAddress) dc.getLocalAddress()).getPort();
58-
try (Socket s = new Socket(loopback, port, false)) {
59-
// send datagram with socket output stream
60-
byte[] array1 = MESSAGE.getBytes("UTF-8");
61-
s.getOutputStream().write(array1);
62-
63-
// receive the datagram
64-
var buf = ByteBuffer.allocate(100);
65-
SocketAddress remote = dc.receive(buf);
66-
buf.flip();
67-
assertTrue(buf.remaining() == MESSAGE.length(), "Unexpected size");
41+
@Test
42+
public void testUDPConstructors() throws Exception {
43+
try {
44+
new Socket("doesnotmatter", 12345, false);
45+
fail("Socket constructor was expected to throw IllegalArgumentException" +
46+
" for stream=false, but didn't");
47+
} catch (IllegalArgumentException iae) {
48+
// verify it's thrown for the right reason
49+
assertExceptionMessage(iae);
50+
}
6851

69-
// echo the datagram
70-
dc.send(buf, remote);
52+
try {
53+
new Socket(InetAddress.getLoopbackAddress(), 12345, false);
54+
fail("Socket constructor was expected to throw IllegalArgumentException" +
55+
" for stream=false, but didn't");
56+
} catch (IllegalArgumentException iae) {
57+
// verify it's thrown for the right reason
58+
assertExceptionMessage(iae);
59+
}
60+
}
7161

72-
// receive datagram with the socket input stream
73-
byte[] array2 = new byte[100];
74-
int n = s.getInputStream().read(array2);
75-
assertTrue(n == MESSAGE.length(), "Unexpected size");
76-
assertEquals(Arrays.copyOf(array1, n), Arrays.copyOf(array2, n),
77-
"Unexpected contents");
78-
}
62+
private static void assertExceptionMessage(final IllegalArgumentException iae) {
63+
final String msg = iae.getMessage();
64+
if (msg != null && msg.contains(
65+
"Socket constructor does not support creation of datagram socket")) {
66+
// contains the expected message
67+
return;
7968
}
69+
// unexpected exception message, propagate the original exception
70+
throw iae;
8071
}
8172
}

0 commit comments

Comments
 (0)