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