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