blob: cd45c5762a3be721f1e64b9a6620865fd6b6a81a [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 1999-2003 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package com.sun.tools.jdi;
27
28import com.sun.jdi.*;
29import com.sun.jdi.connect.*;
30import com.sun.jdi.connect.spi.*;
31
32import java.io.IOException;
33import java.util.Map;
34import java.util.ResourceBundle;
35
36class SharedMemoryTransportService extends TransportService {
37 private ResourceBundle messages = null;
38
39 /**
40 * The listener returned by startListening
41 */
42 static class SharedMemoryListenKey extends ListenKey {
43 long id;
44 String name;
45
46 SharedMemoryListenKey(long id, String name) {
47 this.id = id;
48 this.name = name;
49 }
50
51 long id() {
52 return id;
53 }
54
55 void setId(long id) {
56 this.id = id;
57 }
58
59 public String address() {
60 return name;
61 }
62
63 public String toString() {
64 return address();
65 }
66 }
67
68 SharedMemoryTransportService() {
69 System.loadLibrary("dt_shmem");
70 initialize();
71 }
72
73 public String name() {
74 return "SharedMemory";
75 }
76
77 public String defaultAddress() {
78 return "javadebug";
79 }
80
81 /**
82 * Return localized description of this transport service
83 */
84 public String description() {
85 synchronized (this) {
86 if (messages == null) {
87 messages = ResourceBundle.getBundle("com.sun.tools.jdi.resources.jdi");
88 }
89 }
90 return messages.getString("memory_transportservice.description");
91 }
92
93 public Capabilities capabilities() {
94 return new SharedMemoryTransportServiceCapabilities();
95 }
96
97 private native void initialize();
98 private native long startListening0(String address) throws IOException;
99 private native long attach0(String address, long attachTimeout) throws IOException;
100 private native void stopListening0(long id) throws IOException;
101 private native long accept0(long id, long acceptTimeout) throws IOException;
102 private native String name(long id) throws IOException;
103
104 public Connection attach(String address, long attachTimeout, long handshakeTimeout) throws IOException {
105 if (address == null) {
106 throw new NullPointerException("address is null");
107 }
108 long id = attach0(address, attachTimeout);
109 SharedMemoryConnection conn = new SharedMemoryConnection(id);
110 conn.handshake(handshakeTimeout);
111 return conn;
112 }
113
114 public TransportService.ListenKey startListening(String address) throws IOException {
115 if (address == null || address.length() == 0) {
116 address = defaultAddress();
117 }
118 long id = startListening0(address);
119 return new SharedMemoryListenKey(id, name(id));
120 }
121
122 public ListenKey startListening() throws IOException {
123 return startListening(null);
124 }
125
126 public void stopListening(ListenKey listener) throws IOException {
127 if (!(listener instanceof SharedMemoryListenKey)) {
128 throw new IllegalArgumentException("Invalid listener");
129 }
130
131 long id;
132 SharedMemoryListenKey key = (SharedMemoryListenKey)listener;
133 synchronized (key) {
134 id = key.id();
135 if (id == 0) {
136 throw new IllegalArgumentException("Invalid listener");
137 }
138
139 // invalidate the id
140 key.setId(0);
141 }
142 stopListening0(id);
143 }
144
145 public Connection accept(ListenKey listener, long acceptTimeout, long handshakeTimeout) throws IOException {
146 if (!(listener instanceof SharedMemoryListenKey)) {
147 throw new IllegalArgumentException("Invalid listener");
148 }
149
150 long transportId;
151 SharedMemoryListenKey key = (SharedMemoryListenKey)listener;
152 synchronized (key) {
153 transportId = key.id();
154 if (transportId == 0) {
155 throw new IllegalArgumentException("Invalid listener");
156 }
157 }
158
159 // in theory another thread could call stopListening before
160 // accept0 is called. In that case accept0 will try to accept
161 // with an invalid "transport id" - this should result in an
162 // IOException.
163
164 long connectId = accept0(transportId, acceptTimeout);
165 SharedMemoryConnection conn = new SharedMemoryConnection(connectId);
166 conn.handshake(handshakeTimeout);
167 return conn;
168 }
169}
170
171class SharedMemoryConnection extends Connection {
172 private long id;
173 private Object receiveLock = new Object();
174 private Object sendLock = new Object();
175 private Object closeLock = new Object();
176 private boolean closed = false;
177
178 private native byte receiveByte0(long id) throws IOException;
179 private native void sendByte0(long id, byte b) throws IOException;
180 private native void close0(long id);
181 private native byte[] receivePacket0(long id)throws IOException;
182 private native void sendPacket0(long id, byte b[]) throws IOException;
183
184 // handshake with the target VM
185 void handshake(long handshakeTimeout) throws IOException {
186 byte[] hello = "JDWP-Handshake".getBytes("UTF-8");
187
188 for (int i=0; i<hello.length; i++) {
189 sendByte0(id, hello[i]);
190 }
191 for (int i=0; i<hello.length; i++) {
192 byte b = receiveByte0(id);
193 if (b != hello[i]) {
194 throw new IOException("handshake failed - unrecognized message from target VM");
195 }
196 }
197 }
198
199
200 SharedMemoryConnection(long id) throws IOException {
201 this.id = id;
202 }
203
204 public void close() {
205 synchronized (closeLock) {
206 if (!closed) {
207 close0(id);
208 closed = true;
209 }
210 }
211 }
212
213 public boolean isOpen() {
214 synchronized (closeLock) {
215 return !closed;
216 }
217 }
218
219 public byte[] readPacket() throws IOException {
220 if (!isOpen()) {
221 throw new ClosedConnectionException("Connection closed");
222 }
223 byte b[];
224 try {
225 // only one thread may be reading at a time
226 synchronized (receiveLock) {
227 b = receivePacket0(id);
228 }
229 } catch (IOException ioe) {
230 if (!isOpen()) {
231 throw new ClosedConnectionException("Connection closed");
232 } else {
233 throw ioe;
234 }
235 }
236 return b;
237 }
238
239 public void writePacket(byte b[]) throws IOException {
240 if (!isOpen()) {
241 throw new ClosedConnectionException("Connection closed");
242 }
243
244 /*
245 * Check the packet size
246 */
247 if (b.length < 11) {
248 throw new IllegalArgumentException("packet is insufficient size");
249 }
250 int b0 = b[0] & 0xff;
251 int b1 = b[1] & 0xff;
252 int b2 = b[2] & 0xff;
253 int b3 = b[3] & 0xff;
254 int len = ((b0 << 24) | (b1 << 16) | (b2 << 8) | (b3 << 0));
255 if (len < 11) {
256 throw new IllegalArgumentException("packet is insufficient size");
257 }
258
259 /*
260 * Check that the byte array contains the complete packet
261 */
262 if (len > b.length) {
263 throw new IllegalArgumentException("length mis-match");
264 }
265
266 try {
267 // only one thread may be writing at a time
268 synchronized(sendLock) {
269 sendPacket0(id, b);
270 }
271 } catch (IOException ioe) {
272 if (!isOpen()) {
273 throw new ClosedConnectionException("Connection closed");
274 } else {
275 throw ioe;
276 }
277 }
278 }
279}
280
281
282class SharedMemoryTransportServiceCapabilities extends TransportService.Capabilities {
283
284 public boolean supportsMultipleConnections() {
285 return false;
286 }
287
288 public boolean supportsAttachTimeout() {
289 return true;
290 }
291
292 public boolean supportsAcceptTimeout() {
293 return true;
294 }
295
296 public boolean supportsHandshakeTimeout() {
297 return false;
298 }
299
300}