Home | History | Annotate | Download | only in jdwpspy
      1 /*
      2  * Copyright 2006 The Android Open Source Project
      3  *
      4  * JDWP spy.  This is a rearranged version of the JDWP code from the VM.
      5  */
      6 #include "Common.h"
      7 #include "jdwp/JdwpConstants.h"
      8 
      9 #include <stdlib.h>
     10 #include <unistd.h>
     11 #include <stdio.h>
     12 #include <string.h>
     13 #include <sys/types.h>
     14 #include <sys/socket.h>
     15 #include <netinet/in.h>
     16 #include <netinet/tcp.h>
     17 #include <arpa/inet.h>
     18 #include <netdb.h>
     19 #include <time.h>
     20 #include <errno.h>
     21 #include <assert.h>
     22 
     23 #define kInputBufferSize    (256*1024)
     24 
     25 #define kMagicHandshakeLen  14      /* "JDWP-Handshake" */
     26 #define kJDWPHeaderLen      11
     27 #define kJDWPFlagReply      0x80
     28 
     29 
     30 /*
     31  * Information about the remote end.
     32  */
     33 typedef struct Peer {
     34     char    label[2];           /* 'D' or 'V' */
     35 
     36     int     sock;
     37     unsigned char   inputBuffer[kInputBufferSize];
     38     int     inputCount;
     39 
     40     bool    awaitingHandshake;  /* waiting for "JDWP-Handshake" */
     41 } Peer;
     42 
     43 
     44 /*
     45  * Network state.
     46  */
     47 typedef struct NetState {
     48     /* listen here for connection from debugger */
     49     int     listenSock;
     50 
     51     /* connect here to contact VM */
     52     struct in_addr vmAddr;
     53     short   vmPort;
     54 
     55     Peer    dbg;
     56     Peer    vm;
     57 } NetState;
     58 
     59 /*
     60  * Function names.
     61  */
     62 typedef struct {
     63     u1  cmdSet;
     64     u1  cmd;
     65     const char* descr;
     66 } JdwpHandlerMap;
     67 
     68 /*
     69  * Map commands to names.
     70  *
     71  * Command sets 0-63 are incoming requests, 64-127 are outbound requests,
     72  * and 128-256 are vendor-defined.
     73  */
     74 static const JdwpHandlerMap gHandlerMap[] = {
     75     /* VirtualMachine command set (1) */
     76     { 1,    1,  "VirtualMachine.Version" },
     77     { 1,    2,  "VirtualMachine.ClassesBySignature" },
     78     { 1,    3,  "VirtualMachine.AllClasses" },
     79     { 1,    4,  "VirtualMachine.AllThreads" },
     80     { 1,    5,  "VirtualMachine.TopLevelThreadGroups" },
     81     { 1,    6,  "VirtualMachine.Dispose" },
     82     { 1,    7,  "VirtualMachine.IDSizes" },
     83     { 1,    8,  "VirtualMachine.Suspend" },
     84     { 1,    9,  "VirtualMachine.Resume" },
     85     { 1,    10, "VirtualMachine.Exit" },
     86     { 1,    11, "VirtualMachine.CreateString" },
     87     { 1,    12, "VirtualMachine.Capabilities" },
     88     { 1,    13, "VirtualMachine.ClassPaths" },
     89     { 1,    14, "VirtualMachine.DisposeObjects" },
     90     { 1,    15, "VirtualMachine.HoldEvents" },
     91     { 1,    16, "VirtualMachine.ReleaseEvents" },
     92     { 1,    17, "VirtualMachine.CapabilitiesNew" },
     93     { 1,    18, "VirtualMachine.RedefineClasses" },
     94     { 1,    19, "VirtualMachine.SetDefaultStratum" },
     95     { 1,    20, "VirtualMachine.AllClassesWithGeneric"},
     96     { 1,    21, "VirtualMachine.InstanceCounts"},
     97 
     98     /* ReferenceType command set (2) */
     99     { 2,    1,  "ReferenceType.Signature" },
    100     { 2,    2,  "ReferenceType.ClassLoader" },
    101     { 2,    3,  "ReferenceType.Modifiers" },
    102     { 2,    4,  "ReferenceType.Fields" },
    103     { 2,    5,  "ReferenceType.Methods" },
    104     { 2,    6,  "ReferenceType.GetValues" },
    105     { 2,    7,  "ReferenceType.SourceFile" },
    106     { 2,    8,  "ReferenceType.NestedTypes" },
    107     { 2,    9,  "ReferenceType.Status" },
    108     { 2,    10, "ReferenceType.Interfaces" },
    109     { 2,    11, "ReferenceType.ClassObject" },
    110     { 2,    12, "ReferenceType.SourceDebugExtension" },
    111     { 2,    13, "ReferenceType.SignatureWithGeneric" },
    112     { 2,    14, "ReferenceType.FieldsWithGeneric" },
    113     { 2,    15, "ReferenceType.MethodsWithGeneric" },
    114     { 2,    16, "ReferenceType.Instances" },
    115     { 2,    17, "ReferenceType.ClassFileVersion" },
    116     { 2,    18, "ReferenceType.ConstantPool" },
    117 
    118     /* ClassType command set (3) */
    119     { 3,    1,  "ClassType.Superclass" },
    120     { 3,    2,  "ClassType.SetValues" },
    121     { 3,    3,  "ClassType.InvokeMethod" },
    122     { 3,    4,  "ClassType.NewInstance" },
    123 
    124     /* ArrayType command set (4) */
    125     { 4,    1,  "ArrayType.NewInstance" },
    126 
    127     /* InterfaceType command set (5) */
    128 
    129     /* Method command set (6) */
    130     { 6,    1,  "Method.LineTable" },
    131     { 6,    2,  "Method.VariableTable" },
    132     { 6,    3,  "Method.Bytecodes" },
    133     { 6,    4,  "Method.IsObsolete" },
    134     { 6,    5,  "Method.VariableTableWithGeneric" },
    135 
    136     /* Field command set (8) */
    137 
    138     /* ObjectReference command set (9) */
    139     { 9,    1,  "ObjectReference.ReferenceType" },
    140     { 9,    2,  "ObjectReference.GetValues" },
    141     { 9,    3,  "ObjectReference.SetValues" },
    142     { 9,    4,  "ObjectReference.UNUSED" },
    143     { 9,    5,  "ObjectReference.MonitorInfo" },
    144     { 9,    6,  "ObjectReference.InvokeMethod" },
    145     { 9,    7,  "ObjectReference.DisableCollection" },
    146     { 9,    8,  "ObjectReference.EnableCollection" },
    147     { 9,    9,  "ObjectReference.IsCollected" },
    148     { 9,    10, "ObjectReference.ReferringObjects" },
    149 
    150     /* StringReference command set (10) */
    151     { 10,   1,  "StringReference.Value" },
    152 
    153     /* ThreadReference command set (11) */
    154     { 11,   1,  "ThreadReference.Name" },
    155     { 11,   2,  "ThreadReference.Suspend" },
    156     { 11,   3,  "ThreadReference.Resume" },
    157     { 11,   4,  "ThreadReference.Status" },
    158     { 11,   5,  "ThreadReference.ThreadGroup" },
    159     { 11,   6,  "ThreadReference.Frames" },
    160     { 11,   7,  "ThreadReference.FrameCount" },
    161     { 11,   8,  "ThreadReference.OwnedMonitors" },
    162     { 11,   9,  "ThreadReference.CurrentContendedMonitor" },
    163     { 11,   10, "ThreadReference.Stop" },
    164     { 11,   11, "ThreadReference.Interrupt" },
    165     { 11,   12, "ThreadReference.SuspendCount" },
    166     { 11,   13, "ThreadReference.OwnedMonitorsStackDepthInfo" },
    167     { 11,   14, "ThreadReference.ForceEarlyReturn" },
    168 
    169     /* ThreadGroupReference command set (12) */
    170     { 12,   1,  "ThreadGroupReference.Name" },
    171     { 12,   2,  "ThreadGroupReference.Parent" },
    172     { 12,   3,  "ThreadGroupReference.Children" },
    173 
    174     /* ArrayReference command set (13) */
    175     { 13,   1,  "ArrayReference.Length" },
    176     { 13,   2,  "ArrayReference.GetValues" },
    177     { 13,   3,  "ArrayReference.SetValues" },
    178 
    179     /* ClassLoaderReference command set (14) */
    180     { 14,   1,  "ArrayReference.VisibleClasses" },
    181 
    182     /* EventRequest command set (15) */
    183     { 15,   1,  "EventRequest.Set" },
    184     { 15,   2,  "EventRequest.Clear" },
    185     { 15,   3,  "EventRequest.ClearAllBreakpoints" },
    186 
    187     /* StackFrame command set (16) */
    188     { 16,   1,  "StackFrame.GetValues" },
    189     { 16,   2,  "StackFrame.SetValues" },
    190     { 16,   3,  "StackFrame.ThisObject" },
    191     { 16,   4,  "StackFrame.PopFrames" },
    192 
    193     /* ClassObjectReference command set (17) */
    194     { 17,   1,  "ClassObjectReference.ReflectedType" },
    195 
    196     /* Event command set (64) */
    197     { 64,  100, "Event.Composite" },
    198 
    199     /* DDMS */
    200     { 199,  1,  "DDMS.Chunk" },
    201 };
    202 
    203 /*
    204  * Look up a command's name.
    205  */
    206 static const char* getCommandName(int cmdSet, int cmd)
    207 {
    208     for (int i = 0; i < (int) NELEM(gHandlerMap); i++) {
    209         if (gHandlerMap[i].cmdSet == cmdSet &&
    210             gHandlerMap[i].cmd == cmd)
    211         {
    212             return gHandlerMap[i].descr;
    213         }
    214     }
    215 
    216     return "?UNKNOWN?";
    217 }
    218 
    219 
    220 void jdwpNetFree(NetState* netState);       /* fwd */
    221 
    222 /*
    223  * Allocate state structure and bind to the listen port.
    224  *
    225  * Returns 0 on success.
    226  */
    227 NetState* jdwpNetStartup(unsigned short listenPort, const char* connectHost,
    228     unsigned short connectPort)
    229 {
    230     NetState* netState = (NetState*) malloc(sizeof(*netState));
    231     memset(netState, 0, sizeof(*netState));
    232     netState->listenSock = -1;
    233     netState->dbg.sock = netState->vm.sock = -1;
    234 
    235     strcpy(netState->dbg.label, "D");
    236     strcpy(netState->vm.label, "V");
    237 
    238     /*
    239      * Set up a socket to listen for connections from the debugger.
    240      */
    241 
    242     netState->listenSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
    243     if (netState->listenSock < 0) {
    244         fprintf(stderr, "Socket create failed: %s\n", strerror(errno));
    245         goto fail;
    246     }
    247 
    248     /* allow immediate re-use if we die */
    249     {
    250         int one = 1;
    251         if (setsockopt(netState->listenSock, SOL_SOCKET, SO_REUSEADDR, &one,
    252                 sizeof(one)) < 0)
    253         {
    254             fprintf(stderr, "setsockopt(SO_REUSEADDR) failed: %s\n",
    255                 strerror(errno));
    256             goto fail;
    257         }
    258     }
    259 
    260     struct sockaddr_in addr;
    261     addr.sin_family = AF_INET;
    262     addr.sin_port = htons(listenPort);
    263     addr.sin_addr.s_addr = INADDR_ANY;
    264 
    265     if (bind(netState->listenSock, (struct sockaddr*) &addr, sizeof(addr)) != 0)
    266     {
    267         fprintf(stderr, "attempt to bind to port %u failed: %s\n",
    268             listenPort, strerror(errno));
    269         goto fail;
    270     }
    271 
    272     fprintf(stderr, "+++ bound to port %u\n", listenPort);
    273 
    274     if (listen(netState->listenSock, 5) != 0) {
    275         fprintf(stderr, "Listen failed: %s\n", strerror(errno));
    276         goto fail;
    277     }
    278 
    279     /*
    280      * Do the hostname lookup for the VM.
    281      */
    282     struct hostent* pHost;
    283 
    284     pHost = gethostbyname(connectHost);
    285     if (pHost == NULL) {
    286         fprintf(stderr, "Name lookup of '%s' failed: %s\n",
    287             connectHost, strerror(h_errno));
    288         goto fail;
    289     }
    290 
    291     netState->vmAddr = *((struct in_addr*) pHost->h_addr_list[0]);
    292     netState->vmPort = connectPort;
    293 
    294     fprintf(stderr, "+++ connect host resolved to %s\n",
    295         inet_ntoa(netState->vmAddr));
    296 
    297     return netState;
    298 
    299 fail:
    300     jdwpNetFree(netState);
    301     return NULL;
    302 }
    303 
    304 /*
    305  * Shut down JDWP listener.  Don't free state.
    306  *
    307  * Note that "netState" may be partially initialized if "startup" failed.
    308  */
    309 void jdwpNetShutdown(NetState* netState)
    310 {
    311     int listenSock = netState->listenSock;
    312     int dbgSock = netState->dbg.sock;
    313     int vmSock = netState->vm.sock;
    314 
    315     /* clear these out so it doesn't wake up and try to reuse them */
    316     /* (important when multi-threaded) */
    317     netState->listenSock = netState->dbg.sock = netState->vm.sock = -1;
    318 
    319     if (listenSock >= 0) {
    320         shutdown(listenSock, SHUT_RDWR);
    321         close(listenSock);
    322     }
    323     if (dbgSock >= 0) {
    324         shutdown(dbgSock, SHUT_RDWR);
    325         close(dbgSock);
    326     }
    327     if (vmSock >= 0) {
    328         shutdown(vmSock, SHUT_RDWR);
    329         close(vmSock);
    330     }
    331 }
    332 
    333 /*
    334  * Shut down JDWP listener and free its state.
    335  */
    336 void jdwpNetFree(NetState* netState)
    337 {
    338     if (netState == NULL)
    339         return;
    340 
    341     jdwpNetShutdown(netState);
    342     free(netState);
    343 }
    344 
    345 /*
    346  * Disable the TCP Nagle algorithm, which delays transmission of outbound
    347  * packets until the previous transmissions have been acked.  JDWP does a
    348  * lot of back-and-forth with small packets, so this may help.
    349  */
    350 static int setNoDelay(int fd)
    351 {
    352     int cc, on = 1;
    353 
    354     cc = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on));
    355     assert(cc == 0);
    356     return cc;
    357 }
    358 
    359 /*
    360  * Accept a connection.  This will block waiting for somebody to show up.
    361  */
    362 bool jdwpAcceptConnection(NetState* netState)
    363 {
    364     struct sockaddr_in addr;
    365     socklen_t addrlen;
    366     int sock;
    367 
    368     if (netState->listenSock < 0)
    369         return false;       /* you're not listening! */
    370 
    371     assert(netState->dbg.sock < 0);     /* must not already be talking */
    372 
    373     addrlen = sizeof(addr);
    374     do {
    375         sock = accept(netState->listenSock, (struct sockaddr*) &addr, &addrlen);
    376         if (sock < 0 && errno != EINTR) {
    377             fprintf(stderr, "accept failed: %s\n", strerror(errno));
    378             return false;
    379         }
    380     } while (sock < 0);
    381 
    382     fprintf(stderr, "+++ accepted connection from %s:%u\n",
    383         inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
    384 
    385     netState->dbg.sock = sock;
    386     netState->dbg.awaitingHandshake = true;
    387     netState->dbg.inputCount = 0;
    388 
    389     setNoDelay(sock);
    390 
    391     return true;
    392 }
    393 
    394 /*
    395  * Close the connections to the debugger and VM.
    396  *
    397  * Reset the state so we're ready to receive a new connection.
    398  */
    399 void jdwpCloseConnection(NetState* netState)
    400 {
    401     if (netState->dbg.sock >= 0) {
    402         fprintf(stderr, "+++ closing connection to debugger\n");
    403         close(netState->dbg.sock);
    404         netState->dbg.sock = -1;
    405     }
    406     if (netState->vm.sock >= 0) {
    407         fprintf(stderr, "+++ closing connection to vm\n");
    408         close(netState->vm.sock);
    409         netState->vm.sock = -1;
    410     }
    411 }
    412 
    413 /*
    414  * Figure out if we have a full packet in the buffer.
    415  */
    416 static bool haveFullPacket(Peer* pPeer)
    417 {
    418     long length;
    419 
    420     if (pPeer->awaitingHandshake)
    421         return (pPeer->inputCount >= kMagicHandshakeLen);
    422 
    423     if (pPeer->inputCount < 4)
    424         return false;
    425 
    426     length = get4BE(pPeer->inputBuffer);
    427     return (pPeer->inputCount >= length);
    428 }
    429 
    430 /*
    431  * Consume bytes from the buffer.
    432  *
    433  * This would be more efficient with a circular buffer.  However, we're
    434  * usually only going to find one packet, which is trivial to handle.
    435  */
    436 static void consumeBytes(Peer* pPeer, int count)
    437 {
    438     assert(count > 0);
    439     assert(count <= pPeer->inputCount);
    440 
    441     if (count == pPeer->inputCount) {
    442         pPeer->inputCount = 0;
    443         return;
    444     }
    445 
    446     memmove(pPeer->inputBuffer, pPeer->inputBuffer + count,
    447         pPeer->inputCount - count);
    448     pPeer->inputCount -= count;
    449 }
    450 
    451 /*
    452  * Get the current time.
    453  */
    454 static void getCurrentTime(int* pMin, int* pSec)
    455 {
    456     time_t now;
    457     struct tm* ptm;
    458 
    459     now = time(NULL);
    460     ptm = localtime(&now);
    461     *pMin = ptm->tm_min;
    462     *pSec = ptm->tm_sec;
    463 }
    464 
    465 /*
    466  * Dump the contents of a packet to stdout.
    467  */
    468 static void dumpPacket(const unsigned char* packetBuf, const char* srcName,
    469     const char* dstName)
    470 {
    471     const unsigned char* buf = packetBuf;
    472     char prefix[3];
    473     u4 length, id;
    474     u1 flags, cmdSet=0, cmd=0;
    475     JdwpError error = ERR_NONE;
    476     bool reply;
    477     int dataLen;
    478 
    479     length = get4BE(buf+0);
    480     id = get4BE(buf+4);
    481     flags = get1(buf+8);
    482     if ((flags & kJDWPFlagReply) != 0) {
    483         reply = true;
    484         error = static_cast<JdwpError>(get2BE(buf+9));
    485     } else {
    486         reply = false;
    487         cmdSet = get1(buf+9);
    488         cmd = get1(buf+10);
    489     }
    490 
    491     buf += kJDWPHeaderLen;
    492     dataLen = length - (buf - packetBuf);
    493 
    494     if (!reply) {
    495         prefix[0] = srcName[0];
    496         prefix[1] = '>';
    497     } else {
    498         prefix[0] = dstName[0];
    499         prefix[1] = '<';
    500     }
    501     prefix[2] = '\0';
    502 
    503     int min, sec;
    504     getCurrentTime(&min, &sec);
    505 
    506     if (!reply) {
    507         printf("%s REQUEST dataLen=%-5u id=0x%08x flags=0x%02x cmd=%d/%d [%02d:%02d]\n",
    508             prefix, dataLen, id, flags, cmdSet, cmd, min, sec);
    509         printf("%s   --> %s\n", prefix, getCommandName(cmdSet, cmd));
    510     } else {
    511         printf("%s REPLY   dataLen=%-5u id=0x%08x flags=0x%02x err=%d (%s) [%02d:%02d]\n",
    512             prefix, dataLen, id, flags, error, dvmJdwpErrorStr(error), min,sec);
    513     }
    514     if (dataLen > 0)
    515         printHexDump2(buf, dataLen, prefix);
    516     printf("%s ----------\n", prefix);
    517 }
    518 
    519 /*
    520  * Handle a packet.  Returns "false" if we encounter a connection-fatal error.
    521  */
    522 static bool handlePacket(Peer* pDst, Peer* pSrc)
    523 {
    524     const unsigned char* buf = pSrc->inputBuffer;
    525     u4 length;
    526     u1 flags;
    527     int cc;
    528 
    529     length = get4BE(buf+0);
    530     flags = get1(buf+9);
    531 
    532     assert((int) length <= pSrc->inputCount);
    533 
    534     dumpPacket(buf, pSrc->label, pDst->label);
    535 
    536     cc = write(pDst->sock, buf, length);
    537     if (cc != (int) length) {
    538         fprintf(stderr, "Failed sending packet: %s\n", strerror(errno));
    539         return false;
    540     }
    541     /*printf("*** wrote %d bytes from %c to %c\n",
    542         cc, pSrc->label[0], pDst->label[0]);*/
    543 
    544     consumeBytes(pSrc, length);
    545     return true;
    546 }
    547 
    548 /*
    549  * Handle incoming data.  If we have a full packet in the buffer, process it.
    550  */
    551 static bool handleIncoming(Peer* pWritePeer, Peer* pReadPeer)
    552 {
    553     if (haveFullPacket(pReadPeer)) {
    554         if (pReadPeer->awaitingHandshake) {
    555             printf("Handshake [%c]: %.14s\n",
    556                 pReadPeer->label[0], pReadPeer->inputBuffer);
    557             if (write(pWritePeer->sock, pReadPeer->inputBuffer,
    558                     kMagicHandshakeLen) != kMagicHandshakeLen)
    559             {
    560                 fprintf(stderr,
    561                     "+++ [%c] handshake write failed\n", pReadPeer->label[0]);
    562                 goto fail;
    563             }
    564             consumeBytes(pReadPeer, kMagicHandshakeLen);
    565             pReadPeer->awaitingHandshake = false;
    566         } else {
    567             if (!handlePacket(pWritePeer, pReadPeer))
    568                 goto fail;
    569         }
    570     } else {
    571         /*printf("*** %c not full yet\n", pReadPeer->label[0]);*/
    572     }
    573 
    574     return true;
    575 
    576 fail:
    577     return false;
    578 }
    579 
    580 /*
    581  * Process incoming data.  If no data is available, this will block until
    582  * some arrives.
    583  *
    584  * Returns "false" on error (indicating that the connection has been severed).
    585  */
    586 bool jdwpProcessIncoming(NetState* netState)
    587 {
    588     int cc;
    589 
    590     assert(netState->dbg.sock >= 0);
    591     assert(netState->vm.sock >= 0);
    592 
    593     while (!haveFullPacket(&netState->dbg) && !haveFullPacket(&netState->vm)) {
    594         /* read some more */
    595         int highFd;
    596         fd_set readfds;
    597 
    598         highFd = (netState->dbg.sock > netState->vm.sock) ?
    599             netState->dbg.sock+1 : netState->vm.sock+1;
    600         FD_ZERO(&readfds);
    601         FD_SET(netState->dbg.sock, &readfds);
    602         FD_SET(netState->vm.sock, &readfds);
    603 
    604         errno = 0;
    605         cc = select(highFd, &readfds, NULL, NULL, NULL);
    606         if (cc < 0) {
    607             if (errno == EINTR) {
    608                 fprintf(stderr, "+++ EINTR on select\n");
    609                 continue;
    610             }
    611             fprintf(stderr, "+++ select failed: %s\n", strerror(errno));
    612             goto fail;
    613         }
    614 
    615         if (FD_ISSET(netState->dbg.sock, &readfds)) {
    616             cc = read(netState->dbg.sock,
    617                 netState->dbg.inputBuffer + netState->dbg.inputCount,
    618                 sizeof(netState->dbg.inputBuffer) - netState->dbg.inputCount);
    619             if (cc < 0) {
    620                 if (errno == EINTR) {
    621                     fprintf(stderr, "+++ EINTR on read\n");
    622                     continue;
    623                 }
    624                 fprintf(stderr, "+++ dbg read failed: %s\n", strerror(errno));
    625                 goto fail;
    626             }
    627             if (cc == 0) {
    628                 if (sizeof(netState->dbg.inputBuffer) ==
    629                         netState->dbg.inputCount)
    630                     fprintf(stderr, "+++ debugger sent huge message\n");
    631                 else
    632                     fprintf(stderr, "+++ debugger disconnected\n");
    633                 goto fail;
    634             }
    635 
    636             /*printf("*** %d bytes from dbg\n", cc);*/
    637             netState->dbg.inputCount += cc;
    638         }
    639 
    640         if (FD_ISSET(netState->vm.sock, &readfds)) {
    641             cc = read(netState->vm.sock,
    642                 netState->vm.inputBuffer + netState->vm.inputCount,
    643                 sizeof(netState->vm.inputBuffer) - netState->vm.inputCount);
    644             if (cc < 0) {
    645                 if (errno == EINTR) {
    646                     fprintf(stderr, "+++ EINTR on read\n");
    647                     continue;
    648                 }
    649                 fprintf(stderr, "+++ vm read failed: %s\n", strerror(errno));
    650                 goto fail;
    651             }
    652             if (cc == 0) {
    653                 if (sizeof(netState->vm.inputBuffer) ==
    654                         netState->vm.inputCount)
    655                     fprintf(stderr, "+++ vm sent huge message\n");
    656                 else
    657                     fprintf(stderr, "+++ vm disconnected\n");
    658                 goto fail;
    659             }
    660 
    661             /*printf("*** %d bytes from vm\n", cc);*/
    662             netState->vm.inputCount += cc;
    663         }
    664     }
    665 
    666     if (!handleIncoming(&netState->dbg, &netState->vm))
    667         goto fail;
    668     if (!handleIncoming(&netState->vm, &netState->dbg))
    669         goto fail;
    670 
    671     return true;
    672 
    673 fail:
    674     jdwpCloseConnection(netState);
    675     return false;
    676 }
    677 
    678 /*
    679  * Connect to the VM.
    680  */
    681 bool jdwpConnectToVm(NetState* netState)
    682 {
    683     struct sockaddr_in addr;
    684     int sock = -1;
    685 
    686     sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
    687     if (sock < 0) {
    688         fprintf(stderr, "Socket create failed: %s\n", strerror(errno));
    689         goto fail;
    690     }
    691 
    692     addr.sin_family = AF_INET;
    693     addr.sin_addr = netState->vmAddr;
    694     addr.sin_port = htons(netState->vmPort);
    695     if (connect(sock, (struct sockaddr*) &addr, sizeof(addr)) != 0) {
    696         fprintf(stderr, "Connection to %s:%u failed: %s\n",
    697             inet_ntoa(addr.sin_addr), ntohs(addr.sin_port), strerror(errno));
    698         goto fail;
    699     }
    700     fprintf(stderr, "+++ connected to VM %s:%u\n",
    701         inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
    702 
    703     netState->vm.sock = sock;
    704     netState->vm.awaitingHandshake = true;
    705     netState->vm.inputCount = 0;
    706 
    707     setNoDelay(netState->vm.sock);
    708     return true;
    709 
    710 fail:
    711     if (sock >= 0)
    712         close(sock);
    713     return false;
    714 }
    715 
    716 /*
    717  * Establish network connections and start things running.
    718  *
    719  * We wait for a new connection from the debugger.  When one arrives we
    720  * open a connection to the VM.  If one side or the other goes away, we
    721  * drop both ends and go back to listening.
    722  */
    723 int run(const char* connectHost, int connectPort, int listenPort)
    724 {
    725     NetState* state;
    726 
    727     state = jdwpNetStartup(listenPort, connectHost, connectPort);
    728     if (state == NULL)
    729         return -1;
    730 
    731     while (true) {
    732         if (!jdwpAcceptConnection(state))
    733             break;
    734 
    735         if (jdwpConnectToVm(state)) {
    736             while (true) {
    737                 if (!jdwpProcessIncoming(state))
    738                     break;
    739             }
    740         }
    741 
    742         jdwpCloseConnection(state);
    743     }
    744 
    745     jdwpNetFree(state);
    746 
    747     return 0;
    748 }
    749