1 /* 2 * Copyright (c) 2003, 2013, 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 /* @test 25 * @bug 4531526 26 * @summary Test that more than one debuggee cannot bind to same port 27 * at the same time. 28 * 29 * @build VMConnection ExclusiveBind HelloWorld 30 * @run main ExclusiveBind 31 */ 32 import java.io.InputStream; 33 import java.io.IOException; 34 import java.io.File; 35 import java.net.ServerSocket; 36 import com.sun.jdi.Bootstrap; 37 import com.sun.jdi.VirtualMachine; 38 import com.sun.jdi.connect.Connector; 39 import com.sun.jdi.connect.AttachingConnector; 40 import java.util.Map; 41 import java.util.List; 42 import java.util.Iterator; 43 44 public class ExclusiveBind { 45 46 /* 47 * Helper class to direct process output to the parent 48 * System.out 49 */ 50 static class IOHandler implements Runnable { 51 InputStream in; 52 53 IOHandler(InputStream in) { 54 this.in = in; 55 } 56 57 static void handle(InputStream in) { 58 IOHandler handler = new IOHandler(in); 59 Thread thr = new Thread(handler); 60 thr.setDaemon(true); 61 thr.start(); 62 } 63 64 public void run() { 65 try { 66 byte b[] = new byte[100]; 67 for (;;) { 68 int n = in.read(b); 69 if (n < 0) return; 70 for (int i=0; i<n; i++) { 71 System.out.print((char)b[i]); 72 } 73 } 74 } catch (IOException ioe) { } 75 } 76 77 } 78 79 /* 80 * Find a connector by name 81 */ 82 private static Connector findConnector(String name) { 83 List connectors = Bootstrap.virtualMachineManager().allConnectors(); 84 Iterator iter = connectors.iterator(); 85 while (iter.hasNext()) { 86 Connector connector = (Connector)iter.next(); 87 if (connector.name().equals(name)) { 88 return connector; 89 } 90 } 91 return null; 92 } 93 94 /* 95 * Launch (in server mode) a debuggee with the given address and 96 * suspend mode. 97 */ 98 private static Process launch(String address, boolean suspend, String class_name) throws IOException { 99 String exe = System.getProperty("java.home") + File.separator + "bin" + 100 File.separator + "java"; 101 String cmd = exe + " " + VMConnection.getDebuggeeVMOptions() + 102 " -agentlib:jdwp=transport=dt_socket,server=y,suspend="; 103 if (suspend) { 104 cmd += "y"; 105 } else { 106 cmd += "n"; 107 } 108 cmd += ",address=" + address + " " + class_name; 109 110 System.out.println("Starting: " + cmd); 111 112 Process p = Runtime.getRuntime().exec(cmd); 113 IOHandler.handle(p.getInputStream()); 114 IOHandler.handle(p.getErrorStream()); 115 116 return p; 117 } 118 119 /* 120 * - pick a TCP port 121 * - Launch a debuggee in server=y,suspend=y,address=${port} 122 * - Launch a second debuggee in server=y,suspend=n with the same port 123 * - Second debuggee should fail with an error (address already in use) 124 * - For clean-up we attach to the first debuggee and resume it. 125 */ 126 public static void main(String args[]) throws Exception { 127 // find a free port 128 ServerSocket ss = new ServerSocket(0); 129 int port = ss.getLocalPort(); 130 ss.close(); 131 132 String address = String.valueOf(port); 133 134 // launch the first debuggee 135 Process process1 = launch(address, true, "HelloWorld"); 136 137 // give first debuggee time to suspend 138 Thread.currentThread().sleep(5000); 139 140 // launch a second debuggee with the same address 141 Process process2 = launch(address, false, "HelloWorld"); 142 143 // get exit status from second debuggee 144 int exitCode = process2.waitFor(); 145 146 // clean-up - attach to first debuggee and resume it 147 AttachingConnector conn = (AttachingConnector)findConnector("com.sun.jdi.SocketAttach"); 148 Map conn_args = conn.defaultArguments(); 149 Connector.IntegerArgument port_arg = 150 (Connector.IntegerArgument)conn_args.get("port"); 151 port_arg.setValue(port); 152 VirtualMachine vm = conn.attach(conn_args); 153 vm.resume(); 154 155 // if the second debuggee ran to completion then we've got a problem 156 if (exitCode == 0) { 157 throw new RuntimeException("Test failed - second debuggee didn't fail to bind"); 158 } else { 159 System.out.println("Test passed - second debuggee correctly failed to bind"); 160 } 161 } 162 }