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