1 /* 2 * Copyright (c) 2001, 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.share.jdwp; 25 26 import nsk.share.*; 27 28 import java.util.Vector; 29 import java.io.*; 30 31 /** 32 * This class represents a JDWP packet. 33 */ 34 public class Packet extends ByteBuffer { 35 36 /** JDWP packet flags constant. */ 37 // public final static byte flNoFlags = (byte)0x0; 38 /** JDWP packet flags constant. */ 39 // public final static byte flReply = (byte)0x80; 40 41 /** Offset of "length" field of JDWP packet. */ 42 public final static int LengthOffset = 0; 43 /** Offset of "id" field of JDWP packet. */ 44 public final static int IdOffset = LengthOffset + 4; 45 /** Offset of "flags" field of JDWP packet. */ 46 public final static int FlagsOffset = IdOffset + 4; 47 /** Offset of full "command" field of JDWP packet. */ 48 public final static int FullCommandOffset = FlagsOffset + 1; 49 /** Offset of "command" field of JDWP command packet. */ 50 public final static int CommandSetOffset = FullCommandOffset; 51 /** Offset of "command" field of JDWP command packet. */ 52 public final static int CommandOffset = CommandSetOffset + 1; 53 /** Offset of "error" field of JDWP reply packet. */ 54 public final static int ErrorCodeOffset = FlagsOffset + 1; 55 /** Offset of "data" section of JDWP packet. */ 56 public final static int DataOffset = FullCommandOffset + 2; 57 58 /** Size of JDWP packet header. */ 59 public final static int PacketHeaderSize = DataOffset; 60 61 /** 62 * Makes empty JDWP packet. 63 */ Packet()64 public Packet() { 65 super(); 66 resetBuffer(); 67 } 68 69 /** 70 * Makes JDWP packet with data from the specified byte buffer. 71 */ 72 // public Packet(ByteBuffer packet) { Packet(Packet packet)73 public Packet(Packet packet) { 74 super(packet); 75 resetPosition(); 76 } 77 78 /** 79 * Clear buffer of the packet. 80 */ resetBuffer()81 public void resetBuffer() { 82 super.resetBuffer(); 83 while (length() < PacketHeaderSize) 84 addByte((byte) 0); 85 setLength(); 86 resetPosition(); 87 } 88 89 /** 90 * Return current position from begin of packet data area. 91 */ currentDataPosition()92 public int currentDataPosition() { 93 return currentPosition() - PacketHeaderSize; 94 } 95 96 /** 97 * Return value to the "length" field of JDWP packet. 98 */ getLength()99 public int getLength() { 100 try { 101 return getInt(LengthOffset); 102 } 103 catch (BoundException e) { 104 throw new Failure("Caught unexpected exception while getting packet length value from header:\n\t" 105 + e); 106 } 107 } 108 109 /** 110 * Assign specified value to the "length" field of JDWP packet. 111 */ setLength(int length)112 public void setLength(int length) { 113 try { 114 putInt(LengthOffset, length); 115 } 116 catch (BoundException e) { 117 throw new Failure("Caught unexpected exception while setting packet length value into header:\n\t" 118 + e); 119 } 120 } 121 122 /** 123 * Assign packet length value to the "length" field of JDWP packet. 124 */ setLength()125 public void setLength() { 126 setLength(length()); 127 } 128 129 /** 130 * Return value of the "id" field of JDWP packet. 131 */ getPacketID()132 public int getPacketID() { 133 try { 134 return getInt(IdOffset); 135 } 136 catch (BoundException e) { 137 throw new Failure("Caught unexpected exception while getting packet ID value from header:\n\t" 138 + e); 139 } 140 } 141 142 /** 143 * Assign value to the "id" field of JDWP packet. 144 */ setPacketID(int Id)145 public void setPacketID(int Id) { 146 try { 147 putInt(IdOffset, Id); 148 } 149 catch (BoundException e) { 150 throw new Failure("Caught unexpected exception while setting packet ID value into header:\n\t" 151 + e); 152 } 153 } 154 155 /** 156 * Return value of the "flags" field of JDWP packet. 157 */ getFlags()158 public byte getFlags() { 159 try { 160 return getByte(FlagsOffset); 161 } 162 catch (BoundException e) { 163 throw new Failure("Caught unexpected exception while getting packet flags value from header:\n\t" 164 + e); 165 } 166 } 167 168 /** 169 * Assign value to the "flags" field of JDWP packet. 170 */ setFlags(byte flags)171 public void setFlags(byte flags) { 172 try { 173 putByte(FlagsOffset, flags); 174 } 175 catch (BoundException e) { 176 throw new Failure("Caught unexpected exception while setting packet flags value into header:\n\t" 177 + e); 178 } 179 } 180 181 /** 182 * Sets the current parser position to "data" field of JDWP packet. 183 */ resetPosition()184 public void resetPosition() { 185 resetPosition(PacketHeaderSize); 186 } 187 188 /** 189 * Return size of the "data" part of JDWP packet. 190 */ getDataSize()191 public int getDataSize() { 192 return length() - PacketHeaderSize; 193 } 194 195 ////////////////////////////////////////////////////////////////////////// 196 197 /** 198 * Append fieldID to the end of this buffer. 199 */ addFieldID(long b)200 public void addFieldID(long b) { 201 addID(b, JDWP.TypeSize.FIELD_ID); 202 } 203 204 /** 205 * Append methodID to the end of this buffer. 206 */ addMethodID(long b)207 public void addMethodID(long b) { 208 addID(b, JDWP.TypeSize.METHOD_ID); 209 } 210 211 /** 212 * Append objectID to the end of this buffer. 213 */ addObjectID(long b)214 public void addObjectID(long b) { 215 addID(b, JDWP.TypeSize.OBJECT_ID); 216 } 217 218 /** 219 * Append referenceID to the end of this buffer. 220 */ addReferenceTypeID(long b)221 public void addReferenceTypeID(long b) { 222 addID(b, JDWP.TypeSize.REFERENCE_TYPE_ID); 223 } 224 225 /** 226 * Append frameID to the end of this buffer. 227 */ addFrameID(long b)228 public void addFrameID(long b) { 229 addID(b, JDWP.TypeSize.FRAME_ID); 230 } 231 232 /** 233 * Append string value (an UTF-8 encoded string, not zero terminated, 234 * preceded by a four-byte integer length) to the end of this buffer. 235 */ addString(String value)236 public void addString(String value) { 237 final int count = JDWP.TypeSize.INT + value.length(); 238 addInt(value.length()); 239 try { 240 addBytes(value.getBytes("UTF-8"), 0, value.length()); 241 } catch (UnsupportedEncodingException e) { 242 throw new Failure("Unsupported UTF-8 ecnoding while adding string value to JDWP packet:\n\t" 243 + e); 244 } 245 } 246 247 /** 248 * Append location value to the end of this buffer. 249 */ addLocation(JDWP.Location location)250 public void addLocation(JDWP.Location location) { 251 addBytes(location.getBytes(), 0, location.length()); 252 } 253 254 /** 255 * Append untagged value to the end of this buffer. 256 */ addUntaggedValue(JDWP.UntaggedValue value, byte tag)257 public void addUntaggedValue(JDWP.UntaggedValue value, byte tag) { 258 value.addValueTo(this, tag); 259 } 260 261 /** 262 * Append tagged value to the end of this buffer. 263 */ addValue(JDWP.Value value)264 public void addValue(JDWP.Value value) { 265 value.addValueTo(this); 266 } 267 268 ////////////////////////////////////////////////////////////////////////// 269 // get packet data 270 ////////////////////////////////////////////////////////////////////////// 271 272 /** 273 * Read a fieldID value from byte buffer at the current parser position. 274 * 275 * @throws BoundException if there is no valid value bytes at the given position 276 */ getFieldID()277 public long getFieldID() throws BoundException { 278 return getID(JDWP.TypeSize.FIELD_ID); 279 } 280 281 /** 282 * Read a methodID value from byte buffer at the current parser position. 283 * 284 * @throws BoundException if there is no valid value bytes at the given position 285 */ getMethodID()286 public long getMethodID() throws BoundException { 287 return getID(JDWP.TypeSize.METHOD_ID); 288 } 289 290 /** 291 * Read an objectID value from byte buffer at the current parser position. 292 * 293 * @throws BoundException if there is no valid value bytes at the given position 294 */ getObjectID()295 public long getObjectID() throws BoundException { 296 return getID(JDWP.TypeSize.OBJECT_ID); 297 } 298 299 /** 300 * Read a referenceTypeID value from byte buffer at the current parser position. 301 * 302 * @throws BoundException if there is no valid value bytes at the given position 303 */ getReferenceTypeID()304 public long getReferenceTypeID() throws BoundException { 305 return getID(JDWP.TypeSize.REFERENCE_TYPE_ID); 306 } 307 308 /** 309 * Read a frameID value from byte buffer at the current parser position. 310 * 311 * @throws BoundException if there is no valid value bytes at the given position 312 */ getFrameID()313 public long getFrameID() throws BoundException { 314 return getID(JDWP.TypeSize.FRAME_ID); 315 } 316 317 /** 318 * Read from this buffer a string value at the current parser 319 * position and returns this value. 320 * 321 * @throws BoundException if there are no valid string bytes in the buffer 322 */ getString()323 public String getString() throws BoundException { 324 final int count = JDWP.TypeSize.INT; 325 int available = length() - currentPosition(); 326 if (count > available) { 327 throw new BoundException("Unable to get " + count + " bytes of string length value at " + 328 offsetString() + " (available bytes: " + available + ")" ); 329 } 330 331 int len = getInt(); 332 333 if (len < 0) 334 throw new BoundException("Negative length of string to get: " + len); 335 336 if (len == 0) 337 return ""; 338 339 available = length() - currentPosition(); 340 if (len > available) { 341 throw new BoundException("Unable to get " + len + " bytes of string value at " + 342 offsetString() + " (available bytes: " + available + ")" ); 343 } 344 345 byte[] s = new byte[len]; 346 for (int i = 0; i < len; i++) 347 s[i] = getByte(); 348 349 try { 350 return new String(s, "UTF-8"); 351 } catch (UnsupportedEncodingException e) { 352 throw new Failure("Unsupported UTF-8 ecnoding while extracting string value from JDWP packet:\n\t" 353 + e); 354 } 355 } 356 357 /** 358 * Reads from this buffer an location value at the current parser 359 * position and returns this value. 360 * 361 * @throws BoundException if there are no enough bytes in the buffer 362 */ getLocation()363 public JDWP.Location getLocation() throws BoundException { 364 final int count = JDWP.TypeSize.LOCATION; 365 final int available = length() - currentPosition(); 366 if (count > available) { 367 throw new BoundException("Unable to get " + count + " bytes of location value at " + 368 offsetString() + " (available bytes: " + available + ")" ); 369 } 370 371 JDWP.Location location = new JDWP.Location(); 372 try { 373 for (int i = 0; i < JDWP.TypeSize.LOCATION; i++) { 374 location.putByte(i, getByte()); 375 } 376 } 377 catch (BoundException e) { 378 throw new TestBug("Caught unexpected bound exception while getting " + 379 count + " bytes of location value:\n\t" + e); 380 }; 381 382 return location; 383 } 384 385 /** 386 * Reads from this buffer an untagged value at the current parser 387 * position and returns this value. 388 * 389 * @throws BoundException if there are no enough bytes in the buffer 390 */ getUntaggedValue(byte tag)391 public JDWP.UntaggedValue getUntaggedValue(byte tag) throws BoundException { 392 JDWP.UntaggedValue value = new JDWP.UntaggedValue(); 393 try { 394 value.getValueFrom(this, tag); 395 } 396 catch (BoundException e) { 397 throw new TestBug("Caught unexpected bound exception while getting " + 398 " bytes of a value:\n\t" + e); 399 }; 400 401 return value; 402 } 403 404 /** 405 * Reads from this buffer a tagged value at the current parser 406 * position and returns this value. 407 * 408 * @throws BoundException if there are no enough bytes in the buffer 409 */ getValue()410 public JDWP.Value getValue() throws BoundException { 411 JDWP.Value value = new JDWP.Value(); 412 try { 413 value.getValueFrom(this); 414 } 415 catch (BoundException e) { 416 throw new TestBug("Caught unexpected bound exception while getting " + 417 " bytes of a value:\n\t" + e); 418 }; 419 420 return value; 421 } 422 423 424 //////////////////////////////////////////////////////////////// 425 426 /** 427 * Read packet bytes from the stream. 428 * 429 * @throws IOException if error occured when reading bytes 430 */ readFrom(Transport transport)431 public void readFrom(Transport transport) throws IOException { 432 resetBuffer(); 433 434 // System.err.println("Reading packet header"); 435 try { 436 for (int i = 0; i < PacketHeaderSize; i++) { 437 byte b = transport.read(); 438 putByte(i, b); 439 } 440 } 441 catch (BoundException e) { 442 throw new TestBug(e); 443 } 444 445 int length = getLength(); 446 447 checkSpace(length - PacketHeaderSize); 448 449 // System.err.println("Packet size: " + length); 450 for (int i = PacketHeaderSize; i < length; i++) { 451 byte b = transport.read(); 452 addByte(b); 453 } 454 // System.err.println("Packet read successfully"); 455 } 456 457 /** 458 * Write packet bytes to the stream. 459 * 460 * @throws IOException if error occured when reading bytes 461 */ writeTo(Transport transport)462 public void writeTo(Transport transport) throws IOException { 463 setLength(); 464 // System.err.println("Writing packet bytes: " + length()); 465 transport.write(bytes, 0, length()); 466 } 467 468 /** 469 * Check packet header. 470 * This method check if packet has valid values in header fields. 471 * 472 * @throws PacketFormatException if packet header fields has error or invalid values 473 */ checkHeader()474 public void checkHeader() throws PacketFormatException { 475 if (getLength() != length()) { 476 throw new PacketFormatException("Unexpected packet length value in the header:" 477 + getLength()); 478 } 479 } 480 481 /** 482 * Check if packet is parsed totally and no trailing bytes left unparsed. 483 * This method check if packet has valid values in header fields. 484 * 485 * @throws PacketFormatException if there are trailing bytes left unparsed 486 */ checkParsed()487 public void checkParsed() throws PacketFormatException { 488 if (! isParsed()) { 489 throw new PacketFormatException("Extra trailing bytes found in the packet at: " 490 + offsetString()); 491 } 492 } 493 494 /** 495 * Return string representation of the packet header. 496 */ headerToString()497 public String headerToString() { 498 return "Packet header (" + PacketHeaderSize + " bytes):" + "\n" 499 + " " + toHexString(LengthOffset, 4) + " (length) : 0x" + toHexDecString(getLength(), 8) + "\n" 500 + " " + toHexString(IdOffset, 4) + " (id) : 0x" + toHexDecString(getPacketID(), 8) + "\n" 501 + " " + toHexString(FlagsOffset, 4) + " (flags) : 0x" + toHexDecString(getFlags(), 2) + "\n"; 502 } 503 504 /** 505 * Return string representation of the packet. 506 */ toString()507 public String toString() { 508 return headerToString() 509 + "Entire packet (" + length() + " bytes): " + "\n" 510 + super.toString(0) 511 + "Packet end"; 512 } 513 514 /** 515 * Exception indicated that packet has an ivnalid structure. 516 */ 517 class PacketFormatException extends BoundException { PacketFormatException(String message)518 PacketFormatException(String message) { 519 super(message); 520 } 521 } 522 } 523