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