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