001: /*
002: *
003: *
004: * Copyright 1990-2007 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: */
026:
027: package com.sun.cldchi.tools.memoryprofiler.jdwp;
028:
029: import java.io.IOException;
030: import java.util.Vector;
031:
032: /**
033: * This abstract class represents a generic transport for JDWP. In KJDB it's
034: * used its subclass <code>SocketTransport</code>.
035: *
036: * @see jdwp.SocketTransport
037: */
038:
039: abstract class Transport {
040:
041: /**
042: * A buffer that contains data received via JDWP. KJDB doesn't
043: * use this field.
044: *
045: * @see jdwp.SocketTransportImpl
046: */
047: private static ByteBuffer buffer = new ByteBuffer();
048:
049: /**
050: * A maximum allowed JDWP packet size.
051: */
052: private final static int MaxPacketSize = 0x20000;
053:
054: /**
055: * A delay between attempts to get expected JDWP reply.
056: */
057: private static final int delta = 2;
058:
059: /**
060: * A timeout for handshake.
061: */
062: private static final int handshakeTimeout = 50000;
063:
064: /**
065: * A list of received JDWP repliesa and still not requested
066: * by other parts of the code.
067: */
068: public Vector Replies = new Vector();
069:
070: /**
071: * Returns the number of bytes that can be received immediately.
072: *
073: * @return the number of bytes that can be received immediately
074: */
075: public abstract int available() throws IOException;
076:
077: /**
078: * Receives the next byte of data. The value byte is
079: * returned as an int in the range 0 to 255. If no byte is
080: * available, the value -1 is returned.
081: *
082: * @return the next byte that is read via JDWP
083: */
084: public abstract int read() throws IOException;
085:
086: /**
087: * Sends the specified byte via JDWP.
088: *
089: * @param b a byte to be sent
090: */
091: public abstract void write(int b) throws IOException;
092:
093: /**
094: * Sends the specified bytes via JDWP.
095: *
096: * @param b an array of bytes
097: * @param off an offset of the first byte to be sent
098: * @param len a number of bytes to be sent
099: */
100: public void write(byte[] b, int off, int len) throws IOException {
101: for (int i = 0; i < len; i++)
102: write(b[off + i]);
103: }
104:
105: /**
106: * Performs JDWP "handshake" procedure (undocumented ?). It sends
107: * a <code>"JDWP-Handshake"</code> string and waits for receiving the
108: * same string. After handshaking the JDWP connection is considered
109: * estblished.
110: */
111: public void Handshake() throws IOException {
112:
113: String hs = "JDWP-Handshake";
114: byte[] hsb = hs.getBytes();
115:
116: write(hsb, 0, hsb.length);
117:
118: int handshakeTime = handshakeTimeout;
119: do {
120: Tools.wait(500);
121: handshakeTime -= 500;
122: } while (handshakeTime > 0 && available() < hsb.length);
123:
124: if (available() < hsb.length)
125: throw new IOException("Target failed to handshake.");
126:
127: for (int i = 0; i < hsb.length; i++) {
128: byte b = (byte) (read() & 0xFF);
129: if (b != hsb[i])
130: throw new IOException("Target failed to handshake.");
131: }
132: }
133:
134: /**
135: * Sends JDWP command packet.
136: *
137: * @param c a command to be sent
138: */
139: public void sendCommand(Command c) throws IOException {
140: c.setLength();
141: write(c.bytes, 0, c.length());
142: }
143:
144: /**
145: * Sends JDWP command packet with wrong length field. This method is
146: * never used by KJDB but it's used by CLDC-DI and JavaCard BackEnd
147: * test suite.
148: *
149: * @param c a command to be sent
150: * @param WrongSize a size of the packet
151: */
152: public void sendBadCommandPacket(Command c, int WrongSize)
153: throws IOException {
154:
155: try {
156: c.putInt(Packet.LengthOffset, WrongSize);
157: } catch (BoundException e) {
158: }
159: ;
160: write(c.bytes, 0, c.length());
161: }
162:
163: /**
164: * Receives all available JDWP reply packets and places them into the
165: * vector <code>Replies</code>. This method is overwritten in KJDB and the
166: * code below is not used.
167: *
168: * @see jdwp.SocketTransport
169: * @see jdwp.SocketTransportImpl
170: */
171: public void receive() throws IOException {
172:
173: while (available() > 0)
174: buffer.addByte(read());
175:
176: while (buffer.length() >= Packet.PacketHeaderSize) {
177:
178: int size = 0;
179:
180: buffer.resetParser();
181: try {
182: size = buffer.getInt();
183: } catch (BoundException e) {
184: }
185:
186: if ((size < 0) || (size > MaxPacketSize))
187: throw new IOException("Wrong JDWP packet size: " + size
188: + ".");
189:
190: if (size > buffer.length())
191: return;
192:
193: Reply r = new Reply();
194:
195: r.resetBuffer();
196: r.addBytes(buffer.bytes, 0, size);
197:
198: buffer.deleteBytes(size);
199:
200: Replies.add(r);
201: }
202: }
203:
204: /**
205: * Receives JDWP reply packet.
206: * If there is no reply packet available, function returns packet
207: * with error code <code>Reply.errNotAvailable</code>.
208: *
209: * @return a JDWP reply or <code>Reply.errNotAvailable</code> if not
210: * available
211: */
212: public Reply receiveReply() throws IOException {
213:
214: receive();
215:
216: if (Replies.size() == 0)
217: return Reply.Error(Reply.errNotAvailable);
218:
219: return (Reply) Replies.remove(0);
220: }
221:
222: /**
223: * Tries to receive a JDWP reply packet with specified ID. It looks
224: * into a list of already received packets and tries to locate it.
225: * If the desired packet is not found, <code>Reply.errNotAvailable</code>
226: * is returned.
227: *
228: * @param ReplyID an ID of the desired JDWP reply packet
229: * @return a JDWP reply packet with specified ID or
230: * <code>Reply.errNotAvailable</code> if not found
231: */
232: public Reply receiveReply(int ReplyID) throws IOException {
233:
234: receive();
235:
236: for (int i = 0; i < Replies.size(); i++)
237: if (((Reply) Replies.elementAt(i)).getFlags() == 0x80
238: && ((Reply) Replies.elementAt(i)).getID() == ReplyID)
239: return (Reply) Replies.remove(i);
240:
241: return Reply.Error(Reply.errNotAvailable);
242: }
243:
244: /**
245: * Tries to receive a JDWP reply packet with specified ID. It looks
246: * into a list of already received packets and tries to locate it.
247: * If the desired packet is not found, is makes a pause and then
248: * tries to receive the deired reply again.
249: * In case of timeout <code>Reply.errNotAvailable</code>
250: * is returned.
251: *
252: * @param ReplyID an ID of the desired JDWP reply packet
253: * @param Delay a timeout for this operation
254: * @return a JDWP reply packet with specified ID or
255: * <code>Reply.errNotAvailable</code> if not found
256: */
257: public Reply receiveReply(int ReplyID, int Delay)
258: throws IOException {
259: Reply r = receiveReply(ReplyID);
260:
261: while ((r.getErrorCode() == Reply.errNotAvailable)
262: && (Delay > 0)) {
263: Tools.wait(delta);
264: r = receiveReply(ReplyID);
265: Delay = Delay - delta;
266: }
267: return r;
268: }
269:
270: /**
271: * Tries to receive a JDWP event. It looks
272: * into a list of already received packets and tries to locate it.
273: * If the desired packet is not found, is makes a pause and then
274: * tries to receive the deired reply again.
275: * In case of timeout <code>Reply.errNotAvailable</code>
276: * is returned.
277: *
278: * @param command a command number for Event/Composite JDWP command
279: * (should be always <code>0x4064</code>)
280: * @param Delay a timeout for this operation
281: * @return a JDWP event or <code>Reply.errNotAvailable</code> if not found
282: */
283: public Reply receiveEvent(int command, int Delay)
284: throws IOException {
285:
286: Reply r;
287:
288: while (Delay > 0) {
289: receive();
290: for (int i = 0; i < Replies.size(); i++) {
291: r = (Reply) Replies.elementAt(i);
292: if (r.getFlags() == 0 && r.getErrorCode() == command)
293: return (Reply) Replies.remove(i);
294: }
295: Tools.wait(delta);
296: Delay = Delay - delta;
297: }
298: return Reply.Error(Reply.errNotAvailable);
299: }
300: }
|