• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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