USBIP classes

Change-Id: I4256e666e48e77e04c82aa67d7d4b6b59d6e20cb
(cherry picked from commit 0bb107f3853d88748ad59b435cef85dacd94ad26)
diff --git a/vadb/usbip/BUILD b/vadb/usbip/BUILD
new file mode 100644
index 0000000..29109b9
--- /dev/null
+++ b/vadb/usbip/BUILD
@@ -0,0 +1,27 @@
+cc_library(
+    name = "usbip_lib",
+    srcs = [
+        "client.cpp",
+        "client.h",
+        "device.h",
+        "device_pool.cpp",
+        "device_pool.h",
+        "messages.cpp",
+        "messages.h",
+        "server.cpp",
+        "server.h",
+    ],
+    hdrs = [
+        "client.h",
+        "device.h",
+        "device_pool.h",
+        "messages.h",
+        "server.h",
+    ],
+    deps = [
+        "@cuttlefish//common/libs/fs",
+        "@gflags_repo//:gflags",
+        "@glog_repo//:glog",
+    ],
+)
+
diff --git a/vadb/usbip/README.md b/vadb/usbip/README.md
new file mode 100644
index 0000000..e652352
--- /dev/null
+++ b/vadb/usbip/README.md
@@ -0,0 +1,36 @@
+# USB/IP server library
+
+This folder contains set of classes and structures that constitute basic USB/IP 
+server.
+
+Protocol used in this library is defined as part of
+[Linux kernel documentation](https://www.kernel.org/doc/Documentation/usb/usbip_protocol.txt).
+
+## Structure
+
+### [`vadb::usbip::Device`](./device.h)[](#Device)
+
+Structure describing individual device accessible over USB/IP protocol.
+
+### [`vadb::usbip::DevicePool`](./device_pool.h)[](#DevicePool)
+
+DevicePool holds a set of [Devices](#Device) that can be enumerated and
+accessed by clients of this Server.
+
+### [`vadb::usbip::Server`](./server.h)
+
+Purpose of this class is to start a new listening socket and accept incoming
+USB/IP connections & requests.
+
+### [`vadb::usbip::Client`](./client.h)
+
+Client class represents individual USB/IP connection. Client enables remote
+USB/IP client to enumerate and access devices registered in
+[DevicePool](#DevicePool).
+
+### [`USB/IP Messages`](./messages.h)
+
+This file contains structures and enum values defined by the USB/IP protocol.
+All definitions found there have been collected from
+[Linux kernel documentation](https://www.kernel.org/doc/Documentation/usb/usbip_protocol.txt)
+.
diff --git a/vadb/usbip/client.cpp b/vadb/usbip/client.cpp
new file mode 100644
index 0000000..c483f42
--- /dev/null
+++ b/vadb/usbip/client.cpp
@@ -0,0 +1,386 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "host/vadb/usbip/client.h"
+
+#include <glog/logging.h>
+#include <iostream>
+
+#include "host/vadb/usbip/device.h"
+#include "host/vadb/usbip/messages.h"
+
+namespace vadb {
+namespace usbip {
+namespace {
+// Parse BUI ID (typically in form #-#) and extract root hub and bus.
+// We use these values as synonyms to bus and device numbers internally.
+// Returns false, if extracting BusDevNumber was unsuccessful.
+bool ParseBusID(const OpReqRepBusId& busid, DevicePool::BusDevNumber* dn) {
+  return sscanf(busid, "%hu-%hu", &dn->bus_number, &dn->dev_number) == 2;
+}
+
+// Build USBIP Device Report.
+void BuildDeviceNode(DevicePool::BusDevNumber dn, const Device& dd,
+                     OpRepDeviceInfo* node) {
+  memset(node, 0, sizeof(*node));
+
+  snprintf(node->usb_path, sizeof(node->usb_path),
+           "/sys/devices/usb/vhci/%hu-%hu", dn.bus_number, dn.dev_number);
+  snprintf(node->bus_id, sizeof(node->bus_id), "%hu-%hu", dn.bus_number,
+           dn.dev_number);
+
+  node->bus_num = dn.bus_number;
+  node->dev_num = dn.dev_number;
+
+  // TODO(ender): How is this defined?
+  node->speed = 2;
+
+  node->id_vendor = dd.vendor_id;
+  node->id_product = dd.product_id;
+  node->bcd_device = dd.dev_version;
+  node->device_class = dd.dev_class;
+  node->device_subclass = dd.dev_subclass;
+  node->device_protocol = dd.dev_protocol;
+  node->configuration_value = dd.configuration_number;
+  node->num_configurations = dd.configurations_count;
+  node->num_interfaces = dd.interfaces.size();
+}
+}  // namespace
+
+// Handle incoming USB/IP message.
+// USB/IP messages have two forms:
+// - OPs (OPERATIONs) - are executed only before remote device is attached,
+// - CMDs (COMMANDs)  - are executed only after remote device is attached.
+// The two types of commands are incompatible with one another, so it's
+// impossible to tell which is being parsed, unless you know the state of this
+// connection.
+//
+// Returns false, if connection should be dropped.
+bool Client::HandleIncomingMessage() {
+  return attached_ ? HandleCommand() : HandleOperation();
+}
+
+// Handle incoming OPERATION.
+//
+// Reads next OP from client channel.
+// Returns false, if connection should be dropped.
+bool Client::HandleOperation() {
+  OpHeader hdr;
+  if (!RecvUSBIPMsg(fd_, &hdr)) {
+    LOG(ERROR) << "Could not read operation header: " << fd_->StrError();
+    return false;
+  }
+
+  if (hdr.status != 0) {
+    // This really shouldn't happen unless we're already reading random bytes.
+    LOG(ERROR) << "Unexpected request status: " << hdr.status;
+    return false;
+  }
+
+  // USB/IP version is client-driven. Client requires server to support the
+  // version reported by client, so we need to cache it somehow.
+  if (!proto_version_) {
+    proto_version_ = hdr.version;
+    if ((proto_version_ < kMinVersion) || (proto_version_ > kMaxVersion)) {
+      LOG(ERROR) << "Unsupported USB/IP protocol version: " << proto_version_
+                 << ", want: [" << kMinVersion << "-" << kMaxVersion << "].";
+      return false;
+    }
+  } else {
+    // Now that we cache client version, we can use it to verify if we're not
+    // reading random data bytes again. Sort-of like a MAGIC word.
+    if (proto_version_ != hdr.version) {
+      LOG(ERROR) << "Inconsistent USB/IP version support reported by client; "
+                 << "I've seen " << proto_version_
+                 << ", and now i see: " << hdr.version
+                 << ". Client is not sane. Disconnecting.";
+      return false;
+    }
+  }
+
+  // Protocol itself. Behold.
+  switch (hdr.command) {
+    case kUsbIpOpReqDevList:
+      return HandleListOp();
+
+    case kUsbIpOpReqImport:
+      return HandleImportOp();
+
+    default:
+      LOG(WARNING) << "Ignoring unknown command: " << hdr.command;
+      // Drop connection at this point. Client may attempt to send some request
+      // data after header, and we risk interpreting this as another OP.
+      return false;
+  }
+}
+
+// Handle incoming DEVICE LIST OPERATION.
+//
+// Send list of (virtual) devices attached to this USB/IP server.
+// Returns false, if connection should be dropped.
+bool Client::HandleListOp() {
+  LOG(INFO) << "Client requests device list";
+  // NOTE: Device list Request is currently empty. Do not attempt to read.
+
+  // Send command header
+  OpHeader op{};
+  op.version = proto_version_;
+  op.command = kUsbIpOpRepDevList;
+  op.status = 0;
+  if (!SendUSBIPMsg(fd_, op)) {
+    LOG(ERROR) << "Could not send device list header: " << fd_->StrError();
+    return false;
+  }
+
+  // Send devlist header
+  OpRepDeviceListInfo rep{};
+  rep.num_exported_devices = pool_.Size();
+  if (!SendUSBIPMsg(fd_, rep)) {
+    LOG(ERROR) << "Could not send device list header: " << fd_->StrError();
+    return false;
+  }
+
+  // Send device reports.
+  for (const auto& pair : pool_) {
+    OpRepDeviceInfo device;
+    BuildDeviceNode(pair.first, *pair.second, &device);
+    if (!SendUSBIPMsg(fd_, device)) {
+      LOG(ERROR) << "Could not send device list node: " << fd_->StrError();
+      return false;
+    }
+
+    OpRepInterfaceInfo repif;
+    // Interfaces are ligth. Copying value is easier than dereferencing
+    // reference.
+    for (auto iface : pair.second->interfaces) {
+      repif.iface_class = iface.iface_class;
+      repif.iface_subclass = iface.iface_subclass;
+      repif.iface_protocol = iface.iface_protocol;
+      if (!SendUSBIPMsg(fd_, repif)) {
+        LOG(ERROR) << "Could not send device list interface: "
+                   << fd_->StrError();
+        return false;
+      }
+    }
+  }
+
+  LOG(INFO) << "Device list sent.";
+  return true;
+}
+
+// Handle incoming IMPORT OPERATION.
+//
+// Attach device to remote host. Flip internal state machine to start processing
+// COMMANDs.
+// Returns false, if connection should be dropped.
+bool Client::HandleImportOp() {
+  // Request contains BUS ID
+  OpReqRepBusId req;
+  if (!RecvUSBIPMsg(fd_, &req)) {
+    LOG(ERROR) << "Could not read op import data: " << fd_->StrError();
+    return false;
+  }
+  LOG(INFO) << "Client requests device import for bus" << req;
+
+  // Craft response header.
+  OpHeader op{};
+  op.version = proto_version_;
+  op.command = kUsbIpOpRepImport;
+  op.status = 0;
+
+  Device* device = nullptr;
+  DevicePool::BusDevNumber dn;
+
+  // Find requested device.
+  if (ParseBusID(req, &dn)) {
+    device = pool_.GetDevice(dn);
+    if (!device) {
+      op.status = 1;
+      LOG(ERROR) << "Import failed; No device registered on bus " << req;
+    }
+  } else {
+    LOG(ERROR) << "Could not parse BUS ID: " << req;
+    op.status = 1;
+  }
+
+  // Craft response data, if device was found.
+  OpRepDeviceInfo rep{};
+  if (device) {
+    BuildDeviceNode(dn, *device, &rep);
+  }
+
+  // Send response header.
+  if (!SendUSBIPMsg(fd_, op)) {
+    LOG(ERROR) << "Could not send import header: " << fd_->StrError();
+    return false;
+  }
+
+  // Send response data, if header indicates success.
+  if (!op.status) {
+    if (!SendUSBIPMsg(fd_, rep)) {
+      LOG(ERROR) << "Could not send import body: " << fd_->StrError();
+      return false;
+    }
+    attached_ = true;
+    LOG(INFO) << "Virtual USB attach successful.";
+  }
+
+  return true;
+}
+
+// Handle incoming COMMAND.
+//
+// Read next CMD from client channel.
+// Returns false, if connection should be dropped.
+bool Client::HandleCommand() {
+  CmdHeader hdr;
+  if (!RecvUSBIPMsg(fd_, &hdr)) {
+    LOG(ERROR) << "Could not read command header: " << fd_->StrError();
+    return false;
+  }
+
+  // And the protocol, again.
+  switch (hdr.command) {
+    case kUsbIpCmdReqSubmit:
+      HandleSubmitCmd(hdr);
+      break;
+
+    case kUsbIpCmdReqUnlink:
+      HandleUnlinkCmd(hdr);
+      break;
+
+    default:
+      LOG(ERROR) << "Unsupported command requested: " << hdr.command;
+      return false;
+  }
+  return true;
+}
+
+// Handle incoming SUBMIT COMMAND.
+//
+// Execute command on specified USB device.
+// Returns false, if connection should be dropped.
+bool Client::HandleSubmitCmd(const CmdHeader& cmd) {
+  CmdReqSubmit req;
+  if (!RecvUSBIPMsg(fd_, &req)) {
+    LOG(ERROR) << "Could not read submit command: " << fd_->StrError();
+    return false;
+  }
+
+  // Response template.
+  // - in header, host doesn't care about anything else except for command type
+  //   and sequence number.
+  // - in body, report status == !OK unless we completed everything
+  //   successfully.
+  CmdHeader rephdr{};
+  rephdr.command = kUsbIpCmdRepSubmit;
+  rephdr.seq_num = cmd.seq_num;
+  CmdRepSubmit rep{};
+  rep.status = 1;
+
+  std::vector<uint8_t> payload_in;
+  std::vector<uint8_t> payload_out;
+  int payload_length = req.transfer_buffer_length;
+
+  // Find requested device and execute command.
+  auto device = pool_.GetDevice({cmd.bus_num, cmd.dev_num});
+  if (device) {
+    // Read DATA_IN, if specified.
+    if (cmd.direction == kUsbIpDirectionOut && payload_length) {
+      LOG(INFO) << "Reading payload (" << payload_length << " bytes).";
+      payload_in.resize(payload_length);
+      auto read = fd_->Recv(payload_in.data(), payload_in.size(), MSG_NOSIGNAL);
+      if (read != payload_in.size()) {
+        LOG(ERROR) << "Short read while receiving payload; want="
+                   << payload_in.size() << ", got=" << read
+                   << ", err: " << fd_->StrError();
+        return false;
+      }
+    }
+
+    // Indicate execution result. Status is 0 when everything is OK.
+    rep.status = !device->handle_request(req.setup, payload_in, &payload_out);
+
+    // Trim / expand output payload length. Client will expect this number of
+    // bytes and may just freeze trying to read what it just requested.
+    if (cmd.direction == kUsbIpDirectionIn) {
+      // Erase output payload buffer if status is not OK.
+      payload_out.resize(rep.status ? 0 : payload_length);
+    }
+  }
+
+  rep.actual_length = payload_out.size();
+
+  // Data out.
+  if (!SendUSBIPMsg(fd_, rephdr)) {
+    LOG(ERROR) << "Failed to send response header: " << fd_->StrError();
+    return false;
+  }
+
+  if (!SendUSBIPMsg(fd_, rep)) {
+    LOG(ERROR) << "Failed to send response body: " << fd_->StrError();
+    return false;
+  }
+
+  if (payload_out.size()) {
+    if (fd_->Send(payload_out.data(), payload_out.size(), MSG_NOSIGNAL) !=
+        payload_out.size()) {
+      LOG(ERROR) << "Failed to send response payload: " << fd_->StrError();
+      return false;
+    }
+  }
+
+  return true;
+}
+
+// Handle incoming UNLINK COMMAND.
+//
+// Unlink removes command specified via seq_num from a list of commands to be
+// executed.
+// We don't schedule commands for execution, so technically every UNLINK will
+// come in late.
+// Returns false, if connection should be dropped.
+bool Client::HandleUnlinkCmd(const CmdHeader& cmd) {
+  CmdReqUnlink req;
+  if (!RecvUSBIPMsg(fd_, &req)) {
+    LOG(ERROR) << "Could not read unlink command: " << fd_->StrError();
+    return false;
+  }
+  LOG(INFO) << "Client requested to unlink previously submitted command: "
+            << req.seq_num;
+
+  CmdHeader rephdr{};
+  rephdr.command = kUsbIpCmdRepUnlink;
+  rephdr.seq_num = cmd.seq_num;
+
+  // Technically we do not schedule commands for execution, so we cannot
+  // de-queue commands, either. Indicate this by sending status != ok.
+  CmdRepUnlink rep;
+  rep.status = 1;
+
+  if (!SendUSBIPMsg(fd_, rephdr)) {
+    LOG(ERROR) << "Could not send unlink command header: " << fd_->StrError();
+    return false;
+  }
+
+  if (!SendUSBIPMsg(fd_, rep)) {
+    LOG(ERROR) << "Could not send unlink command data: " << fd_->StrError();
+    return false;
+  }
+  return true;
+}
+
+}  // namespace usbip
+}  // namespace vadb
diff --git a/vadb/usbip/client.h b/vadb/usbip/client.h
new file mode 100644
index 0000000..572d7c2
--- /dev/null
+++ b/vadb/usbip/client.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include "common/libs/fs/shared_fd.h"
+#include "host/vadb/usbip/device_pool.h"
+#include "host/vadb/usbip/messages.h"
+
+namespace vadb {
+namespace usbip {
+
+// Represents USB/IP client, or individual connection to our USB/IP server.
+// Multiple clients are allowed, even if practically we anticipate only one
+// connection at the time.
+class Client final {
+ public:
+  Client(const DevicePool& pool, const avd::SharedFD& fd)
+      : pool_(pool), fd_(fd) {}
+
+  ~Client() {}
+
+  // Respond to message from remote client.
+  // Returns false, if client violated protocol or disconnected, indicating,
+  // that this instance should no longer be used.
+  bool HandleIncomingMessage();
+
+  const avd::SharedFD& fd() const { return fd_; }
+
+ private:
+  // Process messages that are valid only while client is detached.
+  // Returns false, if conversation was unsuccessful.
+  bool HandleOperation();
+
+  // Process messages that are valid only while client is attached.
+  // Returns false, if connection should be dropped.
+  bool HandleCommand();
+
+  // List remote USB devices.
+  // Returns false, if connection should be dropped.
+  bool HandleListOp();
+
+  // Attach virtual USB devices to remote host.
+  // Returns false, if connection should be dropped.
+  bool HandleImportOp();
+
+  // Execute command on USB device.
+  // Returns false, if connection should be dropped.
+  bool HandleSubmitCmd(const CmdHeader& hdr);
+
+  // Unlink previously submitted message from device queue.
+  // Returns false, if connection should be dropped.
+  bool HandleUnlinkCmd(const CmdHeader& hdr);
+
+  const DevicePool& pool_;
+  avd::SharedFD fd_;
+
+  // True, if client requested USB device attach.
+  bool attached_ = false;
+  uint16_t proto_version_ = 0;
+
+  Client(const Client&) = delete;
+  Client& operator=(const Client&) = delete;
+};
+
+}  // namespace usbip
+}  // namespace vadb
diff --git a/vadb/usbip/device.h b/vadb/usbip/device.h
new file mode 100644
index 0000000..47ba0c1
--- /dev/null
+++ b/vadb/usbip/device.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include <cstdint>
+#include <functional>
+#include <map>
+#include <memory>
+#include <vector>
+
+#include "host/vadb/usbip/messages.h"
+
+namespace vadb {
+namespace usbip {
+
+// The device descriptor of a USB device represents a USB device that is
+// available for import.
+class Device {
+ public:
+  // Interface provides minimal description of device's interface.
+  struct Interface {
+    uint8_t iface_class;
+    uint8_t iface_subclass;
+    uint8_t iface_protocol;
+  };
+
+  // vendor_id and product_id identify device manufacturer and type.
+  // dev_version describes device version (as BCD).
+  uint16_t vendor_id;
+  uint16_t product_id;
+  uint16_t dev_version;
+
+  // Class, Subclass and Protocol define device type.
+  uint8_t dev_class;
+  uint8_t dev_subclass;
+  uint8_t dev_protocol;
+
+  // ConfigurationsCount and ConfigurationNumber describe total number of device
+  // configurations and currently activated device configuration.
+  size_t configurations_count;
+  size_t configuration_number;
+
+  // Interfaces returns a collection of device interfaces.
+  std::vector<Interface> interfaces;
+
+  // Device request dispatcher.
+  std::function<bool(const CmdRequest& request,
+                     const std::vector<uint8_t>& data_in,
+                     std::vector<uint8_t>* data_out)>
+      handle_request;
+};
+
+}  // namespace usbip
+}  // namespace vadb
diff --git a/vadb/usbip/device_pool.cpp b/vadb/usbip/device_pool.cpp
new file mode 100644
index 0000000..be026d1
--- /dev/null
+++ b/vadb/usbip/device_pool.cpp
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "host/vadb/usbip/device_pool.h"
+
+#include <glog/logging.h>
+
+namespace vadb {
+namespace usbip {
+
+void DevicePool::AddDevice(BusDevNumber bdn, std::unique_ptr<Device> device) {
+  LOG_IF(FATAL, devices_.find(bdn) != devices_.end())
+      << "Node already defined for bus=" << bdn.bus_number
+      << ", dev=" << bdn.dev_number;
+  devices_[bdn] = std::move(device);
+}
+
+Device* DevicePool::GetDevice(BusDevNumber bus_id) const {
+  auto iter = devices_.find(bus_id);
+  if (iter == devices_.end()) return nullptr;
+  return iter->second.get();
+}
+
+}  // namespace usbip
+}  // namespace vadb
diff --git a/vadb/usbip/device_pool.h b/vadb/usbip/device_pool.h
new file mode 100644
index 0000000..4a7c637
--- /dev/null
+++ b/vadb/usbip/device_pool.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include <map>
+#include <string>
+
+#include "host/vadb/usbip/device.h"
+
+namespace vadb {
+namespace usbip {
+// Container for all virtual USB/IP devices.
+// Stores devices by virtual BUS ID.
+class DevicePool {
+ public:
+  // BusDevNumber is a pair uniquely identifying bus and device.
+  struct BusDevNumber {
+    uint16_t bus_number;
+    uint16_t dev_number;
+
+    bool operator<(BusDevNumber other) const {
+      return (bus_number << 16 | dev_number) <
+             (other.bus_number << 16 | other.dev_number);
+    }
+  };
+
+  // Internal container type.
+  using MapType = std::map<BusDevNumber, std::unique_ptr<Device>>;
+
+  DevicePool() = default;
+  virtual ~DevicePool() = default;
+
+  // Add new device associated with virtual BUS ID.
+  void AddDevice(BusDevNumber bus_id, std::unique_ptr<Device> device);
+
+  // Get device associated with supplied virtual bus/device number.
+  Device* GetDevice(BusDevNumber bus_dev_num) const;
+
+  // Get total number of USB/IP devices.
+  size_t Size() const { return devices_.size(); }
+
+  MapType::const_iterator begin() const { return devices_.cbegin(); }
+  MapType::const_iterator end() const { return devices_.cend(); }
+
+ private:
+  MapType devices_;
+
+  DevicePool(const DevicePool&) = delete;
+  DevicePool& operator=(const DevicePool&) = delete;
+};
+
+}  // namespace usbip
+}  // namespace vadb
diff --git a/vadb/usbip/messages.cpp b/vadb/usbip/messages.cpp
new file mode 100644
index 0000000..962905c
--- /dev/null
+++ b/vadb/usbip/messages.cpp
@@ -0,0 +1,303 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "host/vadb/usbip/messages.h"
+
+#include <netinet/in.h>
+#include <iostream>
+
+#include <glog/logging.h>
+
+namespace vadb {
+namespace usbip {
+namespace {
+// Basic sanity checking.
+// We're using CmdHeader + CmdReq/Rep in case any of the fields is moved between
+// structures.
+constexpr int kUsbIpCmdLength = 48;
+
+static_assert(sizeof(CmdHeader) + sizeof(CmdReqSubmit) == kUsbIpCmdLength,
+              "USB/IP command + header must be exactly 48 bytes.");
+static_assert(sizeof(CmdHeader) + sizeof(CmdRepSubmit) == kUsbIpCmdLength,
+              "USB/IP command + header must be exactly 48 bytes.");
+static_assert(sizeof(CmdHeader) + sizeof(CmdReqUnlink) == kUsbIpCmdLength,
+              "USB/IP command + header must be exactly 48 bytes.");
+static_assert(sizeof(CmdHeader) + sizeof(CmdRepUnlink) == kUsbIpCmdLength,
+              "USB/IP command + header must be exactly 48 bytes.");
+}  // namespace
+
+// NetToHost and HostToNet are used to reduce risk of copy/paste errors and to
+// provide uniform method of converting messages between different endian types.
+namespace internal {
+
+template <>
+void NetToHost(uint32_t* t) {
+  *t = ntohl(*t);
+}
+
+template <>
+void NetToHost(Command* t) {
+  *t = static_cast<Command>(ntohl(*t));
+}
+
+template <>
+void NetToHost(Direction* t) {
+  *t = static_cast<Direction>(ntohl(*t));
+}
+
+template <>
+void NetToHost(uint16_t* t) {
+  *t = ntohs(*t);
+}
+
+template <>
+void NetToHost(Operation* t) {
+  *t = static_cast<Operation>(ntohs(*t));
+}
+
+template <>
+void NetToHost(CmdHeader* t) {
+  NetToHost(&t->command);
+  NetToHost(&t->seq_num);
+  NetToHost(&t->bus_num);
+  NetToHost(&t->dev_num);
+  NetToHost(&t->direction);
+  NetToHost(&t->endpoint);
+}
+
+template <>
+void NetToHost(CmdReqSubmit* t) {
+  NetToHost(&t->transfer_flags);
+  NetToHost(&t->transfer_buffer_length);
+  NetToHost(&t->start_frame);
+  NetToHost(&t->number_of_packets);
+  NetToHost(&t->deadline_interval);
+}
+
+template <>
+void NetToHost(OpHeader* t) {
+  NetToHost(&t->version);
+  NetToHost(&t->command);
+  NetToHost(&t->status);
+}
+
+template <>
+void NetToHost(OpReqRepBusId* t) {}
+
+template <>
+void NetToHost(CmdReqUnlink* t) {
+  NetToHost(&t->seq_num);
+}
+
+template <>
+void HostToNet(uint32_t* t) {
+  *t = htonl(*t);
+}
+
+template <>
+void HostToNet(Command* t) {
+  *t = static_cast<Command>(htonl(*t));
+}
+
+template <>
+void HostToNet(Direction* t) {
+  *t = static_cast<Direction>(htonl(*t));
+}
+
+template <>
+void HostToNet(uint16_t* t) {
+  *t = htons(*t);
+}
+
+template <>
+void HostToNet(Operation* t) {
+  *t = static_cast<Operation>(htons(*t));
+}
+
+template <>
+void HostToNet(CmdHeader* t) {
+  HostToNet(&t->command);
+  HostToNet(&t->seq_num);
+  HostToNet(&t->bus_num);
+  HostToNet(&t->dev_num);
+  HostToNet(&t->direction);
+  HostToNet(&t->endpoint);
+}
+
+template <>
+void HostToNet(CmdRepSubmit* t) {
+  HostToNet(&t->status);
+  HostToNet(&t->actual_length);
+  HostToNet(&t->start_frame);
+  HostToNet(&t->number_of_packets);
+  HostToNet(&t->error_count);
+}
+
+template <>
+void HostToNet(OpHeader* t) {
+  HostToNet(&t->version);
+  HostToNet(&t->command);
+  HostToNet(&t->status);
+}
+
+template <>
+void HostToNet(OpRepDeviceListInfo* t) {
+  HostToNet(&t->num_exported_devices);
+}
+
+template <>
+void HostToNet(OpRepDeviceInfo* t) {
+  HostToNet(&t->bus_num);
+  HostToNet(&t->dev_num);
+  HostToNet(&t->speed);
+
+  // Note: The following should not be rotated when exporting host USB devices.
+  // We only rotate these here because we are using native endian everywhere.
+  HostToNet(&t->id_vendor);
+  HostToNet(&t->id_product);
+  HostToNet(&t->bcd_device);
+}
+
+template <>
+void HostToNet(CmdRepUnlink* t) {
+  HostToNet(&t->status);
+}
+
+template <>
+void HostToNet(OpRepInterfaceInfo* t) {}
+
+}  // namespace internal
+
+// Output and diagnostic functionality.
+std::ostream& operator<<(std::ostream& out, Operation op) {
+  switch (op) {
+    case kUsbIpOpReqDevList:
+      out << "OpReqDevList";
+      break;
+    case kUsbIpOpRepDevList:
+      out << "OpRepDevList";
+      break;
+    case kUsbIpOpReqImport:
+      out << "OpReqImport";
+      break;
+    case kUsbIpOpRepImport:
+      out << "OpRepImport";
+      break;
+    default:
+      out << "UNKNOWN (" << int(op) << ")";
+      break;
+  }
+  return out;
+}
+
+std::ostream& operator<<(std::ostream& out, const CmdHeader& header) {
+  out << "CmdHeader\n";
+  out << "\t\tcmd:\t" << header.command << '\n';
+  out << "\t\tseq#:\t" << header.seq_num << '\n';
+  out << "\t\tbus#:\t0x" << header.bus_num << '\n';
+  out << "\t\tdev#:\t0x" << header.dev_num << '\n';
+  out << "\t\tdir:\t" << (header.direction ? "in" : "out") << '\n';
+  out << "\t\tendpt:\t" << header.endpoint << "\n";
+  return out;
+}
+
+std::ostream& operator<<(std::ostream& out, const CmdRequest& setup) {
+  out << "Request\n";
+  out << "\t\t\ttype:\t" << std::hex << int(setup.type) << '\n';
+  out << "\t\t\treq:\t" << int(setup.cmd) << std::dec << '\n';
+  out << "\t\t\tval:\t" << setup.value << '\n';
+  out << "\t\t\tidx:\t" << setup.index << '\n';
+  out << "\t\t\tlen:\t" << setup.length << '\n';
+  return out;
+}
+
+std::ostream& operator<<(std::ostream& out, const CmdReqSubmit& submit) {
+  out << "CmdReqSubmit\n";
+  out << "\t\ttr_flg:\t" << std::hex << submit.transfer_flags << std::dec
+      << '\n';
+  out << "\t\ttr_len:\t" << submit.transfer_buffer_length << '\n';
+  out << "\t\tstart:\t" << submit.start_frame << '\n';
+  out << "\t\tpktcnt:\t" << submit.number_of_packets << '\n';
+  out << "\t\tttl:\t" << submit.deadline_interval << '\n';
+  out << "\t\tsetup:\t" << submit.setup << '\n';
+  return out;
+}
+
+std::ostream& operator<<(std::ostream& out, const CmdRepSubmit& submit) {
+  out << "CmdRepSubmit\n";
+  out << "\t\tstatus:\t" << submit.status << '\n';
+  out << "\t\tlen:\t" << submit.actual_length << '\n';
+  out << "\t\tstart:\t" << submit.start_frame << '\n';
+  out << "\t\tpktcnt:\t" << submit.number_of_packets << '\n';
+  out << "\t\terrors:\t" << submit.error_count << '\n';
+  out << "\t\tsetup:\t" << submit.setup << '\n';
+  return out;
+}
+
+std::ostream& operator<<(std::ostream& out, const CmdReqUnlink& unlink) {
+  out << "CmdReqUnlink\n";
+  out << "\t\tseq#:\t" << unlink.seq_num << '\n';
+  return out;
+}
+
+std::ostream& operator<<(std::ostream& out, const CmdRepUnlink& unlink) {
+  out << "CmdRepUnlink\n";
+  out << "\t\tstatus:\t" << unlink.status << '\n';
+  return out;
+}
+
+std::ostream& operator<<(std::ostream& out, const OpHeader& header) {
+  out << "OpHeader\n";
+  out << "\t\tvrsn:\t" << std::hex << header.version << '\n';
+  out << "\t\tcmd:\t" << header.command << '\n';
+  out << "\t\tstatus:\t" << header.status << std::dec << '\n';
+  return out;
+}
+
+std::ostream& operator<<(std::ostream& out, const OpRepDeviceInfo& import) {
+  out << "OpRepDeviceInfo\n";
+  out << "\t\tsysfs:\t" << import.usb_path << '\n';
+  out << "\t\tbusid:\t" << import.bus_id << '\n';
+  out << "\t\tbus#:\t" << import.bus_num << '\n';
+  out << "\t\tdev#:\t" << import.dev_num << '\n';
+  out << "\t\tspeed:\t" << import.speed << '\n';
+  out << "\t\tvendor:\t" << std::hex << import.id_vendor << std::dec << '\n';
+  out << "\t\tprodct:\t" << std::hex << import.id_product << std::dec << '\n';
+  out << "\t\trel:\t" << std::hex << import.bcd_device << std::dec << '\n';
+  out << "\t\tcls:\t" << int(import.device_class) << '\n';
+  out << "\t\tsubcls:\t" << int(import.device_subclass) << '\n';
+  out << "\t\tproto:\t" << int(import.device_protocol) << '\n';
+  out << "\t\tcfg#:\t" << int(import.configuration_value) << '\n';
+  out << "\t\tcfgs#:\t" << int(import.num_configurations) << '\n';
+  out << "\t\tifs#:\t" << int(import.num_interfaces) << '\n';
+  return out;
+}
+
+std::ostream& operator<<(std::ostream& out, const OpRepDeviceListInfo& list) {
+  out << "OpRepDeviceListInfo\n";
+  out << "\t\tcount:\t" << list.num_exported_devices << '\n';
+  return out;
+}
+
+std::ostream& operator<<(std::ostream& out, const OpRepInterfaceInfo& i) {
+  out << "OpRepDevListIface\n";
+  out << "\t\tcls:\t" << int(i.iface_class) << '\n';
+  out << "\t\tsubcls:\t" << int(i.iface_subclass) << '\n';
+  out << "\t\tproto:\t" << int(i.iface_protocol) << '\n';
+  return out;
+}
+
+}  // namespace usbip
+}  // namespace vadb
diff --git a/vadb/usbip/messages.h b/vadb/usbip/messages.h
new file mode 100644
index 0000000..7137940
--- /dev/null
+++ b/vadb/usbip/messages.h
@@ -0,0 +1,229 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include <glog/logging.h>
+#include <stdint.h>
+
+#include "common/libs/fs/shared_fd.h"
+
+// Requests and constants below are defined in kernel documentation file:
+// https://www.kernel.org/doc/Documentation/usb/usbip_protocol.txt
+namespace vadb {
+namespace usbip {
+namespace internal {
+// Rotate endianness of the data to match protocol.
+template <typename T>
+void HostToNet(T* data);
+template <typename T>
+void NetToHost(T* data);
+}  // namespace internal
+
+// This is the range of USB/IP versions in which we should be safe to operate.
+// USB/IP expects (and the expectation is strong) that the version reported by
+// server is *same* as version reported by client, so we have to mock this for
+// every client.
+// TODO(ender): find if this is documented anywhere.
+constexpr int kMinVersion = 0x100;  // 1.0.0
+constexpr int kMaxVersion = 0x111;  // 1.1?.1?
+
+// Send message to USB/IP client.
+// Accept data by value and modify it to match net endian locally.
+// Returns true, if message was sent successfully.
+template <typename T>
+bool SendUSBIPMsg(const avd::SharedFD& fd, T data) {
+  VLOG(2) << "Sending " << sizeof(T) << " bytes...";
+  VLOG(1) << data;
+  internal::HostToNet(&data);
+  return fd->Send(&data, sizeof(T), MSG_NOSIGNAL) == sizeof(T);
+}
+
+// Receive message from USB/IP client.
+// After message is received, it's updated to match host endian.
+// Returns true, if message was received successfully.
+template <typename T>
+bool RecvUSBIPMsg(const avd::SharedFD& fd, T* data) {
+  VLOG(2) << "Reading " << sizeof(T) << " bytes...";
+  bool res = fd->Recv(data, sizeof(T), MSG_NOSIGNAL) == sizeof(T);
+  if (res) {
+    internal::NetToHost(data);
+    VLOG(1) << *data;
+  }
+  return res;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// OPERATIONS
+////////////////////////////////////////////////////////////////////////////////
+
+// Operation numbers. Operations are valid only when USB device is detached.
+enum Operation : uint16_t {
+  // Request import (~attach) USB device. Request data format:
+  // - OpReqRepBusId - describing BUS ID.
+  kUsbIpOpReqImport = 0x8003,
+
+  // Import (~attach) response. Response format:
+  // - OpRepDeviceInfo - USBIP device descriptor.
+  kUsbIpOpRepImport = 3,
+
+  // Request list available devices. No request data.
+  kUsbIpOpReqDevList = 0x8005,
+
+  // Device list response. Response format:
+  // - OpRepDeviceListInfo - specifies number of device list reports that follow
+  //   (n),
+  // - n * OpRepDeviceInfo - USBIP device descriptor, including # interfaces
+  //   (m),
+  // - m * OpRepInterfaceInfo - for every OpRepDeviceInfo, list of interfaces.
+  kUsbIpOpRepDevList = 5,
+};
+
+// Header precedes all OPERATION requests and responses.
+// Header does NOT precede COMMAND requests and responses.
+struct OpHeader {
+  uint16_t version;   // BCD. Server must obey client, not the other way around.
+  Operation command;  // Request or response type.
+  uint32_t status;    // Status; 0 = ok, 1 = error.
+};
+
+// OPERATION request/response body is essentially several structures glued
+// together. Because half of these messages are nested arrays of arbitrary
+// lengths each, we can't define a single structure explaining full request or
+// response body. Instead we will define components that, when combined,
+// constitute this body.
+//
+// OpReqRepBusId functions both as a device info field and request body.
+using OpReqRepBusId = char[32];
+
+// OpRepDeviceListInfo is a header preceding an array of OpRepDeviceInfo devices
+// offered by this server.
+struct OpRepDeviceListInfo {
+  uint32_t num_exported_devices;
+} __attribute__((packed));
+
+// OpRepDeviceInfo is used both as a partial response to OpReqDeviceList and
+// OpReqImport. Depending on operation type it may or may not be followed by an
+// array of OpRepInterfaceInfo interfaces this device exports.
+struct OpRepDeviceInfo {
+  char usb_path[256];
+  OpReqRepBusId bus_id;
+  uint32_t bus_num;
+  uint32_t dev_num;
+  uint32_t speed;
+  uint16_t id_vendor;
+  uint16_t id_product;
+  uint16_t bcd_device;
+  uint8_t device_class;
+  uint8_t device_subclass;
+  uint8_t device_protocol;
+  uint8_t configuration_value;
+  uint8_t num_configurations;
+  uint8_t num_interfaces;
+} __attribute__((packed));
+
+// OpRepInterfaceInfo lists interface details of a particular USB device.
+struct OpRepInterfaceInfo {
+  uint8_t iface_class;
+  uint8_t iface_subclass;
+  uint8_t iface_protocol;
+  uint8_t reserved;
+} __attribute__((packed));
+
+////////////////////////////////////////////////////////////////////////////////
+// COMMANDS
+////////////////////////////////////////////////////////////////////////////////
+
+// Command numbers. Commands are valid only once USB device is attached.
+enum Command : uint32_t {
+  kUsbIpCmdReqSubmit = 1,  // Submit request
+  kUsbIpCmdReqUnlink = 2,  // Unlink request
+  kUsbIpCmdRepSubmit = 3,  // Submit response
+  kUsbIpCmdRepUnlink = 4,  // Unlink response
+};
+
+// Direction of data flow.
+enum Direction : uint32_t {
+  kUsbIpDirectionOut = 0,
+  kUsbIpDirectionIn = 1,
+};
+
+// Setup structure is explained in great detail here:
+// - http://www.beyondlogic.org/usbnutshell/usb6.shtml
+// - http://www.usbmadesimple.co.uk/ums_4.htm
+struct CmdRequest {
+  uint8_t type;
+  uint8_t cmd;
+  uint16_t value;
+  uint16_t index;
+  uint16_t length;
+} __attribute__((packed));
+
+// CmdHeader precedes any command request or response body.
+struct CmdHeader {
+  Command command;
+  uint32_t seq_num;
+  uint16_t bus_num;
+  uint16_t dev_num;
+  Direction direction;
+  uint32_t endpoint;  // valid values: 0-15
+} __attribute__((packed));
+
+// Command data for submitting an USB request.
+struct CmdReqSubmit {
+  uint32_t transfer_flags;
+  uint32_t transfer_buffer_length;
+  uint32_t start_frame;
+  uint32_t number_of_packets;
+  uint32_t deadline_interval;
+  CmdRequest setup;
+} __attribute__((packed));
+
+// Command response for submitting an USB request.
+struct CmdRepSubmit {
+  uint32_t status;  // 0 = success.
+  uint32_t actual_length;
+  uint32_t start_frame;
+  uint32_t number_of_packets;
+  uint32_t error_count;
+  CmdRequest setup;
+} __attribute__((packed));
+
+// Unlink USB request.
+struct CmdReqUnlink {
+  uint32_t seq_num;
+  uint32_t reserved[6];
+} __attribute__((packed));
+
+// Unlink USB response.
+struct CmdRepUnlink {
+  uint32_t status;
+  uint32_t reserved[6];
+} __attribute__((packed));
+
+// Diagnostics.
+std::ostream& operator<<(std::ostream& out, Operation op);
+std::ostream& operator<<(std::ostream& out, const OpHeader& header);
+std::ostream& operator<<(std::ostream& out, const OpRepDeviceInfo& data);
+std::ostream& operator<<(std::ostream& out, const OpRepDeviceListInfo& list);
+std::ostream& operator<<(std::ostream& out, const OpRepInterfaceInfo& i);
+std::ostream& operator<<(std::ostream& out, const CmdHeader& header);
+std::ostream& operator<<(std::ostream& out, const CmdReqSubmit& data);
+std::ostream& operator<<(std::ostream& out, const CmdRepSubmit& data);
+std::ostream& operator<<(std::ostream& out, const CmdReqUnlink& data);
+std::ostream& operator<<(std::ostream& out, const CmdRepUnlink& data);
+
+}  // namespace usbip
+}  // namespace vadb
diff --git a/vadb/usbip/server.cpp b/vadb/usbip/server.cpp
new file mode 100644
index 0000000..fb83922
--- /dev/null
+++ b/vadb/usbip/server.cpp
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "host/vadb/usbip/server.h"
+
+#include <glog/logging.h>
+#include <netinet/in.h>
+
+#include "common/libs/fs/shared_select.h"
+
+using avd::SharedFD;
+
+namespace vadb {
+namespace usbip {
+namespace {
+// USB-IP server port. USBIP will attempt to connect to this server to attach
+// new virtual USB devices to host.
+static constexpr int kServerPort = 3240;
+}  // namespace
+
+Server::Server(const DevicePool &devices) : device_pool_(devices) {}
+
+bool Server::Init() { return CreateServerSocket(); }
+
+// Open new listening server socket.
+// Returns false, if listening socket could not be created.
+bool Server::CreateServerSocket() {
+  LOG(INFO) << "Starting server socket on port " << kServerPort;
+  server_ = SharedFD::Socket(PF_INET6, SOCK_STREAM, 0);
+  if (!server_->IsOpen()) {
+    LOG(ERROR) << "Could not create socket: " << server_->StrError();
+    return false;
+  }
+
+  int n = 1;
+  if (server_->SetSockOpt(SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n)) == -1) {
+    LOG(ERROR) << "SetSockOpt failed " << server_->StrError();
+    return false;
+  }
+
+  struct sockaddr_in6 addr = {
+      AF_INET6, htons(kServerPort), 0, in6addr_loopback, 0,
+  };
+
+  if (server_->Bind((struct sockaddr *)&addr, sizeof(addr)) == -1) {
+    LOG(ERROR) << "Could not bind socket: " << server_->StrError();
+    return false;
+  }
+
+  if (server_->Listen(1) == -1) {
+    LOG(ERROR) << "Could not start listening: " << server_->StrError();
+    return false;
+  }
+
+  return true;
+}
+
+// Serve incoming USB/IP connections.
+void Server::Serve() {
+  LOG(INFO) << "Serving USB/IP connections.";
+  while (true) {
+    avd::SharedFDSet fd_read;
+    fd_read.Set(server_);
+    for (const auto &client : clients_) fd_read.Set(client.fd());
+
+    int ret = avd::Select(&fd_read, nullptr, nullptr, nullptr);
+    if (ret <= 0) continue;
+
+    if (fd_read.IsSet(server_)) HandleIncomingConnection();
+
+    for (auto iter = clients_.begin(); iter != clients_.end();) {
+      if (fd_read.IsSet(iter->fd())) {
+        // If client conversation failed, hang up.
+        if (!iter->HandleIncomingMessage()) {
+          iter = clients_.erase(iter);
+          continue;
+        }
+      }
+      ++iter;
+    }
+  }
+  LOG(INFO) << "Server exiting.";
+}
+
+// Accept new USB/IP connection. Add it to client pool.
+void Server::HandleIncomingConnection() {
+  SharedFD client = SharedFD::Accept(*server_, nullptr, nullptr);
+  if (!client->IsOpen()) {
+    LOG(ERROR) << "Client connection failed: " << client->StrError();
+    return;
+  }
+
+  clients_.emplace_back(device_pool_, client);
+}
+}  // namespace usbip
+}  // namespace vadb
diff --git a/vadb/usbip/server.h b/vadb/usbip/server.h
new file mode 100644
index 0000000..2e8223f
--- /dev/null
+++ b/vadb/usbip/server.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include <list>
+
+#include "common/libs/fs/shared_fd.h"
+#include "host/vadb/usbip/device_pool.h"
+#include "host/vadb/usbip/client.h"
+
+namespace vadb {
+namespace usbip {
+
+class Server final {
+ public:
+  Server(const DevicePool& device_pool);
+  ~Server() = default;
+
+  // Initialize this instance of Server.
+  // Returns true, if initialization was successful.
+  bool Init();
+
+  // Main server loop. Handles all incoming connections as well as client data
+  // exchange.
+  void Serve();
+
+ private:
+  // Create USBIP server socket.
+  // Returns true, if socket was successfully created.
+  bool CreateServerSocket();
+
+  // Handle new client connection.
+  // New clients will be appended to clients_ list.
+  void HandleIncomingConnection();
+
+  avd::SharedFD server_;
+  std::list<Client> clients_;
+  const DevicePool& device_pool_;
+
+  Server(const Server&) = delete;
+  Server& operator=(const Server&) = delete;
+};
+
+}  // namespace usbip
+}  // namespace vadb