8067105: Socket returned by ServerSocket.accept() is inherited by child process on Windows
Reviewed-by: alanb, igerasim
--- a/jdk/src/java.base/windows/native/libnet/DualStackPlainSocketImpl.c Thu Jan 29 14:59:42 2015 +0000
+++ b/jdk/src/java.base/windows/native/libnet/DualStackPlainSocketImpl.c Thu Jan 29 20:45:30 2015 +0000
@@ -296,6 +296,8 @@
return -1;
}
+ SetHandleInformation((HANDLE)(UINT_PTR)newfd, HANDLE_FLAG_INHERIT, 0);
+
ia = NET_SockaddrToInetAddress(env, (struct sockaddr *)&sa, &port);
isa = (*env)->NewObject(env, isa_class, isa_ctorID, ia, port);
(*env)->SetObjectArrayElement(env, isaa, 0, isa);
--- a/jdk/src/java.base/windows/native/libnet/TwoStacksPlainSocketImpl.c Thu Jan 29 14:59:42 2015 +0000
+++ b/jdk/src/java.base/windows/native/libnet/TwoStacksPlainSocketImpl.c Thu Jan 29 20:45:30 2015 +0000
@@ -699,6 +699,7 @@
}
return;
}
+ SetHandleInformation((HANDLE)(UINT_PTR)fd, HANDLE_FLAG_INHERIT, 0);
(*env)->SetIntField(env, socketFdObj, IO_fd_fdID, fd);
if (him.him.sa_family == AF_INET) {
--- a/jdk/src/java.base/windows/native/libnio/ch/ServerSocketChannelImpl.c Thu Jan 29 14:59:42 2015 +0000
+++ b/jdk/src/java.base/windows/native/libnio/ch/ServerSocketChannelImpl.c Thu Jan 29 20:45:30 2015 +0000
@@ -105,6 +105,7 @@
return IOS_THROWN;
}
+ SetHandleInformation((HANDLE)(UINT_PTR)newfd, HANDLE_FLAG_INHERIT, 0);
(*env)->SetIntField(env, newfdo, fd_fdID, newfd);
remote_ia = NET_SockaddrToInetAddress(env, (struct sockaddr *)&sa, (int *)&remote_port);
CHECK_NULL_RETURN(remote_ia, IOS_THROWN);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/ServerSocket/AcceptInheritHandle.java Thu Jan 29 20:45:30 2015 +0000
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2015, 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
+ * @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.List;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Supplier;
+
+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);
+ test(ServerSocketProducer.JAVA_NET, "-Djava.net.preferIPv4Stack=true");
+ }
+ static void testNioServerSocketChannel() throws Exception {
+ test(ServerSocketProducer.NIO_CHANNELS);
+ }
+
+ static void test(ServerSocketProducer ssp, String... sysProps) throws Exception {
+ System.out.println("\nStarting test for " + ssp.name());
+
+ List<String> commands = new ArrayList<>();
+ commands.add(JAVA);
+ for (String prop : sysProps)
+ commands.add(prop);
+ commands.add("-cp");
+ commands.add(CLASSPATH);
+ commands.add("AcceptInheritHandle");
+ commands.add(ssp.name());
+
+ System.out.println("Executing: "+ commands);
+ ProcessBuilder pb = new ProcessBuilder(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...");
+
+ Socket socket = new Socket("localhost", 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()) {
+ ss.bind(new InetSocketAddress(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);
+ }
+ }
+}