1 //
2 // Copyright (C) 2022 The Android Open Source Project
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 // http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15
16 #include <chrono>
17 #include <set>
18 #include <thread>
19
20 #include "common/frontend/socket_vsock_proxy/server.h"
21 #include "common/libs/utils/contains.h"
22
23 namespace cuttlefish {
24 namespace socket_proxy {
25 namespace {
26
socketErrorIsRecoverable(int error)27 bool socketErrorIsRecoverable(int error) {
28 std::set<int> unrecoverable{EACCES, EAFNOSUPPORT, EINVAL, EPROTONOSUPPORT, EADDRINUSE};
29 return !Contains(unrecoverable, error);
30 }
31
SleepForever()32 [[noreturn]] static void SleepForever() {
33 while (true) {
34 sleep(std::numeric_limits<unsigned int>::max());
35 }
36 }
37
38 }
39
TcpServer(int port,int retries_count,std::chrono::milliseconds retries_delay)40 TcpServer::TcpServer(int port, int retries_count, std::chrono::milliseconds retries_delay)
41 : port_(port),
42 retries_count_(retries_count),
43 retries_delay_(retries_delay) {};
44
Start()45 Result<SharedFD> TcpServer::Start() {
46 SharedFD server;
47 int last_error = 0;
48
49 for (int i = 0; i < retries_count_; i++) {
50 server = SharedFD::SocketLocalServer(port_, SOCK_STREAM);
51 if (server->IsOpen()) {
52 return server;
53 }
54 last_error = server->GetErrno();
55
56 LOG(INFO) << "Failed to start TCP server on port: " << port_
57 << " after attempt #" << i + 1 << " (going to have "
58 << retries_count_ << " total attempts). Error: " << last_error;
59
60 std::this_thread::sleep_for(retries_delay_);
61 }
62
63 return CF_ERR("Could not start TCP server on port: " << port_
64 << "after " << retries_count_ << " attempts. Last error: " << last_error);
65 }
66
Describe() const67 std::string TcpServer::Describe() const {
68 return fmt::format("tcp: {}", port_);
69 }
70
VsockServer(int port,std::optional<int> vhost_user_vsock_cid)71 VsockServer::VsockServer(int port, std::optional<int> vhost_user_vsock_cid)
72 : port_(port), vhost_user_vsock_cid_(vhost_user_vsock_cid) {}
73
Start()74 Result<SharedFD> VsockServer::Start() {
75 SharedFD server;
76 do {
77 server = SharedFD::VsockServer(port_, SOCK_STREAM, vhost_user_vsock_cid_);
78 if (!server->IsOpen() && !socketErrorIsRecoverable(server->GetErrno())) {
79 LOG(ERROR) << "Could not open vsock socket: " << server->StrError();
80 // socket_vsock_proxy will now wait forever in the guest on encountering an
81 // "unrecoverable" errno. This is to prevent churn from being restarted by
82 // init.vsoc.rc.
83 SleepForever();
84 }
85 } while (!server->IsOpen());
86
87 return server;
88 }
89
Describe() const90 std::string VsockServer::Describe() const {
91 return fmt::format("vsock: {}", port_);
92 }
93
DupServer(int fd)94 DupServer::DupServer(int fd) : fd_(fd), sfd_(SharedFD::Dup(fd_)) {
95 close(fd);
96 }
97
Start()98 Result<SharedFD> DupServer::Start() {
99 CF_EXPECT(sfd_->IsOpen(), "Could not start duplicate server for passed fd");
100 return sfd_;
101 }
102
Describe() const103 std::string DupServer::Describe() const {
104 return fmt::format("fd: {}", fd_);
105 }
106
107 }
108 } // namespace cuttlefish
109