blob: 0ffb0e2920ab8f26b28fa1ecb64eda76db642ac3 [file] [log] [blame]
// Copyright 2018 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 "arc/vm/vsock_proxy/client_proxy.h"
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
// Needs to be included after sys/socket.h
#include <linux/vm_sockets.h>
#include <utility>
#include <base/bind.h>
#include <base/files/file_path.h>
#include <base/logging.h>
#include <base/posix/eintr_wrapper.h>
#include "arc/vm/vsock_proxy/file_descriptor_util.h"
#include "arc/vm/vsock_proxy/message.pb.h"
#include "arc/vm/vsock_proxy/vsock_proxy.h"
namespace arc {
namespace {
// Path to the socket file for ArcBridgeService.
constexpr char kGuestSocketPath[] = "/var/run/chrome/arc_bridge.sock";
// Path to the socket file for ArcBridgeService in host.
constexpr char kHostSocketPath[] = "/run/chrome/arc_bridge.sock";
// Port for VSOCK.
constexpr unsigned int kVSockPort = 9900;
base::ScopedFD ConnectVSock() {
LOG(INFO) << "Creating VSOCK...";
struct sockaddr_vm sa = {};
sa.svm_family = AF_VSOCK;
sa.svm_cid = VMADDR_CID_HOST;
sa.svm_port = kVSockPort;
// TODO(hidehiko): Consider to time out.
while (true) {
base::ScopedFD fd(
socket(AF_VSOCK, SOCK_STREAM | SOCK_CLOEXEC, 0 /* protocol */));
if (!fd.is_valid()) {
PLOG(ERROR) << "Failed to create VSOCK";
return {};
}
LOG(INFO) << "Connecting VSOCK";
if (HANDLE_EINTR(connect(fd.get(),
reinterpret_cast<const struct sockaddr*>(&sa),
sizeof(sa))) == -1) {
fd.reset();
PLOG(ERROR) << "Failed to connect. Waiting and then retry...";
sleep(1); // Arbitrary wait.
continue;
}
LOG(INFO) << "VSOCK created.";
return fd;
}
}
} // namespace
ClientProxy::ClientProxy() = default;
ClientProxy::~ClientProxy() = default;
bool ClientProxy::Initialize() {
// For the details of connection procedure, please find the comment in
// ServerProxy::Initialize().
vsock_proxy_ = std::make_unique<VSockProxy>(VSockProxy::Type::CLIENT, nullptr,
ConnectVSock());
arc_bridge_socket_ = CreateUnixDomainSocket(base::FilePath(kGuestSocketPath));
if (!arc_bridge_socket_.is_valid())
return false;
LOG(INFO) << "Start observing " << kGuestSocketPath;
arc_bridge_socket_controller_ = base::FileDescriptorWatcher::WatchReadable(
arc_bridge_socket_.get(),
base::BindRepeating(&ClientProxy::OnLocalSocketReadReady,
weak_factory_.GetWeakPtr()));
return true;
}
void ClientProxy::OnLocalSocketReadReady() {
LOG(INFO) << "Initial socket connection comes";
arc_bridge_socket_controller_.reset();
vsock_proxy_->Connect(
base::FilePath(kHostSocketPath),
base::BindOnce(&ClientProxy::OnConnected, weak_factory_.GetWeakPtr()));
}
void ClientProxy::OnConnected(int error_code, int64_t handle) {
LOG(INFO) << "Connection in host is done: " << error_code;
if (error_code == 0) {
vsock_proxy_->RegisterFileDescriptor(AcceptSocket(arc_bridge_socket_.get()),
arc_proxy::FileDescriptor::SOCKET,
handle);
LOG(INFO) << "ClientProxy has started to work.";
}
arc_bridge_socket_.reset();
}
} // namespace arc