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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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