001: /*
002: * Copyright 1999-2003 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package com.sun.tools.jdi;
027:
028: import com.sun.jdi.*;
029: import com.sun.jdi.connect.*;
030: import com.sun.jdi.connect.spi.*;
031:
032: import java.io.IOException;
033: import java.util.Map;
034: import java.util.ResourceBundle;
035:
036: class SharedMemoryTransportService extends TransportService {
037: private ResourceBundle messages = null;
038:
039: /**
040: * The listener returned by startListening
041: */
042: static class SharedMemoryListenKey extends ListenKey {
043: long id;
044: String name;
045:
046: SharedMemoryListenKey(long id, String name) {
047: this .id = id;
048: this .name = name;
049: }
050:
051: long id() {
052: return id;
053: }
054:
055: void setId(long id) {
056: this .id = id;
057: }
058:
059: public String address() {
060: return name;
061: }
062:
063: public String toString() {
064: return address();
065: }
066: }
067:
068: SharedMemoryTransportService() {
069: System.loadLibrary("dt_shmem");
070: initialize();
071: }
072:
073: public String name() {
074: return "SharedMemory";
075: }
076:
077: public String defaultAddress() {
078: return "javadebug";
079: }
080:
081: /**
082: * Return localized description of this transport service
083: */
084: public String description() {
085: synchronized (this ) {
086: if (messages == null) {
087: messages = ResourceBundle
088: .getBundle("com.sun.tools.jdi.resources.jdi");
089: }
090: }
091: return messages
092: .getString("memory_transportservice.description");
093: }
094:
095: public Capabilities capabilities() {
096: return new SharedMemoryTransportServiceCapabilities();
097: }
098:
099: private native void initialize();
100:
101: private native long startListening0(String address)
102: throws IOException;
103:
104: private native long attach0(String address, long attachTimeout)
105: throws IOException;
106:
107: private native void stopListening0(long id) throws IOException;
108:
109: private native long accept0(long id, long acceptTimeout)
110: throws IOException;
111:
112: private native String name(long id) throws IOException;
113:
114: public Connection attach(String address, long attachTimeout,
115: long handshakeTimeout) throws IOException {
116: if (address == null) {
117: throw new NullPointerException("address is null");
118: }
119: long id = attach0(address, attachTimeout);
120: SharedMemoryConnection conn = new SharedMemoryConnection(id);
121: conn.handshake(handshakeTimeout);
122: return conn;
123: }
124:
125: public TransportService.ListenKey startListening(String address)
126: throws IOException {
127: if (address == null || address.length() == 0) {
128: address = defaultAddress();
129: }
130: long id = startListening0(address);
131: return new SharedMemoryListenKey(id, name(id));
132: }
133:
134: public ListenKey startListening() throws IOException {
135: return startListening(null);
136: }
137:
138: public void stopListening(ListenKey listener) throws IOException {
139: if (!(listener instanceof SharedMemoryListenKey)) {
140: throw new IllegalArgumentException("Invalid listener");
141: }
142:
143: long id;
144: SharedMemoryListenKey key = (SharedMemoryListenKey) listener;
145: synchronized (key) {
146: id = key.id();
147: if (id == 0) {
148: throw new IllegalArgumentException("Invalid listener");
149: }
150:
151: // invalidate the id
152: key.setId(0);
153: }
154: stopListening0(id);
155: }
156:
157: public Connection accept(ListenKey listener, long acceptTimeout,
158: long handshakeTimeout) throws IOException {
159: if (!(listener instanceof SharedMemoryListenKey)) {
160: throw new IllegalArgumentException("Invalid listener");
161: }
162:
163: long transportId;
164: SharedMemoryListenKey key = (SharedMemoryListenKey) listener;
165: synchronized (key) {
166: transportId = key.id();
167: if (transportId == 0) {
168: throw new IllegalArgumentException("Invalid listener");
169: }
170: }
171:
172: // in theory another thread could call stopListening before
173: // accept0 is called. In that case accept0 will try to accept
174: // with an invalid "transport id" - this should result in an
175: // IOException.
176:
177: long connectId = accept0(transportId, acceptTimeout);
178: SharedMemoryConnection conn = new SharedMemoryConnection(
179: connectId);
180: conn.handshake(handshakeTimeout);
181: return conn;
182: }
183: }
184:
185: class SharedMemoryConnection extends Connection {
186: private long id;
187: private Object receiveLock = new Object();
188: private Object sendLock = new Object();
189: private Object closeLock = new Object();
190: private boolean closed = false;
191:
192: private native byte receiveByte0(long id) throws IOException;
193:
194: private native void sendByte0(long id, byte b) throws IOException;
195:
196: private native void close0(long id);
197:
198: private native byte[] receivePacket0(long id) throws IOException;
199:
200: private native void sendPacket0(long id, byte b[])
201: throws IOException;
202:
203: // handshake with the target VM
204: void handshake(long handshakeTimeout) throws IOException {
205: byte[] hello = "JDWP-Handshake".getBytes("UTF-8");
206:
207: for (int i = 0; i < hello.length; i++) {
208: sendByte0(id, hello[i]);
209: }
210: for (int i = 0; i < hello.length; i++) {
211: byte b = receiveByte0(id);
212: if (b != hello[i]) {
213: throw new IOException(
214: "handshake failed - unrecognized message from target VM");
215: }
216: }
217: }
218:
219: SharedMemoryConnection(long id) throws IOException {
220: this .id = id;
221: }
222:
223: public void close() {
224: synchronized (closeLock) {
225: if (!closed) {
226: close0(id);
227: closed = true;
228: }
229: }
230: }
231:
232: public boolean isOpen() {
233: synchronized (closeLock) {
234: return !closed;
235: }
236: }
237:
238: public byte[] readPacket() throws IOException {
239: if (!isOpen()) {
240: throw new ClosedConnectionException("Connection closed");
241: }
242: byte b[];
243: try {
244: // only one thread may be reading at a time
245: synchronized (receiveLock) {
246: b = receivePacket0(id);
247: }
248: } catch (IOException ioe) {
249: if (!isOpen()) {
250: throw new ClosedConnectionException("Connection closed");
251: } else {
252: throw ioe;
253: }
254: }
255: return b;
256: }
257:
258: public void writePacket(byte b[]) throws IOException {
259: if (!isOpen()) {
260: throw new ClosedConnectionException("Connection closed");
261: }
262:
263: /*
264: * Check the packet size
265: */
266: if (b.length < 11) {
267: throw new IllegalArgumentException(
268: "packet is insufficient size");
269: }
270: int b0 = b[0] & 0xff;
271: int b1 = b[1] & 0xff;
272: int b2 = b[2] & 0xff;
273: int b3 = b[3] & 0xff;
274: int len = ((b0 << 24) | (b1 << 16) | (b2 << 8) | (b3 << 0));
275: if (len < 11) {
276: throw new IllegalArgumentException(
277: "packet is insufficient size");
278: }
279:
280: /*
281: * Check that the byte array contains the complete packet
282: */
283: if (len > b.length) {
284: throw new IllegalArgumentException("length mis-match");
285: }
286:
287: try {
288: // only one thread may be writing at a time
289: synchronized (sendLock) {
290: sendPacket0(id, b);
291: }
292: } catch (IOException ioe) {
293: if (!isOpen()) {
294: throw new ClosedConnectionException("Connection closed");
295: } else {
296: throw ioe;
297: }
298: }
299: }
300: }
301:
302: class SharedMemoryTransportServiceCapabilities extends
303: TransportService.Capabilities {
304:
305: public boolean supportsMultipleConnections() {
306: return false;
307: }
308:
309: public boolean supportsAttachTimeout() {
310: return true;
311: }
312:
313: public boolean supportsAcceptTimeout() {
314: return true;
315: }
316:
317: public boolean supportsHandshakeTimeout() {
318: return false;
319: }
320:
321: }
|