blob: 032969c7bea832c8fbaea4136dde8fdb82b89b4d [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#include <string.h>
26
27#include "jdwpTransport.h"
28#include "shmemBase.h"
29#include "sysShmem.h"
30#include "sys.h"
31
32/*
33 * The Shared Memory Transport Library.
34 *
35 * This module is an implementation of the Java Debug Wire Protocol Transport
36 * Service Provider Interface - see src/share/javavm/export/jdwpTransport.h.
37 */
38
39static SharedMemoryTransport *transport = NULL; /* maximum of 1 transport */
40static SharedMemoryConnection *connection = NULL; /* maximum of 1 connection */
41static jdwpTransportCallback *callbacks;
42static jboolean initialized;
43static struct jdwpTransportNativeInterface_ interface;
44static jdwpTransportEnv single_env = (jdwpTransportEnv)&interface;
45
46/*
47 * Thread-local index to the per-thread error message
48 */
49static int tlsIndex;
50
51/*
52 * Return an error and record the error message associated with
53 * the error. Note the if (1==1) { } usage here is to avoid
54 * compilers complaining that a statement isn't reached which
55 * will arise if the semicolon (;) appears after the macro,
56 */
57#define RETURN_ERROR(err, msg) \
58 if (1==1) { \
59 setLastError(err, msg); \
60 return err; \
61 }
62
63/*
64 * Return an I/O error and record the error message.
65 */
66#define RETURN_IO_ERROR(msg) RETURN_ERROR(JDWPTRANSPORT_ERROR_IO_ERROR, msg);
67
68
69/*
70 * Set the error message for this thread. If the error is an I/O
71 * error then augment the supplied error message with the textual
72 * representation of the I/O error.
73 */
74static void
75setLastError(int err, char *newmsg) {
76 char buf[255];
77 char *msg;
78
79 /* get any I/O first in case any system calls override errno */
80 if (err == JDWPTRANSPORT_ERROR_IO_ERROR) {
81 if (shmemBase_getlasterror(buf, sizeof(buf)) != SYS_OK) {
82 buf[0] = '\0';
83 }
84 }
85
86 /* free any current error */
87 msg = (char *)sysTlsGet(tlsIndex);
88 if (msg != NULL) {
89 (*callbacks->free)(msg);
90 }
91
92 /*
93 * For I/O errors append the I/O error message with to the
94 * supplied message. For all other errors just use the supplied
95 * message.
96 */
97 if (err == JDWPTRANSPORT_ERROR_IO_ERROR) {
98 char *join_str = ": ";
99 int msg_len = strlen(newmsg) + strlen(join_str) + strlen(buf) + 3;
100 msg = (*callbacks->alloc)(msg_len);
101 if (msg != NULL) {
102 strcpy(msg, newmsg);
103 strcat(msg, join_str);
104 strcat(msg, buf);
105 }
106 } else {
107 msg = (*callbacks->alloc)(strlen(newmsg)+1);
108 if (msg != NULL) {
109 strcpy(msg, newmsg);
110 }
111 }
112
113 /* Put a pointer to the message in TLS */
114 sysTlsPut(tlsIndex, msg);
115}
116
117static jdwpTransportError
118handshake()
119{
120 char *hello = "JDWP-Handshake";
121 unsigned int i;
122
123 for (i=0; i<strlen(hello); i++) {
124 jbyte b;
125 int rv = shmemBase_receiveByte(connection, &b);
126 if (rv != 0) {
127 RETURN_IO_ERROR("receive failed during handshake");
128 }
129 if ((char)b != hello[i]) {
130 RETURN_IO_ERROR("handshake failed - debugger sent unexpected message");
131 }
132 }
133
134 for (i=0; i<strlen(hello); i++) {
135 int rv = shmemBase_sendByte(connection, (jbyte)hello[i]);
136 if (rv != 0) {
137 RETURN_IO_ERROR("write failed during handshake");
138 }
139 }
140
141 return JDWPTRANSPORT_ERROR_NONE;
142}
143
144
145/*
146 * Return the capabilities of the shared memory transport. The shared
147 * memory transport supports both the attach and accept timeouts but
148 * doesn't support a handshake timeout.
149 */
150static jdwpTransportError JNICALL
151shmemGetCapabilities(jdwpTransportEnv* env, JDWPTransportCapabilities *capabilitiesPtr)
152{
153 JDWPTransportCapabilities result;
154
155 memset(&result, 0, sizeof(result));
156 result.can_timeout_attach = JNI_TRUE;
157 result.can_timeout_accept = JNI_TRUE;
158 result.can_timeout_handshake = JNI_FALSE;
159
160 *capabilitiesPtr = result;
161
162 return JDWPTRANSPORT_ERROR_NONE;
163}
164
165
166static jdwpTransportError JNICALL
167shmemStartListening(jdwpTransportEnv* env, const char *address, char **actualAddress)
168{
169 jint rc;
170
171 if (connection != NULL || transport != NULL) {
172 RETURN_ERROR(JDWPTRANSPORT_ERROR_ILLEGAL_STATE, "already connected or already listening");
173 }
174
175 rc = shmemBase_listen(address, &transport);
176
177 /*
178 * If a name was selected by the function above, find it and return
179 * it in place of the original arg.
180 */
181 if (rc == SYS_OK) {
182 char *name;
183 char *name2;
184 rc = shmemBase_name(transport, &name);
185 if (rc == SYS_OK) {
186 name2 = (callbacks->alloc)(strlen(name) + 1);
187 if (name2 == NULL) {
188 RETURN_ERROR(JDWPTRANSPORT_ERROR_OUT_OF_MEMORY, "out of memory");
189 } else {
190 strcpy(name2, name);
191 *actualAddress = name2;
192 }
193 }
194 } else {
195 RETURN_IO_ERROR("failed to create shared memory listener");
196 }
197 return JDWPTRANSPORT_ERROR_NONE;
198}
199
200static jdwpTransportError JNICALL
201shmemAccept(jdwpTransportEnv* env, jlong acceptTimeout, jlong handshakeTimeout)
202{
203 jint rc;
204
205 if (connection != NULL) {
206 RETURN_ERROR(JDWPTRANSPORT_ERROR_ILLEGAL_STATE, "already connected");
207 }
208 if (transport == NULL) {
209 RETURN_ERROR(JDWPTRANSPORT_ERROR_ILLEGAL_STATE, "transport not listening");
210 }
211
212 rc = shmemBase_accept(transport, (long)acceptTimeout, &connection);
213 if (rc != SYS_OK) {
214 if (rc == SYS_TIMEOUT) {
215 RETURN_ERROR(JDWPTRANSPORT_ERROR_TIMEOUT, "Timed out waiting for connection");
216 } else {
217 RETURN_IO_ERROR("failed to accept shared memory connection");
218 }
219 }
220
221 rc = handshake();
222 if (rc != JDWPTRANSPORT_ERROR_NONE) {
223 shmemBase_closeConnection(connection);
224 connection = NULL;
225 }
226 return rc;
227}
228
229static jdwpTransportError JNICALL
230shmemStopListening(jdwpTransportEnv* env)
231{
232 if (transport != NULL) {
233 shmemBase_closeTransport(transport);
234 transport = NULL;
235 }
236 return JDWPTRANSPORT_ERROR_NONE;
237}
238
239static jdwpTransportError JNICALL
240shmemAttach(jdwpTransportEnv* env, const char *address, jlong attachTimeout, jlong handshakeTimeout)
241{
242 jint rc;
243
244 if (connection != NULL) {
245 RETURN_ERROR(JDWPTRANSPORT_ERROR_ILLEGAL_STATE, "already connected");
246 }
247 rc = shmemBase_attach(address, (long)attachTimeout, &connection);
248 if (rc != SYS_OK) {
249 if (rc == SYS_NOMEM) {
250 RETURN_ERROR(JDWPTRANSPORT_ERROR_OUT_OF_MEMORY, "out of memory");
251 }
252 if (rc == SYS_TIMEOUT) {
253 RETURN_ERROR(JDWPTRANSPORT_ERROR_TIMEOUT, "Timed out waiting to attach");
254 }
255 RETURN_IO_ERROR("failed to attach to shared memory connection");
256 }
257
258 rc = handshake();
259 if (rc != JDWPTRANSPORT_ERROR_NONE) {
260 shmemBase_closeConnection(connection);
261 connection = NULL;
262 }
263 return rc;
264}
265
266static jdwpTransportError JNICALL
267shmemWritePacket(jdwpTransportEnv* env, const jdwpPacket *packet)
268{
269 if (packet == NULL) {
270 RETURN_ERROR(JDWPTRANSPORT_ERROR_ILLEGAL_ARGUMENT, "packet is null");
271 }
272 if (packet->type.cmd.len < 11) {
273 RETURN_ERROR(JDWPTRANSPORT_ERROR_ILLEGAL_ARGUMENT, "invalid length");
274 }
275 if (connection == NULL) {
276 RETURN_ERROR(JDWPTRANSPORT_ERROR_ILLEGAL_STATE, "not connected");
277 }
278 if (shmemBase_sendPacket(connection, packet) == SYS_OK) {
279 return JDWPTRANSPORT_ERROR_NONE;
280 } else {
281 RETURN_IO_ERROR("write packet failed");
282 }
283}
284
285static jdwpTransportError JNICALL
286shmemReadPacket(jdwpTransportEnv* env, jdwpPacket *packet)
287{
288 if (packet == NULL) {
289 RETURN_ERROR(JDWPTRANSPORT_ERROR_ILLEGAL_ARGUMENT, "packet is null");
290 }
291 if (connection == NULL) {
292 RETURN_ERROR(JDWPTRANSPORT_ERROR_ILLEGAL_STATE, "not connected");
293 }
294 if (shmemBase_receivePacket(connection, packet) == SYS_OK) {
295 return JDWPTRANSPORT_ERROR_NONE;
296 } else {
297 RETURN_IO_ERROR("receive packet failed");
298 }
299}
300
301static jboolean JNICALL
302shmemIsOpen(jdwpTransportEnv* env)
303{
304 if (connection != NULL) {
305 return JNI_TRUE;
306 } else {
307 return JNI_FALSE;
308 }
309}
310
311static jdwpTransportError JNICALL
312shmemClose(jdwpTransportEnv* env)
313{
314 SharedMemoryConnection* current_connection = connection;
315 if (current_connection != NULL) {
316 connection = NULL;
317 shmemBase_closeConnection(current_connection);
318 }
319 return JDWPTRANSPORT_ERROR_NONE;
320}
321
322/*
323 * Return the error message for this thread.
324 */
325static jdwpTransportError JNICALL
326shmemGetLastError(jdwpTransportEnv* env, char **msgP)
327{
328 char *msg = (char *)sysTlsGet(tlsIndex);
329 if (msg == NULL) {
330 return JDWPTRANSPORT_ERROR_MSG_NOT_AVAILABLE;
331 }
332 *msgP = (*callbacks->alloc)(strlen(msg)+1);
333 if (*msgP == NULL) {
334 return JDWPTRANSPORT_ERROR_OUT_OF_MEMORY;
335 }
336 strcpy(*msgP, msg);
337 return JDWPTRANSPORT_ERROR_NONE;
338}
339
340JNIEXPORT jint JNICALL
341jdwpTransport_OnLoad(JavaVM *vm, jdwpTransportCallback* cbTablePtr,
342 jint version, jdwpTransportEnv** result)
343{
344 if (version != JDWPTRANSPORT_VERSION_1_0) {
345 return JNI_EVERSION;
346 }
347 if (initialized) {
348 /*
349 * This library doesn't support multiple environments (yet)
350 */
351 return JNI_EEXIST;
352 }
353 initialized = JNI_TRUE;
354
355 /* initialize base shared memory system */
356 (void) shmemBase_initialize(vm, cbTablePtr);
357
358 /* save callbacks */
359 callbacks = cbTablePtr;
360
361 /* initialize interface table */
362 interface.GetCapabilities = &shmemGetCapabilities;
363 interface.Attach = &shmemAttach;
364 interface.StartListening = &shmemStartListening;
365 interface.StopListening = &shmemStopListening;
366 interface.Accept = &shmemAccept;
367 interface.IsOpen = &shmemIsOpen;
368 interface.Close = &shmemClose;
369 interface.ReadPacket = &shmemReadPacket;
370 interface.WritePacket = &shmemWritePacket;
371 interface.GetLastError = &shmemGetLastError;
372 *result = &single_env;
373
374 /* initialized TLS */
375 tlsIndex = sysTlsAlloc();
376
377 return JNI_OK;
378}