Remove the separate JdwpTransport objects.
Structs containing nothing but function pointers? What are we? C programmers?
Change-Id: I4fbc9dc0d8fc10557afa020b27cda85c939965c3
diff --git a/src/jdwp/jdwp.h b/src/jdwp/jdwp.h
index f2dba0b..436525c 100644
--- a/src/jdwp/jdwp.h
+++ b/src/jdwp/jdwp.h
@@ -95,7 +95,6 @@
struct JdwpEvent;
struct JdwpNetStateBase;
-struct JdwpTransport;
struct ModBasket;
struct Request;
@@ -307,7 +306,6 @@
private:
bool run;
- const JdwpTransport* transport_;
public: // TODO: fix privacy
JdwpNetStateBase* netState;
diff --git a/src/jdwp/jdwp_adb.cc b/src/jdwp/jdwp_adb.cc
index 3ce2064..9652f60 100644
--- a/src/jdwp/jdwp_adb.cc
+++ b/src/jdwp/jdwp_adb.cc
@@ -52,66 +52,77 @@
namespace JDWP {
-struct JdwpNetState : public JdwpNetStateBase {
- int controlSock;
- bool shuttingDown;
- int wakeFds[2];
+struct JdwpAdbState : public JdwpNetStateBase {
+ public:
+ JdwpAdbState(JdwpState* state) : JdwpNetStateBase(state) {
+ control_sock_ = -1;
+ shutting_down_ = false;
- socklen_t controlAddrLen;
+ control_addr_.controlAddrUn.sun_family = AF_UNIX;
+ control_addr_len_ = sizeof(control_addr_.controlAddrUn.sun_family) + kJdwpControlNameLen;
+ memcpy(control_addr_.controlAddrUn.sun_path, kJdwpControlName, kJdwpControlNameLen);
+ }
+
+ ~JdwpAdbState() {
+ if (clientSock != -1) {
+ shutdown(clientSock, SHUT_RDWR);
+ close(clientSock);
+ }
+ if (control_sock_ != -1) {
+ shutdown(control_sock_, SHUT_RDWR);
+ close(control_sock_);
+ }
+ }
+
+ virtual bool Accept();
+
+ virtual bool Establish(const JdwpOptions*) {
+ return false;
+ }
+
+ virtual void Shutdown() {
+ shutting_down_ = true;
+
+ int control_sock = this->control_sock_;
+ int clientSock = this->clientSock;
+
+ /* clear these out so it doesn't wake up and try to reuse them */
+ this->control_sock_ = this->clientSock = -1;
+
+ if (clientSock != -1) {
+ shutdown(clientSock, SHUT_RDWR);
+ }
+
+ if (control_sock != -1) {
+ shutdown(control_sock, SHUT_RDWR);
+ }
+
+ WakePipe();
+ }
+
+ virtual bool ProcessIncoming();
+
+ private:
+ int ReceiveClientFd();
+
+ int control_sock_;
+ bool shutting_down_;
+
+ socklen_t control_addr_len_;
union {
- sockaddr_un controlAddrUn;
- sockaddr controlAddrPlain;
- } controlAddr;
-
- JdwpNetState() {
- controlSock = -1;
- shuttingDown = false;
- wakeFds[0] = -1;
- wakeFds[1] = -1;
-
- controlAddr.controlAddrUn.sun_family = AF_UNIX;
- controlAddrLen = sizeof(controlAddr.controlAddrUn.sun_family) + kJdwpControlNameLen;
- memcpy(controlAddr.controlAddrUn.sun_path, kJdwpControlName, kJdwpControlNameLen);
- }
+ sockaddr_un controlAddrUn;
+ sockaddr controlAddrPlain;
+ } control_addr_;
};
-static JdwpNetState* GetNetState(JdwpState* state) {
- return reinterpret_cast<JdwpNetState*>(state->netState);
-}
-
-static void adbStateFree(JdwpNetState* netState) {
- if (netState == NULL) {
- return;
- }
-
- if (netState->clientSock >= 0) {
- shutdown(netState->clientSock, SHUT_RDWR);
- close(netState->clientSock);
- }
- if (netState->controlSock >= 0) {
- shutdown(netState->controlSock, SHUT_RDWR);
- close(netState->controlSock);
- }
- if (netState->wakeFds[0] >= 0) {
- close(netState->wakeFds[0]);
- netState->wakeFds[0] = -1;
- }
- if (netState->wakeFds[1] >= 0) {
- close(netState->wakeFds[1]);
- netState->wakeFds[1] = -1;
- }
-
- delete netState;
-}
-
/*
* Do initial prep work, e.g. binding to ports and opening files. This
* runs in the main thread, before the JDWP thread starts, so it shouldn't
* do anything that might block forever.
*/
-static bool startup(JdwpState* state, const JdwpOptions*) {
+bool InitAdbTransport(JdwpState* state, const JdwpOptions*) {
VLOG(jdwp) << "ADB transport startup";
- state->netState = new JdwpNetState;
+ state->netState = new JdwpAdbState(state);
return (state->netState != NULL);
}
@@ -120,21 +131,20 @@
* directly with a debugger or DDMS.
*
* Returns the file descriptor on success. On failure, returns -1 and
- * closes netState->controlSock.
+ * closes netState->control_sock_.
*/
-static int receiveClientFd(JdwpNetState* netState) {
- msghdr msg;
- cmsghdr* cmsg;
- iovec iov;
- char dummy = '!';
+int JdwpAdbState::ReceiveClientFd() {
+ char dummy = '!';
union {
cmsghdr cm;
char buffer[CMSG_SPACE(sizeof(int))];
} cm_un;
- int ret;
+ iovec iov;
iov.iov_base = &dummy;
iov.iov_len = 1;
+
+ msghdr msg;
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_iov = &iov;
@@ -143,22 +153,20 @@
msg.msg_control = cm_un.buffer;
msg.msg_controllen = sizeof(cm_un.buffer);
- cmsg = CMSG_FIRSTHDR(&msg);
+ cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
cmsg->cmsg_len = msg.msg_controllen;
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
((int*)(void*)CMSG_DATA(cmsg))[0] = -1;
- do {
- ret = recvmsg(netState->controlSock, &msg, 0);
- } while (ret < 0 && errno == EINTR);
+ int rc = TEMP_FAILURE_RETRY(recvmsg(control_sock_, &msg, 0));
- if (ret <= 0) {
- if (ret < 0) {
- PLOG(WARNING) << "Receiving file descriptor from ADB failed (socket " << netState->controlSock << ")";
+ if (rc <= 0) {
+ if (rc == -1) {
+ PLOG(WARNING) << "Receiving file descriptor from ADB failed (socket " << control_sock_ << ")";
}
- close(netState->controlSock);
- netState->controlSock = -1;
+ close(control_sock_);
+ control_sock_ = -1;
return -1;
}
@@ -172,30 +180,28 @@
* This needs to un-block and return "false" if the VM is shutting down. It
* should return "true" when it successfully accepts a connection.
*/
-static bool acceptConnection(JdwpState* state) {
- JdwpNetState* netState = GetNetState(state);
+bool JdwpAdbState::Accept() {
int retryCount = 0;
/* first, ensure that we get a connection to the ADB daemon */
retry:
- if (netState->shuttingDown) {
+ if (shutting_down_) {
return false;
}
- if (netState->controlSock < 0) {
+ if (control_sock_ == -1) {
int sleep_ms = 500;
const int sleep_max_ms = 2*1000;
char buff[5];
- netState->controlSock = socket(PF_UNIX, SOCK_STREAM, 0);
- if (netState->controlSock < 0) {
+ control_sock_ = socket(PF_UNIX, SOCK_STREAM, 0);
+ if (control_sock_ < 0) {
PLOG(ERROR) << "Could not create ADB control socket";
return false;
}
- if (pipe(netState->wakeFds) < 0) {
- PLOG(ERROR) << "pipe failed";
+ if (!MakePipe()) {
return false;
}
@@ -216,11 +222,11 @@
* up after a few minutes in case somebody ships an app with
* the debuggable flag set.
*/
- int ret = connect(netState->controlSock, &netState->controlAddr.controlAddrPlain, netState->controlAddrLen);
+ int ret = connect(control_sock_, &control_addr_.controlAddrPlain, control_addr_len_);
if (!ret) {
#ifdef HAVE_ANDROID_OS
- if (!socket_peer_is_trusted(netState->controlSock)) {
- if (shutdown(netState->controlSock, SHUT_RDWR)) {
+ if (!socket_peer_is_trusted(control_sock_)) {
+ if (shutdown(control_sock_, SHUT_RDWR)) {
PLOG(ERROR) << "trouble shutting down socket";
}
return false;
@@ -228,7 +234,7 @@
#endif
/* now try to send our pid to the ADB daemon */
- ret = TEMP_FAILURE_RETRY(send(netState->controlSock, buff, 4, 0));
+ ret = TEMP_FAILURE_RETRY(send(control_sock_, buff, 4, 0));
if (ret >= 0) {
VLOG(jdwp) << StringPrintf("PID sent as '%.*s' to ADB", 4, buff);
break;
@@ -247,7 +253,7 @@
if (sleep_ms > sleep_max_ms) {
sleep_ms = sleep_max_ms;
}
- if (netState->shuttingDown) {
+ if (shutting_down_) {
return false;
}
}
@@ -255,78 +261,25 @@
VLOG(jdwp) << "trying to receive file descriptor from ADB";
/* now we can receive a client file descriptor */
- netState->clientSock = receiveClientFd(netState);
- if (netState->shuttingDown) {
+ clientSock = ReceiveClientFd();
+ if (shutting_down_) {
return false; // suppress logs and additional activity
}
- if (netState->clientSock < 0) {
+ if (clientSock == -1) {
if (++retryCount > 5) {
LOG(ERROR) << "adb connection max retries exceeded";
return false;
}
goto retry;
} else {
- VLOG(jdwp) << "received file descriptor " << netState->clientSock << " from ADB";
- netState->SetAwaitingHandshake(true);
- netState->inputCount = 0;
+ VLOG(jdwp) << "received file descriptor " << clientSock << " from ADB";
+ SetAwaitingHandshake(true);
+ input_count_ = 0;
return true;
}
}
/*
- * Connect out to a debugger (for server=n). Not required.
- */
-static bool establishConnection(JdwpState*, const JdwpOptions*) {
- return false;
-}
-
-/*
- * Close all network stuff, including the socket we use to listen for
- * new connections.
- *
- * May be called from a non-JDWP thread, e.g. when the VM is shutting down.
- */
-static void adbStateShutdown(JdwpNetState* netState) {
- int controlSock;
- int clientSock;
-
- if (netState == NULL) {
- return;
- }
-
- netState->shuttingDown = true;
-
- clientSock = netState->clientSock;
- if (clientSock >= 0) {
- shutdown(clientSock, SHUT_RDWR);
- netState->clientSock = -1;
- }
-
- controlSock = netState->controlSock;
- if (controlSock >= 0) {
- shutdown(controlSock, SHUT_RDWR);
- netState->controlSock = -1;
- }
-
- if (netState->wakeFds[1] >= 0) {
- VLOG(jdwp) << "+++ writing to wakePipe";
- TEMP_FAILURE_RETRY(write(netState->wakeFds[1], "", 1));
- }
-}
-
-static void netShutdown(JdwpState* state) {
- adbStateShutdown(GetNetState(state));
-}
-
-/*
- * Free up anything we put in state->netState. This is called after
- * "netShutdown", after the JDWP thread has stopped.
- */
-static void netFree(JdwpState* state) {
- adbStateFree(GetNetState(state));
-}
-
-/*
* Process incoming data. If no data is available, this will block until
* some arrives.
*
@@ -341,13 +294,12 @@
* Returns "false" on error (indicating that the connection has been severed),
* "true" if things are still okay.
*/
-static bool processIncoming(JdwpState* state) {
- JdwpNetState* netState = GetNetState(state);
+bool JdwpAdbState::ProcessIncoming() {
int readCount;
- CHECK_GE(netState->clientSock, 0);
+ CHECK(clientSock != -1);
- if (!netState->HaveFullPacket()) {
+ if (!HaveFullPacket()) {
/* read some more, looping until we have data */
errno = 0;
while (1) {
@@ -359,21 +311,21 @@
FD_ZERO(&readfds);
/* configure fds; note these may get zapped by another thread */
- fd = netState->controlSock;
+ fd = control_sock_;
if (fd >= 0) {
FD_SET(fd, &readfds);
if (maxfd < fd) {
maxfd = fd;
}
}
- fd = netState->clientSock;
+ fd = clientSock;
if (fd >= 0) {
FD_SET(fd, &readfds);
if (maxfd < fd) {
maxfd = fd;
}
}
- fd = netState->wakeFds[0];
+ fd = wake_pipe_[0];
if (fd >= 0) {
FD_SET(fd, &readfds);
if (maxfd < fd) {
@@ -395,7 +347,7 @@
* 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
+ * EINTR, (2) open an additional fd ("wake pipe") 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.
@@ -409,26 +361,25 @@
goto fail;
}
- if (netState->wakeFds[0] >= 0 && FD_ISSET(netState->wakeFds[0], &readfds)) {
+ if (wake_pipe_[0] >= 0 && FD_ISSET(wake_pipe_[0], &readfds)) {
LOG(DEBUG) << "Got wake-up signal, bailing out of select";
goto fail;
}
- if (netState->controlSock >= 0 && FD_ISSET(netState->controlSock, &readfds)) {
- int sock = receiveClientFd(netState);
+ if (control_sock_ >= 0 && FD_ISSET(control_sock_, &readfds)) {
+ int sock = ReceiveClientFd();
if (sock >= 0) {
LOG(INFO) << "Ignoring second debugger -- accepting and dropping";
close(sock);
} else {
- CHECK_LT(netState->controlSock, 0);
+ CHECK(control_sock_ == -1);
/*
* Remote side most likely went away, so our next read
- * on netState->clientSock will fail and throw us out
- * of the loop.
+ * on clientSock will fail and throw us out of the loop.
*/
}
}
- if (netState->clientSock >= 0 && FD_ISSET(netState->clientSock, &readfds)) {
- readCount = read(netState->clientSock, netState->inputBuffer + netState->inputCount, sizeof(netState->inputBuffer) - netState->inputCount);
+ if (clientSock >= 0 && FD_ISSET(clientSock, &readfds)) {
+ readCount = read(clientSock, input_buffer_ + input_count_, sizeof(input_buffer_) - input_count_);
if (readCount < 0) {
/* read failed */
if (errno != EINTR) {
@@ -446,8 +397,8 @@
}
}
- netState->inputCount += readCount;
- if (!netState->HaveFullPacket()) {
+ input_count_ += readCount;
+ if (!HaveFullPacket()) {
return true; /* still not there yet */
}
}
@@ -460,23 +411,21 @@
*
* Other than this one case, the protocol [claims to be] stateless.
*/
- if (netState->IsAwaitingHandshake()) {
- int cc;
-
- if (memcmp(netState->inputBuffer, kMagicHandshake, kMagicHandshakeLen) != 0) {
- LOG(ERROR) << StringPrintf("ERROR: bad handshake '%.14s'", netState->inputBuffer);
+ if (IsAwaitingHandshake()) {
+ if (memcmp(input_buffer_, kMagicHandshake, kMagicHandshakeLen) != 0) {
+ LOG(ERROR) << StringPrintf("ERROR: bad handshake '%.14s'", input_buffer_);
goto fail;
}
errno = 0;
- cc = TEMP_FAILURE_RETRY(write(netState->clientSock, netState->inputBuffer, kMagicHandshakeLen));
+ int cc = TEMP_FAILURE_RETRY(write(clientSock, input_buffer_, kMagicHandshakeLen));
if (cc != kMagicHandshakeLen) {
PLOG(ERROR) << "Failed writing handshake bytes (" << cc << " of " << kMagicHandshakeLen << ")";
goto fail;
}
- netState->ConsumeBytes(kMagicHandshakeLen);
- netState->SetAwaitingHandshake(false);
+ ConsumeBytes(kMagicHandshakeLen);
+ SetAwaitingHandshake(false);
VLOG(jdwp) << "+++ handshake complete";
return true;
}
@@ -484,32 +433,13 @@
/*
* Handle this packet.
*/
- return state->HandlePacket();
+ return state_->HandlePacket();
fail:
- netState->Close();
+ Close();
return false;
}
-/*
- * Our functions.
- */
-static const JdwpTransport adbTransport = {
- startup,
- acceptConnection,
- establishConnection,
- netShutdown,
- netFree,
- processIncoming,
-};
-
-/*
- * Return our set.
- */
-const JdwpTransport* AndroidAdbTransport() {
- return &adbTransport;
-}
-
} // namespace JDWP
} // namespace art
diff --git a/src/jdwp/jdwp_main.cc b/src/jdwp/jdwp_main.cc
index e23d80d..df74988 100644
--- a/src/jdwp/jdwp_main.cc
+++ b/src/jdwp/jdwp_main.cc
@@ -35,34 +35,64 @@
/*
* JdwpNetStateBase class implementation
*/
-JdwpNetStateBase::JdwpNetStateBase() : socket_lock_("JdwpNetStateBase lock") {
+JdwpNetStateBase::JdwpNetStateBase(JdwpState* state)
+ : state_(state), socket_lock_("JdwpNetStateBase lock") {
clientSock = -1;
- inputCount = 0;
+ wake_pipe_[0] = -1;
+ wake_pipe_[1] = -1;
+ input_count_ = 0;
awaiting_handshake_ = false;
}
+JdwpNetStateBase::~JdwpNetStateBase() {
+ if (wake_pipe_[0] != -1) {
+ close(wake_pipe_[0]);
+ wake_pipe_[0] = -1;
+ }
+ if (wake_pipe_[1] != -1) {
+ close(wake_pipe_[1]);
+ wake_pipe_[1] = -1;
+ }
+}
+
+bool JdwpNetStateBase::MakePipe() {
+ if (pipe(wake_pipe_) == -1) {
+ PLOG(ERROR) << "pipe failed";
+ return false;
+ }
+ return true;
+}
+
+void JdwpNetStateBase::WakePipe() {
+ // If we might be sitting in select, kick us loose.
+ if (wake_pipe_[1] != -1) {
+ VLOG(jdwp) << "+++ writing to wake pipe";
+ TEMP_FAILURE_RETRY(write(wake_pipe_[1], "", 1));
+ }
+}
+
void JdwpNetStateBase::ConsumeBytes(size_t count) {
CHECK_GT(count, 0U);
- CHECK_LE(count, inputCount);
+ CHECK_LE(count, input_count_);
- if (count == inputCount) {
- inputCount = 0;
+ if (count == input_count_) {
+ input_count_ = 0;
return;
}
- memmove(inputBuffer, inputBuffer + count, inputCount - count);
- inputCount -= count;
+ memmove(input_buffer_, input_buffer_ + count, input_count_ - count);
+ input_count_ -= count;
}
bool JdwpNetStateBase::HaveFullPacket() {
if (awaiting_handshake_) {
- return (inputCount >= kMagicHandshakeLen);
+ return (input_count_ >= kMagicHandshakeLen);
}
- if (inputCount < 4) {
+ if (input_count_ < 4) {
return false;
}
- uint32_t length = Get4BE(inputBuffer);
- return (inputCount >= length);
+ uint32_t length = Get4BE(input_buffer_);
+ return (input_count_ >= length);
}
bool JdwpNetStateBase::IsAwaitingHandshake() {
@@ -177,7 +207,6 @@
debug_thread_started_(false),
debug_thread_id_(0),
run(false),
- transport_(NULL),
netState(NULL),
attach_lock_("JDWP attach lock", kJdwpAttachLock),
attach_cond_("JDWP attach condition variable", attach_lock_),
@@ -208,23 +237,17 @@
UniquePtr<JdwpState> state(new JdwpState(options));
switch (options->transport) {
case kJdwpTransportSocket:
- // LOGD("prepping for JDWP over TCP");
- state->transport_ = SocketTransport();
+ InitSocketTransport(state.get(), options);
break;
#ifdef HAVE_ANDROID_OS
case kJdwpTransportAndroidAdb:
- // LOGD("prepping for JDWP over ADB");
- state->transport_ = AndroidAdbTransport();
+ InitAdbTransport(state.get(), options);
break;
#endif
default:
LOG(FATAL) << "Unknown transport: " << options->transport;
}
- if (!(*state->transport_->startup)(state.get(), options)) {
- return NULL;
- }
-
/*
* Grab a mutex or two before starting the thread. This ensures they
* won't signal the cond var before we're waiting.
@@ -320,7 +343,7 @@
* Tell the JDWP thread to shut down. Frees "state".
*/
JdwpState::~JdwpState() {
- if (transport_ != NULL) {
+ if (netState != NULL) {
if (IsConnected()) {
PostVMDeath();
}
@@ -329,7 +352,7 @@
* Close down the network to inspire the thread to halt.
*/
VLOG(jdwp) << "JDWP shutting down net...";
- (*transport_->shutdown)(this);
+ netState->Shutdown();
if (debug_thread_started_) {
run = false;
@@ -340,7 +363,7 @@
}
VLOG(jdwp) << "JDWP freeing netstate...";
- (*transport_->free)(this);
+ delete netState;
netState = NULL;
}
CHECK(netState == NULL);
@@ -358,7 +381,7 @@
// Returns "false" if we encounter a connection-fatal error.
bool JdwpState::HandlePacket() {
JdwpNetStateBase* netStateBase = reinterpret_cast<JdwpNetStateBase*>(netState);
- JDWP::Request request(netStateBase->inputBuffer, netStateBase->inputCount);
+ JDWP::Request request(netStateBase->input_buffer_, netStateBase->input_count_);
ExpandBuf* pReply = expandBufAlloc();
ProcessRequest(request, pReply);
@@ -424,7 +447,7 @@
* Block forever, waiting for a connection. To support the
* "timeout=xxx" option we'll need to tweak this.
*/
- if (!(*transport_->accept)(this)) {
+ if (!netState->Accept()) {
break;
}
} else {
@@ -434,7 +457,7 @@
* have a timeout if the handshake reply isn't received in a
* reasonable amount of time.
*/
- if (!(*transport_->establish)(this, options_)) {
+ if (!netState->Establish(options_)) {
/* wake anybody who was waiting for us to succeed */
MutexLock mu(thread_, attach_lock_);
attach_cond_.Broadcast(thread_);
@@ -454,7 +477,7 @@
CHECK_EQ(thread_->GetState(), kWaitingInMainDebuggerLoop);
}
- if (!(*transport_->processIncoming)(this)) {
+ if (!netState->ProcessIncoming()) {
/* blocking read */
break;
}
diff --git a/src/jdwp/jdwp_priv.h b/src/jdwp/jdwp_priv.h
index 1de4c41..c8a7b26 100644
--- a/src/jdwp/jdwp_priv.h
+++ b/src/jdwp/jdwp_priv.h
@@ -45,49 +45,50 @@
struct JdwpState;
-/*
- * Transport functions.
- */
-struct JdwpTransport {
- bool (*startup)(JdwpState* state, const JdwpOptions* options);
- bool (*accept)(JdwpState* state);
- bool (*establish)(JdwpState* state, const JdwpOptions* options);
- void (*shutdown)(JdwpState* state);
- void (*free)(JdwpState* state);
- bool (*processIncoming)(JdwpState* state);
-};
-
-const JdwpTransport* SocketTransport();
-const JdwpTransport* AndroidAdbTransport();
+bool InitSocketTransport(JdwpState*, const JdwpOptions*);
+bool InitAdbTransport(JdwpState*, const JdwpOptions*);
/*
* Base class for the adb and socket JdwpNetState implementations.
*/
class JdwpNetStateBase {
public:
- int clientSock; /* active connection to debugger */
+ JdwpNetStateBase(JdwpState*);
+ virtual ~JdwpNetStateBase();
- enum { kInputBufferSize = 8192 };
-
- unsigned char inputBuffer[kInputBufferSize];
- size_t inputCount;
-
- JdwpNetStateBase();
+ virtual bool Accept() = 0;
+ virtual bool Establish(const JdwpOptions*) = 0;
+ virtual void Shutdown() = 0;
+ virtual bool ProcessIncoming() = 0;
void ConsumeBytes(size_t byte_count);
bool IsConnected();
bool IsAwaitingHandshake();
- void SetAwaitingHandshake(bool new_state);
-
- bool HaveFullPacket();
void Close();
ssize_t WritePacket(ExpandBuf* pReply);
ssize_t WriteBufferedPacket(const iovec* iov, int iov_count);
+ int clientSock; // Active connection to debugger.
+
+ int wake_pipe_[2]; // Used to break out of select.
+
+ uint8_t input_buffer_[8192];
+ size_t input_count_;
+
+ protected:
+ bool HaveFullPacket();
+
+ bool MakePipe();
+ void WakePipe();
+
+ void SetAwaitingHandshake(bool new_state);
+
+ JdwpState* state_;
+
private:
// Used to serialize writes to the socket.
Mutex socket_lock_;
diff --git a/src/jdwp/jdwp_socket.cc b/src/jdwp/jdwp_socket.cc
index 755ded5..08b4859 100644
--- a/src/jdwp/jdwp_socket.cc
+++ b/src/jdwp/jdwp_socket.cc
@@ -42,45 +42,41 @@
*
* We only talk to one debugger at a time.
*/
-struct JdwpNetState : public JdwpNetStateBase {
+struct JdwpSocketState : public JdwpNetStateBase {
uint16_t listenPort;
int listenSock; /* listen for connection from debugger */
- int wakePipe[2]; /* break out of select */
- in_addr remoteAddr;
- uint16_t remotePort;
-
- JdwpNetState() {
+ JdwpSocketState(JdwpState* state) : JdwpNetStateBase(state) {
listenPort = 0;
listenSock = -1;
- wakePipe[0] = -1;
- wakePipe[1] = -1;
}
+
+ virtual bool Accept();
+ virtual bool Establish(const JdwpOptions*);
+ virtual void Shutdown();
+ virtual bool ProcessIncoming();
+
+ private:
+ in_addr remote_addr_;
+ uint16_t remote_port_;
};
-static void socketStateShutdown(JdwpNetState* state);
-static void socketStateFree(JdwpNetState* state);
-
-static JdwpNetState* GetNetState(JdwpState* state) {
- return reinterpret_cast<JdwpNetState*>(state->netState);
-}
-
-static JdwpNetState* netStartup(uint16_t port, bool probe);
+static JdwpSocketState* SocketStartup(JdwpState* state, uint16_t port, bool probe);
/*
* Set up some stuff for transport=dt_socket.
*/
-static bool prepareSocket(JdwpState* state, const JdwpOptions* options) {
+bool InitSocketTransport(JdwpState* state, const JdwpOptions* options) {
uint16_t port = options->port;
if (options->server) {
if (options->port != 0) {
/* try only the specified port */
- state->netState = netStartup(port, false);
+ state->netState = SocketStartup(state, port, false);
} else {
/* scan through a range of ports, binding to the first available */
for (port = kBasePort; port <= kMaxPort; port++) {
- state->netState = netStartup(port, true);
+ state->netState = SocketStartup(state, port, true);
if (state->netState != NULL) {
break;
}
@@ -91,7 +87,7 @@
return false;
}
} else {
- state->netState = netStartup(0, false);
+ state->netState = SocketStartup(state, 0, false);
}
if (options->suspend) {
@@ -115,8 +111,8 @@
*
* Returns 0 on success.
*/
-static JdwpNetState* netStartup(uint16_t port, bool probe) {
- JdwpNetState* netState = new JdwpNetState;
+static JdwpSocketState* SocketStartup(JdwpState* state, uint16_t port, bool probe) {
+ JdwpSocketState* netState = new JdwpSocketState(state);
if (port == 0) {
return netState;
}
@@ -159,80 +155,38 @@
return netState;
fail:
- socketStateShutdown(netState);
- socketStateFree(netState);
+ netState->Shutdown();
+ delete netState;
return NULL;
}
/*
* Shut down JDWP listener. Don't free state.
*
- * Note that "netState" may be partially initialized if "startup" failed.
- *
* This may be called from a non-JDWP thread as part of shutting the
* JDWP thread down.
*
* (This is currently called several times during startup as we probe
* for an open port.)
*/
-static void socketStateShutdown(JdwpNetState* netState) {
- if (netState == NULL) {
- return;
- }
-
- int listenSock = netState->listenSock;
- int clientSock = netState->clientSock;
+void JdwpSocketState::Shutdown() {
+ int listenSock = this->listenSock;
+ int clientSock = this->clientSock;
/* clear these out so it doesn't wake up and try to reuse them */
- netState->listenSock = netState->clientSock = -1;
+ this->listenSock = this->clientSock = -1;
/* "shutdown" dislodges blocking read() and accept() calls */
- if (listenSock >= 0) {
+ if (listenSock != -1) {
shutdown(listenSock, SHUT_RDWR);
close(listenSock);
}
- if (clientSock >= 0) {
+ if (clientSock != -1) {
shutdown(clientSock, SHUT_RDWR);
close(clientSock);
}
- /* if we might be sitting in select, kick us loose */
- if (netState->wakePipe[1] >= 0) {
- VLOG(jdwp) << "+++ writing to wakePipe";
- TEMP_FAILURE_RETRY(write(netState->wakePipe[1], "", 1));
- }
-}
-
-static void netShutdown(JdwpState* state) {
- socketStateShutdown(GetNetState(state));
-}
-
-/*
- * Free JDWP state.
- *
- * Call this after shutting the network down with socketStateShutdown().
- */
-static void socketStateFree(JdwpNetState* netState) {
- if (netState == NULL) {
- return;
- }
- CHECK_EQ(netState->listenSock, -1);
- CHECK_EQ(netState->clientSock, -1);
-
- if (netState->wakePipe[0] >= 0) {
- close(netState->wakePipe[0]);
- netState->wakePipe[0] = -1;
- }
- if (netState->wakePipe[1] >= 0) {
- close(netState->wakePipe[1]);
- netState->wakePipe[1] = -1;
- }
-
- delete netState;
-}
-
-static void netFree(JdwpState* state) {
- socketStateFree(GetNetState(state));
+ WakePipe();
}
/*
@@ -240,7 +194,7 @@
* packets until the previous transmissions have been acked. JDWP does a
* lot of back-and-forth with small packets, so this may help.
*/
-static int setNoDelay(int fd) {
+static int SetNoDelay(int fd) {
int on = 1;
int cc = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on));
CHECK_EQ(cc, 0);
@@ -252,8 +206,7 @@
* If that's not desirable, use checkConnection() to make sure something
* is pending.
*/
-static bool acceptConnection(JdwpState* state) {
- JdwpNetState* netState = GetNetState(state);
+bool JdwpSocketState::Accept() {
union {
sockaddr_in addrInet;
sockaddr addrPlain;
@@ -261,15 +214,15 @@
socklen_t addrlen;
int sock;
- if (netState->listenSock < 0) {
+ if (listenSock < 0) {
return false; /* you're not listening! */
}
- CHECK_LT(netState->clientSock, 0); /* must not already be talking */
+ CHECK(clientSock == -1); /* must not already be talking */
addrlen = sizeof(addr);
do {
- sock = accept(netState->listenSock, &addr.addrPlain, &addrlen);
+ sock = accept(listenSock, &addr.addrPlain, &addrlen);
if (sock < 0 && errno != EINTR) {
// When we call shutdown() on the socket, accept() returns with
// EINVAL. Don't gripe about it.
@@ -284,19 +237,18 @@
}
} while (sock < 0);
- netState->remoteAddr = addr.addrInet.sin_addr;
- netState->remotePort = ntohs(addr.addrInet.sin_port);
- VLOG(jdwp) << "+++ accepted connection from " << inet_ntoa(netState->remoteAddr) << ":" << netState->remotePort;
+ remote_addr_ = addr.addrInet.sin_addr;
+ remote_port_ = ntohs(addr.addrInet.sin_port);
+ VLOG(jdwp) << "+++ accepted connection from " << inet_ntoa(remote_addr_) << ":" << remote_port_;
- netState->clientSock = sock;
- netState->SetAwaitingHandshake(true);
- netState->inputCount = 0;
+ clientSock = sock;
+ SetAwaitingHandshake(true);
+ input_count_ = 0;
VLOG(jdwp) << "Setting TCP_NODELAY on accepted socket";
- setNoDelay(netState->clientSock);
+ SetNoDelay(clientSock);
- if (pipe(netState->wakePipe) < 0) {
- PLOG(ERROR) << "pipe failed";
+ if (!MakePipe()) {
return false;
}
@@ -306,14 +258,13 @@
/*
* Create a connection to a waiting debugger.
*/
-static bool establishConnection(JdwpState* state, const JdwpOptions* options) {
+bool JdwpSocketState::Establish(const JdwpOptions* options) {
union {
sockaddr_in addrInet;
sockaddr addrPlain;
} addr;
hostent* pEntry;
- CHECK(state != NULL && state->netState != NULL);
CHECK(!options->server);
CHECK(!options->host.empty());
CHECK_NE(options->port, 0);
@@ -321,8 +272,6 @@
/*
* Start by resolving the host name.
*/
-//#undef HAVE_GETHOSTBYNAME_R
-//#warning "forcing non-R"
#ifdef HAVE_GETHOSTBYNAME_R
hostent he;
char auxBuf[128];
@@ -352,9 +301,8 @@
/*
* Create a socket.
*/
- JdwpNetState* netState = GetNetState(state);
- netState->clientSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
- if (netState->clientSock < 0) {
+ clientSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (clientSock < 0) {
PLOG(ERROR) << "Unable to create socket";
return false;
}
@@ -362,21 +310,20 @@
/*
* Try to connect.
*/
- if (connect(netState->clientSock, &addr.addrPlain, sizeof(addr)) != 0) {
+ if (connect(clientSock, &addr.addrPlain, sizeof(addr)) != 0) {
PLOG(ERROR) << "Unable to connect to " << inet_ntoa(addr.addrInet.sin_addr) << ":" << ntohs(addr.addrInet.sin_port);
- close(netState->clientSock);
- netState->clientSock = -1;
+ close(clientSock);
+ clientSock = -1;
return false;
}
LOG(INFO) << "Connection established to " << options->host << " (" << inet_ntoa(addr.addrInet.sin_addr) << ":" << ntohs(addr.addrInet.sin_port) << ")";
- netState->SetAwaitingHandshake(true);
- netState->inputCount = 0;
+ SetAwaitingHandshake(true);
+ input_count_ = 0;
- setNoDelay(netState->clientSock);
+ SetNoDelay(clientSock);
- if (pipe(netState->wakePipe) < 0) {
- PLOG(ERROR) << "pipe failed";
+ if (!MakePipe()) {
return false;
}
@@ -398,27 +345,45 @@
* Returns "false" on error (indicating that the connection has been severed),
* "true" if things are still okay.
*/
-static bool processIncoming(JdwpState* state) {
- JdwpNetState* netState = GetNetState(state);
+bool JdwpSocketState::ProcessIncoming() {
int readCount;
- CHECK_GE(netState->clientSock, 0);
+ CHECK(clientSock != -1);
- if (!netState->HaveFullPacket()) {
+ if (!HaveFullPacket()) {
/* read some more, looping until we have data */
errno = 0;
while (1) {
int selCount;
fd_set readfds;
- int maxfd;
+ int maxfd = -1;
int fd;
- maxfd = netState->listenSock;
- if (netState->clientSock > maxfd) {
- maxfd = netState->clientSock;
+ FD_ZERO(&readfds);
+
+ /* configure fds; note these may get zapped by another thread */
+ fd = listenSock;
+ if (fd >= 0) {
+ FD_SET(fd, &readfds);
+ if (maxfd < fd) {
+ maxfd = fd;
+ }
}
- if (netState->wakePipe[0] > maxfd) {
- maxfd = netState->wakePipe[0];
+ fd = clientSock;
+ if (fd >= 0) {
+ FD_SET(fd, &readfds);
+ if (maxfd < fd) {
+ maxfd = fd;
+ }
+ }
+ fd = wake_pipe_[0];
+ if (fd >= 0) {
+ FD_SET(fd, &readfds);
+ if (maxfd < fd) {
+ maxfd = fd;
+ }
+ } else {
+ LOG(INFO) << "NOTE: entering select w/o wakepipe";
}
if (maxfd < 0) {
@@ -426,24 +391,6 @@
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 {
- LOG(INFO) << "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,
@@ -451,7 +398,7 @@
* 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
+ * EINTR, (2) open an additional fd ("wake pipe") 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.
@@ -465,15 +412,15 @@
goto fail;
}
- if (netState->wakePipe[0] >= 0 && FD_ISSET(netState->wakePipe[0], &readfds)) {
- if (netState->listenSock >= 0) {
+ if (wake_pipe_[0] >= 0 && FD_ISSET(wake_pipe_[0], &readfds)) {
+ if (listenSock >= 0) {
LOG(ERROR) << "Exit wake set, but not exiting?";
} else {
LOG(DEBUG) << "Got wake-up signal, bailing out of select";
}
goto fail;
}
- if (netState->listenSock >= 0 && FD_ISSET(netState->listenSock, &readfds)) {
+ if (listenSock >= 0 && FD_ISSET(listenSock, &readfds)) {
LOG(INFO) << "Ignoring second debugger -- accepting and dropping";
union {
sockaddr_in addrInet;
@@ -481,15 +428,15 @@
} addr;
socklen_t addrlen;
int tmpSock;
- tmpSock = accept(netState->listenSock, &addr.addrPlain, &addrlen);
+ tmpSock = accept(listenSock, &addr.addrPlain, &addrlen);
if (tmpSock < 0) {
LOG(INFO) << "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 (clientSock >= 0 && FD_ISSET(clientSock, &readfds)) {
+ readCount = read(clientSock, input_buffer_ + input_count_, sizeof(input_buffer_) - input_count_);
if (readCount < 0) {
/* read failed */
if (errno != EINTR) {
@@ -507,8 +454,8 @@
}
}
- netState->inputCount += readCount;
- if (!netState->HaveFullPacket()) {
+ input_count_ += readCount;
+ if (!HaveFullPacket()) {
return true; /* still not there yet */
}
}
@@ -521,23 +468,21 @@
*
* Other than this one case, the protocol [claims to be] stateless.
*/
- if (netState->IsAwaitingHandshake()) {
- int cc;
-
- if (memcmp(netState->inputBuffer, kMagicHandshake, kMagicHandshakeLen) != 0) {
- LOG(ERROR) << StringPrintf("ERROR: bad handshake '%.14s'", netState->inputBuffer);
+ if (IsAwaitingHandshake()) {
+ if (memcmp(input_buffer_, kMagicHandshake, kMagicHandshakeLen) != 0) {
+ LOG(ERROR) << StringPrintf("ERROR: bad handshake '%.14s'", input_buffer_);
goto fail;
}
errno = 0;
- cc = TEMP_FAILURE_RETRY(write(netState->clientSock, netState->inputBuffer, kMagicHandshakeLen));
+ int cc = TEMP_FAILURE_RETRY(write(clientSock, input_buffer_, kMagicHandshakeLen));
if (cc != kMagicHandshakeLen) {
PLOG(ERROR) << "Failed writing handshake bytes (" << cc << " of " << kMagicHandshakeLen << ")";
goto fail;
}
- netState->ConsumeBytes(kMagicHandshakeLen);
- netState->SetAwaitingHandshake(false);
+ ConsumeBytes(kMagicHandshakeLen);
+ SetAwaitingHandshake(false);
VLOG(jdwp) << "+++ handshake complete";
return true;
}
@@ -545,36 +490,13 @@
/*
* Handle this packet.
*/
- return state->HandlePacket();
+ return state_->HandlePacket();
fail:
- netState->Close();
+ Close();
return false;
}
-/*
- * Our functions.
- *
- * We can't generally share the implementations with other transports,
- * even if they're also socket-based, because our JdwpNetState will be
- * different from theirs.
- */
-static const JdwpTransport socketTransport = {
- prepareSocket,
- acceptConnection,
- establishConnection,
- netShutdown,
- netFree,
- processIncoming,
-};
-
-/*
- * Return our set.
- */
-const JdwpTransport* SocketTransport() {
- return &socketTransport;
-}
-
} // namespace JDWP
} // namespace art