Frames | No Frames |
1: /* JdwpPacket.java -- Base class for JDWP command and reply packets 2: Copyright (C) 2005 Free Software Foundation 3: 4: This file is part of GNU Classpath. 5: 6: GNU Classpath is free software; you can redistribute it and/or modify 7: it under the terms of the GNU General Public License as published by 8: the Free Software Foundation; either version 2, or (at your option) 9: any later version. 10: 11: GNU Classpath is distributed in the hope that it will be useful, but 12: WITHOUT ANY WARRANTY; without even the implied warranty of 13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14: General Public License for more details. 15: 16: You should have received a copy of the GNU General Public License 17: along with GNU Classpath; see the file COPYING. If not, write to the 18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19: 02110-1301 USA. 20: 21: Linking this library statically or dynamically with other modules is 22: making a combined work based on this library. Thus, the terms and 23: conditions of the GNU General Public License cover the whole 24: combination. 25: 26: As a special exception, the copyright holders of this library give you 27: permission to link this library with independent modules to produce an 28: executable, regardless of the license terms of these independent 29: modules, and to copy and distribute the resulting executable under 30: terms of your choice, provided that you also meet, for each linked 31: terms of your choice, provided that you also meet, for each linked 32: independent module, the terms and conditions of the license of that 33: module. An independent module is a module which is not derived from 34: or based on this library. If you modify this library, you may extend 35: this exception to your version of the library, but you are not 36: obligated to do so. If you do not wish to do so, delete this 37: exception statement from your version. */ 38: 39: 40: package gnu.classpath.jdwp.transport; 41: 42: import java.io.DataOutputStream; 43: import java.io.IOException; 44: 45: /** 46: * All command and reply packets in JDWP share 47: * common header type information: 48: * 49: * length (4 bytes) : size of entire packet, including length 50: * id (4 bytes) : unique packet id 51: * flags (1 byte) : flag byte 52: * [command packet stuff | reply packet stuff] 53: * data (variable) : unique command-/reply-specific data 54: * 55: * This class deal with everything except the command- and reply-specific 56: * data, which get handled in {@link 57: * gnu.classpath.jdwp.transport.JdwpCommandPacket} and {@link 58: * gnu.classpath.jdwp.transport.JdwpReplyPacket}. 59: * 60: * @author Keith Seitz <keiths@redhat.com> 61: */ 62: public abstract class JdwpPacket 63: { 64: // Last id of packet constructed 65: protected static int _last_id = 0; 66: 67: // JDWP reply packet flag 68: protected static final int JDWP_FLAG_REPLY = 0x80; 69: 70: /** 71: * Minimum packet size excluding sub-class data 72: * ( length (4) + id (4) + flags (1) ) 73: */ 74: protected static final int MINIMUM_SIZE = 9; 75: 76: /** 77: * Id of command/reply 78: */ 79: protected int _id; 80: 81: /** 82: * Packet flags 83: */ 84: protected byte _flags; 85: 86: /** 87: * Packet-specific data 88: */ 89: protected byte[] _data; 90: 91: /** 92: * Constructor 93: */ 94: public JdwpPacket () 95: { 96: // By default, DON'T assign an id. This way when a packet 97: // is constructed from fromBytes, _last_id won't increment (i.e., 98: // it won't leave holes in the outgoing packet ids). 99: } 100: 101: /** 102: * Constructs a <code>JdwpPacket</code> with the id 103: * from the given packet. 104: * 105: * @param pkt a packet whose id will be used in this new packet 106: */ 107: public JdwpPacket (JdwpPacket pkt) 108: { 109: _id = pkt.getId (); 110: } 111: 112: /** 113: * Returns the packet id 114: */ 115: public int getId () 116: { 117: return _id; 118: } 119: 120: /** 121: * Sets the packet id 122: */ 123: public void setId (int id) 124: { 125: _id = id; 126: } 127: 128: /** 129: * Returns the packet flags 130: */ 131: public byte getFlags () 132: { 133: return _flags; 134: } 135: 136: /** 137: * Sets the packet flags 138: */ 139: public void setFlags (byte flags) 140: { 141: _flags = flags; 142: } 143: 144: /** 145: * Gets the command/reply-specific data in this packet 146: */ 147: public byte[] getData () 148: { 149: return _data; 150: } 151: 152: /** 153: * Sets the command/reply-specific data in this packet 154: */ 155: public void setData (byte[] data) 156: { 157: _data = data; 158: } 159: 160: /** 161: * Returns the length of this entire packet 162: */ 163: public int getLength () 164: { 165: return MINIMUM_SIZE + (_data == null ? 0 : _data.length); 166: } 167: 168: /** 169: * Allow subclasses to initialize from data 170: * 171: * @param bytes packet data from the wire 172: * @param index index into <code>bytes</code> to start processing 173: * @return number of bytes in <code>bytes</code> processed 174: */ 175: protected abstract int myFromBytes (byte[] bytes, int index); 176: 177: /** 178: * Convert the given bytes into a <code>JdwpPacket</code>. Uses the 179: * abstract method <code>myFromBytes</code> to allow subclasses to 180: * process data. 181: * 182: * If the given data does not represent a valid JDWP packet, it returns 183: * <code>null</code>. 184: * 185: * @param bytes packet data from the wire 186: * @return number of bytes in <code>bytes</code> processed 187: */ 188: public static JdwpPacket fromBytes (byte[] bytes) 189: { 190: int i = 0; 191: int length = ((bytes[i++] & 0xff) << 24 | (bytes[i++] & 0xff) << 16 192: | (bytes[i++] & 0xff) << 8 | (bytes[i++] & 0xff)); 193: int id = 0; 194: byte flags = 0; 195: 196: if (bytes.length == length) 197: { 198: id = ((bytes[i++] & 0xff) << 24 | (bytes[i++] & 0xff) << 16 199: | (bytes[i++] & 0xff) << 8 | (bytes[i++] & 0xff)); 200: flags = bytes[i++]; 201: 202: Class clazz = null; 203: if (flags == 0) 204: clazz = JdwpCommandPacket.class; 205: else if ((flags & JDWP_FLAG_REPLY) != 0) 206: clazz = JdwpReplyPacket.class; 207: else 208: { 209: // Malformed packet. Discard it. 210: return null; 211: } 212: 213: JdwpPacket pkt = null; 214: try 215: { 216: pkt = (JdwpPacket) clazz.newInstance (); 217: } 218: catch (InstantiationException ie) 219: { 220: // Discard packet 221: return null; 222: } 223: catch (IllegalAccessException iae) 224: { 225: // Discard packet 226: return null; 227: } 228: 229: pkt.setId (id); 230: pkt.setFlags (flags); 231: 232: i += pkt.myFromBytes (bytes, i); 233: byte[] data = new byte[length - i]; 234: System.arraycopy (bytes, i, data, 0, data.length); 235: pkt.setData (data); 236: 237: return pkt; 238: } 239: 240: return null; 241: } 242: 243: /** 244: * Put subclass information onto the stream 245: * 246: * @param dos the output stream to which to write 247: */ 248: protected abstract void myWrite (DataOutputStream dos) 249: throws IOException; 250: 251: /** 252: * Writes the packet to the output stream 253: * 254: * @param dos the output stream to which to write the packet 255: */ 256: public void write (DataOutputStream dos) 257: throws IOException 258: { 259: // length 260: int length = getLength (); 261: dos.writeInt (length); 262: 263: // ID 264: dos.writeInt (getId ()); 265: 266: // flag 267: dos.writeByte (getFlags ()); 268: 269: // packet-specific stuff 270: myWrite (dos); 271: 272: // data (if any) 273: byte[] data = getData (); 274: if (data != null && data.length > 0) 275: dos.write (data, 0, data.length); 276: } 277: }