1 /* 2 * Copyright (c) 2006, 2016, 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 * author Edward Wang 26 * 27 * @test 28 * @bug 6368984 29 * @summary Configuring unconnected Socket before passing to implAccept 30 * can cause fd leak 31 * @requires (os.family != "windows") 32 * @library /test/lib 33 * @run main/othervm AcceptCauseFileDescriptorLeak root 34 */ 35 36 import java.io.IOException; 37 import java.net.ServerSocket; 38 import java.net.Socket; 39 import java.util.List; 40 41 import jdk.test.lib.JDKToolFinder; 42 import jdk.test.lib.process.OutputAnalyzer; 43 44 public class AcceptCauseFileDescriptorLeak { 45 private static final int REPS = 2048; 46 private static final int THRESHOLD = 1024; 47 48 public static void main(String[] args) throws Exception { 49 if (args.length != 0) { 50 OutputAnalyzer analyzer = execCmd("ulimit -n -H"); 51 String output = analyzer.getOutput(); 52 if (output == null || output.length() == 0) { 53 throw new RuntimeException("\"ulimit -n -H\" output nothing" 54 + " and its exit code is " + analyzer.getExitValue()); 55 } else { 56 output = output.trim(); 57 // Set max open file descriptors to 1024 58 // if it is unlimited or greater than 1024, 59 // otherwise just do test directly 60 if ("unlimited".equals(output) 61 || Integer.valueOf(output) > THRESHOLD) { 62 analyzer = execCmd("ulimit -n " + THRESHOLD + "; " 63 + composeJavaTestStr()); 64 System.out.println("Output: [" 65 + analyzer.getOutput() + "]"); 66 int rc = analyzer.getExitValue(); 67 if (rc != 0) { 68 throw new RuntimeException( 69 "Unexpected exit code: " + rc); 70 } 71 return; 72 } 73 } 74 } 75 76 final ServerSocket ss = new ServerSocket(0) { 77 public Socket accept() throws IOException { 78 Socket s = new Socket() { 79 }; 80 s.setSoTimeout(10000); 81 implAccept(s); 82 return s; 83 } 84 }; 85 Thread t = new Thread(new Runnable() { 86 public void run() { 87 try { 88 for (int i = 0; i < REPS; i++) { 89 (new Socket("localhost", ss.getLocalPort())).close(); 90 } 91 } catch (IOException e) { 92 e.printStackTrace(); 93 } 94 } 95 }); 96 t.start(); 97 try { 98 for (int i = 0; i < REPS; i++) { 99 ss.accept().close(); 100 } 101 } finally { 102 ss.close(); 103 } 104 t.join(); 105 } 106 107 /** 108 * Execute command with shell 109 * 110 * @param command 111 * @return OutputAnalyzer 112 * @throws IOException 113 */ 114 static OutputAnalyzer execCmd(String command) throws IOException { 115 List<String> cmd = List.of("sh", "-c", command); 116 System.out.println("Executing: " + cmd); 117 ProcessBuilder pb = new ProcessBuilder(cmd); 118 return new OutputAnalyzer(pb.start()); 119 } 120 121 static String composeJavaTestStr() { 122 return JDKToolFinder.getTestJDKTool("java") + " " 123 + AcceptCauseFileDescriptorLeak.class.getName(); 124 } 125 } 126