30 import java.net.Inet4Address; |
30 import java.net.Inet4Address; |
31 import java.net.Inet6Address; |
31 import java.net.Inet6Address; |
32 import java.net.InetAddress; |
32 import java.net.InetAddress; |
33 import java.net.NetworkInterface; |
33 import java.net.NetworkInterface; |
34 import java.net.SocketException; |
34 import java.net.SocketException; |
|
35 import java.net.UnknownHostException; |
35 import java.util.Arrays; |
36 import java.util.Arrays; |
36 import java.util.Enumeration; |
37 import java.util.Enumeration; |
37 import java.util.Iterator; |
38 import java.util.Iterator; |
38 import java.util.LinkedList; |
39 import java.util.LinkedList; |
39 import java.util.List; |
40 import java.util.List; |
40 import java.util.Map; |
41 import java.util.Map; |
41 import java.util.concurrent.Callable; |
42 import java.util.concurrent.Callable; |
42 import java.util.concurrent.ExecutorService; |
43 import java.util.concurrent.ExecutorService; |
43 import java.util.concurrent.Executors; |
44 import java.util.concurrent.Executors; |
44 import java.util.concurrent.TimeUnit; |
|
45 |
45 |
46 /* |
46 /* |
47 * @test |
47 * @test |
48 * @bug 8184770 |
48 * @bug 8184770 |
49 * @summary Tests for JDWP agent attach functionality (including IPv6 support) |
49 * @summary Tests for JDWP agent attach functionality (including IPv6 support) |
52 * @build HelloWorld JdwpAttachTest |
52 * @build HelloWorld JdwpAttachTest |
53 * @run main/othervm JdwpAttachTest |
53 * @run main/othervm JdwpAttachTest |
54 */ |
54 */ |
55 public class JdwpAttachTest { |
55 public class JdwpAttachTest { |
56 |
56 |
|
57 private static final boolean IsWindows = System.getProperty("os.name").toLowerCase().contains("windows"); |
|
58 |
|
59 // Set to true to perform testing of attach from wrong address (expected to fail). |
|
60 // It's off by default as it caused significant test time increase\ |
|
61 // (tests <number_of_addresses> * <number_of_addresses> cases, each case fails by timeout). |
|
62 private static boolean testFailedAttach = false; |
|
63 |
57 public static void main(String[] args) throws Exception { |
64 public static void main(String[] args) throws Exception { |
58 List<InetAddress> addresses = getAddresses(); |
65 List<InetAddress> addresses = getAddresses(); |
59 |
66 |
60 boolean ipv4EnclosedTested = false; |
67 boolean ipv4EnclosedTested = false; |
61 boolean ipv6EnclosedTested = false; |
68 boolean ipv6EnclosedTested = false; |
62 for (InetAddress addr: addresses) { |
69 for (InetAddress addr: addresses) { |
63 // also test that addresses enclosed in square brackets are supported |
70 if (testFailedAttach) { |
64 attachTest(addr.getHostAddress(), addr.getHostAddress()); |
71 for (InetAddress connectAddr : addresses) { |
|
72 attachTest(addr.getHostAddress(), connectAddr.getHostAddress(), addr.equals(connectAddr)); |
|
73 } |
|
74 } else { |
|
75 attachTest(addr.getHostAddress(), addr.getHostAddress(), true); |
|
76 } |
65 // listening on "*" should accept connections from all addresses |
77 // listening on "*" should accept connections from all addresses |
66 attachTest("*", addr.getHostAddress()); |
78 attachTest("*", addr.getHostAddress(), true); |
67 |
79 |
68 // test that addresses enclosed in square brackets are supported. |
80 // also test that addresses enclosed in square brackets are supported. |
69 if (addr instanceof Inet4Address && !ipv4EnclosedTested) { |
81 if (addr instanceof Inet4Address && !ipv4EnclosedTested) { |
70 attachTest("[" + addr.getHostAddress() + "]", "[" + addr.getHostAddress() + "]"); |
82 attachTest("[" + addr.getHostAddress() + "]", "[" + addr.getHostAddress() + "]", true); |
71 ipv4EnclosedTested = true; |
83 ipv4EnclosedTested = true; |
72 } |
84 } |
73 if (addr instanceof Inet6Address && !ipv6EnclosedTested) { |
85 if (addr instanceof Inet6Address && !ipv6EnclosedTested) { |
74 attachTest("[" + addr.getHostAddress() + "]", "[" + addr.getHostAddress() + "]"); |
86 attachTest("[" + addr.getHostAddress() + "]", "[" + addr.getHostAddress() + "]", true); |
75 ipv6EnclosedTested = true; |
87 ipv6EnclosedTested = true; |
76 } |
88 } |
77 } |
89 } |
78 |
90 |
79 // by using "localhost" or empty hostname |
91 // by using "localhost" or empty hostname |
80 // we should be able to attach to both IPv4 and IPv6 addresses (127.0.0.1 & ::1) |
92 // we should be able to attach to both IPv4 and IPv6 addresses (127.0.0.1 & ::1) |
81 InetAddress localAddresses[] = InetAddress.getAllByName("localhost"); |
93 InetAddress localAddresses[] = InetAddress.getAllByName("localhost"); |
82 for (int i = 0; i < localAddresses.length; i++) { |
94 for (int i = 0; i < localAddresses.length; i++) { |
83 attachTest(localAddresses[i].getHostAddress(), ""); |
95 attachTest(localAddresses[i].getHostAddress(), "", true); |
84 } |
96 } |
85 } |
97 } |
86 |
98 |
87 private static void attachTest(String listenAddress, String connectAddresses) |
99 private static void attachTest(String listenAddress, String connectAddress, boolean expectedResult) |
88 throws Exception { |
100 throws Exception { |
89 log("Starting listening at " + listenAddress); |
101 log("\nTest: listen on '" + listenAddress + "', attach to '" + connectAddress + "'"); |
|
102 log(" Starting listening at " + listenAddress); |
90 ListeningConnector connector = getListenConnector(); |
103 ListeningConnector connector = getListenConnector(); |
91 Map<String, Connector.Argument> args = connector.defaultArguments(); |
104 Map<String, Connector.Argument> args = connector.defaultArguments(); |
92 setConnectorArg(args, "localAddress", listenAddress); |
105 setConnectorArg(args, "localAddress", listenAddress); |
93 setConnectorArg(args, "port", "0"); |
106 setConnectorArg(args, "port", "0"); |
94 |
107 |
98 // port from connector.startListening must be the same as values from arguments |
111 // port from connector.startListening must be the same as values from arguments |
99 if (!port.equals(actualPort)) { |
112 if (!port.equals(actualPort)) { |
100 throw new RuntimeException("values from connector.startListening (" + actualPort |
113 throw new RuntimeException("values from connector.startListening (" + actualPort |
101 + " is not equal to values from arguments (" + port + ")"); |
114 + " is not equal to values from arguments (" + port + ")"); |
102 } |
115 } |
103 log("Listening port: " + port); |
116 log(" Listening port: " + port); |
104 |
117 |
105 log("Attaching from " + connectAddresses); |
118 log(" Attaching from " + connectAddress); |
106 try { |
119 try { |
107 ExecutorService executor = Executors.newSingleThreadExecutor(); |
120 ExecutorService executor = Executors.newSingleThreadExecutor(); |
108 executor.submit((Callable<Exception>)() -> { |
121 executor.submit((Callable<Exception>)() -> { |
109 VirtualMachine vm = connector.accept(args); |
122 VirtualMachine vm = connector.accept(args); |
110 log("ACCEPTED."); |
|
111 vm.dispose(); |
123 vm.dispose(); |
112 return null; |
124 return null; |
113 }); |
125 }); |
114 executor.shutdown(); |
126 executor.shutdown(); |
115 |
127 |
116 LingeredApp debuggee = LingeredApp.startApp( |
128 try { |
117 Arrays.asList("-agentlib:jdwp=transport=dt_socket" |
129 LingeredApp debuggee = LingeredApp.startApp( |
118 +",address=" + connectAddresses + ":" + port |
130 Arrays.asList("-agentlib:jdwp=transport=dt_socket" |
119 + ",server=n,suspend=n")); |
131 + ",address=" + connectAddress + ":" + port |
120 debuggee.stopApp(); |
132 + ",server=n,suspend=n" |
121 |
133 // if failure is expected set small timeout (default is 20 sec) |
122 executor.awaitTermination(20, TimeUnit.SECONDS); |
134 + (!expectedResult ? ",timeout=1000" : ""))); |
|
135 debuggee.stopApp(); |
|
136 if (expectedResult) { |
|
137 log("OK: attached as expected"); |
|
138 } else { |
|
139 throw new RuntimeException("ERROR: LingeredApp.startApp was able to attach"); |
|
140 } |
|
141 } catch (Exception ex) { |
|
142 if (expectedResult) { |
|
143 throw new RuntimeException("ERROR: LingeredApp.startApp was able to attach"); |
|
144 } else { |
|
145 log("OK: failed to attach as expected"); |
|
146 } |
|
147 } |
123 } finally { |
148 } finally { |
124 connector.stopListening(args); |
149 connector.stopListening(args); |
125 } |
150 } |
|
151 } |
|
152 |
|
153 private static void addAddr(List<InetAddress> list, InetAddress addr) { |
|
154 log(" - (" + addr.getClass().getSimpleName() + ") " + addr.getHostAddress()); |
|
155 list.add(addr); |
126 } |
156 } |
127 |
157 |
128 private static List<InetAddress> getAddresses() { |
158 private static List<InetAddress> getAddresses() { |
129 List<InetAddress> result = new LinkedList<>(); |
159 List<InetAddress> result = new LinkedList<>(); |
130 try { |
160 try { |
134 try { |
164 try { |
135 if (iface.isUp()) { |
165 if (iface.isUp()) { |
136 Enumeration<InetAddress> addresses = iface.getInetAddresses(); |
166 Enumeration<InetAddress> addresses = iface.getInetAddresses(); |
137 while (addresses.hasMoreElements()) { |
167 while (addresses.hasMoreElements()) { |
138 InetAddress addr = addresses.nextElement(); |
168 InetAddress addr = addresses.nextElement(); |
139 // Java reports link local addresses with named scope, |
169 // Java reports link local addresses with symbolic scope, |
140 // but Windows sockets routines support only numeric scope id. |
170 // but on Windows java.net.NetworkInterface generates its own scope names |
141 // skip such addresses. |
171 // which are incompatible with native Windows routines. |
|
172 // So on Windows test only addresses with numeric scope. |
|
173 // On other platforms test both symbolic and numeric scopes. |
142 if (addr instanceof Inet6Address) { |
174 if (addr instanceof Inet6Address) { |
143 Inet6Address addr6 = (Inet6Address)addr; |
175 Inet6Address addr6 = (Inet6Address)addr; |
144 if (addr6.getScopedInterface() != null) { |
176 NetworkInterface scopeIface = addr6.getScopedInterface(); |
145 continue; |
177 if (scopeIface != null && scopeIface.getName() != null) { |
|
178 // On some test machines VPN creates link local addresses |
|
179 // which we cannot connect to. |
|
180 // Skip them. |
|
181 if (scopeIface.isPointToPoint()) { |
|
182 continue; |
|
183 } |
|
184 |
|
185 try { |
|
186 // the same address with numeric scope |
|
187 addAddr(result, Inet6Address.getByAddress(null, addr6.getAddress(), addr6.getScopeId())); |
|
188 } catch (UnknownHostException e) { |
|
189 // cannot happen! |
|
190 throw new RuntimeException("Unexpected", e); |
|
191 } |
|
192 |
|
193 if (IsWindows) { |
|
194 // don't add addresses with symbolic scope |
|
195 continue; |
|
196 } |
146 } |
197 } |
147 } |
198 } |
148 log(" - (" + addr.getClass().getSimpleName() + ") " + addr.getHostAddress()); |
199 addAddr(result, addr); |
149 result.add(addr); |
|
150 } |
200 } |
151 } |
201 } |
152 } catch (SocketException e) { |
202 } catch (SocketException e) { |
153 log("Interface " + iface.getDisplayName() + ": failed to get addresses"); |
203 log("Interface " + iface.getDisplayName() + ": failed to get addresses"); |
154 } |
204 } |