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.transprot.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: * @param index index into <code>bytes</code> to start processing 187: * @return number of bytes in <code>bytes</code> processed 188: */ 189: public static JdwpPacket fromBytes (byte[] bytes) 190: { 191: int i = 0; 192: int length = ((bytes[i++] & 0xff) << 24 | (bytes[i++] & 0xff) << 16 193: | (bytes[i++] & 0xff) << 8 | (bytes[i++] & 0xff)); 194: int id = 0; 195: byte flags = 0; 196: 197: if (bytes.length == length) 198: { 199: id = ((bytes[i++] & 0xff) << 24 | (bytes[i++] & 0xff) << 16 200: | (bytes[i++] & 0xff) << 8 | (bytes[i++] & 0xff)); 201: flags = bytes[i++]; 202: 203: Class clazz = null; 204: if (flags == 0) 205: clazz = JdwpCommandPacket.class; 206: else if ((flags & JDWP_FLAG_REPLY) != 0) 207: clazz = JdwpReplyPacket.class; 208: else 209: { 210: // Malformed packet. Discard it. 211: return null; 212: } 213: 214: JdwpPacket pkt = null; 215: try 216: { 217: pkt = (JdwpPacket) clazz.newInstance (); 218: } 219: catch (InstantiationException ie) 220: { 221: // Discard packet 222: return null; 223: } 224: catch (IllegalAccessException iae) 225: { 226: // Discard packet 227: return null; 228: } 229: 230: pkt.setId (id); 231: pkt.setFlags (flags); 232: 233: i += pkt.myFromBytes (bytes, i); 234: byte[] data = new byte[length - i]; 235: System.arraycopy (bytes, i, data, 0, data.length); 236: pkt.setData (data); 237: 238: return pkt; 239: } 240: 241: return null; 242: } 243: 244: /** 245: * Put subclass information onto the stream 246: * 247: * @param dos the output stream to which to write 248: */ 249: protected abstract void myWrite (DataOutputStream dos) 250: throws IOException; 251: 252: /** 253: * Writes the packet to the output stream 254: * 255: * @param dos the output stream to which to write the packet 256: */ 257: public void write (DataOutputStream dos) 258: throws IOException 259: { 260: // length 261: int length = getLength (); 262: dos.writeInt (length); 263: 264: // ID 265: dos.writeInt (getId ()); 266: 267: // flag 268: dos.writeByte (getFlags ()); 269: 270: // packet-specific stuff 271: myWrite (dos); 272: 273: // data (if any) 274: byte[] data = getData (); 275: if (data != null && data.length > 0) 276: dos.write (data, 0, data.length); 277: } 278: }