test/jdk/com/sun/jdi/BadHandshakeTest.java
changeset 58088 e2de6e166880
parent 51754 594919232b8f
equal deleted inserted replaced
58087:03964761a23c 58088:e2de6e166880
     1 /*
     1 /*
     2  * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
     2  * Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     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
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.
     7  * published by the Free Software Foundation.
    19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    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
    20  * or visit www.oracle.com if you need additional information or have any
    21  * questions.
    21  * questions.
    22  */
    22  */
    23 
    23 
       
    24 import java.net.ConnectException;
    24 import java.net.Socket;
    25 import java.net.Socket;
    25 
    26 
    26 import com.sun.jdi.Bootstrap;
    27 import com.sun.jdi.Bootstrap;
    27 import com.sun.jdi.VirtualMachine;
    28 import com.sun.jdi.VirtualMachine;
    28 import com.sun.jdi.event.*;
    29 import com.sun.jdi.event.*;
    32 
    33 
    33 import java.util.Map;
    34 import java.util.Map;
    34 import java.util.List;
    35 import java.util.List;
    35 import java.util.Iterator;
    36 import java.util.Iterator;
    36 import java.util.concurrent.TimeUnit;
    37 import java.util.concurrent.TimeUnit;
    37 import java.util.concurrent.atomic.AtomicBoolean;
       
    38 
    38 
    39 import jdk.test.lib.Utils;
    39 import lib.jdb.Debuggee;
    40 import jdk.test.lib.process.ProcessTools;
       
    41 
    40 
    42 /* @test
    41 /* @test
    43  * @bug 6306165 6432567
    42  * @bug 6306165 6432567
    44  * @summary Check that a bad handshake doesn't cause a debuggee to abort
    43  * @summary Check that a bad handshake doesn't cause a debuggee to abort
    45  * @library /test/lib
    44  * @library /test/lib
    46  *
    45  *
    47  * @modules java.management
    46  * @modules java.management
    48  *          jdk.jdi
    47  *          jdk.jdi
    49  * @build VMConnection BadHandshakeTest Exit0
    48  * @build BadHandshakeTest Exit0
    50  * @run driver BadHandshakeTest
    49  * @run driver BadHandshakeTest
    51  */
    50  */
    52 public class BadHandshakeTest {
    51 public class BadHandshakeTest {
    53 
    52 
    54     /*
    53     /*
    56      */
    55      */
    57     private static Connector findConnector(String name) {
    56     private static Connector findConnector(String name) {
    58         List<Connector> connectors = Bootstrap.virtualMachineManager().allConnectors();
    57         List<Connector> connectors = Bootstrap.virtualMachineManager().allConnectors();
    59         Iterator<Connector> iter = connectors.iterator();
    58         Iterator<Connector> iter = connectors.iterator();
    60         while (iter.hasNext()) {
    59         while (iter.hasNext()) {
    61             Connector connector = (Connector)iter.next();
    60             Connector connector = iter.next();
    62             if (connector.name().equals(name)) {
    61             if (connector.name().equals(name)) {
    63                 return connector;
    62                 return connector;
    64             }
    63             }
    65         }
    64         }
    66         return null;
    65         return null;
    67     }
    66     }
    68 
    67 
    69     /*
    68     private static void log(Object s) {
    70      * Launch a server debuggee with the given address
    69         System.out.println(String.valueOf(s));
    71      */
       
    72     private static LaunchResult launch(String address, String class_name) throws Exception {
       
    73         String[] args = VMConnection.insertDebuggeeVMOptions(new String[] {
       
    74             "-agentlib:jdwp=transport=dt_socket" +
       
    75             ",server=y" + ",suspend=y" + ",address=" + address,
       
    76             class_name
       
    77         });
       
    78 
       
    79         ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(args);
       
    80 
       
    81         final AtomicBoolean success = new AtomicBoolean();
       
    82         final AtomicBoolean bindFailed = new AtomicBoolean();
       
    83         Process p = ProcessTools.startProcess(
       
    84             class_name,
       
    85             pb,
       
    86             (line) -> {
       
    87                 // 'Listening for transport dt_socket at address: xxxxx'
       
    88                 // indicates the debuggee is ready to accept connections
       
    89                 if (line.contains("Listening for transport dt_socket at address:")) {
       
    90                     success.set(true);
       
    91                     return true;
       
    92                 }
       
    93                 // 'Address already in use' indicates
       
    94                 // the debuggee has failed to start due to busy port.
       
    95                 if (line.contains("Address already in use")) {
       
    96                     bindFailed.set(true);
       
    97                     return true;
       
    98                 }
       
    99                 return false;
       
   100             },
       
   101             Integer.MAX_VALUE,
       
   102             TimeUnit.MILLISECONDS
       
   103         );
       
   104 
       
   105         return new LaunchResult(success.get() ? p : null,
       
   106                 bindFailed.get());
       
   107     }
    70     }
   108 
    71 
   109     /*
       
   110      * - pick a TCP port
       
   111      * - Launch a server debuggee: server=y,suspend=y,address=${port}
       
   112      * - run it to VM death
       
   113      * - verify we saw no error
       
   114      */
       
   115     public static void main(String args[]) throws Exception {
    72     public static void main(String args[]) throws Exception {
   116         // Launch the server debuggee
    73         // Launch the server debugee
   117         int port = 0;
    74         log("Starting debuggee...");
   118         Process process = null;
    75         try (Debuggee debuggee = Debuggee.launcher("Exit0").launch()) {
   119         while (process == null) {
    76             log("Debuggee started.");
   120             port = Utils.getFreePort();
    77             int port = Integer.parseInt(debuggee.getAddress());
   121             String address = String.valueOf(port);
    78             log("Debuggee port: " + port);
   122             LaunchResult launchResult = launch(address, "Exit0");
    79 
   123             process = launchResult.getProcess();
    80             log("testcase 1...");
   124             if (launchResult.isBindFailed()) {
    81             // Connect to the debuggee and handshake with garbage
   125                 System.out.println("Port " + port + " already in use. Trying to restart debuggee with a new one...");
    82             Socket s = new Socket("localhost", port);
   126                 Thread.sleep(100);
    83             s.getOutputStream().write("Here's a poke in the eye".getBytes("UTF-8"));
   127             } else if (process == null ) {
    84             s.close();
   128                 throw new RuntimeException("Unable to start debugee");
    85 
       
    86             log("testcase 2...");
       
    87             // Re-connect and do a partial handshake - don't disconnect
       
    88             // Re-connect just after disconnect may cause "connection refused" error (see JDK-8192057)
       
    89             Exception error = null;
       
    90             long retryDelay = 20;
       
    91             for (int retry = 0; retry < 5; retry++) {
       
    92                 if (error != null) {
       
    93                     try {
       
    94                         Thread.sleep(retryDelay);
       
    95                     } catch (InterruptedException ex) {
       
    96                         // ignore
       
    97                     }
       
    98                     retryDelay *= 2;
       
    99                     error = null;
       
   100                 }
       
   101                 try {
       
   102                     log("retry: " + retry);
       
   103                     s = new Socket("localhost", port);
       
   104                     s.getOutputStream().write("JDWP-".getBytes("UTF-8"));
       
   105                     break;
       
   106                 } catch (ConnectException ex) {
       
   107                     log("got exception: " + ex.toString());
       
   108                     error = ex;
       
   109                 }
   129             }
   110             }
       
   111             if (error != null) {
       
   112                 throw error;
       
   113             }
       
   114 
       
   115             log("cleaning...");
       
   116             // Attach to server debuggee and resume it so it can exit
       
   117             AttachingConnector conn = (AttachingConnector)findConnector("com.sun.jdi.SocketAttach");
       
   118             Map<String, Argument> conn_args = conn.defaultArguments();
       
   119             Connector.IntegerArgument port_arg =
       
   120                     (Connector.IntegerArgument)conn_args.get("port");
       
   121             port_arg.setValue(port);
       
   122             VirtualMachine vm = conn.attach(conn_args);
       
   123 
       
   124             // The first event is always a VMStartEvent, and it is always in
       
   125             // an EventSet by itself.  Wait for it.
       
   126             EventSet evtSet = vm.eventQueue().remove();
       
   127             for (Event event : evtSet) {
       
   128                 if (event instanceof VMStartEvent) {
       
   129                     break;
       
   130                 }
       
   131                 throw new RuntimeException("Test failed - debuggee did not start properly");
       
   132             }
       
   133 
       
   134             vm.eventRequestManager().deleteAllBreakpoints();
       
   135             vm.resume();
       
   136 
       
   137             debuggee.waitFor(10, TimeUnit.SECONDS);
   130         }
   138         }
   131 
       
   132         // Connect to the debuggee and handshake with garbage
       
   133         Socket s = new Socket("localhost", port);
       
   134         s.getOutputStream().write("Here's a poke in the eye".getBytes("UTF-8"));
       
   135         s.close();
       
   136 
       
   137         // Re-connect and to a partial handshake - don't disconnect
       
   138         s = new Socket("localhost", port);
       
   139         s.getOutputStream().write("JDWP-".getBytes("UTF-8"));
       
   140 
       
   141 
       
   142         // Attach to server debuggee and resume it so it can exit
       
   143         AttachingConnector conn = (AttachingConnector)findConnector("com.sun.jdi.SocketAttach");
       
   144         Map<String, Argument> conn_args = conn.defaultArguments();
       
   145         Connector.IntegerArgument port_arg =
       
   146             (Connector.IntegerArgument)conn_args.get("port");
       
   147         port_arg.setValue(port);
       
   148         VirtualMachine vm = conn.attach(conn_args);
       
   149 
       
   150         // The first event is always a VMStartEvent, and it is always in
       
   151         // an EventSet by itself.  Wait for it.
       
   152         EventSet evtSet = vm.eventQueue().remove();
       
   153         for (Event event: evtSet) {
       
   154             if (event instanceof VMStartEvent) {
       
   155                 break;
       
   156             }
       
   157             throw new RuntimeException("Test failed - debuggee did not start properly");
       
   158         }
       
   159 
       
   160         vm.eventRequestManager().deleteAllBreakpoints();
       
   161         vm.resume();
       
   162 
       
   163         process.waitFor();
       
   164     }
   139     }
   165 
       
   166     private static class LaunchResult {
       
   167 
       
   168         private final Process p;
       
   169         private final boolean bindFailed;
       
   170 
       
   171         public LaunchResult(Process p, boolean bindFailed) {
       
   172             this.p = p;
       
   173             this.bindFailed = bindFailed;
       
   174         }
       
   175 
       
   176         public Process getProcess() {
       
   177             return p;
       
   178         }
       
   179 
       
   180         public boolean isBindFailed() {
       
   181             return bindFailed;
       
   182         }
       
   183 
       
   184     }
       
   185 
       
   186 }
   140 }