blob: 9754e29c6c13213ebffc2c7535e54f03ec4036b7 [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 "system-proxy/server_proxy.h"
#include <iostream>
#include <string>
#include <utility>
#include <vector>
#include <base/bind.h>
#include <base/bind_helpers.h>
#include <base/callback_helpers.h>
#include <base/posix/eintr_wrapper.h>
#include <base/files/file_util.h>
#include <base/threading/thread.h>
#include <base/threading/thread_task_runner_handle.h>
#include "bindings/worker_common.pb.h"
#include "system-proxy/protobuf_util.h"
namespace system_proxy {
namespace {
const int kMaxConn = 1000;
} // namespace
ServerProxy::ServerProxy(base::OnceClosure quit_closure)
: quit_closure_(std::move(quit_closure)) {}
void ServerProxy::Init() {
// Start listening for input.
stdin_watcher_ = base::FileDescriptorWatcher::WatchReadable(
GetStdinPipe(),
base::Bind(&ServerProxy::HandleStdinReadable, base::Unretained(this)));
// Handle termination signals.
signal_handler_.Init();
for (int signal : {SIGINT, SIGTERM, SIGHUP, SIGQUIT}) {
signal_handler_.RegisterHandler(
signal, base::BindRepeating(&ServerProxy::HandleSignal,
base::Unretained(this)));
}
}
ServerProxy::~ServerProxy() = default;
void ServerProxy::HandleStdinReadable() {
WorkerConfigs config;
if (!ReadProtobuf(GetStdinPipe(), &config)) {
LOG(ERROR) << "Error decoding protobuf configurations." << std::endl;
return;
}
if (config.has_credentials()) {
username_ = config.credentials().username();
password_ = config.credentials().password();
}
if (config.has_listening_address()) {
if (listening_addr_ != 0) {
LOG(ERROR)
<< "Failure to set configurations: listening port was already set."
<< std::endl;
return;
}
listening_addr_ = config.listening_address().addr();
listening_port_ = config.listening_address().port();
CreateListeningSocket();
}
}
bool ServerProxy::HandleSignal(const struct signalfd_siginfo& siginfo) {
base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
std::move(quit_closure_));
return true;
}
int ServerProxy::GetStdinPipe() {
return STDIN_FILENO;
}
void ServerProxy::CreateListeningSocket() {
listening_fd_ = std::make_unique<arc_networkd::Socket>(
AF_INET, SOCK_STREAM | SOCK_NONBLOCK);
struct sockaddr_in addr = {0};
addr.sin_family = AF_INET;
addr.sin_port = htons(listening_port_);
addr.sin_addr.s_addr = listening_addr_;
if (!listening_fd_->Bind((const struct sockaddr*)&addr, sizeof(addr))) {
LOG(ERROR) << "Cannot bind source socket" << std::endl;
return;
}
if (!listening_fd_->Listen(kMaxConn)) {
LOG(ERROR) << "Cannot listen on source socket." << std::endl;
return;
}
fd_watcher_ = base::FileDescriptorWatcher::WatchReadable(
listening_fd_->fd(),
base::BindRepeating(&ServerProxy::OnConnectionRequest,
base::Unretained(this)));
}
void ServerProxy::OnConnectionRequest() {
struct sockaddr_storage client_src = {};
socklen_t sockaddr_len = sizeof(client_src);
if (auto client_conn =
listening_fd_->Accept((struct sockaddr*)&client_src, &sockaddr_len)) {
// TODO(acostinas,chromium:1042626): Do curl authentication.
}
}
} // namespace system_proxy