Source for gnu.classpath.jdwp.transport.JdwpConnection

   1: /* JdwpConnection.java -- A JDWP-speaking connection
   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 gnu.classpath.jdwp.Jdwp;
  43: import gnu.classpath.jdwp.event.Event;
  44: import gnu.classpath.jdwp.event.EventRequest;
  45: 
  46: import java.io.ByteArrayOutputStream;
  47: import java.io.DataInputStream;
  48: import java.io.DataOutputStream;
  49: import java.io.IOException;
  50: import java.util.ArrayList;
  51: import java.util.Arrays;
  52: 
  53: /**
  54:  * A connection via some transport to some JDWP-speaking entity.
  55:  * This is also a thread which handles all communications to/from
  56:  * the debugger. While access to the transport layer may be accessed by
  57:  * several threads, start-up and initialization should not be allowed
  58:  * to occur more than once.
  59:  *
  60:  * <p>This class is also a thread that is responsible for pulling
  61:  * packets off the wire and sticking them in a queue for packet
  62:  * processing threads.
  63:  * 
  64:  * @author Keith Seitz (keiths@redhat.com)
  65:  */
  66: public class JdwpConnection
  67:   extends Thread
  68: {
  69:   // The JDWP handshake
  70:   private static final byte[] _HANDSHAKE = {'J', 'D', 'W', 'P', '-', 'H', 'a',
  71:                         'n', 'd', 's', 'h', 'a', 'k', 'e'};
  72: 
  73:   // Transport method
  74:   private ITransport _transport;
  75: 
  76:   // Command queue
  77:   private ArrayList _commandQueue;
  78: 
  79:   // Shutdown flag
  80:   private boolean _shutdown;
  81: 
  82:   // Input stream from transport
  83:   private DataInputStream _inStream;
  84: 
  85:   // Output stream from transprot
  86:   private DataOutputStream _outStream;
  87: 
  88:   // A buffer used to construct the packet data
  89:   private ByteArrayOutputStream _bytes;
  90: 
  91:   // A DataOutputStream for the byte buffer
  92:   private DataOutputStream _doStream;
  93: 
  94:   /**
  95:    * Creates a new <code>JdwpConnection</code> instance
  96:    *
  97:    * @param transport  the transport to use for communications
  98:    */
  99:   public JdwpConnection (ThreadGroup group, ITransport transport)
 100:   {
 101:     super (group, "JDWP connection thread");
 102:     _transport = transport;
 103:     _commandQueue = new ArrayList ();
 104:     _shutdown = false;
 105:     _bytes = new ByteArrayOutputStream ();
 106:     _doStream = new DataOutputStream (_bytes);
 107:   }
 108: 
 109:   /**
 110:    * Initializes the connection, including connecting
 111:    * to socket or shared memory endpoint
 112:    *
 113:    * @throws TransportException if initialization fails
 114:    */
 115:   public void initialize ()
 116:     throws TransportException
 117:   {
 118:     // Initialize transport (connect socket, e.g.)
 119:     _transport.initialize ();
 120: 
 121:     // Do handshake
 122:     try
 123:       {
 124:     _inStream = new DataInputStream (_transport.getInputStream ());
 125:     _outStream = new DataOutputStream (_transport.getOutputStream ());
 126:     _doHandshake ();
 127:       }
 128:     catch (IOException ioe)
 129:       {
 130:     throw new TransportException (ioe);
 131:       }
 132:   }
 133: 
 134:   /* Does the JDWP handshake -- this should not need synchronization
 135:      because this is called by VM startup code, i.e., no packet
 136:      processing threads have started yet. */
 137:   private void _doHandshake ()
 138:     throws IOException
 139:   {
 140:     // According to the spec, the handshake is always initiated by
 141:     // the debugger, regardless of whether the JVM is in client mode or
 142:     // server mode.
 143: 
 144:     // Wait for handshake from debugger
 145:     byte[] hshake = new byte[_HANDSHAKE.length];
 146:     _inStream.readFully (hshake, 0, _HANDSHAKE.length);
 147: 
 148:     if (Arrays.equals (hshake, _HANDSHAKE))
 149:       {
 150:     // Send reply handshake
 151:     _outStream.write (_HANDSHAKE, 0, _HANDSHAKE.length);
 152:     return;
 153:       }
 154:     else
 155:       {
 156:     throw new IOException ("invalid JDWP handshake (\"" + hshake + "\")");
 157:       }
 158:   }
 159: 
 160:   /**
 161:    * Main run method for the thread. This thread loops waiting for
 162:    * packets to be read via the connection. When a packet is complete
 163:    * and ready for processing, it places the packet in a queue that can
 164:    * be accessed via <code>getPacket</code>
 165:    */
 166:   public void run ()
 167:   {
 168:     while (!_shutdown)
 169:       {
 170:     try
 171:       {
 172:         _readOnePacket ();
 173:       }
 174:     catch (IOException ioe)
 175:       {
 176:         /* IOException can occur for two reasons:
 177:            1. Lost connection with the other side
 178:            2. Transport was shutdown
 179:            In either case, we make sure that all of the
 180:            back-end gets shutdown. */
 181:         Jdwp.getDefault().shutdown ();
 182:       }
 183:     catch (Throwable t)
 184:       {
 185:         System.out.println ("JdwpConnection.run: caught an exception: "
 186:                 + t);
 187:         // Just keep going
 188:       }
 189:       }
 190:   }
 191: 
 192:   // Reads a single packet from the connection, adding it to the packet
 193:   // queue when a complete packet is ready.
 194:   private void _readOnePacket ()
 195:     throws IOException
 196:   {
 197:     byte[] data = null;
 198: 
 199:     // Read in the packet
 200:     int length = _inStream.readInt ();
 201:     if (length < 11)
 202:       {
 203:     throw new IOException ("JDWP packet length < 11 (" 
 204:                    + length + ")");
 205:       }
 206: 
 207:     data = new byte[length];
 208:     data[0] = (byte) (length >>> 24);
 209:     data[1] = (byte) (length >>> 16);
 210:     data[2] = (byte) (length >>> 8);
 211:     data[3] = (byte) length;
 212:     _inStream.readFully (data, 4, length - 4);
 213: 
 214:     JdwpPacket packet = JdwpPacket.fromBytes (data);
 215:     if (packet != null)
 216:       {
 217:     synchronized (_commandQueue)
 218:       {
 219:         _commandQueue.add (packet);
 220:         _commandQueue.notifyAll ();
 221:       }
 222:       }
 223:   }
 224: 
 225:   /**
 226:    * Returns a packet from the queue of ready packets
 227:    *
 228:    * @returns  a <code>JdwpPacket</code> ready for processing
 229:    *           <code>null</code> when shutting down
 230:    */
 231:   public JdwpPacket getPacket ()
 232:   {
 233:     synchronized (_commandQueue)
 234:       {
 235:     while (_commandQueue.isEmpty ())
 236:       {
 237:         try
 238:           {
 239:         _commandQueue.wait ();
 240:           }
 241:         catch (InterruptedException ie)
 242:           {
 243:         /* PacketProcessor is interrupted
 244:            when shutting down */
 245:         return null;
 246:           }
 247:       }
 248: 
 249:     return (JdwpPacket) _commandQueue.remove (0);
 250:       }
 251:   }
 252: 
 253:   /**
 254:    * Send a packet to the debugger
 255:    *
 256:    * @param pkt a <code>JdwpPacket</code> to send
 257:    * @throws IOException
 258:    */
 259:   public void sendPacket (JdwpPacket pkt)
 260:     throws IOException
 261:   {
 262:     pkt.write (_outStream);
 263:   }
 264: 
 265:   /**
 266:    * Send an event notification to the debugger
 267:    *
 268:    * @param request  the debugger request that wanted this event
 269:    * @param event    the event
 270:    * @throws IOException
 271:    */
 272:   public void sendEvent (EventRequest request, Event event)
 273:     throws IOException
 274:   {
 275:     JdwpPacket pkt;
 276: 
 277:     synchronized (_bytes)
 278:       {
 279:     _bytes.reset ();
 280:     pkt = event.toPacket (_doStream, request);
 281:     pkt.setData (_bytes.toByteArray ());
 282:       }
 283: 
 284:     sendPacket (pkt);
 285:   }
 286: 
 287:   /**
 288:    * Shutdown the connection
 289:    */
 290:   public void shutdown ()
 291:   {
 292:     if (!_shutdown)
 293:       {
 294:     _transport.shutdown ();
 295:     _shutdown = true;
 296:     interrupt ();
 297:       }
 298:   }
 299: }