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