arc: Move platform2/arc/network/ to platform2/patchpanel
Next step in the arc-networkd -> patchpanel rename, this patch moves the
location of the code.
BUG=b:151879931
TEST=units,flashed image to atlas
TEST=tasts arc.PlayStore, crostini.LaunchTerminal.download
Change-Id: I1b5cf8d670e1631d46f6449b725395157bf88dde
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform2/+/2115863
Tested-by: Garrick Evans <garrick@chromium.org>
Commit-Queue: Garrick Evans <garrick@chromium.org>
Reviewed-by: Hidehiko Abe <hidehiko@chromium.org>
Reviewed-by: Eric Caruso <ejcaruso@chromium.org>
Reviewed-by: Chirantan Ekbote <chirantan@chromium.org>
Reviewed-by: Hugo Benichi <hugobenichi@google.com>
diff --git a/patchpanel/adb_proxy.cc b/patchpanel/adb_proxy.cc
new file mode 100644
index 0000000..0f94ec3
--- /dev/null
+++ b/patchpanel/adb_proxy.cc
@@ -0,0 +1,197 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "patchpanel/adb_proxy.h"
+
+#include <linux/vm_sockets.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <sysexits.h>
+
+#include <set>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <base/bind.h>
+#include <base/logging.h>
+#include <base/strings/string_number_conversions.h>
+#include <base/strings/stringprintf.h>
+#include <brillo/key_value_store.h>
+
+#include "patchpanel/manager.h"
+#include "patchpanel/minijailed_process_runner.h"
+#include "patchpanel/net_util.h"
+
+namespace patchpanel {
+namespace {
+// adb-proxy will connect to adbd on its standard TCP port.
+constexpr uint16_t kTcpConnectPort = 5555;
+constexpr uint32_t kTcpAddr = Ipv4Addr(100, 115, 92, 2);
+constexpr uint32_t kVsockPort = 5555;
+constexpr int kMaxConn = 16;
+// Reference: "device/google/cheets2/init.usb.rc".
+constexpr char kUnixConnectAddr[] = "/run/arc/adb/adb.sock";
+
+const std::set<GuestMessage::GuestType> kArcGuestTypes{GuestMessage::ARC,
+ GuestMessage::ARC_VM};
+} // namespace
+
+AdbProxy::AdbProxy(base::ScopedFD control_fd)
+ : msg_dispatcher_(std::move(control_fd)),
+ arc_type_(GuestMessage::UNKNOWN_GUEST),
+ arcvm_vsock_cid_(-1) {
+ msg_dispatcher_.RegisterFailureHandler(
+ base::Bind(&AdbProxy::OnParentProcessExit, weak_factory_.GetWeakPtr()));
+
+ msg_dispatcher_.RegisterGuestMessageHandler(
+ base::Bind(&AdbProxy::OnGuestMessage, weak_factory_.GetWeakPtr()));
+}
+
+AdbProxy::~AdbProxy() = default;
+
+int AdbProxy::OnInit() {
+ // Prevent the main process from sending us any signals.
+ if (setsid() < 0) {
+ PLOG(ERROR) << "Failed to created a new session with setsid; exiting";
+ return EX_OSERR;
+ }
+ EnterChildProcessJail();
+ return Daemon::OnInit();
+}
+
+void AdbProxy::Reset() {
+ src_watcher_.reset();
+ src_.reset();
+ fwd_.clear();
+ arcvm_vsock_cid_ = -1;
+ arc_type_ = GuestMessage::UNKNOWN_GUEST;
+}
+
+void AdbProxy::OnParentProcessExit() {
+ LOG(ERROR) << "Quitting because the parent process died";
+ Reset();
+ Quit();
+}
+
+void AdbProxy::OnFileCanReadWithoutBlocking() {
+ struct sockaddr_storage client_src = {};
+ socklen_t sockaddr_len = sizeof(client_src);
+ if (auto client_conn =
+ src_->Accept((struct sockaddr*)&client_src, &sockaddr_len)) {
+ LOG(INFO) << "new adb connection from " << client_src;
+ if (auto adbd_conn = Connect()) {
+ auto fwd = std::make_unique<SocketForwarder>(
+ base::StringPrintf("adbp%d-%d", client_conn->fd(), adbd_conn->fd()),
+ std::move(client_conn), std::move(adbd_conn));
+ fwd->Start();
+ fwd_.emplace_back(std::move(fwd));
+ }
+ }
+
+ // Cleanup any defunct forwarders.
+ for (auto it = fwd_.begin(); it != fwd_.end();) {
+ if (!(*it)->IsRunning() && (*it)->HasBeenStarted())
+ it = fwd_.erase(it);
+ else
+ ++it;
+ }
+}
+
+std::unique_ptr<Socket> AdbProxy::Connect() const {
+ switch (arc_type_) {
+ case GuestMessage::ARC: {
+ struct sockaddr_un addr_un = {0};
+ addr_un.sun_family = AF_UNIX;
+ snprintf(addr_un.sun_path, sizeof(addr_un.sun_path), "%s",
+ kUnixConnectAddr);
+ auto dst = std::make_unique<Socket>(AF_UNIX, SOCK_STREAM);
+ if (dst->Connect((const struct sockaddr*)&addr_un, sizeof(addr_un))) {
+ LOG(INFO) << "Established adbd connection to " << addr_un;
+ return dst;
+ }
+
+ LOG(WARNING) << "Failed to connect to UNIX domain socket: "
+ << kUnixConnectAddr << " - falling back to TCP";
+
+ struct sockaddr_in addr_in = {0};
+ addr_in.sin_family = AF_INET;
+ addr_in.sin_port = htons(kTcpConnectPort);
+ addr_in.sin_addr.s_addr = kTcpAddr;
+ dst = std::make_unique<Socket>(AF_INET, SOCK_STREAM);
+ if (!dst->Connect((const struct sockaddr*)&addr_in, sizeof(addr_in)))
+ return nullptr;
+ LOG(INFO) << "Established adbd connection to " << addr_in;
+ return dst;
+ }
+ case GuestMessage::ARC_VM: {
+ struct sockaddr_vm addr_vm = {0};
+ addr_vm.svm_family = AF_VSOCK;
+ addr_vm.svm_port = kVsockPort;
+ addr_vm.svm_cid = arcvm_vsock_cid_;
+ auto dst = std::make_unique<Socket>(AF_VSOCK, SOCK_STREAM);
+ if (!dst->Connect((const struct sockaddr*)&addr_vm, sizeof(addr_vm)))
+ return nullptr;
+ LOG(INFO) << "Established adbd connection to " << addr_vm;
+ return dst;
+ }
+ default:
+ LOG(DFATAL) << "Unexpected connect - no ARC guest";
+ return nullptr;
+ }
+}
+
+void AdbProxy::OnGuestMessage(const GuestMessage& msg) {
+ if (msg.type() == GuestMessage::UNKNOWN_GUEST) {
+ LOG(DFATAL) << "Unexpected message from unknown guest";
+ return;
+ }
+
+ if (kArcGuestTypes.find(msg.type()) == kArcGuestTypes.end()) {
+ return;
+ }
+
+ arc_type_ = msg.type();
+ arcvm_vsock_cid_ = msg.arcvm_vsock_cid();
+
+ // On ARC up, start accepting connections.
+ if (msg.event() == GuestMessage::START) {
+ src_ = std::make_unique<Socket>(AF_INET, SOCK_STREAM | SOCK_NONBLOCK);
+ // Need to set this to reuse the port on localhost.
+ int on = 1;
+ if (setsockopt(src_->fd(), SOL_SOCKET, SO_REUSEADDR, &on, sizeof(int)) <
+ 0) {
+ PLOG(ERROR) << "setsockopt(SO_REUSEADDR) failed";
+ return;
+ }
+ struct sockaddr_in addr = {0};
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(kAdbProxyTcpListenPort);
+ addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ if (!src_->Bind((const struct sockaddr*)&addr, sizeof(addr))) {
+ LOG(ERROR) << "Cannot bind source socket to " << addr;
+ return;
+ }
+
+ if (!src_->Listen(kMaxConn)) {
+ LOG(ERROR) << "Cannot listen on " << addr;
+ return;
+ }
+
+ // Run the accept loop.
+ LOG(INFO) << "Accepting connections on " << addr;
+ src_watcher_ = base::FileDescriptorWatcher::WatchReadable(
+ src_->fd(), base::BindRepeating(&AdbProxy::OnFileCanReadWithoutBlocking,
+ base::Unretained(this)));
+ return;
+ }
+
+ // On ARC down, cull any open connections and stop listening.
+ if (msg.event() == GuestMessage::STOP) {
+ Reset();
+ }
+}
+
+} // namespace patchpanel