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