1 /*
2 * Copyright (c) 1998, 2013, Oracle and/or its affiliates. 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. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25 #include <stdio.h>
26 #include <string.h>
27 #include <errno.h>
28 #include <stdlib.h>
29 #include <ctype.h>
30
31 #include "jdwpTransport.h"
32 #include "sysSocket.h"
33
34 /*
35 * The Socket Transport Library.
36 *
37 * This module is an implementation of the Java Debug Wire Protocol Transport
38 * Service Provider Interface - see src/share/javavm/export/jdwpTransport.h.
39 */
40
41 static int serverSocketFD;
42 static int socketFD = -1;
43 static jdwpTransportCallback *callback;
44 static JavaVM *jvm;
45 static int tlsIndex;
46 static jboolean initialized;
47 static struct jdwpTransportNativeInterface_ interface;
48 static jdwpTransportEnv single_env = (jdwpTransportEnv)&interface;
49
50 #define RETURN_ERROR(err, msg) \
51 if (1==1) { \
52 setLastError(err, msg); \
53 return err; \
54 }
55
56 #define RETURN_IO_ERROR(msg) RETURN_ERROR(JDWPTRANSPORT_ERROR_IO_ERROR, msg);
57
58 #define RETURN_RECV_ERROR(n) \
59 if (n == 0) { \
60 RETURN_ERROR(JDWPTRANSPORT_ERROR_IO_ERROR, "premature EOF"); \
61 } else { \
62 RETURN_IO_ERROR("recv error"); \
63 }
64
65 #define HEADER_SIZE 11
66 #define MAX_DATA_SIZE 1000
67
68 static jint recv_fully(int, char *, int);
69 static jint send_fully(int, char *, int);
70
71 /*
72 * Record the last error for this thread.
73 */
74 static void
setLastError(jdwpTransportError err,char * newmsg)75 setLastError(jdwpTransportError 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 dbgsysGetLastIOError(buf, sizeof(buf));
82 }
83
84 msg = (char *)dbgsysTlsGet(tlsIndex);
85 if (msg != NULL) {
86 (*callback->free)(msg);
87 }
88
89 if (err == JDWPTRANSPORT_ERROR_IO_ERROR) {
90 char *join_str = ": ";
91 int msg_len = (int)strlen(newmsg) + (int)strlen(join_str) +
92 (int)strlen(buf) + 3;
93 msg = (*callback->alloc)(msg_len);
94 if (msg != NULL) {
95 strcpy(msg, newmsg);
96 strcat(msg, join_str);
97 strcat(msg, buf);
98 }
99 } else {
100 msg = (*callback->alloc)((int)strlen(newmsg)+1);
101 if (msg != NULL) {
102 strcpy(msg, newmsg);
103 }
104 }
105
106 dbgsysTlsPut(tlsIndex, msg);
107 }
108
109 /*
110 * Return the last error for this thread (may be NULL)
111 */
112 static char*
getLastError()113 getLastError() {
114 return (char *)dbgsysTlsGet(tlsIndex);
115 }
116
117 static jdwpTransportError
setOptions(int fd)118 setOptions(int fd)
119 {
120 jvalue dontcare;
121 int err;
122
123 dontcare.i = 0; /* keep compiler happy */
124
125 err = dbgsysSetSocketOption(fd, SO_REUSEADDR, JNI_TRUE, dontcare);
126 if (err < 0) {
127 RETURN_IO_ERROR("setsockopt SO_REUSEADDR failed");
128 }
129
130 err = dbgsysSetSocketOption(fd, TCP_NODELAY, JNI_TRUE, dontcare);
131 if (err < 0) {
132 RETURN_IO_ERROR("setsockopt TCPNODELAY failed");
133 }
134
135 return JDWPTRANSPORT_ERROR_NONE;
136 }
137
138 static jdwpTransportError
handshake(int fd,jlong timeout)139 handshake(int fd, jlong timeout) {
140 const char *hello = "JDWP-Handshake";
141 char b[16];
142 int rv, helloLen, received;
143
144 if (timeout > 0) {
145 dbgsysConfigureBlocking(fd, JNI_FALSE);
146 }
147 helloLen = (int)strlen(hello);
148 received = 0;
149 while (received < helloLen) {
150 int n;
151 char *buf;
152 if (timeout > 0) {
153 rv = dbgsysPoll(fd, JNI_TRUE, JNI_FALSE, (long)timeout);
154 if (rv <= 0) {
155 setLastError(0, "timeout during handshake");
156 return JDWPTRANSPORT_ERROR_IO_ERROR;
157 }
158 }
159 buf = b;
160 buf += received;
161 n = recv_fully(fd, buf, helloLen-received);
162 if (n == 0) {
163 setLastError(0, "handshake failed - connection prematurally closed");
164 return JDWPTRANSPORT_ERROR_IO_ERROR;
165 }
166 if (n < 0) {
167 RETURN_IO_ERROR("recv failed during handshake");
168 }
169 received += n;
170 }
171 if (timeout > 0) {
172 dbgsysConfigureBlocking(fd, JNI_TRUE);
173 }
174 if (strncmp(b, hello, received) != 0) {
175 char msg[80+2*16];
176 b[received] = '\0';
177 /*
178 * We should really use snprintf here but it's not available on Windows.
179 * We can't use jio_snprintf without linking the transport against the VM.
180 */
181 sprintf(msg, "handshake failed - received >%s< - expected >%s<", b, hello);
182 setLastError(0, msg);
183 return JDWPTRANSPORT_ERROR_IO_ERROR;
184 }
185
186 if (send_fully(fd, (char*)hello, helloLen) != helloLen) {
187 RETURN_IO_ERROR("send failed during handshake");
188 }
189 return JDWPTRANSPORT_ERROR_NONE;
190 }
191
192 static jdwpTransportError
parseAddress(const char * address,struct sockaddr_in * sa,uint32_t defaultHost)193 parseAddress(const char *address, struct sockaddr_in *sa, uint32_t defaultHost) {
194 char *colon;
195
196 memset((void *)sa,0,sizeof(struct sockaddr_in));
197 sa->sin_family = AF_INET;
198
199 /* check for host:port or port */
200 colon = strchr(address, ':');
201 if (colon == NULL) {
202 u_short port = (u_short)atoi(address);
203 sa->sin_port = dbgsysHostToNetworkShort(port);
204 sa->sin_addr.s_addr = dbgsysHostToNetworkLong(defaultHost);
205 } else {
206 char *buf;
207 char *hostname;
208 u_short port;
209 uint32_t addr;
210
211 buf = (*callback->alloc)((int)strlen(address)+1);
212 if (buf == NULL) {
213 RETURN_ERROR(JDWPTRANSPORT_ERROR_OUT_OF_MEMORY, "out of memory");
214 }
215 strcpy(buf, address);
216 buf[colon - address] = '\0';
217 hostname = buf;
218 port = atoi(colon + 1);
219 sa->sin_port = dbgsysHostToNetworkShort(port);
220
221 /*
222 * First see if the host is a literal IP address.
223 * If not then try to resolve it.
224 */
225 addr = dbgsysInetAddr(hostname);
226 if (addr == 0xffffffff) {
227 struct hostent *hp = dbgsysGetHostByName(hostname);
228 if (hp == NULL) {
229 /* don't use RETURN_IO_ERROR as unknown host is normal */
230 setLastError(0, "gethostbyname: unknown host");
231 (*callback->free)(buf);
232 return JDWPTRANSPORT_ERROR_IO_ERROR;
233 }
234
235 /* lookup was successful */
236 memcpy(&(sa->sin_addr), hp->h_addr_list[0], hp->h_length);
237 } else {
238 sa->sin_addr.s_addr = addr;
239 }
240
241 (*callback->free)(buf);
242 }
243
244 return JDWPTRANSPORT_ERROR_NONE;
245 }
246
247
248 static jdwpTransportError JNICALL
socketTransport_getCapabilities(jdwpTransportEnv * env,JDWPTransportCapabilities * capabilitiesPtr)249 socketTransport_getCapabilities(jdwpTransportEnv* env,
250 JDWPTransportCapabilities* capabilitiesPtr)
251 {
252 JDWPTransportCapabilities result;
253
254 memset(&result, 0, sizeof(result));
255 result.can_timeout_attach = JNI_TRUE;
256 result.can_timeout_accept = JNI_TRUE;
257 result.can_timeout_handshake = JNI_TRUE;
258
259 *capabilitiesPtr = result;
260
261 return JDWPTRANSPORT_ERROR_NONE;
262 }
263
264
265 static jdwpTransportError JNICALL
socketTransport_startListening(jdwpTransportEnv * env,const char * address,char ** actualAddress)266 socketTransport_startListening(jdwpTransportEnv* env, const char* address,
267 char** actualAddress)
268 {
269 struct sockaddr_in sa;
270 int err;
271
272 memset((void *)&sa,0,sizeof(struct sockaddr_in));
273 sa.sin_family = AF_INET;
274
275 /* no address provided */
276 if ((address == NULL) || (address[0] == '\0')) {
277 address = "0";
278 }
279
280 err = parseAddress(address, &sa, INADDR_ANY);
281 if (err != JDWPTRANSPORT_ERROR_NONE) {
282 return err;
283 }
284
285 serverSocketFD = dbgsysSocket(AF_INET, SOCK_STREAM, 0);
286 if (serverSocketFD < 0) {
287 RETURN_IO_ERROR("socket creation failed");
288 }
289
290 err = setOptions(serverSocketFD);
291 if (err) {
292 return err;
293 }
294
295 err = dbgsysBind(serverSocketFD, (struct sockaddr *)&sa, sizeof(sa));
296 if (err < 0) {
297 RETURN_IO_ERROR("bind failed");
298 }
299
300 err = dbgsysListen(serverSocketFD, 1);
301 if (err < 0) {
302 RETURN_IO_ERROR("listen failed");
303 }
304
305 {
306 char buf[20];
307 socklen_t len = sizeof(sa);
308 jint portNum;
309 err = dbgsysGetSocketName(serverSocketFD,
310 (struct sockaddr *)&sa, &len);
311 portNum = dbgsysNetworkToHostShort(sa.sin_port);
312 sprintf(buf, "%d", portNum);
313 *actualAddress = (*callback->alloc)((int)strlen(buf) + 1);
314 if (*actualAddress == NULL) {
315 RETURN_ERROR(JDWPTRANSPORT_ERROR_OUT_OF_MEMORY, "out of memory");
316 } else {
317 strcpy(*actualAddress, buf);
318 }
319 }
320
321 return JDWPTRANSPORT_ERROR_NONE;
322 }
323
324 static jdwpTransportError JNICALL
socketTransport_accept(jdwpTransportEnv * env,jlong acceptTimeout,jlong handshakeTimeout)325 socketTransport_accept(jdwpTransportEnv* env, jlong acceptTimeout, jlong handshakeTimeout)
326 {
327 socklen_t socketLen;
328 int err;
329 struct sockaddr_in socket;
330 jlong startTime = (jlong)0;
331
332 /*
333 * Use a default handshake timeout if not specified - this avoids an indefinite
334 * hang in cases where something other than a debugger connects to our port.
335 */
336 if (handshakeTimeout == 0) {
337 handshakeTimeout = 2000;
338 }
339
340 do {
341 /*
342 * If there is an accept timeout then we put the socket in non-blocking
343 * mode and poll for a connection.
344 */
345 if (acceptTimeout > 0) {
346 int rv;
347 dbgsysConfigureBlocking(serverSocketFD, JNI_FALSE);
348 startTime = dbgsysCurrentTimeMillis();
349 rv = dbgsysPoll(serverSocketFD, JNI_TRUE, JNI_FALSE, (long)acceptTimeout);
350 if (rv <= 0) {
351 /* set the last error here as could be overridden by configureBlocking */
352 if (rv == 0) {
353 setLastError(JDWPTRANSPORT_ERROR_IO_ERROR, "poll failed");
354 }
355 /* restore blocking state */
356 dbgsysConfigureBlocking(serverSocketFD, JNI_TRUE);
357 if (rv == 0) {
358 RETURN_ERROR(JDWPTRANSPORT_ERROR_TIMEOUT, "timed out waiting for connection");
359 } else {
360 return JDWPTRANSPORT_ERROR_IO_ERROR;
361 }
362 }
363 }
364
365 /*
366 * Accept the connection
367 */
368 memset((void *)&socket,0,sizeof(struct sockaddr_in));
369 socketLen = sizeof(socket);
370 socketFD = dbgsysAccept(serverSocketFD,
371 (struct sockaddr *)&socket,
372 &socketLen);
373 /* set the last error here as could be overridden by configureBlocking */
374 if (socketFD < 0) {
375 setLastError(JDWPTRANSPORT_ERROR_IO_ERROR, "accept failed");
376 }
377 /*
378 * Restore the blocking state - note that the accepted socket may be in
379 * blocking or non-blocking mode (platform dependent). However as there
380 * is a handshake timeout set then it will go into non-blocking mode
381 * anyway for the handshake.
382 */
383 if (acceptTimeout > 0) {
384 dbgsysConfigureBlocking(serverSocketFD, JNI_TRUE);
385 }
386 if (socketFD < 0) {
387 return JDWPTRANSPORT_ERROR_IO_ERROR;
388 }
389
390 /* handshake with the debugger */
391 err = handshake(socketFD, handshakeTimeout);
392
393 /*
394 * If the handshake fails then close the connection. If there if an accept
395 * timeout then we must adjust the timeout for the next poll.
396 */
397 if (err) {
398 fprintf(stderr, "Debugger failed to attach: %s\n", getLastError());
399 dbgsysSocketClose(socketFD);
400 socketFD = -1;
401 if (acceptTimeout > 0) {
402 long endTime = dbgsysCurrentTimeMillis();
403 acceptTimeout -= (endTime - startTime);
404 if (acceptTimeout <= 0) {
405 setLastError(JDWPTRANSPORT_ERROR_IO_ERROR,
406 "timeout waiting for debugger to connect");
407 return JDWPTRANSPORT_ERROR_IO_ERROR;
408 }
409 }
410 }
411 } while (socketFD < 0);
412
413 return JDWPTRANSPORT_ERROR_NONE;
414 }
415
416 static jdwpTransportError JNICALL
socketTransport_stopListening(jdwpTransportEnv * env)417 socketTransport_stopListening(jdwpTransportEnv *env)
418 {
419 if (serverSocketFD < 0) {
420 RETURN_ERROR(JDWPTRANSPORT_ERROR_ILLEGAL_STATE, "connection not open");
421 }
422 if (dbgsysSocketClose(serverSocketFD) < 0) {
423 RETURN_IO_ERROR("close failed");
424 }
425 serverSocketFD = -1;
426 return JDWPTRANSPORT_ERROR_NONE;
427 }
428
429 static jdwpTransportError JNICALL
socketTransport_attach(jdwpTransportEnv * env,const char * addressString,jlong attachTimeout,jlong handshakeTimeout)430 socketTransport_attach(jdwpTransportEnv* env, const char* addressString, jlong attachTimeout,
431 jlong handshakeTimeout)
432 {
433 struct sockaddr_in sa;
434 int err;
435
436 if (addressString == NULL || addressString[0] == '\0') {
437 RETURN_ERROR(JDWPTRANSPORT_ERROR_ILLEGAL_ARGUMENT, "address is missing");
438 }
439
440 err = parseAddress(addressString, &sa, 0x7f000001);
441 if (err != JDWPTRANSPORT_ERROR_NONE) {
442 return err;
443 }
444
445 socketFD = dbgsysSocket(AF_INET, SOCK_STREAM, 0);
446 if (socketFD < 0) {
447 RETURN_IO_ERROR("unable to create socket");
448 }
449
450 err = setOptions(socketFD);
451 if (err) {
452 return err;
453 }
454
455 /*
456 * To do a timed connect we make the socket non-blocking
457 * and poll with a timeout;
458 */
459 if (attachTimeout > 0) {
460 dbgsysConfigureBlocking(socketFD, JNI_FALSE);
461 }
462
463 err = dbgsysConnect(socketFD, (struct sockaddr *)&sa, sizeof(sa));
464 if (err == DBG_EINPROGRESS && attachTimeout > 0) {
465 err = dbgsysFinishConnect(socketFD, (long)attachTimeout);
466
467 if (err == DBG_ETIMEOUT) {
468 dbgsysConfigureBlocking(socketFD, JNI_TRUE);
469 RETURN_ERROR(JDWPTRANSPORT_ERROR_TIMEOUT, "connect timed out");
470 }
471 }
472
473 if (err < 0) {
474 RETURN_IO_ERROR("connect failed");
475 }
476
477 if (attachTimeout > 0) {
478 dbgsysConfigureBlocking(socketFD, JNI_TRUE);
479 }
480
481 err = handshake(socketFD, handshakeTimeout);
482 if (err) {
483 dbgsysSocketClose(socketFD);
484 socketFD = -1;
485 return err;
486 }
487
488 return JDWPTRANSPORT_ERROR_NONE;
489 }
490
491 static jboolean JNICALL
socketTransport_isOpen(jdwpTransportEnv * env)492 socketTransport_isOpen(jdwpTransportEnv* env)
493 {
494 if (socketFD >= 0) {
495 return JNI_TRUE;
496 } else {
497 return JNI_FALSE;
498 }
499 }
500
501 static jdwpTransportError JNICALL
socketTransport_close(jdwpTransportEnv * env)502 socketTransport_close(jdwpTransportEnv* env)
503 {
504 int fd = socketFD;
505 socketFD = -1;
506 if (fd < 0) {
507 return JDWPTRANSPORT_ERROR_NONE;
508 }
509 #ifdef _AIX
510 /*
511 AIX needs a workaround for I/O cancellation, see:
512 http://publib.boulder.ibm.com/infocenter/pseries/v5r3/index.jsp?topic=/com.ibm.aix.basetechref/doc/basetrf1/close.htm
513 ...
514 The close subroutine is blocked until all subroutines which use the file
515 descriptor return to usr space. For example, when a thread is calling close
516 and another thread is calling select with the same file descriptor, the
517 close subroutine does not return until the select call returns.
518 ...
519 */
520 shutdown(fd, 2);
521 #endif
522 if (dbgsysSocketClose(fd) < 0) {
523 /*
524 * close failed - it's pointless to restore socketFD here because
525 * any subsequent close will likely fail as well.
526 */
527 RETURN_IO_ERROR("close failed");
528 }
529 return JDWPTRANSPORT_ERROR_NONE;
530 }
531
532 static jdwpTransportError JNICALL
socketTransport_writePacket(jdwpTransportEnv * env,const jdwpPacket * packet)533 socketTransport_writePacket(jdwpTransportEnv* env, const jdwpPacket *packet)
534 {
535 jint len, data_len, id;
536 /*
537 * room for header and up to MAX_DATA_SIZE data bytes
538 */
539 char header[HEADER_SIZE + MAX_DATA_SIZE];
540 jbyte *data;
541
542 /* packet can't be null */
543 if (packet == NULL) {
544 RETURN_ERROR(JDWPTRANSPORT_ERROR_ILLEGAL_ARGUMENT, "packet is NULL");
545 }
546
547 len = packet->type.cmd.len; /* includes header */
548 data_len = len - HEADER_SIZE;
549
550 /* bad packet */
551 if (data_len < 0) {
552 RETURN_ERROR(JDWPTRANSPORT_ERROR_ILLEGAL_ARGUMENT, "invalid length");
553 }
554
555 /* prepare the header for transmission */
556 len = (jint)dbgsysHostToNetworkLong(len);
557 id = (jint)dbgsysHostToNetworkLong(packet->type.cmd.id);
558
559 memcpy(header + 0, &len, 4);
560 memcpy(header + 4, &id, 4);
561 header[8] = packet->type.cmd.flags;
562 if (packet->type.cmd.flags & JDWPTRANSPORT_FLAGS_REPLY) {
563 jshort errorCode =
564 dbgsysHostToNetworkShort(packet->type.reply.errorCode);
565 memcpy(header + 9, &errorCode, 2);
566 } else {
567 header[9] = packet->type.cmd.cmdSet;
568 header[10] = packet->type.cmd.cmd;
569 }
570
571 data = packet->type.cmd.data;
572 /* Do one send for short packets, two for longer ones */
573 if (data_len <= MAX_DATA_SIZE) {
574 memcpy(header + HEADER_SIZE, data, data_len);
575 if (send_fully(socketFD, (char *)&header, HEADER_SIZE + data_len) !=
576 HEADER_SIZE + data_len) {
577 RETURN_IO_ERROR("send failed");
578 }
579 } else {
580 memcpy(header + HEADER_SIZE, data, MAX_DATA_SIZE);
581 if (send_fully(socketFD, (char *)&header, HEADER_SIZE + MAX_DATA_SIZE) !=
582 HEADER_SIZE + MAX_DATA_SIZE) {
583 RETURN_IO_ERROR("send failed");
584 }
585 /* Send the remaining data bytes right out of the data area. */
586 if (send_fully(socketFD, (char *)data + MAX_DATA_SIZE,
587 data_len - MAX_DATA_SIZE) != data_len - MAX_DATA_SIZE) {
588 RETURN_IO_ERROR("send failed");
589 }
590 }
591
592 return JDWPTRANSPORT_ERROR_NONE;
593 }
594
595 static jint
recv_fully(int f,char * buf,int len)596 recv_fully(int f, char *buf, int len)
597 {
598 int nbytes = 0;
599 while (nbytes < len) {
600 int res = dbgsysRecv(f, buf + nbytes, len - nbytes, 0);
601 if (res < 0) {
602 return res;
603 } else if (res == 0) {
604 break; /* eof, return nbytes which is less than len */
605 }
606 nbytes += res;
607 }
608 return nbytes;
609 }
610
611 jint
send_fully(int f,char * buf,int len)612 send_fully(int f, char *buf, int len)
613 {
614 int nbytes = 0;
615 while (nbytes < len) {
616 int res = dbgsysSend(f, buf + nbytes, len - nbytes, 0);
617 if (res < 0) {
618 return res;
619 } else if (res == 0) {
620 break; /* eof, return nbytes which is less than len */
621 }
622 nbytes += res;
623 }
624 return nbytes;
625 }
626
627 static jdwpTransportError JNICALL
socketTransport_readPacket(jdwpTransportEnv * env,jdwpPacket * packet)628 socketTransport_readPacket(jdwpTransportEnv* env, jdwpPacket* packet) {
629 jint length, data_len;
630 jint n;
631
632 /* packet can't be null */
633 if (packet == NULL) {
634 RETURN_ERROR(JDWPTRANSPORT_ERROR_ILLEGAL_ARGUMENT, "packet is null");
635 }
636
637 /* read the length field */
638 n = recv_fully(socketFD, (char *)&length, sizeof(jint));
639
640 /* check for EOF */
641 if (n == 0) {
642 packet->type.cmd.len = 0;
643 return JDWPTRANSPORT_ERROR_NONE;
644 }
645 if (n != sizeof(jint)) {
646 RETURN_RECV_ERROR(n);
647 }
648
649 length = (jint)dbgsysNetworkToHostLong(length);
650 packet->type.cmd.len = length;
651
652
653 n = recv_fully(socketFD,(char *)&(packet->type.cmd.id),sizeof(jint));
654 if (n < (int)sizeof(jint)) {
655 RETURN_RECV_ERROR(n);
656 }
657
658 packet->type.cmd.id = (jint)dbgsysNetworkToHostLong(packet->type.cmd.id);
659
660 n = recv_fully(socketFD,(char *)&(packet->type.cmd.flags),sizeof(jbyte));
661 if (n < (int)sizeof(jbyte)) {
662 RETURN_RECV_ERROR(n);
663 }
664
665 if (packet->type.cmd.flags & JDWPTRANSPORT_FLAGS_REPLY) {
666 n = recv_fully(socketFD,(char *)&(packet->type.reply.errorCode),sizeof(jbyte));
667 if (n < (int)sizeof(jshort)) {
668 RETURN_RECV_ERROR(n);
669 }
670
671 /* FIXME - should the error be converted to host order?? */
672
673
674 } else {
675 n = recv_fully(socketFD,(char *)&(packet->type.cmd.cmdSet),sizeof(jbyte));
676 if (n < (int)sizeof(jbyte)) {
677 RETURN_RECV_ERROR(n);
678 }
679
680 n = recv_fully(socketFD,(char *)&(packet->type.cmd.cmd),sizeof(jbyte));
681 if (n < (int)sizeof(jbyte)) {
682 RETURN_RECV_ERROR(n);
683 }
684 }
685
686 data_len = length - ((sizeof(jint) * 2) + (sizeof(jbyte) * 3));
687
688 if (data_len < 0) {
689 setLastError(0, "Badly formed packet received - invalid length");
690 return JDWPTRANSPORT_ERROR_IO_ERROR;
691 } else if (data_len == 0) {
692 packet->type.cmd.data = NULL;
693 } else {
694 packet->type.cmd.data= (*callback->alloc)(data_len);
695
696 if (packet->type.cmd.data == NULL) {
697 RETURN_ERROR(JDWPTRANSPORT_ERROR_OUT_OF_MEMORY, "out of memory");
698 }
699
700 n = recv_fully(socketFD,(char *)packet->type.cmd.data, data_len);
701 if (n < data_len) {
702 (*callback->free)(packet->type.cmd.data);
703 RETURN_RECV_ERROR(n);
704 }
705 }
706
707 return JDWPTRANSPORT_ERROR_NONE;
708 }
709
710 static jdwpTransportError JNICALL
socketTransport_getLastError(jdwpTransportEnv * env,char ** msgP)711 socketTransport_getLastError(jdwpTransportEnv* env, char** msgP) {
712 char *msg = (char *)dbgsysTlsGet(tlsIndex);
713 if (msg == NULL) {
714 return JDWPTRANSPORT_ERROR_MSG_NOT_AVAILABLE;
715 }
716 *msgP = (*callback->alloc)((int)strlen(msg)+1);
717 if (*msgP == NULL) {
718 return JDWPTRANSPORT_ERROR_OUT_OF_MEMORY;
719 }
720 strcpy(*msgP, msg);
721 return JDWPTRANSPORT_ERROR_NONE;
722 }
723
724 JNIEXPORT jint JNICALL
jdwpTransport_OnLoad(JavaVM * vm,jdwpTransportCallback * cbTablePtr,jint version,jdwpTransportEnv ** result)725 jdwpTransport_OnLoad(JavaVM *vm, jdwpTransportCallback* cbTablePtr,
726 jint version, jdwpTransportEnv** result)
727 {
728 if (version != JDWPTRANSPORT_VERSION_1_0) {
729 return JNI_EVERSION;
730 }
731 if (initialized) {
732 /*
733 * This library doesn't support multiple environments (yet)
734 */
735 return JNI_EEXIST;
736 }
737 initialized = JNI_TRUE;
738 jvm = vm;
739 callback = cbTablePtr;
740
741 /* initialize interface table */
742 interface.GetCapabilities = &socketTransport_getCapabilities;
743 interface.Attach = &socketTransport_attach;
744 interface.StartListening = &socketTransport_startListening;
745 interface.StopListening = &socketTransport_stopListening;
746 interface.Accept = &socketTransport_accept;
747 interface.IsOpen = &socketTransport_isOpen;
748 interface.Close = &socketTransport_close;
749 interface.ReadPacket = &socketTransport_readPacket;
750 interface.WritePacket = &socketTransport_writePacket;
751 interface.GetLastError = &socketTransport_getLastError;
752 *result = &single_env;
753
754 /* initialized TLS */
755 tlsIndex = dbgsysTlsAlloc();
756 return JNI_OK;
757 }
758