undefect. CWE-407 — 63 sites patched across 27 ecosystems
Authors: russell@unturf.com · brackishbert@gmail.com · foxhop.net · TimeHexOn.com Patches, unit tests, benchmarks, whitepaper, and outreach briefs. Public domain — no copyright claimed. Use freely.
This commit is contained in:
commit
0a580b313d
70422 changed files with 17213626 additions and 0 deletions
|
|
@ -0,0 +1,145 @@
|
|||
/*
|
||||
* Copyright (c) 2006, 2024, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* author Edward Wang
|
||||
*
|
||||
* @test
|
||||
* @bug 6368984
|
||||
* @key intermittent
|
||||
* @summary Configuring unconnected Socket before passing to implAccept
|
||||
* can cause fd leak.
|
||||
* This test may fail intermittently if foreign processes will
|
||||
* try to establish connection to the test server socket.
|
||||
* @requires os.family != "windows"
|
||||
* @requires vm.flagless
|
||||
* @library /test/lib
|
||||
* @build jdk.test.lib.Utils
|
||||
* jdk.test.lib.Asserts
|
||||
* jdk.test.lib.JDKToolFinder
|
||||
* jdk.test.lib.JDKToolLauncher
|
||||
* jdk.test.lib.Platform
|
||||
* jdk.test.lib.process.*
|
||||
* AcceptCauseFileDescriptorLeak
|
||||
* @run main/othervm AcceptCauseFileDescriptorLeak root
|
||||
*/
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.util.List;
|
||||
|
||||
import jdk.test.lib.JDKToolFinder;
|
||||
import jdk.test.lib.process.OutputAnalyzer;
|
||||
|
||||
public class AcceptCauseFileDescriptorLeak {
|
||||
private static final int REPS = 2048;
|
||||
private static final int THRESHOLD = 1024;
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
if (args.length != 0) {
|
||||
OutputAnalyzer analyzer = execCmd("ulimit -n -H");
|
||||
String output = analyzer.getOutput();
|
||||
if (output == null || output.length() == 0) {
|
||||
throw new RuntimeException("\"ulimit -n -H\" output nothing"
|
||||
+ " and its exit code is " + analyzer.getExitValue());
|
||||
} else {
|
||||
output = output.trim();
|
||||
// Set max open file descriptors to 1024
|
||||
// if it is unlimited or greater than 1024,
|
||||
// otherwise just do test directly
|
||||
if ("unlimited".equals(output)
|
||||
|| Integer.valueOf(output) > THRESHOLD) {
|
||||
analyzer = execCmd("ulimit -n " + THRESHOLD + "; "
|
||||
+ composeJavaTestStr());
|
||||
System.out.println("Output: ["
|
||||
+ analyzer.getOutput() + "]");
|
||||
int rc = analyzer.getExitValue();
|
||||
if (rc != 0) {
|
||||
throw new RuntimeException(
|
||||
"Unexpected exit code: " + rc);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final ServerSocket ss = new ServerSocket() {
|
||||
public Socket accept() throws IOException {
|
||||
Socket s = new Socket() {
|
||||
};
|
||||
s.setSoTimeout(10000);
|
||||
implAccept(s);
|
||||
return s;
|
||||
}
|
||||
};
|
||||
ss.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0));
|
||||
Thread t = new Thread(new Runnable() {
|
||||
public void run() {
|
||||
int repsCompleted = 0;
|
||||
try {
|
||||
for (; repsCompleted < REPS; repsCompleted++) {
|
||||
(new Socket(InetAddress.getLoopbackAddress(), ss.getLocalPort())).close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
System.out.println("Client iterations completed:" + repsCompleted);
|
||||
}
|
||||
}
|
||||
});
|
||||
t.start();
|
||||
int repsCompleted = 0;
|
||||
try {
|
||||
for (; repsCompleted < REPS; repsCompleted++) {
|
||||
ss.accept().close();
|
||||
}
|
||||
} finally {
|
||||
System.out.println("Server iterations completed:" + repsCompleted);
|
||||
ss.close();
|
||||
}
|
||||
t.join();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute command with shell
|
||||
*
|
||||
* @param command
|
||||
* @return OutputAnalyzer
|
||||
* @throws IOException
|
||||
*/
|
||||
static OutputAnalyzer execCmd(String command) throws IOException {
|
||||
List<String> cmd = List.of("sh", "-c", command);
|
||||
System.out.println("Executing: " + cmd);
|
||||
ProcessBuilder pb = new ProcessBuilder(cmd);
|
||||
return new OutputAnalyzer(pb.start());
|
||||
}
|
||||
|
||||
static String composeJavaTestStr() {
|
||||
return JDKToolFinder.getTestJDKTool("java") + " "
|
||||
+ AcceptCauseFileDescriptorLeak.class.getName();
|
||||
}
|
||||
}
|
||||
|
||||
158
test/jdk/java/net/ServerSocket/AcceptInheritHandle.java
Normal file
158
test/jdk/java/net/ServerSocket/AcceptInheritHandle.java
Normal file
|
|
@ -0,0 +1,158 @@
|
|||
/*
|
||||
* Copyright (c) 2015, 2024, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8067105
|
||||
* @library /test/lib
|
||||
* @summary Socket returned by ServerSocket.accept() is inherited by child process on Windows
|
||||
* @author Chris Hegarty
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
import java.net.*;
|
||||
import java.nio.channels.ServerSocketChannel;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Supplier;
|
||||
import jdk.test.lib.net.IPSupport;
|
||||
import jdk.test.lib.process.ProcessTools;
|
||||
|
||||
public class AcceptInheritHandle {
|
||||
|
||||
enum ServerSocketProducer {
|
||||
JAVA_NET(() -> {
|
||||
try {
|
||||
return new ServerSocket();
|
||||
} catch(IOException x) {
|
||||
throw new UncheckedIOException(x);
|
||||
}
|
||||
}),
|
||||
NIO_CHANNELS(() -> {
|
||||
try {
|
||||
return ServerSocketChannel.open().socket();
|
||||
} catch (IOException x) {
|
||||
throw new UncheckedIOException(x);
|
||||
}
|
||||
});
|
||||
|
||||
final Supplier<ServerSocket> supplier;
|
||||
ServerSocketProducer(Supplier<ServerSocket> supplier) {
|
||||
this.supplier = supplier;
|
||||
}
|
||||
Supplier<ServerSocket> supplier () { return supplier; }
|
||||
}
|
||||
|
||||
static final String JAVA = System.getProperty("java.home")
|
||||
+ File.separator + "bin" + File.separator + "java";
|
||||
|
||||
static final String CLASSPATH = System.getProperty("java.class.path");
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
if (args.length == 1)
|
||||
server(ServerSocketProducer.valueOf(args[0]));
|
||||
else
|
||||
mainEntry();
|
||||
}
|
||||
|
||||
static void mainEntry() throws Exception {
|
||||
testJavaNetServerSocket();
|
||||
testNioServerSocketChannel();
|
||||
}
|
||||
|
||||
static void testJavaNetServerSocket() throws Exception {
|
||||
test(ServerSocketProducer.JAVA_NET);
|
||||
if (IPSupport.hasIPv4()) {
|
||||
test(ServerSocketProducer.JAVA_NET, "-Djava.net.preferIPv4Stack=true");
|
||||
}
|
||||
}
|
||||
static void testNioServerSocketChannel() throws Exception {
|
||||
test(ServerSocketProducer.NIO_CHANNELS);
|
||||
}
|
||||
|
||||
static void test(ServerSocketProducer ssp, String... jvmArgs) throws Exception {
|
||||
System.out.println("\nStarting test for " + ssp.name());
|
||||
|
||||
List<String> commands = new ArrayList<>();
|
||||
Collections.addAll(commands, jvmArgs);
|
||||
commands.add("AcceptInheritHandle");
|
||||
commands.add(ssp.name());
|
||||
|
||||
System.out.println("Executing: "+ commands);
|
||||
ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder(commands);
|
||||
pb.redirectError(ProcessBuilder.Redirect.INHERIT);
|
||||
Process serverProcess = pb.start();
|
||||
DataInputStream dis = new DataInputStream(serverProcess.getInputStream());
|
||||
|
||||
int port = dis.readInt();
|
||||
System.out.println("Server process listening on " + port + ", connecting...");
|
||||
|
||||
String address;
|
||||
if (Arrays.stream(jvmArgs).anyMatch("-Djava.net.preferIPv4Stack=true"::equals)) {
|
||||
address = "127.0.0.1";
|
||||
} else {
|
||||
InetAddress loopback = InetAddress.getLoopbackAddress();
|
||||
address = loopback.getHostAddress();
|
||||
}
|
||||
Socket socket = new Socket(address, port);
|
||||
String s = dis.readUTF();
|
||||
System.out.println("Server process said " + s);
|
||||
|
||||
serverProcess.destroy();
|
||||
serverProcess.waitFor(30, TimeUnit.SECONDS);
|
||||
System.out.println("serverProcess exitCode:" + serverProcess.exitValue());
|
||||
|
||||
try {
|
||||
socket.setSoTimeout(10 * 1000);
|
||||
socket.getInputStream().read();
|
||||
} catch (SocketTimeoutException x) {
|
||||
// failed
|
||||
throw new RuntimeException("Failed: should get reset, not " + x);
|
||||
} catch (SocketException x) {
|
||||
System.out.println("Expected:" + x);
|
||||
}
|
||||
}
|
||||
|
||||
static void server(ServerSocketProducer producer) throws Exception {
|
||||
try (ServerSocket ss = producer.supplier().get()) {
|
||||
InetAddress loopback = InetAddress.getLoopbackAddress();
|
||||
ss.bind(new InetSocketAddress(loopback, 0));
|
||||
int port = ss.getLocalPort();
|
||||
DataOutputStream dos = new DataOutputStream(System.out);
|
||||
dos.writeInt(port);
|
||||
dos.flush();
|
||||
|
||||
ss.accept(); // do not close
|
||||
|
||||
Runtime.getRuntime().exec("sleep 20");
|
||||
Thread.sleep(3 * 1000);
|
||||
|
||||
dos.writeUTF("kill me!");
|
||||
dos.flush();
|
||||
Thread.sleep(30 * 1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
75
test/jdk/java/net/ServerSocket/AnotherSelectFdsLimit.java
Normal file
75
test/jdk/java/net/ServerSocket/AnotherSelectFdsLimit.java
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* Copyright (c) 2014, 2025, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8035897
|
||||
* @summary FD_SETSIZE should be set on macosx
|
||||
* @requires os.family == "mac"
|
||||
* @run main/othervm AnotherSelectFdsLimit 1023
|
||||
* @run main/othervm AnotherSelectFdsLimit 1024
|
||||
* @run main/othervm AnotherSelectFdsLimit 1025
|
||||
* @run main/othervm AnotherSelectFdsLimit 1600
|
||||
*/
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class AnotherSelectFdsLimit {
|
||||
static final int DEFAULT_FDS_TO_USE = 1600;
|
||||
|
||||
public static void main(String [] args) throws Exception {
|
||||
|
||||
int fdsToUse = DEFAULT_FDS_TO_USE;
|
||||
if (args.length == 1)
|
||||
fdsToUse = Integer.parseInt(args[0]);
|
||||
|
||||
System.out.println("Using " + fdsToUse + " fds.");
|
||||
|
||||
List<Thread> threads = new ArrayList<>();
|
||||
for (int i=0; i<fdsToUse; i++)
|
||||
threads.add(new WorkerThread());
|
||||
|
||||
for (Thread t : threads)
|
||||
t.start();
|
||||
|
||||
for (Thread t : threads)
|
||||
t.join();
|
||||
}
|
||||
|
||||
static class WorkerThread extends Thread {
|
||||
public void run() {
|
||||
try (ServerSocket ss = new ServerSocket(0)) {
|
||||
ss.setSoTimeout(2000);
|
||||
ss.accept();
|
||||
} catch (SocketTimeoutException x) {
|
||||
// expected
|
||||
} catch (IOException x) {
|
||||
throw new java.io.UncheckedIOException(x);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
123
test/jdk/java/net/ServerSocket/ClosedServerSocketTest.java
Normal file
123
test/jdk/java/net/ServerSocket/ClosedServerSocketTest.java
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
/*
|
||||
* Copyright (c) 2024, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.SocketException;
|
||||
import java.net.StandardSocketOptions;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrowsExactly;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @summary verifies that the APIs on java.net.ServerSocket throw expected exceptions
|
||||
* when invoked on a closed ServerSocket
|
||||
* @run junit ClosedServerSocketTest
|
||||
*/
|
||||
public class ClosedServerSocketTest {
|
||||
|
||||
private static final InetAddress loopback = InetAddress.getLoopbackAddress();
|
||||
private static final InetSocketAddress loopbackEphemeral = new InetSocketAddress(loopback, 0);
|
||||
|
||||
/**
|
||||
* Verifies that various operations that specify to throw an IOException on a
|
||||
* closed ServerSocket, do indeed throw it.
|
||||
*/
|
||||
@Test
|
||||
public void testIOExceptionThrown() throws Exception {
|
||||
try (final ServerSocket ss = new ServerSocket()) {
|
||||
// close and then invoke the operations on the ServerSocket
|
||||
ss.close();
|
||||
assertTrue(ss.isClosed(), "ServerSocket isn't closed");
|
||||
assertThrows(IOException.class,
|
||||
ss::accept,
|
||||
"accept() when already closed didn't throw IOException");
|
||||
assertThrows(IOException.class,
|
||||
() -> ss.bind(loopbackEphemeral),
|
||||
"bind() when already closed didn't throw IOException");
|
||||
assertThrows(IOException.class,
|
||||
() -> ss.bind(loopbackEphemeral, 10),
|
||||
"bind(SocketAddress, int) when already closed didn't throw IOException");
|
||||
assertThrows(IOException.class,
|
||||
() -> ss.getOption(StandardSocketOptions.SO_RCVBUF),
|
||||
"getOption() when already closed didn't throw IOException");
|
||||
assertThrows(IOException.class,
|
||||
ss::getSoTimeout,
|
||||
"getSoTimeout() when already closed didn't throw IOException");
|
||||
assertThrows(IOException.class,
|
||||
() -> ss.setOption(StandardSocketOptions.SO_RCVBUF, 1024),
|
||||
"setOption() when already closed didn't throw IOException");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that various operations that specify to throw a SocketOperation on a
|
||||
* closed ServerSocket, do indeed throw it.
|
||||
*/
|
||||
@Test
|
||||
public void testSocketExceptionThrown() throws Exception {
|
||||
try (final ServerSocket ss = new ServerSocket()) {
|
||||
// close and then invoke the operations on the ServerSocket
|
||||
ss.close();
|
||||
assertTrue(ss.isClosed(), "ServerSocket isn't closed");
|
||||
assertThrowsExactly(SocketException.class,
|
||||
ss::getReceiveBufferSize,
|
||||
"getReceiveBufferSize() when already closed didn't throw SocketException");
|
||||
assertThrowsExactly(SocketException.class,
|
||||
ss::getReuseAddress,
|
||||
"getReuseAddress() when already closed didn't throw SocketException");
|
||||
assertThrowsExactly(SocketException.class,
|
||||
() -> ss.setReceiveBufferSize(1024),
|
||||
"setReceiveBufferSize() when already closed didn't throw SocketException");
|
||||
assertThrowsExactly(SocketException.class,
|
||||
() -> ss.setReuseAddress(false),
|
||||
"setReuseAddress() when already closed didn't throw SocketException");
|
||||
assertThrowsExactly(SocketException.class,
|
||||
() -> ss.setSoTimeout(1000),
|
||||
"setSoTimeout() when already closed didn't throw SocketException");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that various operations that aren't expected to throw an exception on a
|
||||
* closed ServerSocket, complete normally.
|
||||
*/
|
||||
@Test
|
||||
public void testNoExceptionThrown() throws Exception {
|
||||
try (final ServerSocket ss = new ServerSocket()) {
|
||||
// close and then invoke the operations on the ServerSocket
|
||||
ss.close();
|
||||
assertTrue(ss.isClosed(), "ServerSocket isn't closed");
|
||||
ss.getInetAddress();
|
||||
ss.getLocalPort();
|
||||
ss.getLocalSocketAddress();
|
||||
ss.isBound();
|
||||
ss.supportedOptions();
|
||||
}
|
||||
}
|
||||
}
|
||||
293
test/jdk/java/net/ServerSocket/ImplAccept.java
Normal file
293
test/jdk/java/net/ServerSocket/ImplAccept.java
Normal file
|
|
@ -0,0 +1,293 @@
|
|||
/*
|
||||
* Copyright (c) 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8278326
|
||||
* @modules java.base/java.net:+open
|
||||
* @run junit ImplAccept
|
||||
* @summary Test ServerSocket.implAccept with a Socket in different states.
|
||||
*/
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.net.SocketImpl;
|
||||
import java.net.SocketOption;
|
||||
import java.net.StandardSocketOptions;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.junit.*;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class ImplAccept {
|
||||
|
||||
/**
|
||||
* Test ServerSocket.implAccept with an unbound Socket.
|
||||
*/
|
||||
@Test
|
||||
public void testUnbound() throws Exception {
|
||||
try (Socket socket = new Socket()) {
|
||||
|
||||
// Socket.impl -> DelegatingSocketImpl
|
||||
SocketImpl si = getSocketImpl(socket);
|
||||
assertTrue(isDelegatingSocketImpl(si));
|
||||
|
||||
try (ServerSocket ss = serverSocketToAccept(socket);
|
||||
Socket peer = new Socket(ss.getInetAddress(), ss.getLocalPort())) {
|
||||
|
||||
Socket s = ss.accept();
|
||||
assertTrue(s == socket);
|
||||
|
||||
// Socket.impl should be replaced with a new PlatformSocketImpl
|
||||
SocketImpl psi = getSocketImpl(socket);
|
||||
assertTrue(isPlatformSocketImpl(psi));
|
||||
|
||||
// socket and peer should be connected to each other
|
||||
pingPong(socket, peer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test ServerSocket.implAccept with a bound Socket. The usage is nonsensical
|
||||
* but we can test that the accepted Socket is connected and the underlying
|
||||
* socket from the original SocketImpl is closed.
|
||||
*/
|
||||
@Test
|
||||
public void testBound() throws Exception {
|
||||
try (Socket socket = new Socket()) {
|
||||
|
||||
// Socket.impl -> DelegatingSocketImpl -> PlatformSocketImpl
|
||||
SocketImpl si = getSocketImpl(socket);
|
||||
SocketImpl psi1 = getDelegate(si);
|
||||
assertTrue(isPlatformSocketImpl(psi1));
|
||||
|
||||
// bind to local address
|
||||
socket.bind(loopbackSocketAddress());
|
||||
assertTrue(isSocketOpen(psi1));
|
||||
|
||||
try (ServerSocket ss = serverSocketToAccept(socket);
|
||||
Socket peer = new Socket(ss.getInetAddress(), ss.getLocalPort())) {
|
||||
|
||||
Socket s = ss.accept();
|
||||
assertTrue(s == socket);
|
||||
|
||||
// Socket.impl should be replaced with a new PlatformSocketImpl
|
||||
SocketImpl psi2 = getSocketImpl(socket);
|
||||
assertTrue(isPlatformSocketImpl(psi2));
|
||||
|
||||
// psi1 should be closed
|
||||
assertFalse(isSocketOpen(psi1));
|
||||
|
||||
// socket and peer should be connected to each other
|
||||
pingPong(socket, peer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test ServerSocket.implAccept with a connected Socket. The usage is nonsensical
|
||||
* but we can test that the accepted Socket is connected and the underlying
|
||||
* socket from the original SocketImpl is closed.
|
||||
*/
|
||||
@Test
|
||||
public void testConnected() throws Exception {
|
||||
Socket socket;
|
||||
Socket peer1;
|
||||
try (ServerSocket ss = new ServerSocket()) {
|
||||
ss.bind(loopbackSocketAddress());
|
||||
socket = new Socket(ss.getInetAddress(), ss.getLocalPort());
|
||||
peer1 = ss.accept();
|
||||
}
|
||||
|
||||
try {
|
||||
// Socket.impl -> DelegatingSocketImpl -> PlatformSocketImpl
|
||||
SocketImpl si = getSocketImpl(socket);
|
||||
SocketImpl psi1 = getDelegate(si);
|
||||
assertTrue(isPlatformSocketImpl(psi1));
|
||||
|
||||
try (ServerSocket ss = serverSocketToAccept(socket);
|
||||
Socket peer2 = new Socket(ss.getInetAddress(), ss.getLocalPort())) {
|
||||
|
||||
Socket s = ss.accept();
|
||||
assertTrue(s == socket);
|
||||
|
||||
// Socket.impl should be replaced with a new PlatformSocketImpl
|
||||
SocketImpl psi2 = getSocketImpl(socket);
|
||||
assertTrue(isPlatformSocketImpl(psi2));
|
||||
|
||||
// psi1 should be closed and peer1 should read EOF
|
||||
assertFalse(isSocketOpen(psi1));
|
||||
assertTrue(peer1.getInputStream().read() == -1);
|
||||
|
||||
// socket and peer2 should be connected to each other
|
||||
pingPong(socket, peer2);
|
||||
}
|
||||
} finally {
|
||||
socket.close();
|
||||
peer1.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test ServerSocket.implAccept with a closed Socket. The usage is nonsensical
|
||||
* but we can test ServerSocket.accept throws and that it closes the connection
|
||||
* to the peer.
|
||||
*/
|
||||
@Test
|
||||
public void testClosed() throws Exception {
|
||||
Socket socket = new Socket();
|
||||
socket.close();
|
||||
|
||||
try (ServerSocket ss = serverSocketToAccept(socket);
|
||||
Socket peer = new Socket(ss.getInetAddress(), ss.getLocalPort())) {
|
||||
|
||||
SocketImpl si = getSocketImpl(socket);
|
||||
|
||||
// accept should throw and peer should read EOF
|
||||
assertThrows(IOException.class, ss::accept);
|
||||
assertTrue(peer.getInputStream().read() == -1);
|
||||
|
||||
// the SocketImpl should have not changed
|
||||
assertTrue(getSocketImpl(socket) == si);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the socket's SocketImpl.
|
||||
*/
|
||||
private static SocketImpl getSocketImpl(Socket s) {
|
||||
try {
|
||||
Field f = Socket.class.getDeclaredField("impl");
|
||||
f.setAccessible(true);
|
||||
return (SocketImpl) f.get(s);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the SocketImpl that the given SocketImpl delegates to.
|
||||
*/
|
||||
private static SocketImpl getDelegate(SocketImpl si) {
|
||||
try {
|
||||
Class<?> clazz = Class.forName("java.net.DelegatingSocketImpl");
|
||||
Field f = clazz.getDeclaredField("delegate");
|
||||
f.setAccessible(true);
|
||||
return (SocketImpl) f.get(si);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the SocketImpl is a DelegatingSocketImpl.
|
||||
*/
|
||||
private static boolean isDelegatingSocketImpl(SocketImpl si) {
|
||||
try {
|
||||
Class<?> clazz = Class.forName("java.net.DelegatingSocketImpl");
|
||||
return clazz.isInstance(si);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the SocketImpl is a PlatformSocketImpl.
|
||||
*/
|
||||
private static boolean isPlatformSocketImpl(SocketImpl si) {
|
||||
try {
|
||||
Class<?> clazz = Class.forName("sun.net.PlatformSocketImpl");
|
||||
return clazz.isInstance(si);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the SocketImpl has an open socket.
|
||||
*/
|
||||
private static boolean isSocketOpen(SocketImpl si) throws Exception {
|
||||
assertTrue(isPlatformSocketImpl(si));
|
||||
|
||||
// check if SocketImpl.fd is set
|
||||
Field f = SocketImpl.class.getDeclaredField("fd");
|
||||
f.setAccessible(true);
|
||||
FileDescriptor fd = (FileDescriptor) f.get(si);
|
||||
if (fd == null) {
|
||||
return false; // not created
|
||||
}
|
||||
|
||||
// call getOption to get the value of the SO_REUSEADDR socket option
|
||||
Method m = SocketImpl.class.getDeclaredMethod("getOption", SocketOption.class);
|
||||
m.setAccessible(true);
|
||||
try {
|
||||
m.invoke(si, StandardSocketOptions.SO_REUSEADDR);
|
||||
return true; // socket is open
|
||||
} catch (InvocationTargetException e) {
|
||||
if (e.getCause() instanceof IOException) {
|
||||
return false; // assume socket is closed
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that two sockets are connected to each other.
|
||||
*/
|
||||
private static void pingPong(Socket s1, Socket s2) throws Exception {
|
||||
s1.getOutputStream().write(11);
|
||||
s2.getOutputStream().write(22);
|
||||
assertTrue(s1.getInputStream().read() == 22);
|
||||
assertTrue(s2.getInputStream().read() == 11);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a ServerSocket that returns the given Socket from accept.
|
||||
*/
|
||||
private static ServerSocket serverSocketToAccept(Socket s) throws IOException {
|
||||
ServerSocket ss = new ServerSocket() {
|
||||
@Override
|
||||
public Socket accept() throws IOException {
|
||||
implAccept(s);
|
||||
return s;
|
||||
}
|
||||
};
|
||||
ss.bind(loopbackSocketAddress());
|
||||
return ss;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new InetSocketAddress with the loopback interface and port 0.
|
||||
*/
|
||||
private static InetSocketAddress loopbackSocketAddress() {
|
||||
InetAddress loopback = InetAddress.getLoopbackAddress();
|
||||
return new InetSocketAddress(loopback, 0);
|
||||
}
|
||||
}
|
||||
81
test/jdk/java/net/ServerSocket/IsClosedAfterAsyncClose.java
Normal file
81
test/jdk/java/net/ServerSocket/IsClosedAfterAsyncClose.java
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* Copyright (c) 2021, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @bug 8278339
|
||||
* @summary Test that ServerSocket::isClosed returns true after async close
|
||||
*/
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
|
||||
public class IsClosedAfterAsyncClose {
|
||||
|
||||
private static final int ITERATIONS = 100;
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
for (int i = 0; i < ITERATIONS; i++) {
|
||||
System.out.printf("Test %d...%n", i);
|
||||
|
||||
// create listener bound to the loopback address
|
||||
ServerSocket listener = new ServerSocket();
|
||||
InetAddress loopback = InetAddress.getLoopbackAddress();
|
||||
listener.bind(new InetSocketAddress(loopback, 0));
|
||||
|
||||
// task to close listener after a delay
|
||||
Runnable closeListener = () -> {
|
||||
try {
|
||||
Thread.sleep(100);
|
||||
listener.close();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
};
|
||||
|
||||
// main thread blocks in accept. When listener is closed then accept
|
||||
// should wakeup with an IOException and isClosed should be true.
|
||||
try (listener) {
|
||||
Thread closer = new Thread(closeListener);
|
||||
closer.start();
|
||||
try {
|
||||
while (true) {
|
||||
Socket s = listener.accept();
|
||||
// close spurious connection
|
||||
s.close();
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
if (!listener.isClosed()) {
|
||||
throw new RuntimeException("isClosed returned false!!");
|
||||
}
|
||||
} finally {
|
||||
closer.join();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
110
test/jdk/java/net/ServerSocket/LargeBacklogTest.java
Normal file
110
test/jdk/java/net/ServerSocket/LargeBacklogTest.java
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
/*
|
||||
* Copyright (c) 2025, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.nio.channels.AsynchronousServerSocketChannel;
|
||||
import java.nio.channels.ServerSocketChannel;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8330940
|
||||
* @summary verify that java.net.ServerSocket and the server socket channels in java.nio.channels
|
||||
* when configured with a backlog of >=200 on Windows, will allow for those many
|
||||
* backlogged Socket connections
|
||||
* @requires os.family == "windows"
|
||||
* @run junit LargeBacklogTest
|
||||
*/
|
||||
class LargeBacklogTest {
|
||||
|
||||
@Test
|
||||
void testServerSocket() throws Exception {
|
||||
final int backlog = 242;
|
||||
// Create a ServerSocket configured with the given backlog.
|
||||
// The ServerSocket never accept()s a connection so each connect() attempt
|
||||
// will be backlogged.
|
||||
try (var server = new ServerSocket(0, backlog, InetAddress.getLoopbackAddress())) {
|
||||
final int serverPort = server.getLocalPort();
|
||||
testBackloggedConnects(backlog, serverPort);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testServerSocketChannel() throws Exception {
|
||||
final int backlog = 213;
|
||||
// Create a ServerSocketChannel configured with the given backlog.
|
||||
// The channel never accept()s a connection so each connect() attempt
|
||||
// will be backlogged.
|
||||
try (var serverChannel = ServerSocketChannel.open()) {
|
||||
serverChannel.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0), backlog);
|
||||
final int serverPort = ((InetSocketAddress) serverChannel.getLocalAddress()).getPort();
|
||||
testBackloggedConnects(backlog, serverPort);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAsynchronousServerSocketChannel() throws Exception {
|
||||
final int backlog = 209;
|
||||
// Create a AsynchronousServerSocketChannel configured with the given backlog.
|
||||
// The channel never accept()s a connection so each connect() attempt
|
||||
// will be backlogged.
|
||||
try (var serverChannel = AsynchronousServerSocketChannel.open()) {
|
||||
serverChannel.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0), backlog);
|
||||
final int serverPort = ((InetSocketAddress) serverChannel.getLocalAddress()).getPort();
|
||||
testBackloggedConnects(backlog, serverPort);
|
||||
}
|
||||
}
|
||||
|
||||
private static void testBackloggedConnects(final int backlog, final int serverPort) {
|
||||
int numSuccessfulConnects = 0;
|
||||
System.err.println("attempting " + backlog + " connections to port " + serverPort);
|
||||
// attempt the Socket connections
|
||||
for (int i = 1; i <= backlog; i++) {
|
||||
try (final Socket sock = new Socket(InetAddress.getLoopbackAddress(), serverPort)) {
|
||||
numSuccessfulConnects++;
|
||||
System.err.println("connection " + i + " established " + sock);
|
||||
} catch (IOException ioe) {
|
||||
System.err.println("connection attempt " + i + " failed: " + ioe);
|
||||
// do not attempt any more connections
|
||||
break;
|
||||
}
|
||||
}
|
||||
System.err.println(numSuccessfulConnects + " connections successfully established");
|
||||
// ideally we expect the number of successful connections to be equal to the backlog value.
|
||||
// however in certain environments, it's possible that some other process attempts a
|
||||
// connection to the server's port. so we allow for a small number of connection attempts
|
||||
// to fail (due to exceeding the backlog)
|
||||
final int minimumExpectedSuccessfulConns = backlog - 5;
|
||||
if (numSuccessfulConnects < minimumExpectedSuccessfulConns) {
|
||||
fail("expected at least " + minimumExpectedSuccessfulConns
|
||||
+ " successful connections for a backlog of " + backlog + ", but only "
|
||||
+ numSuccessfulConnects + " were successful");
|
||||
}
|
||||
}
|
||||
}
|
||||
42
test/jdk/java/net/ServerSocket/NullConstructor.java
Normal file
42
test/jdk/java/net/ServerSocket/NullConstructor.java
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright (c) 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @bug 8223457
|
||||
* @run main NullConstructor
|
||||
* @summary java.net.ServerSocket protected constructor should throw NPE if impl null
|
||||
*/
|
||||
|
||||
import java.net.ServerSocket;
|
||||
import java.net.SocketImpl;
|
||||
|
||||
public class NullConstructor {
|
||||
|
||||
public static void main(String args[]) throws Exception {
|
||||
try {
|
||||
ServerSocket server = new ServerSocket((SocketImpl)null) {};
|
||||
throw new RuntimeException("Test failed");
|
||||
} catch (NullPointerException ee) {}
|
||||
}
|
||||
}
|
||||
98
test/jdk/java/net/ServerSocket/SelectFdsLimit.java
Normal file
98
test/jdk/java/net/ServerSocket/SelectFdsLimit.java
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
* Copyright (c) 2013, 2025, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8021820
|
||||
* @summary The total number of file descriptors is limited to
|
||||
* 1024(FDSET_SIZE) on MacOSX (the size of fd array passed to select()
|
||||
* call in java.net classes is limited to this value).
|
||||
* @requires os.family == "mac"
|
||||
* @run main/othervm SelectFdsLimit
|
||||
* @author aleksej.efimov@oracle.com
|
||||
*/
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.SocketTimeoutException;
|
||||
|
||||
|
||||
/*
|
||||
* Test must be run in othervm mode to ensure that all files
|
||||
* opened by openFiles() are closed propertly.
|
||||
*/
|
||||
public class SelectFdsLimit {
|
||||
static final int FDTOOPEN = 1023;
|
||||
static final String TESTFILE = "testfile";
|
||||
static FileInputStream [] testFIS;
|
||||
|
||||
static void prepareTestEnv() throws IOException {
|
||||
File fileToCreate = new File(TESTFILE);
|
||||
if (!fileToCreate.exists())
|
||||
if (!fileToCreate.createNewFile())
|
||||
throw new RuntimeException("Can't create test file");
|
||||
}
|
||||
|
||||
//If there will be some problem (i.e. ulimits on number of opened files will fail)
|
||||
//then this method will fail with exception and test will be considered as
|
||||
//failed. But allocated fds will be released because the test is executed by
|
||||
//dedicated VM (@run main/othervm).
|
||||
static void openFiles(int fn, File f) throws FileNotFoundException, IOException {
|
||||
testFIS = new FileInputStream[FDTOOPEN];
|
||||
for (;;) {
|
||||
if (0 == fn)
|
||||
break;
|
||||
FileInputStream fis = new FileInputStream(f);
|
||||
testFIS[--fn] = fis;
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String [] args) throws IOException, FileNotFoundException {
|
||||
|
||||
//Create test directory with test files
|
||||
prepareTestEnv();
|
||||
|
||||
//Consume FD ids for this java process to overflow the 1024
|
||||
openFiles(FDTOOPEN,new File(TESTFILE));
|
||||
|
||||
//Wait for incoming connection and make the select() used in java.net
|
||||
//classes fail the limitation on FDSET_SIZE
|
||||
ServerSocket socket = new ServerSocket(0);
|
||||
|
||||
//Set the minimal timeout, no one is
|
||||
//going to connect to this server socket
|
||||
socket.setSoTimeout(1);
|
||||
|
||||
// The accept() call will throw SocketException if the
|
||||
// select() has failed due to limitation on fds size,
|
||||
// indicating test failure. A SocketTimeoutException
|
||||
// is expected, so it is caught and ignored, and the test
|
||||
// passes.
|
||||
try {
|
||||
socket.accept();
|
||||
} catch (SocketTimeoutException e) { }
|
||||
}
|
||||
}
|
||||
80
test/jdk/java/net/ServerSocket/TestAfterClose.java
Normal file
80
test/jdk/java/net/ServerSocket/TestAfterClose.java
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* Copyright (c) 2007, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 6505016
|
||||
* @summary Socket spec should clarify what getInetAddress/getPort/etc return after the Socket is closed
|
||||
*/
|
||||
|
||||
import java.net.*;
|
||||
import java.io.*;
|
||||
|
||||
public class TestAfterClose
|
||||
{
|
||||
static int failCount;
|
||||
|
||||
public static void main(String[] args) {
|
||||
try {
|
||||
ServerSocket ss = new ServerSocket(0, 0, null);
|
||||
test(ss);
|
||||
} catch (IOException ioe) {
|
||||
ioe.printStackTrace();
|
||||
}
|
||||
|
||||
if (failCount > 0)
|
||||
throw new RuntimeException("Failed: failcount = " + failCount);
|
||||
|
||||
}
|
||||
|
||||
static void test(ServerSocket ss) throws IOException {
|
||||
//Before Close
|
||||
InetAddress ssInetAddress = ss.getInetAddress();
|
||||
int ssLocalPort = ss.getLocalPort();
|
||||
SocketAddress ssLocalSocketAddress = ss.getLocalSocketAddress();
|
||||
|
||||
//After Close
|
||||
ss.close();
|
||||
|
||||
if (ssLocalPort != ss.getLocalPort()) {
|
||||
System.out.println("ServerSocket.getLocalPort failed");
|
||||
failCount++;
|
||||
}
|
||||
|
||||
if (!ss.getInetAddress().equals(ssInetAddress)) {
|
||||
System.out.println("ServerSocket.getInetAddress failed");
|
||||
failCount++;
|
||||
}
|
||||
|
||||
if (!ss.getLocalSocketAddress().equals(ssLocalSocketAddress)) {
|
||||
System.out.println("ServerSocket.getLocalSocketAddress failed");
|
||||
failCount++;
|
||||
}
|
||||
|
||||
if (!ss.isBound()) {
|
||||
System.out.println("ServerSocket.isBound failed");
|
||||
failCount++;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
288
test/jdk/java/net/ServerSocket/UnreferencedSockets.java
Normal file
288
test/jdk/java/net/ServerSocket/UnreferencedSockets.java
Normal file
|
|
@ -0,0 +1,288 @@
|
|||
/*
|
||||
* Copyright (c) 2017, 2025, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @library /test/lib
|
||||
* @modules java.management java.base/java.io:+open java.base/java.net:+open
|
||||
* @run main/othervm/timeout=480 UnreferencedSockets
|
||||
* @run main/othervm/timeout=480 -Djava.net.preferIPv4Stack=true UnreferencedSockets
|
||||
* @summary Check that unreferenced sockets are closed
|
||||
*/
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.lang.management.OperatingSystemMXBean;
|
||||
import java.lang.ref.ReferenceQueue;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.lang.reflect.Field;
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.net.SocketImpl;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import com.sun.management.UnixOperatingSystemMXBean;
|
||||
|
||||
import jdk.test.lib.net.IPSupport;
|
||||
|
||||
public class UnreferencedSockets {
|
||||
|
||||
/**
|
||||
* The set of sockets we have to check up on.
|
||||
*/
|
||||
final static ArrayDeque<NamedWeak> pendingSockets = new ArrayDeque<>(100);
|
||||
|
||||
/**
|
||||
* Queued sockets when they are unreferenced.
|
||||
*/
|
||||
final static ReferenceQueue<Object> pendingQueue = new ReferenceQueue<>();
|
||||
|
||||
// Server to echo a stream
|
||||
static class Server implements Runnable {
|
||||
|
||||
ServerSocket ss;
|
||||
|
||||
Server(InetAddress address) throws IOException {
|
||||
ss = new ServerSocket(0, 0, address);
|
||||
pendingSockets.add(new NamedWeak(ss, pendingQueue, "serverSocket"));
|
||||
extractRefs(ss, "serverSocket");
|
||||
}
|
||||
|
||||
public int localPort() {
|
||||
return ss.getLocalPort();
|
||||
}
|
||||
|
||||
public void run() {
|
||||
try {
|
||||
Socket s = ss.accept();
|
||||
pendingSockets.add(new NamedWeak(s, pendingQueue, "acceptedSocket"));
|
||||
extractRefs(s, "acceptedSocket");
|
||||
|
||||
InputStream in = s.getInputStream();
|
||||
int b = in.read();
|
||||
OutputStream out = s.getOutputStream();
|
||||
out.write(b);
|
||||
// do NOT close but 'forget' the socket reference
|
||||
out = null;
|
||||
in = null;
|
||||
s = null;
|
||||
} catch (Exception ioe) {
|
||||
ioe.printStackTrace();
|
||||
} finally {
|
||||
try {
|
||||
ss.close();
|
||||
ss = null;
|
||||
} catch (IOException x) {
|
||||
x.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String args[]) throws Exception {
|
||||
IPSupport.throwSkippedExceptionIfNonOperational();
|
||||
InetAddress lba = InetAddress.getLoopbackAddress();
|
||||
// Create and close a ServerSocket to warm up the FD count for side effects.
|
||||
try (ServerSocket s = new ServerSocket(0, 0, lba)) {
|
||||
// no-op; close immediately
|
||||
s.getLocalPort(); // no-op
|
||||
}
|
||||
|
||||
long fdCount0 = getFdCount();
|
||||
listProcFD();
|
||||
|
||||
// start a server
|
||||
Server svr = new Server(lba);
|
||||
Thread thr = new Thread(svr);
|
||||
thr.start();
|
||||
|
||||
Socket s = new Socket(lba, svr.localPort());
|
||||
pendingSockets.add(new NamedWeak(s, pendingQueue, "clientSocket"));
|
||||
extractRefs(s, "clientSocket");
|
||||
|
||||
OutputStream out = s.getOutputStream();
|
||||
out.write('x');
|
||||
out.flush();
|
||||
InputStream in = s.getInputStream();
|
||||
int b = in.read(); // wait for it back
|
||||
System.out.printf(" data sent and received%n");
|
||||
// Do NOT close the Socket; forget it
|
||||
|
||||
Object ref;
|
||||
int loops = 20;
|
||||
while (!pendingSockets.isEmpty() && loops-- > 0) {
|
||||
ref = pendingQueue.remove(1000L);
|
||||
if (ref != null) {
|
||||
pendingSockets.remove(ref);
|
||||
System.out.printf(" ref queued: %s, remaining: %d%n", ref, pendingSockets.size());
|
||||
} else {
|
||||
s = null;
|
||||
out = null;
|
||||
in = null;
|
||||
System.gc();
|
||||
}
|
||||
}
|
||||
|
||||
thr.join();
|
||||
|
||||
// List the open file descriptors
|
||||
long fdCount = getFdCount();
|
||||
System.out.printf("Initial fdCount: %d, final fdCount: %d%n", fdCount0, fdCount);
|
||||
listProcFD();
|
||||
|
||||
if (loops == 0) {
|
||||
throw new AssertionError("Not all references reclaimed");
|
||||
}
|
||||
}
|
||||
|
||||
// Get the count of open file descriptors, or -1 if not available
|
||||
private static long getFdCount() {
|
||||
OperatingSystemMXBean mxBean = ManagementFactory.getOperatingSystemMXBean();
|
||||
return (mxBean instanceof UnixOperatingSystemMXBean)
|
||||
? ((UnixOperatingSystemMXBean) mxBean).getOpenFileDescriptorCount()
|
||||
: -1L;
|
||||
}
|
||||
|
||||
// Reflect to find references in the socket implementation that will be gc'd
|
||||
private static void extractRefs(Socket s, String name) {
|
||||
try {
|
||||
|
||||
Field socketImplField = Socket.class.getDeclaredField("impl");
|
||||
socketImplField.setAccessible(true);
|
||||
Object socketImpl = socketImplField.get(s);
|
||||
|
||||
Field fileDescriptorField = SocketImpl.class.getDeclaredField("fd");
|
||||
fileDescriptorField.setAccessible(true);
|
||||
FileDescriptor fileDescriptor = (FileDescriptor) fileDescriptorField.get(socketImpl);
|
||||
extractRefs(fileDescriptor, name);
|
||||
} catch (NoSuchFieldException | IllegalAccessException ex) {
|
||||
ex.printStackTrace();
|
||||
throw new AssertionError("missing field", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private static void extractRefs(FileDescriptor fileDescriptor, String name) {
|
||||
Object cleanup = null;
|
||||
int rawfd = -1;
|
||||
try {
|
||||
if (fileDescriptor != null) {
|
||||
Field fd1Field = FileDescriptor.class.getDeclaredField("fd");
|
||||
fd1Field.setAccessible(true);
|
||||
rawfd = fd1Field.getInt(fileDescriptor);
|
||||
|
||||
Field cleanupfdField = FileDescriptor.class.getDeclaredField("cleanup");
|
||||
cleanupfdField.setAccessible(true);
|
||||
cleanup = cleanupfdField.get(fileDescriptor);
|
||||
pendingSockets.add(new NamedWeak(fileDescriptor, pendingQueue,
|
||||
name + "::fileDescriptor: " + rawfd));
|
||||
pendingSockets.add(new NamedWeak(cleanup, pendingQueue, name + "::fdCleanup: " + rawfd));
|
||||
|
||||
}
|
||||
} catch (NoSuchFieldException | IllegalAccessException ex) {
|
||||
ex.printStackTrace();
|
||||
throw new AssertionError("missing field", ex);
|
||||
} finally {
|
||||
System.out.print(String.format(" fd: %s, fd: %d, cleanup: %s%n",
|
||||
fileDescriptor, rawfd, cleanup));
|
||||
}
|
||||
}
|
||||
|
||||
private static void extractRefs(ServerSocket s, String name) {
|
||||
try {
|
||||
|
||||
Field socketImplField = ServerSocket.class.getDeclaredField("impl");
|
||||
socketImplField.setAccessible(true);
|
||||
Object socketImpl = socketImplField.get(s);
|
||||
|
||||
Field fileDescriptorField = SocketImpl.class.getDeclaredField("fd");
|
||||
fileDescriptorField.setAccessible(true);
|
||||
FileDescriptor fileDescriptor = (FileDescriptor) fileDescriptorField.get(socketImpl);
|
||||
|
||||
Field fdField = FileDescriptor.class.getDeclaredField("fd");
|
||||
fdField.setAccessible(true);
|
||||
int rawfd = fdField.getInt(fileDescriptor);
|
||||
|
||||
Field cleanupField = FileDescriptor.class.getDeclaredField("cleanup");
|
||||
cleanupField.setAccessible(true);
|
||||
Object cleanup = cleanupField.get(fileDescriptor);
|
||||
|
||||
System.out.print(String.format(" fd: %s, fd: %d, cleanup: %s, socket: %s%n",
|
||||
fileDescriptor, rawfd, cleanup, s));
|
||||
|
||||
pendingSockets.add(new NamedWeak(fileDescriptor, pendingQueue,
|
||||
name + "::fileDescriptor: " + rawfd));
|
||||
pendingSockets.add(new NamedWeak(cleanup, pendingQueue, name + "::fdCleanup: " + rawfd));
|
||||
|
||||
} catch (NoSuchFieldException | IllegalAccessException ex) {
|
||||
ex.printStackTrace();
|
||||
throw new AssertionError("missing field", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to list the open file descriptors (if supported by the 'lsof' command).
|
||||
*/
|
||||
static void listProcFD() {
|
||||
List<String> lsofDirs = List.of("/usr/bin", "/usr/sbin");
|
||||
Optional<Path> lsof = lsofDirs.stream()
|
||||
.map(s -> Paths.get(s, "lsof"))
|
||||
.filter(f -> Files.isExecutable(f))
|
||||
.findFirst();
|
||||
lsof.ifPresent(exe -> {
|
||||
try {
|
||||
System.out.printf("Open File Descriptors:%n");
|
||||
long pid = ProcessHandle.current().pid();
|
||||
ProcessBuilder pb = new ProcessBuilder(exe.toString(), "-p", Integer.toString((int) pid));
|
||||
pb.inheritIO();
|
||||
Process p = pb.start();
|
||||
p.waitFor(10, TimeUnit.SECONDS);
|
||||
} catch (IOException | InterruptedException ie) {
|
||||
ie.printStackTrace();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Simple class to identify which refs have been queued
|
||||
static class NamedWeak extends WeakReference<Object> {
|
||||
private final String name;
|
||||
|
||||
NamedWeak(Object o, ReferenceQueue<Object> queue, String name) {
|
||||
super(o, queue);
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return name + "; " + super.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue