• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  */
getCommandName(int cmdSet,int cmd)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  */
jdwpNetStartup(uint16_t listenPort,const char * connectHost,uint16_t connectPort)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  */
jdwpNetShutdown(NetState * netState)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  */
jdwpNetFree(NetState * netState)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  */
setNoDelay(int fd)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  */
jdwpAcceptConnection(NetState * netState)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  */
jdwpCloseConnection(NetState * netState)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  */
haveFullPacket(Peer * pPeer)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  */
consumeBytes(Peer * pPeer,int count)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  */
getCurrentTime(int * pMin,int * pSec)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  */
dumpPacket(const unsigned char * packetBuf,const char * srcName,const char * dstName)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  */
handlePacket(Peer * pDst,Peer * pSrc)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  */
handleIncoming(Peer * pWritePeer,Peer * pReadPeer)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  */
jdwpProcessIncoming(NetState * netState)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  */
jdwpConnectToVm(NetState * netState)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  */
run(const char * connectHost,int connectPort,int listenPort)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