/* * 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 #include #include #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 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 unrecoverable{EACCES, EAFNOSUPPORT, EINVAL, EPROTONOSUPPORT}; return unrecoverable.find(error) == unrecoverable.end(); } [[noreturn]] static void SleepForever() { while (true) { sleep(std::numeric_limits::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; } }