• 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     int i;
209 
210     for (i = 0; i < (int) NELEM(gHandlerMap); i++) {
211         if (gHandlerMap[i].cmdSet == cmdSet &&
212             gHandlerMap[i].cmd == cmd)
213         {
214             return gHandlerMap[i].descr;
215         }
216     }
217 
218     return "?UNKNOWN?";
219 }
220 
221 
222 void jdwpNetFree(NetState* netState);       /* fwd */
223 
224 /*
225  * Allocate state structure and bind to the listen port.
226  *
227  * Returns 0 on success.
228  */
jdwpNetStartup(unsigned short listenPort,const char * connectHost,unsigned short connectPort)229 NetState* jdwpNetStartup(unsigned short listenPort, const char* connectHost,
230     unsigned short connectPort)
231 {
232     NetState* netState;
233     int one = 1;
234 
235     netState = (NetState*) malloc(sizeof(*netState));
236     memset(netState, 0, sizeof(*netState));
237     netState->listenSock = -1;
238     netState->dbg.sock = netState->vm.sock = -1;
239 
240     strcpy(netState->dbg.label, "D");
241     strcpy(netState->vm.label, "V");
242 
243     /*
244      * Set up a socket to listen for connections from the debugger.
245      */
246 
247     netState->listenSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
248     if (netState->listenSock < 0) {
249         fprintf(stderr, "Socket create failed: %s\n", strerror(errno));
250         goto fail;
251     }
252 
253     /* allow immediate re-use if we die */
254     if (setsockopt(netState->listenSock, SOL_SOCKET, SO_REUSEADDR, &one,
255             sizeof(one)) < 0)
256     {
257         fprintf(stderr, "setsockopt(SO_REUSEADDR) failed: %s\n",
258             strerror(errno));
259         goto fail;
260     }
261 
262     struct sockaddr_in addr;
263     addr.sin_family = AF_INET;
264     addr.sin_port = htons(listenPort);
265     addr.sin_addr.s_addr = INADDR_ANY;
266 
267     if (bind(netState->listenSock, (struct sockaddr*) &addr, sizeof(addr)) != 0)
268     {
269         fprintf(stderr, "attempt to bind to port %u failed: %s\n",
270             listenPort, strerror(errno));
271         goto fail;
272     }
273 
274     fprintf(stderr, "+++ bound to port %u\n", listenPort);
275 
276     if (listen(netState->listenSock, 5) != 0) {
277         fprintf(stderr, "Listen failed: %s\n", strerror(errno));
278         goto fail;
279     }
280 
281     /*
282      * Do the hostname lookup for the VM.
283      */
284     struct hostent* pHost;
285 
286     pHost = gethostbyname(connectHost);
287     if (pHost == NULL) {
288         fprintf(stderr, "Name lookup of '%s' failed: %s\n",
289             connectHost, strerror(h_errno));
290         goto fail;
291     }
292 
293     netState->vmAddr = *((struct in_addr*) pHost->h_addr_list[0]);
294     netState->vmPort = connectPort;
295 
296     fprintf(stderr, "+++ connect host resolved to %s\n",
297         inet_ntoa(netState->vmAddr));
298 
299     return netState;
300 
301 fail:
302     jdwpNetFree(netState);
303     return NULL;
304 }
305 
306 /*
307  * Shut down JDWP listener.  Don't free state.
308  *
309  * Note that "netState" may be partially initialized if "startup" failed.
310  */
jdwpNetShutdown(NetState * netState)311 void jdwpNetShutdown(NetState* netState)
312 {
313     int listenSock = netState->listenSock;
314     int dbgSock = netState->dbg.sock;
315     int vmSock = netState->vm.sock;
316 
317     /* clear these out so it doesn't wake up and try to reuse them */
318     /* (important when multi-threaded) */
319     netState->listenSock = netState->dbg.sock = netState->vm.sock = -1;
320 
321     if (listenSock >= 0) {
322         shutdown(listenSock, SHUT_RDWR);
323         close(listenSock);
324     }
325     if (dbgSock >= 0) {
326         shutdown(dbgSock, SHUT_RDWR);
327         close(dbgSock);
328     }
329     if (vmSock >= 0) {
330         shutdown(vmSock, SHUT_RDWR);
331         close(vmSock);
332     }
333 }
334 
335 /*
336  * Shut down JDWP listener and free its state.
337  */
jdwpNetFree(NetState * netState)338 void jdwpNetFree(NetState* netState)
339 {
340     if (netState == NULL)
341         return;
342 
343     jdwpNetShutdown(netState);
344     free(netState);
345 }
346 
347 /*
348  * Disable the TCP Nagle algorithm, which delays transmission of outbound
349  * packets until the previous transmissions have been acked.  JDWP does a
350  * lot of back-and-forth with small packets, so this may help.
351  */
setNoDelay(int fd)352 static int setNoDelay(int fd)
353 {
354     int cc, on = 1;
355 
356     cc = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on));
357     assert(cc == 0);
358     return cc;
359 }
360 
361 /*
362  * Accept a connection.  This will block waiting for somebody to show up.
363  */
jdwpAcceptConnection(NetState * netState)364 bool jdwpAcceptConnection(NetState* netState)
365 {
366     struct sockaddr_in addr;
367     socklen_t addrlen;
368     int sock;
369 
370     if (netState->listenSock < 0)
371         return false;       /* you're not listening! */
372 
373     assert(netState->dbg.sock < 0);     /* must not already be talking */
374 
375     addrlen = sizeof(addr);
376     do {
377         sock = accept(netState->listenSock, (struct sockaddr*) &addr, &addrlen);
378         if (sock < 0 && errno != EINTR) {
379             fprintf(stderr, "accept failed: %s\n", strerror(errno));
380             return false;
381         }
382     } while (sock < 0);
383 
384     fprintf(stderr, "+++ accepted connection from %s:%u\n",
385         inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
386 
387     netState->dbg.sock = sock;
388     netState->dbg.awaitingHandshake = true;
389     netState->dbg.inputCount = 0;
390 
391     setNoDelay(sock);
392 
393     return true;
394 }
395 
396 /*
397  * Close the connections to the debugger and VM.
398  *
399  * Reset the state so we're ready to receive a new connection.
400  */
jdwpCloseConnection(NetState * netState)401 void jdwpCloseConnection(NetState* netState)
402 {
403     if (netState->dbg.sock >= 0) {
404         fprintf(stderr, "+++ closing connection to debugger\n");
405         close(netState->dbg.sock);
406         netState->dbg.sock = -1;
407     }
408     if (netState->vm.sock >= 0) {
409         fprintf(stderr, "+++ closing connection to vm\n");
410         close(netState->vm.sock);
411         netState->vm.sock = -1;
412     }
413 }
414 
415 /*
416  * Figure out if we have a full packet in the buffer.
417  */
haveFullPacket(Peer * pPeer)418 static bool haveFullPacket(Peer* pPeer)
419 {
420     long length;
421 
422     if (pPeer->awaitingHandshake)
423         return (pPeer->inputCount >= kMagicHandshakeLen);
424 
425     if (pPeer->inputCount < 4)
426         return false;
427 
428     length = get4BE(pPeer->inputBuffer);
429     return (pPeer->inputCount >= length);
430 }
431 
432 /*
433  * Consume bytes from the buffer.
434  *
435  * This would be more efficient with a circular buffer.  However, we're
436  * usually only going to find one packet, which is trivial to handle.
437  */
consumeBytes(Peer * pPeer,int count)438 static void consumeBytes(Peer* pPeer, int count)
439 {
440     assert(count > 0);
441     assert(count <= pPeer->inputCount);
442 
443     if (count == pPeer->inputCount) {
444         pPeer->inputCount = 0;
445         return;
446     }
447 
448     memmove(pPeer->inputBuffer, pPeer->inputBuffer + count,
449         pPeer->inputCount - count);
450     pPeer->inputCount -= count;
451 }
452 
453 /*
454  * Get the current time.
455  */
getCurrentTime(int * pMin,int * pSec)456 static void getCurrentTime(int* pMin, int* pSec)
457 {
458     time_t now;
459     struct tm* ptm;
460 
461     now = time(NULL);
462     ptm = localtime(&now);
463     *pMin = ptm->tm_min;
464     *pSec = ptm->tm_sec;
465 }
466 
467 /*
468  * Dump the contents of a packet to stdout.
469  */
dumpPacket(const unsigned char * packetBuf,const char * srcName,const char * dstName)470 static void dumpPacket(const unsigned char* packetBuf, const char* srcName,
471     const char* dstName)
472 {
473     const unsigned char* buf = packetBuf;
474     char prefix[3];
475     u4 length, id;
476     u1 flags, cmdSet=0, cmd=0;
477     u2 error=0;
478     bool reply;
479     int dataLen;
480 
481     length = get4BE(buf+0);
482     id = get4BE(buf+4);
483     flags = get1(buf+8);
484     if ((flags & kJDWPFlagReply) != 0) {
485         reply = true;
486         error = get2BE(buf+9);
487     } else {
488         reply = false;
489         cmdSet = get1(buf+9);
490         cmd = get1(buf+10);
491     }
492 
493     buf += kJDWPHeaderLen;
494     dataLen = length - (buf - packetBuf);
495 
496     if (!reply) {
497         prefix[0] = srcName[0];
498         prefix[1] = '>';
499     } else {
500         prefix[0] = dstName[0];
501         prefix[1] = '<';
502     }
503     prefix[2] = '\0';
504 
505     int min, sec;
506     getCurrentTime(&min, &sec);
507 
508     if (!reply) {
509         printf("%s REQUEST dataLen=%-5u id=0x%08x flags=0x%02x cmd=%d/%d [%02d:%02d]\n",
510             prefix, dataLen, id, flags, cmdSet, cmd, min, sec);
511         printf("%s   --> %s\n", prefix, getCommandName(cmdSet, cmd));
512     } else {
513         printf("%s REPLY   dataLen=%-5u id=0x%08x flags=0x%02x err=%d (%s) [%02d:%02d]\n",
514             prefix, dataLen, id, flags, error, dvmJdwpErrorStr(error), min,sec);
515     }
516     if (dataLen > 0)
517         printHexDump2(buf, dataLen, prefix);
518     printf("%s ----------\n", prefix);
519 }
520 
521 /*
522  * Handle a packet.  Returns "false" if we encounter a connection-fatal error.
523  */
handlePacket(Peer * pDst,Peer * pSrc)524 static bool handlePacket(Peer* pDst, Peer* pSrc)
525 {
526     const unsigned char* buf = pSrc->inputBuffer;
527     u4 length;
528     u1 flags;
529     int cc;
530 
531     length = get4BE(buf+0);
532     flags = get1(buf+9);
533 
534     assert((int) length <= pSrc->inputCount);
535 
536     dumpPacket(buf, pSrc->label, pDst->label);
537 
538     cc = write(pDst->sock, buf, length);
539     if (cc != (int) length) {
540         fprintf(stderr, "Failed sending packet: %s\n", strerror(errno));
541         return false;
542     }
543     /*printf("*** wrote %d bytes from %c to %c\n",
544         cc, pSrc->label[0], pDst->label[0]);*/
545 
546     consumeBytes(pSrc, length);
547     return true;
548 }
549 
550 /*
551  * Handle incoming data.  If we have a full packet in the buffer, process it.
552  */
handleIncoming(Peer * pWritePeer,Peer * pReadPeer)553 static bool handleIncoming(Peer* pWritePeer, Peer* pReadPeer)
554 {
555     if (haveFullPacket(pReadPeer)) {
556         if (pReadPeer->awaitingHandshake) {
557             printf("Handshake [%c]: %.14s\n",
558                 pReadPeer->label[0], pReadPeer->inputBuffer);
559             if (write(pWritePeer->sock, pReadPeer->inputBuffer,
560                     kMagicHandshakeLen) != kMagicHandshakeLen)
561             {
562                 fprintf(stderr,
563                     "+++ [%c] handshake write failed\n", pReadPeer->label[0]);
564                 goto fail;
565             }
566             consumeBytes(pReadPeer, kMagicHandshakeLen);
567             pReadPeer->awaitingHandshake = false;
568         } else {
569             if (!handlePacket(pWritePeer, pReadPeer))
570                 goto fail;
571         }
572     } else {
573         /*printf("*** %c not full yet\n", pReadPeer->label[0]);*/
574     }
575 
576     return true;
577 
578 fail:
579     return false;
580 }
581 
582 /*
583  * Process incoming data.  If no data is available, this will block until
584  * some arrives.
585  *
586  * Returns "false" on error (indicating that the connection has been severed).
587  */
jdwpProcessIncoming(NetState * netState)588 bool jdwpProcessIncoming(NetState* netState)
589 {
590     int cc;
591 
592     assert(netState->dbg.sock >= 0);
593     assert(netState->vm.sock >= 0);
594 
595     while (!haveFullPacket(&netState->dbg) && !haveFullPacket(&netState->vm)) {
596         /* read some more */
597         int highFd;
598         fd_set readfds;
599 
600         highFd = (netState->dbg.sock > netState->vm.sock) ?
601             netState->dbg.sock+1 : netState->vm.sock+1;
602         FD_ZERO(&readfds);
603         FD_SET(netState->dbg.sock, &readfds);
604         FD_SET(netState->vm.sock, &readfds);
605 
606         errno = 0;
607         cc = select(highFd, &readfds, NULL, NULL, NULL);
608         if (cc < 0) {
609             if (errno == EINTR) {
610                 fprintf(stderr, "+++ EINTR on select\n");
611                 continue;
612             }
613             fprintf(stderr, "+++ select failed: %s\n", strerror(errno));
614             goto fail;
615         }
616 
617         if (FD_ISSET(netState->dbg.sock, &readfds)) {
618             cc = read(netState->dbg.sock,
619                 netState->dbg.inputBuffer + netState->dbg.inputCount,
620                 sizeof(netState->dbg.inputBuffer) - netState->dbg.inputCount);
621             if (cc < 0) {
622                 if (errno == EINTR) {
623                     fprintf(stderr, "+++ EINTR on read\n");
624                     continue;
625                 }
626                 fprintf(stderr, "+++ dbg read failed: %s\n", strerror(errno));
627                 goto fail;
628             }
629             if (cc == 0) {
630                 if (sizeof(netState->dbg.inputBuffer) ==
631                         netState->dbg.inputCount)
632                     fprintf(stderr, "+++ debugger sent huge message\n");
633                 else
634                     fprintf(stderr, "+++ debugger disconnected\n");
635                 goto fail;
636             }
637 
638             /*printf("*** %d bytes from dbg\n", cc);*/
639             netState->dbg.inputCount += cc;
640         }
641 
642         if (FD_ISSET(netState->vm.sock, &readfds)) {
643             cc = read(netState->vm.sock,
644                 netState->vm.inputBuffer + netState->vm.inputCount,
645                 sizeof(netState->vm.inputBuffer) - netState->vm.inputCount);
646             if (cc < 0) {
647                 if (errno == EINTR) {
648                     fprintf(stderr, "+++ EINTR on read\n");
649                     continue;
650                 }
651                 fprintf(stderr, "+++ vm read failed: %s\n", strerror(errno));
652                 goto fail;
653             }
654             if (cc == 0) {
655                 if (sizeof(netState->vm.inputBuffer) ==
656                         netState->vm.inputCount)
657                     fprintf(stderr, "+++ vm sent huge message\n");
658                 else
659                     fprintf(stderr, "+++ vm disconnected\n");
660                 goto fail;
661             }
662 
663             /*printf("*** %d bytes from vm\n", cc);*/
664             netState->vm.inputCount += cc;
665         }
666     }
667 
668     if (!handleIncoming(&netState->dbg, &netState->vm))
669         goto fail;
670     if (!handleIncoming(&netState->vm, &netState->dbg))
671         goto fail;
672 
673     return true;
674 
675 fail:
676     jdwpCloseConnection(netState);
677     return false;
678 }
679 
680 /*
681  * Connect to the VM.
682  */
jdwpConnectToVm(NetState * netState)683 bool jdwpConnectToVm(NetState* netState)
684 {
685     struct sockaddr_in addr;
686     int sock = -1;
687 
688     sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
689     if (sock < 0) {
690         fprintf(stderr, "Socket create failed: %s\n", strerror(errno));
691         goto fail;
692     }
693 
694     addr.sin_family = AF_INET;
695     addr.sin_addr = netState->vmAddr;
696     addr.sin_port = htons(netState->vmPort);
697     if (connect(sock, (struct sockaddr*) &addr, sizeof(addr)) != 0) {
698         fprintf(stderr, "Connection to %s:%u failed: %s\n",
699             inet_ntoa(addr.sin_addr), ntohs(addr.sin_port), strerror(errno));
700         goto fail;
701     }
702     fprintf(stderr, "+++ connected to VM %s:%u\n",
703         inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
704 
705     netState->vm.sock = sock;
706     netState->vm.awaitingHandshake = true;
707     netState->vm.inputCount = 0;
708 
709     setNoDelay(netState->vm.sock);
710     return true;
711 
712 fail:
713     if (sock >= 0)
714         close(sock);
715     return false;
716 }
717 
718 /*
719  * Establish network connections and start things running.
720  *
721  * We wait for a new connection from the debugger.  When one arrives we
722  * open a connection to the VM.  If one side or the other goes away, we
723  * drop both ends and go back to listening.
724  */
run(const char * connectHost,int connectPort,int listenPort)725 int run(const char* connectHost, int connectPort, int listenPort)
726 {
727     NetState* state;
728 
729     state = jdwpNetStartup(listenPort, connectHost, connectPort);
730     if (state == NULL)
731         return -1;
732 
733     while (true) {
734         if (!jdwpAcceptConnection(state))
735             break;
736 
737         if (jdwpConnectToVm(state)) {
738             while (true) {
739                 if (!jdwpProcessIncoming(state))
740                     break;
741             }
742         }
743 
744         jdwpCloseConnection(state);
745     }
746 
747     jdwpNetFree(state);
748 
749     return 0;
750 }
751 
752