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