blob: 5cdea609e411471b32b46ad1b0672b75b2f336c4 [file] [log] [blame]
/*
* Copyright 2020 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/adbd/arcvm_usb_to_sock.h"
#include <fcntl.h>
#include <unistd.h>
#include <vector>
#include <base/bind.h>
#include <base/files/file_util.h>
#include <base/logging.h>
#include <base/posix/eintr_wrapper.h>
namespace adbd {
namespace {
// Size of the buffer read from USB (OUT) endpoint.
constexpr size_t kUsbReadBufSize = 4 * 1024;
} // namespace
ArcVmUsbToSock::ArcVmUsbToSock(const int sock_fd, const int usb_fd)
: sock_fd_(sock_fd), usb_fd_(usb_fd), thread_("usb->sock") {
DCHECK_GE(sock_fd_, 0);
DCHECK_GE(usb_fd_, 0);
}
ArcVmUsbToSock::~ArcVmUsbToSock() = default;
bool ArcVmUsbToSock::Start() {
if (!thread_.StartWithOptions(
base::Thread::Options(base::MessagePumpType::IO, 0))) {
LOG(ERROR) << "Failed to start thread";
return false;
}
if (!thread_.task_runner()->PostTask(
FROM_HERE,
base::BindOnce(&ArcVmUsbToSock::Run, base::Unretained(this)))) {
LOG(ERROR) << "Failed to dispatch task to thread";
return false;
}
LOG(INFO) << "ArcVmUsbToSock started";
return true;
}
void ArcVmUsbToSock::Run() {
std::vector<char> buf(kUsbReadBufSize);
// Most of the time we will be blocked in reading from USB
// Process any data pending in the buffer first before pull
// more from USB endpoint.
while (true) {
char* data = buf.data();
auto ret = HANDLE_EINTR(read(usb_fd_, data, kUsbReadBufSize));
if (ret < 0) {
PLOG(ERROR) << "failed to read from usb endpoint";
// When any channel broke, there is no point to keep the whole bridge
// service, so we just quit the whole service and rely on the outside
// to restart the service.
break;
}
if (ret && !base::WriteFileDescriptor(sock_fd_, data, ret)) {
PLOG(ERROR) << "failed to write to socket";
break;
}
}
_exit(EXIT_FAILURE);
}
} // namespace adbd