1 /* 2 * Copyright (c) 2005, 2018, 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 import java.net.Socket; 25 26 import com.sun.jdi.Bootstrap; 27 import com.sun.jdi.VirtualMachine; 28 import com.sun.jdi.event.*; 29 import com.sun.jdi.connect.Connector; 30 import com.sun.jdi.connect.AttachingConnector; 31 import com.sun.jdi.connect.Connector.Argument; 32 33 import java.util.Map; 34 import java.util.List; 35 import java.util.Iterator; 36 import java.util.concurrent.TimeUnit; 37 import java.util.concurrent.atomic.AtomicBoolean; 38 39 import jdk.testlibrary.Utils; 40 import jdk.test.lib.process.ProcessTools; 41 42 /* @test 43 * @bug 6306165 6432567 44 * @summary Check that a bad handshake doesn't cause a debuggee to abort 45 * @library /lib/testlibrary 46 * @library /test/lib 47 * 48 * @modules java.management 49 * jdk.jdi 50 * @build jdk.testlibrary.* VMConnection BadHandshakeTest Exit0 51 * @run driver BadHandshakeTest 52 */ 53 public class BadHandshakeTest { 54 55 /* 56 * Find a connector by name 57 */ 58 private static Connector findConnector(String name) { 59 List<Connector> connectors = Bootstrap.virtualMachineManager().allConnectors(); 60 Iterator<Connector> iter = connectors.iterator(); 61 while (iter.hasNext()) { 62 Connector connector = (Connector)iter.next(); 63 if (connector.name().equals(name)) { 64 return connector; 65 } 66 } 67 return null; 68 } 69 70 /* 71 * Launch a server debuggee with the given address 72 */ 73 private static LaunchResult launch(String address, String class_name) throws Exception { 74 String[] args = VMConnection.insertDebuggeeVMOptions(new String[] { 75 "-agentlib:jdwp=transport=dt_socket" + 76 ",server=y" + ",suspend=y" + ",address=" + address, 77 class_name 78 }); 79 80 ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(args); 81 82 final AtomicBoolean success = new AtomicBoolean(); 83 final AtomicBoolean bindFailed = new AtomicBoolean(); 84 Process p = ProcessTools.startProcess( 85 class_name, 86 pb, 87 (line) -> { 88 // 'Listening for transport dt_socket at address: xxxxx' 89 // indicates the debuggee is ready to accept connections 90 if (line.contains("Listening for transport dt_socket at address:")) { 91 success.set(true); 92 return true; 93 } 94 // 'Address already in use' indicates 95 // the debuggee has failed to start due to busy port. 96 if (line.contains("Address already in use")) { 97 bindFailed.set(true); 98 return true; 99 } 100 return false; 101 }, 102 Integer.MAX_VALUE, 103 TimeUnit.MILLISECONDS 104 ); 105 106 return new LaunchResult(success.get() ? p : null, 107 bindFailed.get()); 108 } 109 110 /* 111 * - pick a TCP port 112 * - Launch a server debuggee: server=y,suspend=y,address=${port} 113 * - run it to VM death 114 * - verify we saw no error 115 */ 116 public static void main(String args[]) throws Exception { 117 // Launch the server debuggee 118 int port = 0; 119 Process process = null; 120 while (process == null) { 121 port = Utils.getFreePort(); 122 String address = String.valueOf(port); 123 LaunchResult launchResult = launch(address, "Exit0"); 124 process = launchResult.getProcess(); 125 if (launchResult.isBindFailed()) { 126 System.out.println("Port " + port + " already in use. Trying to restart debuggee with a new one..."); 127 Thread.sleep(100); 128 } else if (process == null ) { 129 throw new RuntimeException("Unable to start debugee"); 130 } 131 } 132 133 // Connect to the debuggee and handshake with garbage 134 Socket s = new Socket("localhost", port); 135 s.getOutputStream().write("Here's a poke in the eye".getBytes("UTF-8")); 136 s.close(); 137 138 // Re-connect and to a partial handshake - don't disconnect 139 s = new Socket("localhost", port); 140 s.getOutputStream().write("JDWP-".getBytes("UTF-8")); 141 142 143 // Attach to server debuggee and resume it so it can exit 144 AttachingConnector conn = (AttachingConnector)findConnector("com.sun.jdi.SocketAttach"); 145 Map<String, Argument> conn_args = conn.defaultArguments(); 146 Connector.IntegerArgument port_arg = 147 (Connector.IntegerArgument)conn_args.get("port"); 148 port_arg.setValue(port); 149 VirtualMachine vm = conn.attach(conn_args); 150 151 // The first event is always a VMStartEvent, and it is always in 152 // an EventSet by itself. Wait for it. 153 EventSet evtSet = vm.eventQueue().remove(); 154 for (Event event: evtSet) { 155 if (event instanceof VMStartEvent) { 156 break; 157 } 158 throw new RuntimeException("Test failed - debuggee did not start properly"); 159 } 160 161 vm.eventRequestManager().deleteAllBreakpoints(); 162 vm.resume(); 163 164 process.waitFor(); 165 } 166 167 private static class LaunchResult { 168 169 private final Process p; 170 private final boolean bindFailed; 171 172 public LaunchResult(Process p, boolean bindFailed) { 173 this.p = p; 174 this.bindFailed = bindFailed; 175 } 176 177 public Process getProcess() { 178 return p; 179 } 180 181 public boolean isBindFailed() { 182 return bindFailed; 183 } 184 185 } 186 187 }