1/*
2 * Copyright (c) 1998, 2017, 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#else
38 #include <arpa/inet.h>
39 #include <sys/socket.h>
40#endif
41
42/*
43 * The Socket Transport Library.
44 *
45 * This module is an implementation of the Java Debug Wire Protocol Transport
46 * Service Provider Interface - see src/share/javavm/export/jdwpTransport.h.
47 */
48
49static int serverSocketFD;
50static int socketFD = -1;
51static jdwpTransportCallback *callback;
52static JavaVM *jvm;
53static int tlsIndex;
54static jboolean initialized;
55static struct jdwpTransportNativeInterface_ interface;
56static jdwpTransportEnv single_env = (jdwpTransportEnv)&interface;
57
58#define RETURN_ERROR(err, msg) \
59        if (1==1) { \
60            setLastError(err, msg); \
61            return err; \
62        }
63
64#define RETURN_IO_ERROR(msg)    RETURN_ERROR(JDWPTRANSPORT_ERROR_IO_ERROR, msg);
65
66#define RETURN_RECV_ERROR(n) \
67        if (n == 0) { \
68            RETURN_ERROR(JDWPTRANSPORT_ERROR_IO_ERROR, "premature EOF"); \
69        } else { \
70            RETURN_IO_ERROR("recv error"); \
71        }
72
73#define HEADER_SIZE     11
74#define MAX_DATA_SIZE 1000
75
76static jint recv_fully(int, char *, int);
77static jint send_fully(int, char *, int);
78
79/* version >= JDWPTRANSPORT_VERSION_1_1 */
80typedef struct {
81    uint32_t subnet;
82    uint32_t netmask;
83} AllowedPeerInfo;
84
85#define STR(x) #x
86#define MAX_PEER_ENTRIES 32
87#define MAX_PEERS_STR STR(MAX_PEER_ENTRIES)
88static AllowedPeerInfo _peers[MAX_PEER_ENTRIES];
89static int _peers_cnt = 0;
90
91
92/*
93 * Record the last error for this thread.
94 */
95static void
96setLastError(jdwpTransportError err, char *newmsg) {
97    char buf[255];
98    char *msg;
99
100    /* get any I/O first in case any system calls override errno */
101    if (err == JDWPTRANSPORT_ERROR_IO_ERROR) {
102        dbgsysGetLastIOError(buf, sizeof(buf));
103    }
104
105    msg = (char *)dbgsysTlsGet(tlsIndex);
106    if (msg != NULL) {
107        (*callback->free)(msg);
108    }
109
110    if (err == JDWPTRANSPORT_ERROR_IO_ERROR) {
111        char *join_str = ": ";
112        int msg_len = (int)strlen(newmsg) + (int)strlen(join_str) +
113                      (int)strlen(buf) + 3;
114        msg = (*callback->alloc)(msg_len);
115        if (msg != NULL) {
116            strcpy(msg, newmsg);
117            strcat(msg, join_str);
118            strcat(msg, buf);
119        }
120    } else {
121        msg = (*callback->alloc)((int)strlen(newmsg)+1);
122        if (msg != NULL) {
123            strcpy(msg, newmsg);
124        }
125    }
126
127    dbgsysTlsPut(tlsIndex, msg);
128}
129
130/*
131 * Return the last error for this thread (may be NULL)
132 */
133static char*
134getLastError() {
135    return (char *)dbgsysTlsGet(tlsIndex);
136}
137
138/* Set options common to client and server sides */
139static jdwpTransportError
140setOptionsCommon(int fd)
141{
142    jvalue dontcare;
143    int err;
144
145    dontcare.i = 0;  /* keep compiler happy */
146
147    err = dbgsysSetSocketOption(fd, TCP_NODELAY, JNI_TRUE, dontcare);
148    if (err < 0) {
149        RETURN_IO_ERROR("setsockopt TCPNODELAY failed");
150    }
151
152    return JDWPTRANSPORT_ERROR_NONE;
153}
154
155/* Set the SO_REUSEADDR option */
156static jdwpTransportError
157setReuseAddrOption(int fd)
158{
159    jvalue dontcare;
160    int err;
161
162    dontcare.i = 0;  /* keep compiler happy */
163
164    err = dbgsysSetSocketOption(fd, SO_REUSEADDR, JNI_TRUE, dontcare);
165    if (err < 0) {
166        RETURN_IO_ERROR("setsockopt SO_REUSEADDR failed");
167    }
168
169    return JDWPTRANSPORT_ERROR_NONE;
170}
171
172static jdwpTransportError
173handshake(int fd, jlong timeout) {
174    const char *hello = "JDWP-Handshake";
175    char b[16];
176    int rv, helloLen, received;
177
178    if (timeout > 0) {
179        dbgsysConfigureBlocking(fd, JNI_FALSE);
180    }
181    helloLen = (int)strlen(hello);
182    received = 0;
183    while (received < helloLen) {
184        int n;
185        char *buf;
186        if (timeout > 0) {
187            rv = dbgsysPoll(fd, JNI_TRUE, JNI_FALSE, (long)timeout);
188            if (rv <= 0) {
189                setLastError(0, "timeout during handshake");
190                return JDWPTRANSPORT_ERROR_IO_ERROR;
191            }
192        }
193        buf = b;
194        buf += received;
195        n = recv_fully(fd, buf, helloLen-received);
196        if (n == 0) {
197            setLastError(0, "handshake failed - connection prematurally closed");
198            return JDWPTRANSPORT_ERROR_IO_ERROR;
199        }
200        if (n < 0) {
201            RETURN_IO_ERROR("recv failed during handshake");
202        }
203        received += n;
204    }
205    if (timeout > 0) {
206        dbgsysConfigureBlocking(fd, JNI_TRUE);
207    }
208    if (strncmp(b, hello, received) != 0) {
209        char msg[80+2*16];
210        b[received] = '\0';
211        /*
212         * We should really use snprintf here but it's not available on Windows.
213         * We can't use jio_snprintf without linking the transport against the VM.
214         */
215        sprintf(msg, "handshake failed - received >%s< - expected >%s<", b, hello);
216        setLastError(0, msg);
217        return JDWPTRANSPORT_ERROR_IO_ERROR;
218    }
219
220    if (send_fully(fd, (char*)hello, helloLen) != helloLen) {
221        RETURN_IO_ERROR("send failed during handshake");
222    }
223    return JDWPTRANSPORT_ERROR_NONE;
224}
225
226static uint32_t
227getLocalHostAddress() {
228    // Simple routine to guess localhost address.
229    // it looks up "localhost" and returns 127.0.0.1 if lookup
230    // fails.
231    struct addrinfo hints, *res = NULL;
232    int err;
233
234    // Use portable way to initialize the structure
235    memset((void *)&hints, 0, sizeof(hints));
236    hints.ai_family = AF_INET;
237
238    err = getaddrinfo("localhost", NULL, &hints, &res);
239    if (err < 0 || res == NULL) {
240        return dbgsysHostToNetworkLong(INADDR_LOOPBACK);
241    }
242
243    // getaddrinfo might return more than one address
244    // but we are using first one only
245    return ((struct sockaddr_in *)(res->ai_addr))->sin_addr.s_addr;
246}
247
248static int
249getPortNumber(const char *s_port) {
250    u_long n;
251    char *eptr;
252
253    if (*s_port == 0) {
254        // bad address - colon with no port number in parameters
255        return -1;
256    }
257
258    n = strtoul(s_port, &eptr, 10);
259    if (eptr != s_port + strlen(s_port)) {
260        // incomplete conversion - port number contains non-digit
261        return -1;
262    }
263
264    if (n > (u_short) -1) {
265        // check that value supplied by user is less than
266        // maximum possible u_short value (65535) and
267        // will not be truncated later.
268        return -1;
269    }
270
271    return n;
272}
273
274static jdwpTransportError
275parseAddress(const char *address, struct sockaddr_in *sa) {
276    char *colon;
277    int port;
278
279    memset((void *)sa, 0, sizeof(struct sockaddr_in));
280    sa->sin_family = AF_INET;
281
282    /* check for host:port or port */
283    colon = strchr(address, ':');
284    port = getPortNumber((colon == NULL) ? address : colon +1);
285    if (port < 0) {
286        RETURN_ERROR(JDWPTRANSPORT_ERROR_ILLEGAL_ARGUMENT, "invalid port number specified");
287    }
288    sa->sin_port = dbgsysHostToNetworkShort((u_short)port);
289
290    if (colon == NULL) {
291        // bind to localhost only if no address specified
292        sa->sin_addr.s_addr = getLocalHostAddress();
293    } else if (strncmp(address, "localhost:", 10) == 0) {
294        // optimize for common case
295        sa->sin_addr.s_addr = getLocalHostAddress();
296    } else if (*address == '*' && *(address+1) == ':') {
297        // we are explicitly asked to bind server to all available IP addresses
298        // has no meaning for client.
299        sa->sin_addr.s_addr = dbgsysHostToNetworkLong(INADDR_ANY);
300     } else {
301        char *buf;
302        char *hostname;
303        uint32_t addr;
304
305        buf = (*callback->alloc)((int)strlen(address) + 1);
306        if (buf == NULL) {
307            RETURN_ERROR(JDWPTRANSPORT_ERROR_OUT_OF_MEMORY, "out of memory");
308        }
309        strcpy(buf, address);
310        buf[colon - address] = '\0';
311        hostname = buf;
312
313        /*
314         * First see if the host is a literal IP address.
315         * If not then try to resolve it.
316         */
317        addr = dbgsysInetAddr(hostname);
318        if (addr == 0xffffffff) {
319            struct hostent *hp = dbgsysGetHostByName(hostname);
320            if (hp == NULL) {
321                /* don't use RETURN_IO_ERROR as unknown host is normal */
322                setLastError(0, "gethostbyname: unknown host");
323                (*callback->free)(buf);
324                return JDWPTRANSPORT_ERROR_IO_ERROR;
325            }
326
327            /* lookup was successful */
328            memcpy(&(sa->sin_addr), hp->h_addr_list[0], hp->h_length);
329        } else {
330            sa->sin_addr.s_addr = addr;
331        }
332
333        (*callback->free)(buf);
334    }
335
336    return JDWPTRANSPORT_ERROR_NONE;
337}
338
339static const char *
340ip_s2u(const char *instr, uint32_t *ip) {
341    // Convert string representation of ip to integer
342    // in network byte order (big-endian)
343    char t[4] = { 0, 0, 0, 0 };
344    const char *s = instr;
345    int i = 0;
346
347    while (1) {
348        if (*s == '.') {
349            ++i;
350            ++s;
351            continue;
352        }
353        if (*s == 0 || *s == '+' || *s == '/') {
354            break;
355        }
356        if (*s < '0' || *s > '9') {
357            return instr;
358        }
359        t[i] = (t[i] * 10) + (*s - '0');
360        ++s;
361    }
362
363    *ip = *(uint32_t*)(t);
364    return s;
365}
366
367static const char *
368mask_s2u(const char *instr, uint32_t *mask) {
369    // Convert the number of bits to a netmask
370    // in network byte order (big-endian)
371    unsigned char m = 0;
372    const char *s = instr;
373
374    while (1) {
375        if (*s == 0 || *s == '+') {
376            break;
377        }
378        if (*s < '0' || *s > '9') {
379            return instr;
380        }
381        m = (m * 10) + (*s - '0');
382        ++s;
383    }
384
385    if (m == 0 || m > 32) {
386       // Drop invalid input
387       return instr;
388    }
389
390    *mask = htonl(-1 << (32 - m));
391    return s;
392}
393
394static int
395ip_in_subnet(uint32_t subnet, uint32_t mask, uint32_t ipaddr) {
396    return (ipaddr & mask) == subnet;
397}
398
399static jdwpTransportError
400parseAllowedPeers(const char *allowed_peers) {
401    // Build a list of allowed peers from char string
402    // of format 192.168.0.10+192.168.0.0/24
403    const char *s = NULL;
404    const char *p = allowed_peers;
405    uint32_t   ip = 0;
406    uint32_t mask = 0xFFFFFFFF;
407
408    while (1) {
409        s = ip_s2u(p, &ip);
410        if (s == p) {
411            _peers_cnt = 0;
412            fprintf(stderr, "Error in allow option: '%s'\n", s);
413            RETURN_ERROR(JDWPTRANSPORT_ERROR_ILLEGAL_ARGUMENT,
414                         "invalid IP address in allow option");
415        }
416
417        if (*s == '/') {
418            // netmask specified
419            s = mask_s2u(s + 1, &mask);
420            if (*(s - 1) == '/') {
421                // Input is not consumed, something bad happened
422                _peers_cnt = 0;
423                fprintf(stderr, "Error in allow option: '%s'\n", s);
424                RETURN_ERROR(JDWPTRANSPORT_ERROR_ILLEGAL_ARGUMENT,
425                             "invalid netmask in allow option");
426            }
427        } else {
428            // reset netmask
429            mask = 0xFFFFFFFF;
430        }
431
432        if (*s == '+' || *s == 0) {
433            if (_peers_cnt >= MAX_PEER_ENTRIES) {
434                fprintf(stderr, "Error in allow option: '%s'\n", allowed_peers);
435                RETURN_ERROR(JDWPTRANSPORT_ERROR_ILLEGAL_ARGUMENT,
436                             "exceeded max number of allowed peers: " MAX_PEERS_STR);
437            }
438            _peers[_peers_cnt].subnet = ip;
439            _peers[_peers_cnt].netmask = mask;
440            _peers_cnt++;
441            if (*s == 0) {
442                // end of options
443                break;
444            }
445            // advance to next IP block
446            p = s + 1;
447        }
448    }
449    return JDWPTRANSPORT_ERROR_NONE;
450}
451
452static int
453isPeerAllowed(struct sockaddr_in *peer) {
454    int i;
455    for (i = 0; i < _peers_cnt; ++i) {
456        int peer_ip = peer->sin_addr.s_addr;
457        if (ip_in_subnet(_peers[i].subnet, _peers[i].netmask, peer_ip)) {
458            return 1;
459        }
460    }
461
462    return 0;
463}
464
465static jdwpTransportError JNICALL
466socketTransport_getCapabilities(jdwpTransportEnv* env,
467        JDWPTransportCapabilities* capabilitiesPtr)
468{
469    JDWPTransportCapabilities result;
470
471    memset(&result, 0, sizeof(result));
472    result.can_timeout_attach = JNI_TRUE;
473    result.can_timeout_accept = JNI_TRUE;
474    result.can_timeout_handshake = JNI_TRUE;
475
476    *capabilitiesPtr = result;
477
478    return JDWPTRANSPORT_ERROR_NONE;
479}
480
481
482static jdwpTransportError JNICALL
483socketTransport_startListening(jdwpTransportEnv* env, const char* address,
484                               char** actualAddress)
485{
486    struct sockaddr_in sa;
487    int err;
488
489    memset((void *)&sa,0,sizeof(struct sockaddr_in));
490    sa.sin_family = AF_INET;
491
492    /* no address provided */
493    if ((address == NULL) || (address[0] == '\0')) {
494        address = "0";
495    }
496
497    err = parseAddress(address, &sa);
498    if (err != JDWPTRANSPORT_ERROR_NONE) {
499        return err;
500    }
501
502    serverSocketFD = dbgsysSocket(AF_INET, SOCK_STREAM, 0);
503    if (serverSocketFD < 0) {
504        RETURN_IO_ERROR("socket creation failed");
505    }
506
507    err = setOptionsCommon(serverSocketFD);
508    if (err) {
509        return err;
510    }
511    if (sa.sin_port != 0) {
512        /*
513         * Only need SO_REUSEADDR if we're using a fixed port. If we
514         * start seeing EADDRINUSE due to collisions in free ports
515         * then we should retry the dbgsysBind() a few times.
516         */
517        err = setReuseAddrOption(serverSocketFD);
518        if (err) {
519            return err;
520        }
521    }
522
523    err = dbgsysBind(serverSocketFD, (struct sockaddr *)&sa, sizeof(sa));
524    if (err < 0) {
525        RETURN_IO_ERROR("bind failed");
526    }
527
528    err = dbgsysListen(serverSocketFD, 1);
529    if (err < 0) {
530        RETURN_IO_ERROR("listen failed");
531    }
532
533    {
534        char buf[20];
535        socklen_t len = sizeof(sa);
536        jint portNum;
537        err = dbgsysGetSocketName(serverSocketFD,
538                               (struct sockaddr *)&sa, &len);
539        portNum = dbgsysNetworkToHostShort(sa.sin_port);
540        sprintf(buf, "%d", portNum);
541        *actualAddress = (*callback->alloc)((int)strlen(buf) + 1);
542        if (*actualAddress == NULL) {
543            RETURN_ERROR(JDWPTRANSPORT_ERROR_OUT_OF_MEMORY, "out of memory");
544        } else {
545            strcpy(*actualAddress, buf);
546        }
547    }
548
549    return JDWPTRANSPORT_ERROR_NONE;
550}
551
552static jdwpTransportError JNICALL
553socketTransport_accept(jdwpTransportEnv* env, jlong acceptTimeout, jlong handshakeTimeout)
554{
555    socklen_t socketLen;
556    int err = JDWPTRANSPORT_ERROR_NONE;
557    struct sockaddr_in socket;
558    jlong startTime = (jlong)0;
559
560    /*
561     * Use a default handshake timeout if not specified - this avoids an indefinite
562     * hang in cases where something other than a debugger connects to our port.
563     */
564    if (handshakeTimeout == 0) {
565        handshakeTimeout = 2000;
566    }
567
568    do {
569        /*
570         * If there is an accept timeout then we put the socket in non-blocking
571         * mode and poll for a connection.
572         */
573        if (acceptTimeout > 0) {
574            int rv;
575            dbgsysConfigureBlocking(serverSocketFD, JNI_FALSE);
576            startTime = dbgsysCurrentTimeMillis();
577            rv = dbgsysPoll(serverSocketFD, JNI_TRUE, JNI_FALSE, (long)acceptTimeout);
578            if (rv <= 0) {
579                /* set the last error here as could be overridden by configureBlocking */
580                if (rv == 0) {
581                    setLastError(JDWPTRANSPORT_ERROR_IO_ERROR, "poll failed");
582                }
583                /* restore blocking state */
584                dbgsysConfigureBlocking(serverSocketFD, JNI_TRUE);
585                if (rv == 0) {
586                    RETURN_ERROR(JDWPTRANSPORT_ERROR_TIMEOUT, "timed out waiting for connection");
587                } else {
588                    return JDWPTRANSPORT_ERROR_IO_ERROR;
589                }
590            }
591        }
592
593        /*
594         * Accept the connection
595         */
596        memset((void *)&socket,0,sizeof(struct sockaddr_in));
597        socketLen = sizeof(socket);
598        socketFD = dbgsysAccept(serverSocketFD,
599                                (struct sockaddr *)&socket,
600                                &socketLen);
601        /* set the last error here as could be overridden by configureBlocking */
602        if (socketFD < 0) {
603            setLastError(JDWPTRANSPORT_ERROR_IO_ERROR, "accept failed");
604        }
605        /*
606         * Restore the blocking state - note that the accepted socket may be in
607         * blocking or non-blocking mode (platform dependent). However as there
608         * is a handshake timeout set then it will go into non-blocking mode
609         * anyway for the handshake.
610         */
611        if (acceptTimeout > 0) {
612            dbgsysConfigureBlocking(serverSocketFD, JNI_TRUE);
613        }
614        if (socketFD < 0) {
615            return JDWPTRANSPORT_ERROR_IO_ERROR;
616        }
617
618        /*
619         * version >= JDWPTRANSPORT_VERSION_1_1:
620         * Verify that peer is allowed to connect.
621         */
622        if (_peers_cnt > 0) {
623            if (!isPeerAllowed(&socket)) {
624                char ebuf[64] = { 0 };
625                char buf[INET_ADDRSTRLEN] = { 0 };
626                const char* addr_str = inet_ntop(AF_INET, &(socket.sin_addr), buf, INET_ADDRSTRLEN);
627                sprintf(ebuf, "ERROR: Peer not allowed to connect: %s\n",
628                        (addr_str == NULL) ? "<bad address>" : addr_str);
629                dbgsysSocketClose(socketFD);
630                socketFD = -1;
631                err = JDWPTRANSPORT_ERROR_ILLEGAL_ARGUMENT;
632                setLastError(err, ebuf);
633            }
634        }
635
636        if (socketFD > 0) {
637          /* handshake with the debugger */
638          err = handshake(socketFD, handshakeTimeout);
639        }
640
641        /*
642         * If the handshake fails then close the connection. If there if an accept
643         * timeout then we must adjust the timeout for the next poll.
644         */
645        if (err != JDWPTRANSPORT_ERROR_NONE) {
646            fprintf(stderr, "Debugger failed to attach: %s\n", getLastError());
647            dbgsysSocketClose(socketFD);
648            socketFD = -1;
649            if (acceptTimeout > 0) {
650                long endTime = dbgsysCurrentTimeMillis();
651                acceptTimeout -= (endTime - startTime);
652                if (acceptTimeout <= 0) {
653                    setLastError(JDWPTRANSPORT_ERROR_IO_ERROR,
654                        "timeout waiting for debugger to connect");
655                    return JDWPTRANSPORT_ERROR_IO_ERROR;
656                }
657            }
658        }
659    } while (socketFD < 0);
660
661    return JDWPTRANSPORT_ERROR_NONE;
662}
663
664static jdwpTransportError JNICALL
665socketTransport_stopListening(jdwpTransportEnv *env)
666{
667    if (serverSocketFD < 0) {
668        RETURN_ERROR(JDWPTRANSPORT_ERROR_ILLEGAL_STATE, "connection not open");
669    }
670    if (dbgsysSocketClose(serverSocketFD) < 0) {
671        RETURN_IO_ERROR("close failed");
672    }
673    serverSocketFD = -1;
674    return JDWPTRANSPORT_ERROR_NONE;
675}
676
677static jdwpTransportError JNICALL
678socketTransport_attach(jdwpTransportEnv* env, const char* addressString, jlong attachTimeout,
679                       jlong handshakeTimeout)
680{
681    struct sockaddr_in sa;
682    int err;
683
684    if (addressString == NULL || addressString[0] == '\0') {
685        RETURN_ERROR(JDWPTRANSPORT_ERROR_ILLEGAL_ARGUMENT, "address is missing");
686    }
687
688    err = parseAddress(addressString, &sa);
689    if (err != JDWPTRANSPORT_ERROR_NONE) {
690        return err;
691    }
692
693    socketFD = dbgsysSocket(AF_INET, SOCK_STREAM, 0);
694    if (socketFD < 0) {
695        RETURN_IO_ERROR("unable to create socket");
696    }
697
698    err = setOptionsCommon(socketFD);
699    if (err) {
700        return err;
701    }
702
703    /*
704     * We don't call setReuseAddrOption() for the non-server socket
705     * case. If we start seeing EADDRINUSE due to collisions in free
706     * ports then we should retry the dbgsysConnect() a few times.
707     */
708
709    /*
710     * To do a timed connect we make the socket non-blocking
711     * and poll with a timeout;
712     */
713    if (attachTimeout > 0) {
714        dbgsysConfigureBlocking(socketFD, JNI_FALSE);
715    }
716
717    err = dbgsysConnect(socketFD, (struct sockaddr *)&sa, sizeof(sa));
718    if (err == DBG_EINPROGRESS && attachTimeout > 0) {
719        err = dbgsysFinishConnect(socketFD, (long)attachTimeout);
720
721        if (err == DBG_ETIMEOUT) {
722            dbgsysConfigureBlocking(socketFD, JNI_TRUE);
723            RETURN_ERROR(JDWPTRANSPORT_ERROR_TIMEOUT, "connect timed out");
724        }
725    }
726
727    if (err < 0) {
728        RETURN_IO_ERROR("connect failed");
729    }
730
731    if (attachTimeout > 0) {
732        dbgsysConfigureBlocking(socketFD, JNI_TRUE);
733    }
734
735    err = handshake(socketFD, handshakeTimeout);
736    if (err) {
737        dbgsysSocketClose(socketFD);
738        socketFD = -1;
739        return err;
740    }
741
742    return JDWPTRANSPORT_ERROR_NONE;
743}
744
745static jboolean JNICALL
746socketTransport_isOpen(jdwpTransportEnv* env)
747{
748    if (socketFD >= 0) {
749        return JNI_TRUE;
750    } else {
751        return JNI_FALSE;
752    }
753}
754
755static jdwpTransportError JNICALL
756socketTransport_close(jdwpTransportEnv* env)
757{
758    int fd = socketFD;
759    socketFD = -1;
760    if (fd < 0) {
761        return JDWPTRANSPORT_ERROR_NONE;
762    }
763#ifdef _AIX
764    /*
765      AIX needs a workaround for I/O cancellation, see:
766      http://publib.boulder.ibm.com/infocenter/pseries/v5r3/index.jsp?topic=/com.ibm.aix.basetechref/doc/basetrf1/close.htm
767      ...
768      The close subroutine is blocked until all subroutines which use the file
769      descriptor return to usr space. For example, when a thread is calling close
770      and another thread is calling select with the same file descriptor, the
771      close subroutine does not return until the select call returns.
772      ...
773    */
774    shutdown(fd, 2);
775#endif
776    if (dbgsysSocketClose(fd) < 0) {
777        /*
778         * close failed - it's pointless to restore socketFD here because
779         * any subsequent close will likely fail as well.
780         */
781        RETURN_IO_ERROR("close failed");
782    }
783    return JDWPTRANSPORT_ERROR_NONE;
784}
785
786static jdwpTransportError JNICALL
787socketTransport_writePacket(jdwpTransportEnv* env, const jdwpPacket *packet)
788{
789    jint len, data_len, id;
790    /*
791     * room for header and up to MAX_DATA_SIZE data bytes
792     */
793    char header[HEADER_SIZE + MAX_DATA_SIZE];
794    jbyte *data;
795
796    /* packet can't be null */
797    if (packet == NULL) {
798        RETURN_ERROR(JDWPTRANSPORT_ERROR_ILLEGAL_ARGUMENT, "packet is NULL");
799    }
800
801    len = packet->type.cmd.len;         /* includes header */
802    data_len = len - HEADER_SIZE;
803
804    /* bad packet */
805    if (data_len < 0) {
806        RETURN_ERROR(JDWPTRANSPORT_ERROR_ILLEGAL_ARGUMENT, "invalid length");
807    }
808
809    /* prepare the header for transmission */
810    len = (jint)dbgsysHostToNetworkLong(len);
811    id = (jint)dbgsysHostToNetworkLong(packet->type.cmd.id);
812
813    memcpy(header + 0, &len, 4);
814    memcpy(header + 4, &id, 4);
815    header[8] = packet->type.cmd.flags;
816    if (packet->type.cmd.flags & JDWPTRANSPORT_FLAGS_REPLY) {
817        jshort errorCode =
818            dbgsysHostToNetworkShort(packet->type.reply.errorCode);
819        memcpy(header + 9, &errorCode, 2);
820    } else {
821        header[9] = packet->type.cmd.cmdSet;
822        header[10] = packet->type.cmd.cmd;
823    }
824
825    data = packet->type.cmd.data;
826    /* Do one send for short packets, two for longer ones */
827    if (data_len <= MAX_DATA_SIZE) {
828        memcpy(header + HEADER_SIZE, data, data_len);
829        if (send_fully(socketFD, (char *)&header, HEADER_SIZE + data_len) !=
830            HEADER_SIZE + data_len) {
831            RETURN_IO_ERROR("send failed");
832        }
833    } else {
834        memcpy(header + HEADER_SIZE, data, MAX_DATA_SIZE);
835        if (send_fully(socketFD, (char *)&header, HEADER_SIZE + MAX_DATA_SIZE) !=
836            HEADER_SIZE + MAX_DATA_SIZE) {
837            RETURN_IO_ERROR("send failed");
838        }
839        /* Send the remaining data bytes right out of the data area. */
840        if (send_fully(socketFD, (char *)data + MAX_DATA_SIZE,
841                       data_len - MAX_DATA_SIZE) != data_len - MAX_DATA_SIZE) {
842            RETURN_IO_ERROR("send failed");
843        }
844    }
845
846    return JDWPTRANSPORT_ERROR_NONE;
847}
848
849static jint
850recv_fully(int f, char *buf, int len)
851{
852    int nbytes = 0;
853    while (nbytes < len) {
854        int res = dbgsysRecv(f, buf + nbytes, len - nbytes, 0);
855        if (res < 0) {
856            return res;
857        } else if (res == 0) {
858            break; /* eof, return nbytes which is less than len */
859        }
860        nbytes += res;
861    }
862    return nbytes;
863}
864
865jint
866send_fully(int f, char *buf, int len)
867{
868    int nbytes = 0;
869    while (nbytes < len) {
870        int res = dbgsysSend(f, buf + nbytes, len - nbytes, 0);
871        if (res < 0) {
872            return res;
873        } else if (res == 0) {
874            break; /* eof, return nbytes which is less than len */
875        }
876        nbytes += res;
877    }
878    return nbytes;
879}
880
881static jdwpTransportError JNICALL
882socketTransport_readPacket(jdwpTransportEnv* env, jdwpPacket* packet) {
883    jint length, data_len;
884    jint n;
885
886    /* packet can't be null */
887    if (packet == NULL) {
888        RETURN_ERROR(JDWPTRANSPORT_ERROR_ILLEGAL_ARGUMENT, "packet is null");
889    }
890
891    /* read the length field */
892    n = recv_fully(socketFD, (char *)&length, sizeof(jint));
893
894    /* check for EOF */
895    if (n == 0) {
896        packet->type.cmd.len = 0;
897        return JDWPTRANSPORT_ERROR_NONE;
898    }
899    if (n != sizeof(jint)) {
900        RETURN_RECV_ERROR(n);
901    }
902
903    length = (jint)dbgsysNetworkToHostLong(length);
904    packet->type.cmd.len = length;
905
906
907    n = recv_fully(socketFD,(char *)&(packet->type.cmd.id), sizeof(jint));
908    if (n < (int)sizeof(jint)) {
909        RETURN_RECV_ERROR(n);
910    }
911
912    packet->type.cmd.id = (jint)dbgsysNetworkToHostLong(packet->type.cmd.id);
913
914    n = recv_fully(socketFD,(char *)&(packet->type.cmd.flags), sizeof(jbyte));
915    if (n < (int)sizeof(jbyte)) {
916        RETURN_RECV_ERROR(n);
917    }
918
919    if (packet->type.cmd.flags & JDWPTRANSPORT_FLAGS_REPLY) {
920        n = recv_fully(socketFD,(char *)&(packet->type.reply.errorCode), sizeof(jbyte));
921        if (n < (int)sizeof(jshort)) {
922            RETURN_RECV_ERROR(n);
923        }
924
925        /* FIXME - should the error be converted to host order?? */
926
927
928    } else {
929        n = recv_fully(socketFD,(char *)&(packet->type.cmd.cmdSet), sizeof(jbyte));
930        if (n < (int)sizeof(jbyte)) {
931            RETURN_RECV_ERROR(n);
932        }
933
934        n = recv_fully(socketFD,(char *)&(packet->type.cmd.cmd), sizeof(jbyte));
935        if (n < (int)sizeof(jbyte)) {
936            RETURN_RECV_ERROR(n);
937        }
938    }
939
940    data_len = length - ((sizeof(jint) * 2) + (sizeof(jbyte) * 3));
941
942    if (data_len < 0) {
943        setLastError(0, "Badly formed packet received - invalid length");
944        return JDWPTRANSPORT_ERROR_IO_ERROR;
945    } else if (data_len == 0) {
946        packet->type.cmd.data = NULL;
947    } else {
948        packet->type.cmd.data= (*callback->alloc)(data_len);
949
950        if (packet->type.cmd.data == NULL) {
951            RETURN_ERROR(JDWPTRANSPORT_ERROR_OUT_OF_MEMORY, "out of memory");
952        }
953
954        n = recv_fully(socketFD,(char *)packet->type.cmd.data, data_len);
955        if (n < data_len) {
956            (*callback->free)(packet->type.cmd.data);
957            RETURN_RECV_ERROR(n);
958        }
959    }
960
961    return JDWPTRANSPORT_ERROR_NONE;
962}
963
964static jdwpTransportError JNICALL
965socketTransport_getLastError(jdwpTransportEnv* env, char** msgP) {
966    char *msg = (char *)dbgsysTlsGet(tlsIndex);
967    if (msg == NULL) {
968        return JDWPTRANSPORT_ERROR_MSG_NOT_AVAILABLE;
969    }
970    *msgP = (*callback->alloc)((int)strlen(msg)+1);
971    if (*msgP == NULL) {
972        return JDWPTRANSPORT_ERROR_OUT_OF_MEMORY;
973    }
974    strcpy(*msgP, msg);
975    return JDWPTRANSPORT_ERROR_NONE;
976}
977
978static jdwpTransportError JNICALL
979socketTransport_setConfiguration(jdwpTransportEnv* env, jdwpTransportConfiguration* cfg) {
980    const char* allowed_peers = NULL;
981
982    if (cfg == NULL) {
983        RETURN_ERROR(JDWPTRANSPORT_ERROR_ILLEGAL_ARGUMENT,
984                     "NULL pointer to transport configuration is invalid");
985    }
986    allowed_peers = cfg->allowed_peers;
987    _peers_cnt = 0;
988    if (allowed_peers != NULL) {
989        size_t len = strlen(allowed_peers);
990        if (len == 0) { /* Impossible: parseOptions() would reject it */
991            fprintf(stderr, "Error in allow option: '%s'\n", allowed_peers);
992            RETURN_ERROR(JDWPTRANSPORT_ERROR_ILLEGAL_ARGUMENT,
993                         "allow option should not be empty");
994        } else if (*allowed_peers == '*') {
995            if (len != 1) {
996                fprintf(stderr, "Error in allow option: '%s'\n", allowed_peers);
997                RETURN_ERROR(JDWPTRANSPORT_ERROR_ILLEGAL_ARGUMENT,
998                             "allow option '*' cannot be expanded");
999            }
1000        } else {
1001            int err = parseAllowedPeers(allowed_peers);
1002            if (err != JDWPTRANSPORT_ERROR_NONE) {
1003                return err;
1004            }
1005        }
1006    }
1007    return JDWPTRANSPORT_ERROR_NONE;
1008}
1009
1010jint JNICALL
1011jdwpTransport_OnLoad(JavaVM *vm, jdwpTransportCallback* cbTablePtr,
1012                     jint version, jdwpTransportEnv** env)
1013{
1014    if (version < JDWPTRANSPORT_VERSION_1_0 ||
1015        version > JDWPTRANSPORT_VERSION_1_1) {
1016        return JNI_EVERSION;
1017    }
1018    if (initialized) {
1019        /*
1020         * This library doesn't support multiple environments (yet)
1021         */
1022        return JNI_EEXIST;
1023    }
1024    initialized = JNI_TRUE;
1025    jvm = vm;
1026    callback = cbTablePtr;
1027
1028    /* initialize interface table */
1029    interface.GetCapabilities = &socketTransport_getCapabilities;
1030    interface.Attach = &socketTransport_attach;
1031    interface.StartListening = &socketTransport_startListening;
1032    interface.StopListening = &socketTransport_stopListening;
1033    interface.Accept = &socketTransport_accept;
1034    interface.IsOpen = &socketTransport_isOpen;
1035    interface.Close = &socketTransport_close;
1036    interface.ReadPacket = &socketTransport_readPacket;
1037    interface.WritePacket = &socketTransport_writePacket;
1038    interface.GetLastError = &socketTransport_getLastError;
1039    if (version >= JDWPTRANSPORT_VERSION_1_1) {
1040        interface.SetTransportConfiguration = &socketTransport_setConfiguration;
1041    }
1042    *env = &single_env;
1043
1044    /* initialized TLS */
1045    tlsIndex = dbgsysTlsAlloc();
1046    return JNI_OK;
1047}
1048