blob: 48b97f33b0e1c3890f970462f483df40f0f4a964 [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 <fcntl.h>
#include <sys/socket.h>
#include <unistd.h>
#include <linux/vm_sockets.h> // Needs to come after sys/socket.h
#include <base/files/file_util.h>
#include <base/files/scoped_file.h>
#include <base/logging.h>
#include <base/posix/eintr_wrapper.h>
#include <base/time/time.h>
#include <brillo/syslog_logging.h>
#include <chromeos/constants/vm_tools.h>
int main(int argc, char* argv[]) {
brillo::InitLog(brillo::kLogToSyslog | brillo::kLogHeader |
brillo::kLogToStderrIfTty);
// Set realtime priority. 10 is the same value as vm_concierge.
const struct sched_param param = {
.sched_priority = 10,
};
PCHECK(sched_setscheduler(0, SCHED_RR, &param) == 0);
base::ScopedFD listen_fd(socket(AF_VSOCK, SOCK_STREAM | SOCK_CLOEXEC, 0));
PCHECK(listen_fd.is_valid());
constexpr struct sockaddr_vm addr = {
.svm_family = AF_VSOCK,
.svm_port = vm_tools::kArcHostClockServicePort,
.svm_cid = VMADDR_CID_ANY,
};
PCHECK(bind(listen_fd.get(), reinterpret_cast<const struct sockaddr*>(&addr),
sizeof(addr)) == 0);
PCHECK(listen(listen_fd.get(), 1) == 0);
// Keep accepting incoming connection.
while (true) {
struct sockaddr_vm addr = {};
socklen_t addr_size = sizeof(addr);
base::ScopedFD fd(HANDLE_EINTR(
accept4(listen_fd.get(), reinterpret_cast<struct sockaddr*>(&addr),
&addr_size, SOCK_CLOEXEC)));
PCHECK(fd.is_valid());
// Keep receiving clockid and returning the corresponding clock value.
while (true) {
// Maximum number of messages processed in a batch. Chosen arbitrarily.
constexpr int kNumElements = 16;
clockid_t message[kNumElements];
size_t num_bytes = 0;
bool read_success = false;
while (!read_success) {
auto buf = reinterpret_cast<char*>(message) + num_bytes;
size_t buf_remaining = sizeof(message) - num_bytes;
ssize_t res = HANDLE_EINTR(read(fd.get(), buf, buf_remaining));
if (res <= 0) {
LOG(ERROR) << "Read failed: num_bytes = " << num_bytes << " "
<< (res < 0 ? logging::SystemErrorCodeToString(
logging::GetLastSystemErrorCode())
: "incomplete message");
break;
}
num_bytes += res;
read_success = num_bytes % sizeof(message[0]) == 0;
}
if (!read_success)
break;
const size_t num_requests = num_bytes / sizeof(message[0]);
int64_t response[kNumElements];
bool error = false;
for (size_t idx = 0; idx < num_requests; ++idx) {
struct timespec ts = {};
if (clock_gettime(message[idx], &ts) != 0) {
PLOG(ERROR) << "clock_gettime failed: clock_id = " << message[idx];
error = true;
break;
}
response[idx] =
ts.tv_sec * base::Time::kNanosecondsPerSecond + ts.tv_nsec;
}
if (error)
break;
if (!base::WriteFileDescriptor(fd.get(),
reinterpret_cast<const char*>(&response),
num_requests * sizeof(response[0]))) {
PLOG(ERROR) << "WriteFileDescriptor failed.";
break;
}
}
}
}