1 /*
  2  * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.
  8  *
  9  * This code is distributed in the hope that it will be useful, but WITHOUT
 10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 12  * version 2 for more details (a copy is included in the LICENSE file that
 13  * accompanied this code).
 14  *
 15  * You should have received a copy of the GNU General Public License version
 16  * 2 along with this work; if not, write to the Free Software Foundation,
 17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 18  *
 19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 20  * or visit www.oracle.com if you need additional information or have any
 21  * questions.
 22  */
 23 
 24 /*
 25  * @test
 26  * @bug 8067105
 27  * @library /test/lib
 28  * @summary Socket returned by ServerSocket.accept() is inherited by child process on Windows
 29  * @author Chris Hegarty
 30  */
 31 
 32 import java.io.*;
 33 import java.net.*;
 34 import java.nio.channels.ServerSocketChannel;
 35 import java.util.ArrayList;
 36 import java.util.Arrays;
 37 import java.util.List;
 38 import java.util.concurrent.TimeUnit;
 39 import java.util.function.Supplier;
 40 import jdk.test.lib.net.IPSupport;
 41 
 42 public class AcceptInheritHandle {
 43 
 44     enum ServerSocketProducer {
 45         JAVA_NET(() -> {
 46             try {
 47                 return new ServerSocket();
 48             } catch(IOException x) {
 49                 throw new UncheckedIOException(x);
 50             }
 51         }),
 52         NIO_CHANNELS(() -> {
 53             try {
 54                 return ServerSocketChannel.open().socket();
 55             } catch (IOException x) {
 56                 throw new UncheckedIOException(x);
 57             }
 58         });
 59 
 60         final Supplier<ServerSocket> supplier;
 61         ServerSocketProducer(Supplier<ServerSocket> supplier) {
 62             this.supplier = supplier;
 63         }
 64         Supplier<ServerSocket> supplier () { return supplier; }
 65     }
 66 
 67     static final String JAVA = System.getProperty("java.home")
 68         + File.separator + "bin" + File.separator + "java";
 69 
 70     static final String CLASSPATH = System.getProperty("java.class.path");
 71 
 72     public static void main(String[] args) throws Exception {
 73         if (args.length == 1)
 74             server(ServerSocketProducer.valueOf(args[0]));
 75         else
 76             mainEntry();
 77     }
 78 
 79     static void mainEntry() throws Exception {
 80         testJavaNetServerSocket();
 81         testNioServerSocketChannel();
 82     }
 83 
 84     static void testJavaNetServerSocket() throws Exception {
 85         test(ServerSocketProducer.JAVA_NET);
 86         if (IPSupport.hasIPv4()) {
 87             test(ServerSocketProducer.JAVA_NET, "-Djava.net.preferIPv4Stack=true");
 88         }
 89     }
 90     static void testNioServerSocketChannel() throws Exception {
 91         test(ServerSocketProducer.NIO_CHANNELS);
 92     }
 93 
 94     static void test(ServerSocketProducer ssp, String... jvmArgs) throws Exception {
 95         System.out.println("\nStarting test for " + ssp.name());
 96 
 97         List<String> commands = new ArrayList<>();
 98         commands.add(JAVA);
 99         for (String arg : jvmArgs)
100             commands.add(arg);
101         commands.add("-cp");
102         commands.add(CLASSPATH);
103         commands.add("AcceptInheritHandle");
104         commands.add(ssp.name());
105 
106         System.out.println("Executing: "+ commands);
107         ProcessBuilder pb = new ProcessBuilder(commands);
108         pb.redirectError(ProcessBuilder.Redirect.INHERIT);
109         Process serverProcess = pb.start();
110         DataInputStream dis = new DataInputStream(serverProcess.getInputStream());
111 
112         int port = dis.readInt();
113         System.out.println("Server process listening on " + port + ", connecting...");
114 
115         String address;
116         if (Arrays.stream(jvmArgs).anyMatch("-Djava.net.preferIPv4Stack=true"::equals)) {
117             address = "127.0.0.1";
118         } else {
119             InetAddress loopback = InetAddress.getLoopbackAddress();
120             address = loopback.getHostAddress();
121         }
122         Socket socket = new Socket(address, port);
123         String s = dis.readUTF();
124         System.out.println("Server process said " + s);
125 
126         serverProcess.destroy();
127         serverProcess.waitFor(30, TimeUnit.SECONDS);
128         System.out.println("serverProcess exitCode:" + serverProcess.exitValue());
129 
130         try {
131             socket.setSoTimeout(10 * 1000);
132             socket.getInputStream().read();
133         } catch (SocketTimeoutException x) {
134             // failed
135             throw new RuntimeException("Failed: should get reset, not " + x);
136         } catch (SocketException x) {
137             System.out.println("Expected:" + x);
138         }
139     }
140 
141     static void server(ServerSocketProducer producer) throws Exception {
142         try (ServerSocket ss = producer.supplier().get()) {
143             InetAddress loopback = InetAddress.getLoopbackAddress();
144             ss.bind(new InetSocketAddress(loopback, 0));
145             int port = ss.getLocalPort();
146             DataOutputStream dos = new DataOutputStream(System.out);
147             dos.writeInt(port);
148             dos.flush();
149 
150             ss.accept();  // do not close
151 
152             Runtime.getRuntime().exec("sleep 20");
153             Thread.sleep(3 * 1000);
154 
155             dos.writeUTF("kill me!");
156             dos.flush();
157             Thread.sleep(30 * 1000);
158         }
159     }
160 }