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