blob: ac421a3919f24b9da5f901317d1c57498a8313d3 [file] [log] [blame]
Cody Schuffelenfa69c382018-12-17 18:57:36 -08001/*
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
Cody Schuffelen3ee23ab2019-01-15 17:22:35 -080017#include <set>
Cody Schuffelenfa69c382018-12-17 18:57:36 -080018#include <thread>
19#include <glog/logging.h>
20#include <gflags/gflags.h>
21
22#include "common/libs/fs/shared_fd.h"
Cody Schuffelen134ff032019-11-22 00:25:32 -080023#include "common/vsoc/lib/socket_forward_region_view.h"
Cody Schuffelenfa69c382018-12-17 18:57:36 -080024
25#ifdef CUTTLEFISH_HOST
26#include "host/libs/config/cuttlefish_config.h"
27#endif
28
Cody Schuffelen134ff032019-11-22 00:25:32 -080029using vsoc::socket_forward::Packet;
Cody Schuffelenfa69c382018-12-17 18:57:36 -080030
Cody Schuffelen27163842019-02-07 15:36:51 -080031DEFINE_uint32(tcp_port, 0, "TCP port (server on host, client on guest)");
32DEFINE_uint32(vsock_port, 0, "vsock port (client on host, server on guest");
Cody Schuffelenfa69c382018-12-17 18:57:36 -080033DEFINE_uint32(vsock_guest_cid, 0, "Guest identifier");
Cody Schuffelenfa69c382018-12-17 18:57:36 -080034
35namespace {
36// Sends packets, Shutdown(SHUT_WR) on destruction
37class SocketSender {
38 public:
39 explicit SocketSender(cvd::SharedFD socket) : socket_{socket} {}
40
41 SocketSender(SocketSender&&) = default;
42 SocketSender& operator=(SocketSender&&) = default;
43
44 SocketSender(const SocketSender&&) = delete;
45 SocketSender& operator=(const SocketSender&) = delete;
46
47 ~SocketSender() {
48 if (socket_.operator->()) { // check that socket_ was not moved-from
49 socket_->Shutdown(SHUT_WR);
50 }
51 }
52
53 ssize_t SendAll(const Packet& packet) {
54 ssize_t written{};
55 while (written < static_cast<ssize_t>(packet.payload_length())) {
56 if (!socket_->IsOpen()) {
57 return -1;
58 }
59 auto just_written =
60 socket_->Send(packet.payload() + written,
61 packet.payload_length() - written, MSG_NOSIGNAL);
62 if (just_written <= 0) {
63 LOG(INFO) << "Couldn't write to client: "
64 << strerror(socket_->GetErrno());
65 return just_written;
66 }
67 written += just_written;
68 }
69 return written;
70 }
71
72 private:
73 cvd::SharedFD socket_;
74};
75
76class SocketReceiver {
77 public:
78 explicit SocketReceiver(cvd::SharedFD socket) : socket_{socket} {}
79
80 SocketReceiver(SocketReceiver&&) = default;
81 SocketReceiver& operator=(SocketReceiver&&) = default;
82
83 SocketReceiver(const SocketReceiver&&) = delete;
84 SocketReceiver& operator=(const SocketReceiver&) = delete;
85
86 // *packet will be empty if Read returns 0 or error
87 void Recv(Packet* packet) {
88 auto size = socket_->Read(packet->payload(), sizeof packet->payload());
89 if (size < 0) {
90 size = 0;
91 }
92 packet->set_payload_length(size);
93 }
94
95 private:
96 cvd::SharedFD socket_;
97};
98
99void SocketToVsock(SocketReceiver socket_receiver,
100 SocketSender vsock_sender) {
101 while (true) {
102 auto packet = Packet::MakeData();
103 socket_receiver.Recv(&packet);
104 if (packet.empty() || vsock_sender.SendAll(packet) < 0) {
105 break;
106 }
107 }
108 LOG(INFO) << "Socket to vsock exiting";
109}
110
111void VsockToSocket(SocketSender socket_sender,
112 SocketReceiver vsock_receiver) {
113 auto packet = Packet::MakeData();
114 while (true) {
115 vsock_receiver.Recv(&packet);
116 CHECK(packet.IsData());
117 if (packet.empty()) {
118 break;
119 }
120 if (socket_sender.SendAll(packet) < 0) {
121 break;
122 }
123 }
124 LOG(INFO) << "Vsock to socket exiting";
125}
126
127// One thread for reading from shm and writing into a socket.
128// One thread for reading from a socket and writing into shm.
129void HandleConnection(cvd::SharedFD vsock,
130 cvd::SharedFD socket) {
131 auto socket_to_vsock =
132 std::thread(SocketToVsock, SocketReceiver{socket}, SocketSender{vsock});
133 VsockToSocket(SocketSender{socket}, SocketReceiver{vsock});
134 socket_to_vsock.join();
135}
136
137#ifdef CUTTLEFISH_HOST
138[[noreturn]] void host() {
Cody Schuffelen27163842019-02-07 15:36:51 -0800139 LOG(INFO) << "starting server on " << FLAGS_tcp_port << " for vsock port "
140 << FLAGS_vsock_port;
141 auto server = cvd::SharedFD::SocketLocalServer(FLAGS_tcp_port, SOCK_STREAM);
142 CHECK(server->IsOpen()) << "Could not start server on " << FLAGS_tcp_port;
Jorge E. Moreiraf15975c2019-03-26 17:44:14 -0700143 LOG(INFO) << "Accepting client connections";
144 int last_failure_reason = 0;
Cody Schuffelenfa69c382018-12-17 18:57:36 -0800145 while (true) {
Cody Schuffelenfa69c382018-12-17 18:57:36 -0800146 auto client_socket = cvd::SharedFD::Accept(*server);
147 CHECK(client_socket->IsOpen()) << "error creating client socket";
Cody Schuffelen3ee23ab2019-01-15 17:22:35 -0800148 cvd::SharedFD vsock_socket = cvd::SharedFD::VsockClient(
Cody Schuffelen27163842019-02-07 15:36:51 -0800149 FLAGS_vsock_guest_cid, FLAGS_vsock_port, SOCK_STREAM);
Jorge E. Moreiraf15975c2019-03-26 17:44:14 -0700150 if (vsock_socket->IsOpen()) {
151 last_failure_reason = 0;
152 LOG(INFO) << "Connected to vsock:" << FLAGS_vsock_guest_cid << ":"
153 << FLAGS_vsock_port;
154 } else {
155 // Don't log if the previous connection failed with the same error
156 if (last_failure_reason != vsock_socket->GetErrno()) {
157 last_failure_reason = vsock_socket->GetErrno();
158 LOG(ERROR) << "Unable to connect to vsock server: "
159 << vsock_socket->StrError();
160 }
Cody Schuffelen3ee23ab2019-01-15 17:22:35 -0800161 continue;
162 }
Cody Schuffelenfa69c382018-12-17 18:57:36 -0800163 auto thread = std::thread(HandleConnection, std::move(vsock_socket),
164 std::move(client_socket));
165 thread.detach();
166 }
167}
168
169#else
170cvd::SharedFD OpenSocketConnection() {
171 while (true) {
Cody Schuffelen27163842019-02-07 15:36:51 -0800172 auto sock = cvd::SharedFD::SocketLocalClient(FLAGS_tcp_port, SOCK_STREAM);
Cody Schuffelenfa69c382018-12-17 18:57:36 -0800173 if (sock->IsOpen()) {
174 return sock;
175 }
Cody Schuffelen27163842019-02-07 15:36:51 -0800176 LOG(WARNING) << "could not connect on port " << FLAGS_tcp_port
Cody Schuffelenfa69c382018-12-17 18:57:36 -0800177 << ". sleeping for 1 second";
178 sleep(1);
179 }
180}
181
Cody Schuffelen3ee23ab2019-01-15 17:22:35 -0800182bool socketErrorIsRecoverable(int error) {
183 std::set<int> unrecoverable{EACCES, EAFNOSUPPORT, EINVAL, EPROTONOSUPPORT};
184 return unrecoverable.find(error) == unrecoverable.end();
185}
186
187[[noreturn]] static void SleepForever() {
188 while (true) {
189 sleep(std::numeric_limits<unsigned int>::max());
190 }
191}
192
Cody Schuffelenfa69c382018-12-17 18:57:36 -0800193[[noreturn]] void guest() {
194 LOG(INFO) << "Starting guest mainloop";
Cody Schuffelen27163842019-02-07 15:36:51 -0800195 LOG(INFO) << "starting server on " << FLAGS_vsock_port;
Cody Schuffelen3ee23ab2019-01-15 17:22:35 -0800196 cvd::SharedFD vsock;
197 do {
Cody Schuffelen27163842019-02-07 15:36:51 -0800198 vsock = cvd::SharedFD::VsockServer(FLAGS_vsock_port, SOCK_STREAM);
Cody Schuffelen3ee23ab2019-01-15 17:22:35 -0800199 if (!vsock->IsOpen() && !socketErrorIsRecoverable(vsock->GetErrno())) {
200 LOG(ERROR) << "Could not open vsock socket: " << vsock->StrError();
201 SleepForever();
202 }
203 } while (!vsock->IsOpen());
Cody Schuffelen27163842019-02-07 15:36:51 -0800204 CHECK(vsock->IsOpen()) << "Could not start server on " << FLAGS_vsock_port;
Cody Schuffelenfa69c382018-12-17 18:57:36 -0800205 while (true) {
206 LOG(INFO) << "waiting for vsock connection";
207 auto vsock_client = cvd::SharedFD::Accept(*vsock);
208 CHECK(vsock_client->IsOpen()) << "error creating vsock socket";
209 LOG(INFO) << "vsock socket accepted";
210 auto client = OpenSocketConnection();
211 CHECK(client->IsOpen()) << "error connecting to guest client";
212 auto thread = std::thread(HandleConnection, std::move(vsock_client),
213 std::move(client));
214 thread.detach();
215 }
216}
217
218#endif
219} // namespace
220
221int main(int argc, char* argv[]) {
222 gflags::ParseCommandLineFlags(&argc, &argv, true);
223
Cody Schuffelen27163842019-02-07 15:36:51 -0800224 CHECK(FLAGS_tcp_port != 0) << "Must specify -tcp_port flag";
225 CHECK(FLAGS_vsock_port != 0) << "Must specify -vsock_port flag";
Cody Schuffelenfa69c382018-12-17 18:57:36 -0800226#ifdef CUTTLEFISH_HOST
Cody Schuffelen27163842019-02-07 15:36:51 -0800227 CHECK(FLAGS_vsock_guest_cid != 0) << "Must specify -vsock_guest_cid flag";
Cody Schuffelenfa69c382018-12-17 18:57:36 -0800228 host();
229#else
230 guest();
231#endif
232}