/* * Handle a packet. Returns "false" if we encounter a connection-fatal error. */ static bool handlePacket(JdwpState* state) { JdwpNetState* netState = state->netState; const unsigned char* buf = netState->inputBuffer; JdwpReqHeader hdr; u4 length, id; u1 flags, cmdSet, cmd; //u2 error; bool reply; int dataLen; cmd = cmdSet = 0; // shut up gcc /*dumpPacket(netState->inputBuffer);*/ length = read4BE(&buf); id = read4BE(&buf); flags = read1(&buf); if ((flags & kJDWPFlagReply) != 0) { reply = true; /*error =*/ read2BE(&buf); } else { reply = false; cmdSet = read1(&buf); cmd = read1(&buf); } assert((int) length <= netState->inputCount); dataLen = length - (buf - netState->inputBuffer); if (!reply) { ExpandBuf* pReply = expandBufAlloc(); hdr.length = length; hdr.id = id; hdr.cmdSet = cmdSet; hdr.cmd = cmd; dvmJdwpProcessRequest(state, &hdr, buf, dataLen, pReply); if (expandBufGetLength(pReply) > 0) { ssize_t cc = netState->writePacket(pReply); if (cc != (ssize_t) expandBufGetLength(pReply)) { ALOGE("Failed sending reply to debugger: %s", strerror(errno)); expandBufFree(pReply); return false; } } else { ALOGW("No reply created for set=%d cmd=%d", cmdSet, cmd); } expandBufFree(pReply); } else { ALOGV("reply?!"); assert(false); } ALOGV("----------"); consumeBytes(netState, length); return true; }
/* * Handle incoming data. If we have a full packet in the buffer, process it. */ static bool handleIncoming(Peer* pWritePeer, Peer* pReadPeer) { if (haveFullPacket(pReadPeer)) { if (pReadPeer->awaitingHandshake) { printf("Handshake [%c]: %.14s\n", pReadPeer->label[0], pReadPeer->inputBuffer); if (write(pWritePeer->sock, pReadPeer->inputBuffer, kMagicHandshakeLen) != kMagicHandshakeLen) { fprintf(stderr, "+++ [%c] handshake write failed\n", pReadPeer->label[0]); goto fail; } consumeBytes(pReadPeer, kMagicHandshakeLen); pReadPeer->awaitingHandshake = false; } else { if (!handlePacket(pWritePeer, pReadPeer)) goto fail; } } else { /*printf("*** %c not full yet\n", pReadPeer->label[0]);*/ } return true; fail: return false; }
/* * Handle a packet. Returns "false" if we encounter a connection-fatal error. */ static bool handlePacket(Peer* pDst, Peer* pSrc) { const unsigned char* buf = pSrc->inputBuffer; u4 length; u1 flags; int cc; length = get4BE(buf+0); flags = get1(buf+9); assert((int) length <= pSrc->inputCount); dumpPacket(buf, pSrc->label, pDst->label); cc = write(pDst->sock, buf, length); if (cc != (int) length) { fprintf(stderr, "Failed sending packet: %s\n", strerror(errno)); return false; } /*printf("*** wrote %d bytes from %c to %c\n", cc, pSrc->label[0], pDst->label[0]);*/ consumeBytes(pSrc, length); return true; }
/** * @brief Reads Null from `Reader`. * @param reader The JSONReader. * @return Null. */ static Null *readNull(JSONReader *reader) { consumeBytes(reader, "null"); Null *null = $$(Null, null); return retain(null); }
/** * @brief Reads a Boole from `reader`. * @param reader The JSONReader. * @return The Boole. */ static _Bool *readBoole(JSONReader *reader) { Boole *boolean = NULL; switch (*reader->b) { case 't': consumeBytes(reader, "true"); boolean = $$(Boole, True); break; case 'f': consumeBytes(reader, "false"); boolean = $$(Boole, False); break; default: assert(false); } return retain(boolean); }
/* * Process incoming data. If no data is available, this will block until * some arrives. * * If we get a full packet, handle it. * * To take some of the mystery out of life, we want to reject incoming * connections if we already have a debugger attached. If we don't, the * debugger will just mysteriously hang until it times out. We could just * close the listen socket, but there's a good chance we won't be able to * bind to the same port again, which would confuse utilities. * * Returns "false" on error (indicating that the connection has been severed), * "true" if things are still okay. */ static bool processIncoming(JdwpState* state) { JdwpNetState* netState = state->netState; int readCount; assert(netState->clientSock >= 0); if (!haveFullPacket(netState)) { /* read some more, looping until we have data */ errno = 0; while (1) { int selCount; fd_set readfds; int maxfd; int fd; maxfd = netState->listenSock; if (netState->clientSock > maxfd) maxfd = netState->clientSock; if (netState->wakePipe[0] > maxfd) maxfd = netState->wakePipe[0]; if (maxfd < 0) { ALOGV("+++ all fds are closed"); return false; } FD_ZERO(&readfds); /* configure fds; note these may get zapped by another thread */ fd = netState->listenSock; if (fd >= 0) FD_SET(fd, &readfds); fd = netState->clientSock; if (fd >= 0) FD_SET(fd, &readfds); fd = netState->wakePipe[0]; if (fd >= 0) { FD_SET(fd, &readfds); } else { ALOGI("NOTE: entering select w/o wakepipe"); } /* * Select blocks until it sees activity on the file descriptors. * Closing the local file descriptor does not count as activity, * so we can't rely on that to wake us up (it works for read() * and accept(), but not select()). * * We can do one of three things: (1) send a signal and catch * EINTR, (2) open an additional fd ("wakePipe") and write to * it when it's time to exit, or (3) time out periodically and * re-issue the select. We're currently using #2, as it's more * reliable than #1 and generally better than #3. Wastes two fds. */ selCount = select(maxfd+1, &readfds, NULL, NULL, NULL); if (selCount < 0) { if (errno == EINTR) continue; ALOGE("select failed: %s", strerror(errno)); goto fail; } if (netState->wakePipe[0] >= 0 && FD_ISSET(netState->wakePipe[0], &readfds)) { if (netState->listenSock >= 0) ALOGE("Exit wake set, but not exiting?"); else ALOGD("Got wake-up signal, bailing out of select"); goto fail; } if (netState->listenSock >= 0 && FD_ISSET(netState->listenSock, &readfds)) { ALOGI("Ignoring second debugger -- accepting and dropping"); union { struct sockaddr_in addrInet; struct sockaddr addrPlain; } addr; socklen_t addrlen; int tmpSock; tmpSock = accept(netState->listenSock, &addr.addrPlain, &addrlen); if (tmpSock < 0) ALOGI("Weird -- accept failed"); else close(tmpSock); } if (netState->clientSock >= 0 && FD_ISSET(netState->clientSock, &readfds)) { readCount = read(netState->clientSock, netState->inputBuffer + netState->inputCount, sizeof(netState->inputBuffer) - netState->inputCount); if (readCount < 0) { /* read failed */ if (errno != EINTR) goto fail; ALOGD("+++ EINTR hit"); return true; } else if (readCount == 0) { /* EOF hit -- far end went away */ ALOGD("+++ peer disconnected"); goto fail; } else break; } } netState->inputCount += readCount; if (!haveFullPacket(netState)) return true; /* still not there yet */ } /* * Special-case the initial handshake. For some bizarre reason we're * expected to emulate bad tty settings by echoing the request back * exactly as it was sent. Note the handshake is always initiated by * the debugger, no matter who connects to whom. * * Other than this one case, the protocol [claims to be] stateless. */ if (netState->awaitingHandshake) { int cc; if (memcmp(netState->inputBuffer, kMagicHandshake, kMagicHandshakeLen) != 0) { ALOGE("ERROR: bad handshake '%.14s'", netState->inputBuffer); goto fail; } errno = 0; cc = write(netState->clientSock, netState->inputBuffer, kMagicHandshakeLen); if (cc != kMagicHandshakeLen) { ALOGE("Failed writing handshake bytes: %s (%d of %d)", strerror(errno), cc, (int) kMagicHandshakeLen); goto fail; } consumeBytes(netState, kMagicHandshakeLen); netState->awaitingHandshake = false; ALOGV("+++ handshake complete"); return true; } /* * Handle this packet. */ return handlePacket(state); fail: closeConnection(state); return false; }
/* * Handle a packet. Returns "false" if we encounter a connection-fatal error. */ static bool handlePacket(JdwpState* state) { JdwpNetState* netState = state->netState; const unsigned char* buf = netState->inputBuffer; JdwpReqHeader hdr; u4 length, id; u1 flags, cmdSet, cmd; u2 error; bool reply; int dataLen; cmd = cmdSet = 0; // shut up gcc /*dumpPacket(netState->inputBuffer);*/ length = read4BE(&buf); id = read4BE(&buf); flags = read1(&buf); if ((flags & kJDWPFlagReply) != 0) { reply = true; error = read2BE(&buf); } else { reply = false; cmdSet = read1(&buf); cmd = read1(&buf); } assert((int) length <= netState->inputCount); dataLen = length - (buf - netState->inputBuffer); if (!reply) { ExpandBuf* pReply = expandBufAlloc(); hdr.length = length; hdr.id = id; hdr.cmdSet = cmdSet; hdr.cmd = cmd; dvmJdwpProcessRequest(state, &hdr, buf, dataLen, pReply); if (expandBufGetLength(pReply) > 0) { int cc; /* * TODO: we currently assume the write() will complete in one * go, which may not be safe for a network socket. We may need * to mutex this against sendRequest(). */ cc = write(netState->clientSock, expandBufGetBuffer(pReply), expandBufGetLength(pReply)); if (cc != (int) expandBufGetLength(pReply)) { LOGE("Failed sending reply to debugger: %s\n", strerror(errno)); expandBufFree(pReply); return false; } } else { LOGW("No reply created for set=%d cmd=%d\n", cmdSet, cmd); } expandBufFree(pReply); } else { LOGV("reply?!\n"); assert(false); } LOGV("----------\n"); consumeBytes(netState, length); return true; }