Frames | No Frames |
1: /* JdwpConnection.java -- A JDWP-speaking connection 2: Copyright (C) 2005, 2006, 2007 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: // Notify initialization thread (gnu.classpath.jdwp.Jdwp) that 169: // the JdwpConnection thread is ready. 170: Jdwp.getDefault().subcomponentInitialized (); 171: 172: while (!_shutdown) 173: { 174: try 175: { 176: _readOnePacket (); 177: } 178: catch (IOException ioe) 179: { 180: /* IOException can occur for two reasons: 181: 1. Lost connection with the other side 182: 2. Transport was shutdown 183: In either case, we make sure that all of the 184: back-end gets shutdown. */ 185: Jdwp.getDefault().shutdown (); 186: } 187: catch (Throwable t) 188: { 189: System.out.println ("JdwpConnection.run: caught an exception: " 190: + t); 191: // Just keep going 192: } 193: } 194: } 195: 196: // Reads a single packet from the connection, adding it to the packet 197: // queue when a complete packet is ready. 198: private void _readOnePacket () 199: throws IOException 200: { 201: byte[] data = null; 202: 203: // Read in the packet 204: int length = _inStream.readInt (); 205: if (length < 11) 206: { 207: throw new IOException ("JDWP packet length < 11 (" 208: + length + ")"); 209: } 210: 211: data = new byte[length]; 212: data[0] = (byte) (length >>> 24); 213: data[1] = (byte) (length >>> 16); 214: data[2] = (byte) (length >>> 8); 215: data[3] = (byte) length; 216: _inStream.readFully (data, 4, length - 4); 217: 218: JdwpPacket packet = JdwpPacket.fromBytes (data); 219: if (packet != null) 220: { 221: synchronized (_commandQueue) 222: { 223: _commandQueue.add (packet); 224: _commandQueue.notifyAll (); 225: } 226: } 227: } 228: 229: /** 230: * Returns a packet from the queue of ready packets 231: * 232: * @returns a <code>JdwpPacket</code> ready for processing 233: * <code>null</code> when shutting down 234: */ 235: public JdwpPacket getPacket () 236: { 237: synchronized (_commandQueue) 238: { 239: while (_commandQueue.isEmpty ()) 240: { 241: try 242: { 243: _commandQueue.wait (); 244: } 245: catch (InterruptedException ie) 246: { 247: /* PacketProcessor is interrupted 248: when shutting down */ 249: return null; 250: } 251: } 252: 253: return (JdwpPacket) _commandQueue.remove (0); 254: } 255: } 256: 257: /** 258: * Send a packet to the debugger 259: * 260: * @param pkt a <code>JdwpPacket</code> to send 261: * @throws IOException 262: */ 263: public void sendPacket (JdwpPacket pkt) 264: throws IOException 265: { 266: pkt.write (_outStream); 267: } 268: 269: /** 270: * Send an event notification to the debugger. Note that this 271: * method will only send out one notification: all the events 272: * are passed in a single Event.COMPOSITE packet. 273: * 274: * @param requests debugger requests for events 275: * @param events the events to send 276: * @param suspendPolicy the suspend policy enforced by the VM 277: * @throws IOException 278: */ 279: public void sendEvents(EventRequest[] requests, Event[] events, 280: byte suspendPolicy) 281: throws IOException 282: { 283: JdwpPacket pkt; 284: 285: synchronized (_bytes) 286: { 287: _bytes.reset (); 288: pkt = Event.toPacket (_doStream, events, requests, suspendPolicy); 289: pkt.setData (_bytes.toByteArray ()); 290: } 291: 292: sendPacket (pkt); 293: } 294: 295: /** 296: * Shutdown the connection 297: */ 298: public void shutdown () 299: { 300: if (!_shutdown) 301: { 302: _transport.shutdown (); 303: _shutdown = true; 304: interrupt (); 305: } 306: } 307: }