1 /*
2  * Copyright (C) 2018 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 
17 #include <set>
18 #include <thread>
19 #include <android-base/logging.h>
20 #include <gflags/gflags.h>
21 
22 #include "common/libs/fs/shared_fd.h"
23 
24 #ifdef CUTTLEFISH_HOST
25 #include "host/libs/config/logging.h"
26 #endif // CUTTLEFISH_HOST
27 
28 constexpr std::size_t kMaxPacketSize = 8192;
29 
30 DEFINE_string(server, "",
31               "The type of server to host, `vsock` or `tcp`. When hosting a server "
32               "of one type, the proxy will take inbound connections of this type and "
33               "make outbound connections of the other type.");
34 DEFINE_uint32(tcp_port, 0, "TCP port");
35 DEFINE_uint32(vsock_port, 0, "vsock port");
36 DEFINE_uint32(vsock_cid, 0, "Vsock cid to initiate connections to");
37 
38 namespace {
39 // Sends packets, Shutdown(SHUT_WR) on destruction
40 class SocketSender {
41  public:
SocketSender(cuttlefish::SharedFD socket)42   explicit SocketSender(cuttlefish::SharedFD socket) : socket_{socket} {}
43 
44   SocketSender(SocketSender&&) = default;
45   SocketSender& operator=(SocketSender&&) = default;
46 
47   SocketSender(const SocketSender&&) = delete;
48   SocketSender& operator=(const SocketSender&) = delete;
49 
~SocketSender()50   ~SocketSender() {
51     if (socket_.operator->()) {  // check that socket_ was not moved-from
52       socket_->Shutdown(SHUT_WR);
53     }
54   }
55 
SendAll(const char * packet,ssize_t length)56   ssize_t SendAll(const char* packet, ssize_t length) {
57     ssize_t written{};
58     while (written < length) {
59       if (!socket_->IsOpen()) {
60         return -1;
61       }
62       auto just_written =
63           socket_->Send(packet + written,
64                         length - written, MSG_NOSIGNAL);
65       if (just_written <= 0) {
66         LOG(WARNING) << "Couldn't write to client: "
67                      << strerror(socket_->GetErrno());
68         return just_written;
69       }
70       written += just_written;
71     }
72     return written;
73   }
74 
75  private:
76   cuttlefish::SharedFD socket_;
77 };
78 
79 class SocketReceiver {
80  public:
SocketReceiver(cuttlefish::SharedFD socket)81   explicit SocketReceiver(cuttlefish::SharedFD socket) : socket_{socket} {}
82 
83   SocketReceiver(SocketReceiver&&) = default;
84   SocketReceiver& operator=(SocketReceiver&&) = default;
85 
86   SocketReceiver(const SocketReceiver&&) = delete;
87   SocketReceiver& operator=(const SocketReceiver&) = delete;
88 
89   // return value will be 0 if Read returns 0 or error
Recv(char * packet,ssize_t length)90   ssize_t Recv(char* packet, ssize_t length) {
91     auto size = socket_->Read(packet, length);
92     if (size < 0) {
93       size = 0;
94     }
95 
96     return size;
97   }
98 
99  private:
100   cuttlefish::SharedFD socket_;
101 };
102 
SocketToVsock(SocketReceiver socket_receiver,SocketSender vsock_sender)103 void SocketToVsock(SocketReceiver socket_receiver,
104                    SocketSender vsock_sender) {
105   char packet[kMaxPacketSize] = {};
106 
107   while (true) {
108     ssize_t length = socket_receiver.Recv(packet, kMaxPacketSize);
109     if (length == 0 || vsock_sender.SendAll(packet, length) < 0) {
110       break;
111     }
112   }
113   LOG(DEBUG) << "Socket to vsock exiting";
114 }
115 
VsockToSocket(SocketSender socket_sender,SocketReceiver vsock_receiver)116 void VsockToSocket(SocketSender socket_sender,
117                    SocketReceiver vsock_receiver) {
118   char packet[kMaxPacketSize] = {};
119 
120   while (true) {
121     ssize_t length = vsock_receiver.Recv(packet, kMaxPacketSize);
122     if (length == 0) {
123       break;
124     }
125     if (socket_sender.SendAll(packet, length) < 0) {
126       break;
127     }
128   }
129   LOG(DEBUG) << "Vsock to socket exiting";
130 }
131 
132 // One thread for reading from shm and writing into a socket.
133 // One thread for reading from a socket and writing into shm.
HandleConnection(cuttlefish::SharedFD vsock,cuttlefish::SharedFD socket)134 void HandleConnection(cuttlefish::SharedFD vsock,
135                       cuttlefish::SharedFD socket) {
136   auto socket_to_vsock =
137       std::thread(SocketToVsock, SocketReceiver{socket}, SocketSender{vsock});
138   VsockToSocket(SocketSender{socket}, SocketReceiver{vsock});
139   socket_to_vsock.join();
140 }
141 
TcpServer()142 [[noreturn]] void TcpServer() {
143   LOG(DEBUG) << "starting TCP server on " << FLAGS_tcp_port
144              << " for vsock port " << FLAGS_vsock_port;
145   auto server = cuttlefish::SharedFD::SocketLocalServer(FLAGS_tcp_port, SOCK_STREAM);
146   CHECK(server->IsOpen()) << "Could not start server on " << FLAGS_tcp_port;
147   LOG(DEBUG) << "Accepting client connections";
148   int last_failure_reason = 0;
149   while (true) {
150     auto client_socket = cuttlefish::SharedFD::Accept(*server);
151     CHECK(client_socket->IsOpen()) << "error creating client socket";
152     cuttlefish::SharedFD vsock_socket = cuttlefish::SharedFD::VsockClient(
153         FLAGS_vsock_cid, FLAGS_vsock_port, SOCK_STREAM);
154     if (vsock_socket->IsOpen()) {
155       last_failure_reason = 0;
156       LOG(DEBUG) << "Connected to vsock:" << FLAGS_vsock_cid << ":"
157                  << FLAGS_vsock_port;
158     } else {
159       // Don't log if the previous connection failed with the same error
160       if (last_failure_reason != vsock_socket->GetErrno()) {
161         last_failure_reason = vsock_socket->GetErrno();
162         LOG(ERROR) << "Unable to connect to vsock server: "
163                    << vsock_socket->StrError();
164       }
165       continue;
166     }
167     auto thread = std::thread(HandleConnection, std::move(vsock_socket),
168                               std::move(client_socket));
169     thread.detach();
170   }
171 }
172 
OpenSocketConnection()173 cuttlefish::SharedFD OpenSocketConnection() {
174   while (true) {
175     auto sock = cuttlefish::SharedFD::SocketLocalClient(FLAGS_tcp_port, SOCK_STREAM);
176     if (sock->IsOpen()) {
177       return sock;
178     }
179     LOG(WARNING) << "could not connect on port " << FLAGS_tcp_port
180                  << ". sleeping for 1 second";
181     sleep(1);
182   }
183 }
184 
socketErrorIsRecoverable(int error)185 bool socketErrorIsRecoverable(int error) {
186   std::set<int> unrecoverable{EACCES, EAFNOSUPPORT, EINVAL, EPROTONOSUPPORT};
187   return unrecoverable.find(error) == unrecoverable.end();
188 }
189 
SleepForever()190 [[noreturn]] static void SleepForever() {
191   while (true) {
192     sleep(std::numeric_limits<unsigned int>::max());
193   }
194 }
195 
VsockServer()196 [[noreturn]] void VsockServer() {
197   LOG(DEBUG) << "Starting vsock server on " << FLAGS_vsock_port;
198   cuttlefish::SharedFD vsock;
199   do {
200     vsock = cuttlefish::SharedFD::VsockServer(FLAGS_vsock_port, SOCK_STREAM);
201     if (!vsock->IsOpen() && !socketErrorIsRecoverable(vsock->GetErrno())) {
202       LOG(ERROR) << "Could not open vsock socket: " << vsock->StrError();
203       SleepForever();
204     }
205   } while (!vsock->IsOpen());
206   CHECK(vsock->IsOpen()) << "Could not start server on " << FLAGS_vsock_port;
207   while (true) {
208     LOG(DEBUG) << "waiting for vsock connection";
209     auto vsock_client = cuttlefish::SharedFD::Accept(*vsock);
210     CHECK(vsock_client->IsOpen()) << "error creating vsock socket";
211     LOG(DEBUG) << "vsock socket accepted";
212     auto client = OpenSocketConnection();
213     CHECK(client->IsOpen()) << "error connecting to guest client";
214     auto thread = std::thread(HandleConnection, std::move(vsock_client),
215                               std::move(client));
216     thread.detach();
217   }
218 }
219 
220 }  // namespace
221 
main(int argc,char * argv[])222 int main(int argc, char* argv[]) {
223 #ifdef CUTTLEFISH_HOST
224   cuttlefish::DefaultSubprocessLogging(argv);
225 #else
226   ::android::base::InitLogging(argv, android::base::LogdLogger());
227 #endif
228   google::ParseCommandLineFlags(&argc, &argv, true);
229 
230   CHECK(FLAGS_tcp_port != 0) << "Must specify -tcp_port flag";
231   CHECK(FLAGS_vsock_port != 0) << "Must specify -vsock_port flag";
232   if (FLAGS_server == "tcp") {
233     CHECK(FLAGS_vsock_cid != 0) << "Must specify -vsock_cid flag";
234     TcpServer();
235   } else if (FLAGS_server == "vsock") {
236     VsockServer();
237   } else {
238     LOG(FATAL) << "Unknown server type: " << FLAGS_server;
239   }
240 }
241