1 /* 2 * Copyright (c) 2003, 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 package nsk.jdi.VirtualMachineManager.createVirtualMachine; 25 26 import com.sun.jdi.*; 27 import com.sun.jdi.connect.*; 28 import com.sun.jdi.connect.spi.*; 29 import java.net.*; 30 import java.io.*; 31 import java.util.*; 32 33 /* 34 * A transport service implementation based on a TCP connection used by 35 * nsk/jdi/VirtualMachineManager/createVirtualMachine/createVM003 test. 36 * It is borrowed from the com.sun.tools.jdi.SocketTransportService 37 */ 38 39 public class CreateVM003_TranspServ extends TransportService { 40 41 /** 42 * The listener returned by startListening encapsulates 43 * the ServerSocket. 44 */ 45 static class SocketListenKey extends ListenKey { 46 ServerSocket ss; 47 SocketListenKey(ServerSocket ss)48 SocketListenKey(ServerSocket ss) { 49 this.ss = ss; 50 } 51 socket()52 ServerSocket socket() { 53 return ss; 54 } 55 address()56 public String address() { 57 InetAddress localaddr = ss.getInetAddress(); 58 int port = ss.getLocalPort(); 59 if (localaddr.isAnyLocalAddress()) { 60 return "" + port; 61 } else { 62 return localaddr + ":" + port; 63 } 64 } 65 toString()66 public String toString() { 67 return address(); 68 } 69 } 70 71 /** 72 * Handshake with the debuggee 73 */ handshake(Socket s, long timeout)74 void handshake(Socket s, long timeout) throws IOException { 75 s.setSoTimeout((int)timeout); 76 77 byte[] hello = "JDWP-Handshake".getBytes("UTF-8"); 78 s.getOutputStream().write(hello); 79 80 byte[] b = new byte[hello.length]; 81 int received = 0; 82 while (received < hello.length) { 83 int n; 84 try { 85 n = s.getInputStream().read(b, received, hello.length-received); 86 } catch (SocketTimeoutException x) { 87 throw new IOException("##> CreateVM003_TranspServ: Handshake timeout"); 88 } 89 if (n < 0) { 90 s.close(); 91 throw new IOException 92 ("##> CreateVM003_TranspServ: Handshake FAILED - connection prematurally closed!"); 93 } 94 received += n; 95 } 96 for (int i=0; i<hello.length; i++) { 97 if (b[i] != hello[i]) { 98 throw new IOException 99 ("##> CreateVM003_TranspServ: Handshake FAILED - unrecognized message from target VM"); 100 } 101 } 102 103 // disable read timeout 104 s.setSoTimeout(0); 105 } 106 107 /** 108 * No-arg constructor 109 */ CreateVM003_TranspServ()110 public CreateVM003_TranspServ() { 111 } 112 113 /** 114 * The name of this transport service 115 */ name()116 public String name() { 117 return "CreateVM003_TranspServ"; 118 } 119 120 /** 121 * The description of this transport service 122 */ description()123 public String description() { 124 return "SocketTransportService for nsk/jdi/VirtualMachineManager/createVirtualMachine/createVM003 test."; 125 } 126 127 /** 128 * Return the capabilities of this transport service 129 */ capabilities()130 public Capabilities capabilities() { 131 return new CreateVM003_TranspServCapabilities(); 132 } 133 134 135 /** 136 * Attach to the specified address with optional attach and handshake 137 * timeout. 138 */ attach(String address, long attachTimeout, long handshakeTimeout)139 public Connection attach(String address, long attachTimeout, long handshakeTimeout) 140 throws IOException { 141 142 if (address == null) { 143 throw new NullPointerException("##> CreateVM003_TranspServ: attach() - address is null"); 144 } 145 if (attachTimeout < 0 || handshakeTimeout < 0) { 146 throw new IllegalArgumentException("##> CreateVM003_TranspServ: attach() - timeout is negative"); 147 } 148 149 int splitIndex = address.indexOf(':'); 150 String host; 151 String portStr; 152 if (splitIndex < 0) { 153 host = InetAddress.getLocalHost().getHostName(); 154 portStr = address; 155 } else { 156 host = address.substring(0, splitIndex); 157 portStr = address.substring(splitIndex+1); 158 } 159 160 int port; 161 try { 162 port = Integer.decode(portStr).intValue(); 163 } catch (NumberFormatException e) { 164 throw new IllegalArgumentException( 165 "##> CreateVM003_TranspServ: attach() - unable to parse port number in address"); 166 } 167 168 169 // open TCP connection to VM 170 171 InetSocketAddress sa = new InetSocketAddress(host, port); 172 Socket s = new Socket(); 173 try { 174 s.connect(sa, (int)attachTimeout); 175 } catch (SocketTimeoutException exc) { 176 try { 177 s.close(); 178 } catch (IOException x) { } 179 throw new TransportTimeoutException 180 ("##> CreateVM003_TranspServ: attach() - timed out trying to establish connection"); 181 } 182 183 // handshake with the target VM 184 try { 185 handshake(s, handshakeTimeout); 186 } catch (IOException exc) { 187 try { 188 s.close(); 189 } catch (IOException x) { } 190 throw exc; 191 } 192 193 return new CreateVM003_Connection(s); 194 } 195 196 /* 197 * Listen on the specified address and port. Return a listener 198 * that encapsulates the ServerSocket. 199 */ startListening(String localaddress, int port)200 ListenKey startListening(String localaddress, int port) throws IOException { 201 InetSocketAddress sa; 202 if (localaddress == null) { 203 sa = new InetSocketAddress(port); 204 } else { 205 sa = new InetSocketAddress(localaddress, port); 206 } 207 ServerSocket ss = new ServerSocket(); 208 // if port is 0 do not set the SO_REUSEADDR flag 209 if (port == 0) { 210 ss.setReuseAddress(false); 211 } 212 ss.bind(sa); 213 return new SocketListenKey(ss); 214 } 215 216 /** 217 * Listen on the specified address 218 */ startListening(String address)219 public ListenKey startListening(String address) throws IOException { 220 // use ephemeral port if address isn't specified. 221 if (address == null || address.length() == 0) { 222 address = "0"; 223 } 224 225 int splitIndex = address.indexOf(':'); 226 String localaddr = null; 227 if (splitIndex >= 0) { 228 localaddr = address.substring(0, splitIndex); 229 address = address.substring(splitIndex+1); 230 } 231 232 int port; 233 try { 234 port = Integer.decode(address).intValue(); 235 } catch (NumberFormatException e) { 236 throw new IllegalArgumentException( 237 "##> CreateVM003_TranspServ: startListening() - unable to parse port number in address"); 238 } 239 240 return startListening(localaddr, port); 241 } 242 243 /** 244 * Listen on the default address 245 */ startListening()246 public ListenKey startListening() throws IOException { 247 return startListening(null, 0); 248 } 249 250 /** 251 * Stop the listener 252 */ stopListening(ListenKey listener)253 public void stopListening(ListenKey listener) throws IOException { 254 if (!(listener instanceof SocketListenKey)) { 255 throw new IllegalArgumentException 256 ("##> CreateVM003_TranspServ: stopListening() - Invalid listener"); 257 } 258 259 synchronized (listener) { 260 ServerSocket ss = ((SocketListenKey)listener).socket(); 261 262 // if the ServerSocket has been closed it means 263 // the listener is invalid 264 if (ss.isClosed()) { 265 throw new IllegalArgumentException 266 ("##> CreateVM003_TranspServ: stopListening() - Invalid listener"); 267 } 268 ss.close(); 269 } 270 } 271 272 /** 273 * Accept a connection from a debuggee and handshake with it. 274 */ accept(ListenKey listener, long acceptTimeout, long handshakeTimeout)275 public Connection accept(ListenKey listener, long acceptTimeout, long handshakeTimeout) throws IOException { 276 if (acceptTimeout < 0 || handshakeTimeout < 0) { 277 throw new IllegalArgumentException 278 ("##> CreateVM003_TranspServ: accept() - timeout is negative"); 279 } 280 if (!(listener instanceof SocketListenKey)) { 281 throw new IllegalArgumentException 282 ("##> CreateVM003_TranspServ: accept() - Invalid listener"); 283 } 284 ServerSocket ss; 285 286 // obtain the ServerSocket from the listener - if the 287 // socket is closed it means the listener is invalid 288 synchronized (listener) { 289 ss = ((SocketListenKey)listener).socket(); 290 if (ss.isClosed()) { 291 throw new IllegalArgumentException 292 ("##> CreateVM003_TranspServ: accept() - Invalid listener"); 293 } 294 } 295 296 ss.setSoTimeout((int)acceptTimeout); 297 Socket s; 298 try { 299 s = ss.accept(); 300 } catch (SocketTimeoutException x) { 301 throw new TransportTimeoutException 302 ("##> CreateVM003_TranspServ: accept() - timeout waiting for connection"); 303 } 304 305 // handshake here 306 handshake(s, handshakeTimeout); 307 308 return new CreateVM003_Connection(s); 309 } 310 toString()311 public String toString() { 312 return name(); 313 } 314 } // end of CreateVM003_TranspServ class 315 316 class CreateVM003_Connection extends Connection { 317 private Socket socket; 318 private boolean closed = false; 319 private OutputStream socketOutput; 320 private InputStream socketInput; 321 private Object receiveLock = new Object(); 322 private Object sendLock = new Object(); 323 private Object closeLock = new Object(); 324 CreateVM003_Connection(Socket socket)325 CreateVM003_Connection(Socket socket) throws IOException { 326 this.socket = socket; 327 socket.setTcpNoDelay(true); 328 socketInput = socket.getInputStream(); 329 socketOutput = socket.getOutputStream(); 330 } 331 close()332 public void close() throws IOException { 333 synchronized (closeLock) { 334 if (closed) { 335 return; 336 } 337 socketOutput.close(); 338 socketInput.close(); 339 socket.close(); 340 closed = true; 341 } 342 } 343 isOpen()344 public boolean isOpen() { 345 synchronized (closeLock) { 346 return !closed; 347 } 348 } 349 readPacket()350 public byte[] readPacket() throws IOException { 351 if (!isOpen()) { 352 throw new ClosedConnectionException 353 ("##> CreateVM003_Connection: readPacket() - connection is closed"); 354 } 355 synchronized (receiveLock) { 356 int b1,b2,b3,b4; 357 358 // length 359 try { 360 b1 = socketInput.read(); 361 b2 = socketInput.read(); 362 b3 = socketInput.read(); 363 b4 = socketInput.read(); 364 } catch (IOException ioe) { 365 if (!isOpen()) { 366 throw new ClosedConnectionException 367 ("##> CreateVM003_Connection: readPacket() - connection is closed"); 368 } else { 369 throw ioe; 370 } 371 } 372 373 if (b1<0 || b2<0 || b3<0 || b4<0) 374 throw new EOFException(); 375 376 int len = ((b1 << 24) | (b2 << 16) | (b3 << 8) | (b4 << 0)); 377 378 if (len < 0) { 379 throw new IOException 380 ("##> CreateVM003_Connection: readPacket() - protocol error: invalid Packet's length"); 381 } 382 383 byte b[] = new byte[len]; 384 b[0] = (byte)b1; 385 b[1] = (byte)b2; 386 b[2] = (byte)b3; 387 b[3] = (byte)b4; 388 389 int off = 4; 390 len -= off; 391 392 while (len > 0) { 393 int count; 394 try { 395 count = socketInput.read(b, off, len); 396 } catch (IOException ioe) { 397 if (!isOpen()) { 398 throw new ClosedConnectionException 399 ("##> CreateVM003_Connection: readPacket() - connection is closed"); 400 } else { 401 throw ioe; 402 } 403 } 404 if (count < 0) { 405 throw new EOFException 406 ("##> CreateVM003_Connection: readPacket() - read() method returns negative value"); 407 } 408 len -= count; 409 off += count; 410 } 411 412 return b; 413 } 414 } 415 writePacket(byte b[])416 public void writePacket(byte b[]) throws IOException { 417 if (!isOpen()) { 418 throw new ClosedConnectionException 419 ("##> CreateVM003_Connection: writePacket() - connection is closed"); 420 } 421 422 /* 423 * Check the packet size 424 */ 425 if (b.length < 11) { 426 throw new IllegalArgumentException 427 ("##> CreateVM003_Connection: writePacket() - packet is insufficient size"); 428 } 429 int b0 = b[0] & 0xff; 430 int b1 = b[1] & 0xff; 431 int b2 = b[2] & 0xff; 432 int b3 = b[3] & 0xff; 433 int len = ((b0 << 24) | (b1 << 16) | (b2 << 8) | (b3 << 0)); 434 if (len < 11) { 435 throw new IllegalArgumentException 436 ("##> CreateVM003_Connection: writePacket() - packet is insufficient size"); 437 } 438 439 /* 440 * Check that the byte array contains the complete packet 441 */ 442 if (len > b.length) { 443 throw new IllegalArgumentException 444 ("##> CreateVM003_Connection: writePacket() - length mis-match"); 445 } 446 447 synchronized (sendLock) { 448 try { 449 /* 450 * Send the packet (ignoring any bytes that follow 451 * the packet in the byte array). 452 */ 453 socketOutput.write(b, 0, len); 454 } catch (IOException ioe) { 455 if (!isOpen()) { 456 throw new ClosedConnectionException 457 ("##> CreateVM003_Connection: writePacket() - connection is closed"); 458 } else { 459 throw ioe; 460 } 461 } 462 } 463 } 464 465 } // end of CreateVM003_Connection class 466 467 /* 468 * The capabilities of the socket transport service 469 */ 470 class CreateVM003_TranspServCapabilities extends TransportService.Capabilities { 471 supportsMultipleConnections()472 public boolean supportsMultipleConnections() { 473 return true; 474 } 475 supportsAttachTimeout()476 public boolean supportsAttachTimeout() { 477 return true; 478 } 479 supportsAcceptTimeout()480 public boolean supportsAcceptTimeout() { 481 return true; 482 } 483 supportsHandshakeTimeout()484 public boolean supportsHandshakeTimeout() { 485 return true; 486 } 487 488 } // end of CreateVM003_TranspServCapabilities class 489