Home | History | Annotate | Download | only in socket
      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
     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*
    113 getLastError() {
    114     return (char *)dbgsysTlsGet(tlsIndex);
    115 }
    116 
    117 static jdwpTransportError
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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