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/createVM002 test. 36 * It is borrowed from the com.sun.tools.jdi.SocketTransportService 37 */ 38 39 public class CreateVM002_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("##> CreateVM002_TranspServ: Handshake timeout"); 88 } 89 if (n < 0) { 90 s.close(); 91 throw new IOException 92 ("##> CreateVM002_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 ("##> CreateVM002_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 */ CreateVM002_TranspServ()110 public CreateVM002_TranspServ() { 111 } 112 113 /** 114 * The name of this transport service 115 */ name()116 public String name() { 117 return "CreateVM002_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/createVM002 test."; 125 } 126 127 /** 128 * Return the capabilities of this transport service 129 */ capabilities()130 public Capabilities capabilities() { 131 return new CreateVM002_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("##> CreateVM002_TranspServ: attach() - address is null"); 144 } 145 if (attachTimeout < 0 || handshakeTimeout < 0) { 146 throw new IllegalArgumentException("##> CreateVM002_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 "##> CreateVM002_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 ("##> CreateVM002_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 CreateVM002_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 "##> CreateVM002_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 ("##> CreateVM002_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 ("##> CreateVM002_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 ("##> CreateVM002_TranspServ: accept() - timeout is negative"); 279 } 280 if (!(listener instanceof SocketListenKey)) { 281 throw new IllegalArgumentException 282 ("##> CreateVM002_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 ("##> CreateVM002_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 ("##> CreateVM002_TranspServ: accept() - timeout waiting for connection"); 303 } 304 305 // handshake here 306 handshake(s, handshakeTimeout); 307 308 return new CreateVM002_Connection(s); 309 } 310 toString()311 public String toString() { 312 return name(); 313 } 314 } // end of CreateVM002_TranspServ class 315 316 class CreateVM002_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 private boolean toPrintPacket = false; 325 private int readPacketRequestNumber = 0; 326 private int writePacketRequestNumber = 0; 327 public boolean wasIOException = false; 328 CreateVM002_Connection(Socket socket)329 CreateVM002_Connection(Socket socket) throws IOException { 330 this.socket = socket; 331 socket.setTcpNoDelay(true); 332 socketInput = socket.getInputStream(); 333 socketOutput = socket.getOutputStream(); 334 } 335 close()336 public void close() throws IOException { 337 synchronized (closeLock) { 338 if (closed) { 339 return; 340 } 341 socketOutput.close(); 342 socketInput.close(); 343 socket.close(); 344 closed = true; 345 } 346 } 347 isOpen()348 public boolean isOpen() { 349 synchronized (closeLock) { 350 return !closed; 351 } 352 } 353 readPacket()354 public byte[] readPacket() throws IOException { 355 if (!isOpen()) { 356 throw new ClosedConnectionException 357 ("##> CreateVM002_Connection: readPacket() - connection is closed: N1"); 358 } 359 synchronized (receiveLock) { 360 int b1,b2,b3,b4; 361 362 // length 363 try { 364 b1 = socketInput.read(); 365 b2 = socketInput.read(); 366 b3 = socketInput.read(); 367 b4 = socketInput.read(); 368 } catch (IOException ioe) { 369 if (!isOpen()) { 370 throw new ClosedConnectionException 371 ("##> CreateVM002_Connection: readPacket() - connection is closed: N2"); 372 } else { 373 throw ioe; 374 } 375 } 376 377 if (b1<0 || b2<0 || b3<0 || b4<0) 378 throw new EOFException(); 379 380 int len = ((b1 << 24) | (b2 << 16) | (b3 << 8) | (b4 << 0)); 381 382 if (len < 0) { 383 throw new IOException 384 ("##> CreateVM002_Connection: readPacket() - protocol error: invalid Packet's length"); 385 } 386 387 byte b[] = new byte[len]; 388 b[0] = (byte)b1; 389 b[1] = (byte)b2; 390 b[2] = (byte)b3; 391 b[3] = (byte)b4; 392 393 int off = 4; 394 len -= off; 395 396 while (len > 0) { 397 int count; 398 try { 399 count = socketInput.read(b, off, len); 400 } catch (IOException ioe) { 401 if (!isOpen()) { 402 throw new ClosedConnectionException 403 ("##> CreateVM002_Connection: readPacket() - connection is closed: N3"); 404 } else { 405 throw ioe; 406 } 407 } 408 if (count < 0) { 409 throw new EOFException 410 ("##> CreateVM002_Connection: readPacket() - read() method returns negative value"); 411 } 412 len -= count; 413 off += count; 414 } 415 416 readPacketRequestNumber++; 417 if ( readPacketRequestNumber == -1 ) { 418 throw new IOException 419 ("Dummy IOException in CreateVM002_Connection.readPacket(); readPacketRequestNumber = " 420 + readPacketRequestNumber); 421 } 422 printPacket("readPacket:", b); 423 return b; 424 } 425 } 426 writePacket(byte b[])427 public void writePacket(byte b[]) throws IOException { 428 writePacketRequestNumber++; 429 if ( writePacketRequestNumber == 2 ) { 430 wasIOException = true; 431 throw new IOException 432 ("Dummy IOException in CreateVM002_Connection.writePacket(); writePacketRequestNumber = " 433 + writePacketRequestNumber); 434 } 435 if (!isOpen()) { 436 throw new ClosedConnectionException 437 ("##> CreateVM002_Connection: writePacket() - connection is closed: N1"); 438 } 439 440 printPacket("writePacket:", b); 441 442 /* 443 * Check the packet size 444 */ 445 if (b.length < 11) { 446 throw new IllegalArgumentException 447 ("##> CreateVM002_Connection: writePacket() - packet is insufficient size: N1"); 448 } 449 int b0 = b[0] & 0xff; 450 int b1 = b[1] & 0xff; 451 int b2 = b[2] & 0xff; 452 int b3 = b[3] & 0xff; 453 int len = ((b0 << 24) | (b1 << 16) | (b2 << 8) | (b3 << 0)); 454 if (len < 11) { 455 throw new IllegalArgumentException 456 ("##> CreateVM002_Connection: writePacket() - packet is insufficient size: N2"); 457 } 458 459 /* 460 * Check that the byte array contains the complete packet 461 */ 462 if (len > b.length) { 463 throw new IllegalArgumentException 464 ("##> CreateVM002_Connection: writePacket() - length mis-match"); 465 } 466 467 synchronized (sendLock) { 468 try { 469 /* 470 * Send the packet (ignoring any bytes that follow 471 * the packet in the byte array). 472 */ 473 socketOutput.write(b, 0, len); 474 } catch (IOException ioe) { 475 if (!isOpen()) { 476 throw new ClosedConnectionException 477 ("##> CreateVM002_Connection: writePacket() - connection is closed: N2"); 478 } else { 479 throw ioe; 480 } 481 } 482 } 483 } 484 toPrintPacket(boolean toPrint)485 public void toPrintPacket(boolean toPrint) { 486 487 if ( toPrintPacket ) { 488 if ( ! toPrint ) { 489 toPrintPacket = false; 490 System.out.println("\n>>>> CreateVM002_Connection: toPrintPacket - Off! " 491 + currentDateWithMlsecs()); 492 } 493 } else { 494 if ( toPrint ) { 495 toPrintPacket = true; 496 System.out.println("\n>>>> CreateVM002_Connection: toPrintPacket - On! " 497 + currentDateWithMlsecs()); 498 } 499 } 500 501 } 502 currentDateWithMlsecs()503 String currentDateWithMlsecs() { 504 GregorianCalendar calendar = new GregorianCalendar(); 505 int year = calendar.get(Calendar.YEAR); 506 int month = calendar.get(Calendar.MONTH) + 1; 507 String strMonth = month > 9 ? "" + month : "0" + month; 508 int day = calendar.get(Calendar.DAY_OF_MONTH); 509 String strDay = day > 9 ? "" + day : "0" + day; 510 int hours = calendar.get(Calendar.HOUR_OF_DAY); 511 String strHours = hours > 9 ? "" + hours : "0" + hours; 512 int minutes = calendar.get(Calendar.MINUTE); 513 String strMinutes = minutes > 9 ? "" + minutes : "0" + minutes; 514 int seconds = calendar.get(Calendar.SECOND); 515 String strSeconds = seconds > 9 ? "" + seconds : "0" + seconds; 516 int mlsecs = (int)(calendar.getTimeInMillis() % 1000); 517 String strMlsecs = mlsecs < 10 ? "00" + mlsecs : (mlsecs < 100 ? "0" + mlsecs : "" + mlsecs); 518 return "" + year + "." + strMonth + "." + strDay + "; " + strHours 519 + ":" + strMinutes + ":" + strSeconds + "::" + strMlsecs; 520 } 521 522 public void printPacket(String headMessage, byte b[]) { 523 524 if ( ! toPrintPacket ) { 525 return; 526 } 527 528 System.out.println("\n>>>> CreateVM005_Connection: printPacket: " + currentDateWithMlsecs()); 529 System.out.println(" >> " + headMessage); 530 int packetLength = b.length; 531 532 String handsHake = "JDWP-Handshake"; 533 534 System.out.println(" >> packet length = " + packetLength); 535 if ( packetLength < 11 ) { 536 System.out.println(" >> Invalid packet length!"); 537 System.out.println("\n>>>> CreateVM005_Connection: printPacket - END\n"); 538 return; 539 } 540 541 String packetString = new String(b); 542 if ( handsHake.equals(packetString) ) { 543 System.out.println(" >> Packet as String = " + packetString); 544 System.out.println("\n>>>> CreateVM005_Connection: printPacket - END\n"); 545 return; 546 } 547 548 int b0 = b[0] & 0xff; 549 int b1 = b[1] & 0xff; 550 int b2 = b[2] & 0xff; 551 int b3 = b[3] & 0xff; 552 int lengthField = ((b0 << 24) | (b1 << 16) | (b2 << 8) | (b3 << 0)); 553 System.out.println(" >> lengthField = " + lengthField); 554 555 int b4 = b[4] & 0xff; 556 int b5 = b[5] & 0xff; 557 int b6 = b[6] & 0xff; 558 int b7 = b[7] & 0xff; 559 int idField = ((b4 << 24) | (b5 << 16) | (b6 << 8) | (b7 << 0)); 560 System.out.println(" >> idField(integer) = " + idField); 561 562 int flagsField = b[8] & 0xff; 563 System.out.println(" >> flagsField(integer) = " + flagsField); 564 int replyPacket = b[8] & 0x80; 565 if ( replyPacket != 0 ) { 566 System.out.println(" >> Replay Packet:"); 567 int b9 = b[9] & 0xff; 568 int b10 = b[10] & 0xff; 569 int errorCodeField = ((b9 << 8) | (b10 << 0)); 570 System.out.println(" >> errorCodeField(integer) = " + errorCodeField); 571 } else { 572 System.out.println(" >> Command Packet:"); 573 int commandSetField = b[9] & 0xff; 574 System.out.println(" >> commandSetField(integer) = " + commandSetField); 575 int commandField = b[10] & 0xff; 576 System.out.println(" >> commandField(integer) = " + commandField); 577 } 578 579 if ( packetLength > 11 ) { 580 int dataLength = packetLength-11; 581 String data = ""; 582 for (int i=0; i < dataLength; i++) { 583 data = data + "," + (int)(b[11+i] & 0xff); 584 } 585 System.out.println(" >> Packet's data = " + data); 586 } 587 System.out.println(">>>> CreateVM005_Connection: printPacket - END"); 588 } 589 590 } // end of CreateVM002_Connection class 591 592 /* 593 * The capabilities of the socket transport service 594 */ 595 class CreateVM002_TranspServCapabilities extends TransportService.Capabilities { 596 597 public boolean supportsMultipleConnections() { 598 return true; 599 } 600 601 public boolean supportsAttachTimeout() { 602 return true; 603 } 604 605 public boolean supportsAcceptTimeout() { 606 return true; 607 } 608 609 public boolean supportsHandshakeTimeout() { 610 return true; 611 } 612 613 } // end of CreateVM002_TranspServCapabilities class 614