blob: 5d08790bf241f1828275cd73b2b5f440f6d1d1ef [file] [log] [blame]
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <set>
#include <android-base/logging.h>
#include <gflags/gflags.h>
#include "common/libs/fs/shared_fd.h"
#include "common/libs/utils/socket2socket_proxy.h"
#include "host/commands/kernel_log_monitor/utils.h"
#ifdef CUTTLEFISH_HOST
#include "host/libs/config/logging.h"
#endif // CUTTLEFISH_HOST
DEFINE_string(server, "",
"The type of server to host, `vsock` or `tcp`. When hosting a server "
"of one type, the proxy will take inbound connections of this type and "
"make outbound connections of the other type.");
DEFINE_uint32(tcp_port, 0, "TCP port");
DEFINE_uint32(vsock_port, 0, "vsock port");
DEFINE_uint32(vsock_cid, 0, "Vsock cid to initiate connections to");
DEFINE_int32(adbd_events_fd, -1, "A file descriptor. If set it will wait for "
"AdbdStarted boot event from the kernel log "
"monitor before creating a tcp-vsock tunnel."
"This option is used by --server=tcp only "
"when socket_vsock_proxy runs as a host service");
DEFINE_int32(
server_fd, -1,
"A file descriptor. If set the passed file descriptor will be used as the "
"server and the corresponding port flag will be ignored");
namespace {
void WaitForAdbdToBeStarted(int events_fd) {
auto evt_shared_fd = cuttlefish::SharedFD::Dup(events_fd);
close(events_fd);
while (evt_shared_fd->IsOpen()) {
std::optional<monitor::ReadEventResult> read_result =
monitor::ReadEvent(evt_shared_fd);
if (!read_result) {
LOG(ERROR) << "Failed to read a complete kernel log adb event.";
// The file descriptor can't be trusted anymore, stop waiting and try to
// connect
return;
}
if (read_result->event == monitor::Event::AdbdStarted) {
LOG(DEBUG) << "Adbd has started in the guest, connecting adb";
return;
}
}
}
// intented to run as cuttlefish host service
void TcpServer() {
LOG(DEBUG) << "starting TCP server on " << FLAGS_tcp_port
<< " for vsock port " << FLAGS_vsock_port;
cuttlefish::SharedFD server;
if (FLAGS_server_fd < 0) {
server =
cuttlefish::SharedFD::SocketLocalServer(FLAGS_tcp_port, SOCK_STREAM);
} else {
server = cuttlefish::SharedFD::Dup(FLAGS_server_fd);
close(FLAGS_server_fd);
}
CHECK(server->IsOpen()) << "Could not start server on " << FLAGS_tcp_port;
LOG(DEBUG) << "Accepting client connections";
int last_failure_reason = 0;
cuttlefish::Proxy(server, [&last_failure_reason]() {
auto vsock_socket = cuttlefish::SharedFD::VsockClient(
FLAGS_vsock_cid, FLAGS_vsock_port, SOCK_STREAM);
if (vsock_socket->IsOpen()) {
last_failure_reason = 0;
LOG(DEBUG) << "Connected to vsock:" << FLAGS_vsock_cid << ":"
<< FLAGS_vsock_port;
} else {
// Don't log if the previous connection failed with the same error
if (last_failure_reason != vsock_socket->GetErrno()) {
last_failure_reason = vsock_socket->GetErrno();
LOG(ERROR) << "Unable to connect to vsock server: "
<< vsock_socket->StrError();
}
}
return vsock_socket;
});
}
cuttlefish::SharedFD OpenSocketConnection() {
while (true) {
auto sock = cuttlefish::SharedFD::SocketLocalClient(FLAGS_tcp_port, SOCK_STREAM);
if (sock->IsOpen()) {
return sock;
}
LOG(WARNING) << "could not connect on port " << FLAGS_tcp_port
<< ". sleeping for 1 second";
sleep(1);
}
}
bool socketErrorIsRecoverable(int error) {
std::set<int> unrecoverable{EACCES, EAFNOSUPPORT, EINVAL, EPROTONOSUPPORT};
return unrecoverable.find(error) == unrecoverable.end();
}
[[noreturn]] static void SleepForever() {
while (true) {
sleep(std::numeric_limits<unsigned int>::max());
}
}
// intended to run inside Android guest
void VsockServer() {
LOG(DEBUG) << "Starting vsock server on " << FLAGS_vsock_port;
cuttlefish::SharedFD vsock;
if (FLAGS_server_fd < 0) {
do {
vsock = cuttlefish::SharedFD::VsockServer(FLAGS_vsock_port, SOCK_STREAM);
if (!vsock->IsOpen() && !socketErrorIsRecoverable(vsock->GetErrno())) {
LOG(ERROR) << "Could not open vsock socket: " << vsock->StrError();
SleepForever();
}
} while (!vsock->IsOpen());
} else {
vsock = cuttlefish::SharedFD::Dup(FLAGS_server_fd);
close(FLAGS_server_fd);
}
CHECK(vsock->IsOpen()) << "Could not start server on " << FLAGS_vsock_port;
cuttlefish::Proxy(vsock, []() {
LOG(DEBUG) << "vsock socket accepted";
auto client = OpenSocketConnection();
CHECK(client->IsOpen()) << "error connecting to guest client";
return client;
});
}
} // namespace
int main(int argc, char* argv[]) {
#ifdef CUTTLEFISH_HOST
cuttlefish::DefaultSubprocessLogging(argv);
#else
::android::base::InitLogging(argv, android::base::LogdLogger());
#endif
google::ParseCommandLineFlags(&argc, &argv, true);
CHECK((FLAGS_server == "tcp" && FLAGS_server_fd >= 0) || FLAGS_tcp_port != 0)
<< "Must specify -tcp_port or -server_fd (with -server=tcp) flag";
CHECK((FLAGS_server == "vsock" && FLAGS_server_fd >= 0) ||
FLAGS_vsock_port != 0)
<< "Must specify -vsock_port or -server_fd (with -server=vsock) flag";
if (FLAGS_adbd_events_fd >= 0) {
LOG(DEBUG) << "Wating AdbdStarted boot event from the kernel log";
WaitForAdbdToBeStarted(FLAGS_adbd_events_fd);
}
if (FLAGS_server == "tcp") {
CHECK(FLAGS_vsock_cid != 0) << "Must specify -vsock_cid flag";
TcpServer();
} else if (FLAGS_server == "vsock") {
VsockServer();
} else {
LOG(FATAL) << "Unknown server type: " << FLAGS_server;
}
}