This is the mail archive of the java-patches@gcc.gnu.org mailing list for the Java project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[RFA] gnu.gcj.jdwp.transport: packet classes


Hi,

So, to start simple, here are three classes to deal with constructing
packets.

JDWP has two packet types: command packets and reply packets. The
debugger sends (only) command packets to the vm. Each packet has its own
packet id.

When a reply is sent from the VM, the reply packet must use the same id
as the corresponding command packet.

Other than that, I don't think there is anything too confusing about
this. A nice and easy one to start. :-)

[Yes, I do have unit tests for this. Someone will send testsuite patches
soon.]

Questions/comments/concerns?
Keith

ChangeLog
2005-05-27  Keith Seitz  <keiths@redhat.com>

        * gnu/gcj/jdwp/transport/JdwpPacket.java: New file.
        * gnu/gcj/jdwp/transport/JdwpCommandPacket.java: New file.
        * gnu/gcj/jdwp/transport/JdwpReplyPacket.java: New file.

Index: gnu/gcj/jdwp/transport/JdwpCommandPacket.java
--- /dev/null
+++ gnu/gcj/jdwp/transport/JdwpCommandPacket.java
@@ -0,0 +1,94 @@
+/* Copyright (C) 2005 Free Software Foundation
+
+   This file is part of libgcj.
+
+This software is copyrighted work licensed under the terms of the
+Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
+details. */
+
+package gnu.gcj.jdwp.transport;
+
+/**
+ * A class representing a JDWP command packet
+ *
+ * @author Keith Seitz  <keiths@redhat.com>
+ */
+public class JdwpCommandPacket extends JdwpPacket
+{
+  // header stuff
+  protected byte _commandSet;
+  protected byte _command;
+
+  // Minimum packet size [excluding super class] ( commandSet (1) + command (1) )
+  private static final int MINIMUM_LENGTH = 2;
+
+  /**
+   * Constructs a new <code>JdwpCommandPacket</code>
+   */
+  public JdwpCommandPacket ()
+  {
+    // Don't assign an id. This constructor is called by
+    // JdwpPacket.fromBytes, and that will assign a packet id.
+  }
+  
+  /**
+   * Constructs a new <code>JdwpCommandPacket</code>
+   * with the given command set and command
+   *
+   * @param set      the command set
+   * @param command  the command
+   */
+  public JdwpCommandPacket (byte set, byte command)
+  {
+    _id = ++_last_id;
+    _commandSet = set;
+    _command = command;
+  }
+
+  /**
+   * Retuns the length of this packet
+   */
+  public int getLength () { return MINIMUM_LENGTH + super.getLength (); }
+
+  /**
+   * Returns the command set
+   */
+  public byte getCommandSet () { return _commandSet; }
+
+  /**
+   * Sets the command set
+   */
+  public void setCommandSet (byte cs) { _commandSet = cs; }
+
+  /**
+   * Returns the command
+   */
+  public byte getCommand () { return _command; }
+
+  /**
+   * Sets the command
+   */
+  public void setCommand (byte cmd) { _command = cmd; }
+
+  // Reads command packet data from the given buffer, starting
+  // at the given offset
+  protected int myFromBytes (byte[] bytes, int index)
+  {
+    int i = 0;
+    setCommandSet (bytes[index + i++]);
+    setCommand (bytes[index + i++]);
+    return i;
+  }
+
+  // Writes the command packet data into the given buffer
+  protected int myToBytes (byte[] bytes, int index)
+  {
+    // Need to add command set & command
+    int i = 0;
+    bytes[index + i++] = getCommandSet ();
+    bytes[index + i++] = getCommand ();
+
+    return i;
+  }
+}
+
Index: gnu/gcj/jdwp/transport/JdwpPacket.java
--- /dev/null
+++ gnu/gcj/jdwp/transport/JdwpPacket.java
@@ -0,0 +1,222 @@
+/* Copyright (C) 2005 Free Software Foundation
+
+   This file is part of libgcj.
+
+This software is copyrighted work licensed under the terms of the
+Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
+details. */
+
+package gnu.gcj.jdwp.transport;
+
+/**
+ * A baseclass representing common data in JDWP packets
+ *
+ * @author Keith Seitz  <keiths@redhat.com>
+ */
+public abstract class JdwpPacket
+{
+  // Last id of packet constructed
+  protected static int _last_id = 0;
+
+  protected static final int JDWP_FLAG_REPLY = 0x80;
+
+  /* Packet layout:
+   * header:
+   *    length (4 bytes) : size of entire packet, including length
+   *    id     (4 bytes) : unique packet id
+   *    flags  (1 byte)  : flag byte
+   *    [command packet stuff | reply packet stuff]
+   *    data   (variable) : unique command-/reply-specific data
+   *
+   * This class deal with everything except the command- and reply-specific
+   * stuff, which get handled in JdwpCommandPacket and JdwpReplyPacket.
+   */ 
+    
+  // Minimum packet size excluding sub-class stuff ( length (4) + id (4) + flags (1) )
+  protected static final int MINIMUM_SIZE = 9;
+
+  // Id of command/reply
+  protected int _id;
+
+  // Flags
+  protected byte _flags;
+
+  // Variable data
+  protected byte[] _data;
+
+  /**
+   * Constructor
+   */
+  public JdwpPacket ()
+  {
+    // By default, DON'T assign an id. This way when a packet
+    // is constructed from fromBytes, _last_id won't increment (i.e.,
+    // it won't leave holes int the outgoing packet ids).
+  }
+
+  /**
+   * Constructs a <code>JdwpPacket</code> with the id
+   * from the given packet.
+   *
+   * @param pkt  a packet whose id will be used in this new packet
+   */
+  public JdwpPacket (JdwpPacket pkt)
+  {
+    _id = pkt.getId ();
+  }
+
+  /**
+   * Returns the packet id
+   */
+  public int getId () { return _id; }
+
+  /**
+   * Sets the packet id
+   */
+  public void setId (int id) { _id = id; }
+
+  /**
+   * Returns the packet flags
+   */
+  public byte getFlags () { return _flags; }
+
+  /**
+   * Sets the packet flags
+   */
+  public void setFlags (byte flags) { _flags = flags; }
+
+  /**
+   * Gets the command/reply-specific data in this packet
+   */
+  public byte[] getData () { return _data; }
+
+  /**
+   * Sets the command/reply-specific data in this packet
+   */
+  public void setData (byte[] data) { _data = data; }
+
+  /**
+   * Returns the length of this entire packet
+   */
+  public int getLength () { return MINIMUM_SIZE + (_data == null ? 0 : _data.length); }
+
+  /**
+   * Allow subclasses to initialize from data
+   * 
+   * @param   bytes  packet data from the wire
+   * @param   index  index into <code>bytes</code> to start processing
+   * @return         number of bytes in <code>bytes</code> processed
+   */
+  protected abstract int myFromBytes (byte[] bytes, int index);
+
+  /**
+   * Convert the given bytes into a <code>JdwpPacket</code>. Uses the
+   * abstract method <code>myFromBytes</code> to allow subclasses to
+   * process data.
+   *
+   * If the given data does not represent a valid JDWP packet, it returns
+   * <code>null</code>.
+   * 
+   * @param   bytes  packet data from the wire
+   * @param   index  index into <code>bytes</code> to start processing
+   * @return         number of bytes in <code>bytes</code> processed
+   */
+  public static JdwpPacket fromBytes (byte[] bytes)
+  {
+    int i = 0;
+    int length = (bytes[i++] << 24) | (bytes[i++] << 16) | (bytes[i++] << 8) | bytes[i++];
+    int id = 0;
+    byte flags = 0;
+
+    if (bytes.length == length)
+      {
+	id = (bytes[i++] << 24) | (bytes[i++] << 16) | (bytes[i++] << 8) | bytes[i++];
+	flags = bytes[i++];
+
+	Class clazz = null;
+	if (flags == 0)
+	  clazz = JdwpCommandPacket.class;
+	else if ((flags & JDWP_FLAG_REPLY) != 0)
+	  clazz = JdwpReplyPacket.class;
+	else
+	  {
+	    // Malformed packet. Discard it.
+	    return null;
+	  }
+
+	JdwpPacket pkt = null;
+	try
+	  {
+	    pkt = (JdwpPacket) clazz.newInstance ();
+	  }
+	catch (InstantiationException ie)
+	  {
+	    // Discard packet
+	    return null;
+	  }
+	catch (IllegalAccessException iae)
+	  {
+	    // Discard packet
+	    return null;
+	  }
+
+	pkt.setId (id);
+	pkt.setFlags (flags);
+
+	i += pkt.myFromBytes (bytes, i);
+	byte[] data = new byte[length - i];
+	System.arraycopy (bytes, i, data, 0, data.length);
+	pkt.setData (data);
+
+	return pkt;
+      }
+	
+    return null;
+  }
+
+  // Put subclass information into bytes
+  protected abstract int myToBytes (byte[] bytes, int index);
+
+  // Convert this packet to it byte representation (ready to send on the wire)
+  // NOTE: All integers should be big-endian.
+  public byte[] toBytes ()
+  {
+    // Allocate a new array to hold contents of packet
+    int length = getLength ();
+    byte[] bytes = new byte[length];
+	
+    int i = 0;
+
+    //
+    // Packet layout: length, id, flags, packet-specific, data (optional)
+    //
+
+    // length
+    bytes[i++] = (byte) ((length >>> 24) & 0xff);
+    bytes[i++] = (byte) ((length >>> 16) & 0xff);
+    bytes[i++] = (byte) ((length >>> 8) & 0xff);
+    bytes[i++] = (byte) (length & 0xff);
+
+    // id
+    bytes[i++] = (byte) ((getId () >>> 24) & 0xff);
+    bytes[i++] = (byte) ((getId () >>> 16) & 0xff);
+    bytes[i++] = (byte) ((getId () >>> 8) & 0xff);
+    bytes[i++] = (byte) (getId () & 0xff);
+
+    // flag
+    bytes[i++] = getFlags ();
+
+    // packet-specific stuff
+    i += myToBytes (bytes, i);
+
+    // data (if any)
+    byte[] data = getData ();
+    if (data.length > 0 && i < length)
+      {
+	// Would it pay to be over cautious?
+	System.arraycopy (data, 0, bytes, i, data.length);
+      }
+
+    return bytes;
+  }
+}
Index: gnu/gcj/jdwp/transport/JdwpReplyPacket.java
--- /dev/null
+++ gnu/gcj/jdwp/transport/JdwpReplyPacket.java
@@ -0,0 +1,81 @@
+/* Copyright (C) 2005 Free Software Foundation
+
+   This file is part of libgcj.
+
+This software is copyrighted work licensed under the terms of the
+Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
+details. */
+package gnu.gcj.jdwp.transport;
+
+/**
+ * This class represents a JDWP reply packet
+ *
+ * @author Keith Seitz  <keiths@redhat.com>
+ */
+public class JdwpReplyPacket extends JdwpPacket
+{
+  // header stuff
+  protected short _errorCode;
+
+  // Minimum packet size [excluding super class] ( errorCode (2) )
+  private static final int MINIMUM_LENGTH = 2;
+
+  /**
+   * Constructs a <code>JdwpReplyPacket</code>.
+   *
+   */
+  public JdwpReplyPacket ()
+  {
+    // Don't assign a packet id. This is called by JdwpPacket.fromBytes
+    // which assigns a packet id. (Not that a VM would do that...)
+  }
+
+  /**
+   * Constructs a <code>JdwpReplyPacket</code> with the
+   * id from the given packet and error code
+   *
+   * @param pkt        the packet whose id this packet will use
+   * @param errorCode  the error code
+   */
+  public JdwpReplyPacket (JdwpPacket pkt, short errorCode)
+  {
+    super (pkt);
+    _flags = (byte) JDWP_FLAG_REPLY;
+    _errorCode = errorCode;
+  }
+
+  /**
+   * Returns the length of this packet
+   */
+  public int getLength () { return MINIMUM_LENGTH + super.getLength (); }
+
+  /**
+   * Returns the error code
+   */
+  public short getErrorCode () { return _errorCode; }
+
+  /**
+   * Sets the error code
+   */
+  public void setErrorCode (short ec) { _errorCode = ec; }
+
+  // Reads command packet data from the given buffer, starting
+  // at the given offset
+  protected int myFromBytes (byte[] bytes, int index)
+  {
+    int i = 0;
+    setErrorCode ((short) ((bytes[index + i++] << 8) | bytes[index + i++]));
+    return i;
+  }
+
+  // Writes the command packet data into the given buffer
+  protected int myToBytes (byte[] bytes, int index)
+  {
+    // Need to add error code
+    int i = 0;
+    bytes[index + i++] = (byte) ((getErrorCode () >>> 8) & 0xff);
+    bytes[index + i++] = (byte) getErrorCode ();
+    
+    return i;
+  }
+}

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]