Source for gnu.classpath.jdwp.transport.JdwpPacket

   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: }