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 <signal.h>
18 #include <android-base/logging.h>
19 #include <gflags/gflags.h>
20
21 #include <chrono>
22 #include <memory>
23 #include <sstream>
24
25 #include "common/frontend/socket_vsock_proxy/client.h"
26 #include "common/frontend/socket_vsock_proxy/server.h"
27 #include "common/libs/fs/shared_fd.h"
28 #include "common/libs/utils/result.h"
29 #include "common/libs/utils/socket2socket_proxy.h"
30 #include "common/libs/utils/tee_logging.h"
31 #include "host/commands/kernel_log_monitor/utils.h"
32
33 #ifdef CUTTLEFISH_HOST
34 #include "host/libs/config/cuttlefish_config.h"
35 #include "host/libs/config/logging.h"
36 #endif // CUTTLEFISH_HOST
37
38 constexpr int TCP_SERVER_START_RETRIES_COUNT = 10;
39 constexpr std::chrono::milliseconds TCP_SERVER_RETRIES_DELAY(1250);
40 constexpr std::chrono::seconds TCP_CLIENT_TIMEOUT(1);
41
42 constexpr char TRANSPORT_TCP[] = "tcp";
43 constexpr char TRANSPORT_VSOCK[] = "vsock";
44
45 DEFINE_string(label, "socket_vsock_proxy", "Label which is used only for logging. "
46 "Log messages will look like [label] message");
47 DEFINE_string(server_type, "", "The type of server to host, `vsock` or `tcp`.");
48 DEFINE_string(client_type, "", "The type of server to host, `vsock` or `tcp`.");
49 DEFINE_uint32(server_tcp_port, 0, "Server TCP port");
50 DEFINE_string(client_tcp_host, "localhost", "Client TCP host (default localhost)");
51 DEFINE_uint32(client_tcp_port, 0, "Client TCP port");
52 DEFINE_uint32(server_vsock_port, 0, "vsock port");
53 DEFINE_uint32(server_vsock_id, 0, "Vsock cid which server listens to");
54 DEFINE_uint32(client_vsock_id, 0, "Vsock cid to initiate connections to");
55 DEFINE_uint32(client_vsock_port, 0, "Vsock port to initiate connections to");
56 DEFINE_int32(server_fd, -1, "A file descriptor. If set the passed file descriptor will be used as "
57 "the server and the corresponding port flag will be ignored");
58
59 DEFINE_uint32(events_fd, -1, "A file descriptor. If set it will listen for the events "
60 "to start / stop proxying. This option can be used only "
61 "if start_event_id is provided (stop_event_id is optional)");
62 DEFINE_uint32(start_event_id, -1, "Kernel event id (cuttlefish::monitor::Event from "
63 "kernel_log_server.h) that we will listen to start proxy");
64 DEFINE_uint32(stop_event_id, -1, "Kernel event id (cuttlefish::monitor::Event from "
65 "kernel_log_server.h) that we will listen to stop proxy");
66 #ifdef CUTTLEFISH_HOST
67 DEFINE_bool(restore, false,
68 "Wait on the restore_adbd_pipe instead of the initial start event");
69 #endif
70 DEFINE_bool(vhost_user_vsock, false, "A flag to user vhost_user_vsock");
71
72 namespace cuttlefish {
73 namespace socket_proxy {
74 namespace {
use_vhost_vsock()75 static bool use_vhost_vsock() {
76 #ifdef CUTTLEFISH_HOST
77 return FLAGS_vhost_user_vsock;
78 #else
79 return false;
80 #endif
81 }
BuildServer()82 static std::unique_ptr<Server> BuildServer() {
83 if (FLAGS_server_fd >= 0) {
84 return std::make_unique<DupServer>(FLAGS_server_fd);
85 }
86
87 CHECK(FLAGS_server_type == TRANSPORT_TCP || FLAGS_server_type == TRANSPORT_VSOCK)
88 << "Must specify -server_type with tcp or vsock values";
89
90 if (FLAGS_server_type == TRANSPORT_TCP) {
91 CHECK(FLAGS_server_tcp_port != 0)
92 << "Must specify -server_tcp_port or -server_fd with -server_type=tcp flag";
93 }
94 if (FLAGS_server_type == TRANSPORT_VSOCK) {
95 CHECK(FLAGS_server_vsock_port != 0)
96 << "Must specify -server_vsock_port or -server_fd with -server_type=vsock flag";
97 if (use_vhost_vsock()) {
98 CHECK(FLAGS_server_vsock_id > VMADDR_CID_HOST)
99 << "Must specify --server_vsock_id with --vhost_user_vsock=true flag";
100 }
101 }
102
103 std::unique_ptr<Server> server = nullptr;
104
105 if (FLAGS_server_type == TRANSPORT_TCP) {
106 server = std::make_unique<TcpServer>(FLAGS_server_tcp_port, TCP_SERVER_START_RETRIES_COUNT,
107 TCP_SERVER_RETRIES_DELAY);
108 } else if (FLAGS_server_type == TRANSPORT_VSOCK) {
109 server = std::make_unique<VsockServer>(
110 FLAGS_server_vsock_port, use_vhost_vsock()
111 ? std::make_optional(FLAGS_server_vsock_id)
112 : std::nullopt);
113 } else {
114 LOG(FATAL) << "Unknown server type: " << FLAGS_server_type;
115 }
116
117 return server;
118 }
119
BuildClient()120 static std::unique_ptr<Client> BuildClient() {
121 CHECK(FLAGS_client_type == TRANSPORT_TCP || FLAGS_client_type == TRANSPORT_VSOCK)
122 << "Must specify -client_type with tcp or vsock values";
123
124 if (FLAGS_client_type == TRANSPORT_TCP) {
125 CHECK(FLAGS_client_tcp_port != 0)
126 << "For -client_type=tcp you must specify -client_tcp_port flag";
127 }
128 if (FLAGS_client_type == TRANSPORT_VSOCK) {
129 CHECK(FLAGS_client_vsock_id >= 0 && FLAGS_client_vsock_port >= 0)
130 << "For -client_type=vsock you must specify -client_vsock_id and -client_vsock_port flags";
131 }
132
133 std::unique_ptr<Client> client = nullptr;
134
135 if (FLAGS_client_type == TRANSPORT_TCP) {
136 client = std::make_unique<TcpClient>(FLAGS_client_tcp_host, FLAGS_client_tcp_port,
137 TCP_CLIENT_TIMEOUT);
138 } else if (FLAGS_client_type == TRANSPORT_VSOCK) {
139 client = std::make_unique<VsockClient>(
140 FLAGS_client_vsock_id, FLAGS_client_vsock_port, use_vhost_vsock());
141 } else {
142 LOG(FATAL) << "Unknown client type: " << FLAGS_client_type;
143 }
144
145 return client;
146 }
147
StartProxyAsync(Server & server,Client & client)148 static Result<std::unique_ptr<ProxyServer>> StartProxyAsync(Server& server, Client& client) {
149 LOG(INFO) << "From: " << server.Describe();
150 LOG(INFO) << "To: " << client.Describe();
151 return ProxyAsync(CF_EXPECT(server.Start()), [&client] { return client.Start(); });
152 }
153
ListenEventsAndProxy(int events_fd,const monitor::Event start,const monitor::Event stop,Server & server,Client & client)154 static Result<void> ListenEventsAndProxy(int events_fd,
155 const monitor::Event start, const monitor::Event stop,
156 Server& server, Client& client) {
157 auto events = SharedFD::Dup(events_fd);
158 close(events_fd);
159
160 std::unique_ptr<ProxyServer> proxy;
161
162 #ifdef CUTTLEFISH_HOST
163 if (FLAGS_restore) {
164 LOG(INFO) << "restoring proxy on CUTTLEFISH_HOST - wait for adbd to come "
165 "online before starting proxy";
166 auto config = CF_EXPECT(CuttlefishConfig::Get());
167 auto instance = config->ForDefaultInstance();
168 SharedFD restore_pipe_read =
169 SharedFD::Open(instance.restore_adbd_pipe_name(), O_RDONLY);
170 if (!restore_pipe_read->IsOpen()) {
171 return CF_ERR(
172 "Error opening restore pipe: " << restore_pipe_read->StrError());
173 }
174 // Try to read from restore pipe. IF successfully reads, that means logcat
175 // has started, and the VM has resumed. Exit the thread.
176 // TODO (@khei): Add a device status tracking mechanism. b/325614380
177 char buff[1];
178 auto read = restore_pipe_read->Read(buff, 1);
179 if (read <= 0) {
180 return CF_ERR(
181 "Could not read restore pipe: " << restore_pipe_read->StrError());
182 }
183 LOG(INFO) << "restoring proxy on CUTTLEFISH_HOST - success";
184 proxy = CF_EXPECT(StartProxyAsync(server, client));
185 }
186 #endif
187
188 LOG(DEBUG) << "Start reading events to start/stop proxying";
189 while (events->IsOpen()) {
190 Result<std::optional<monitor::ReadEventResult>> received_event =
191 monitor::ReadEvent(events);
192
193 // TODO(schuffelen): Investigate if any errors here are recoverable, and
194 // remove the distinction between EOF and other errors if none are
195 // recoverable.
196 if (!received_event) {
197 LOG(ERROR) << "Failed reading kernel log event: "
198 << received_event.error().FormatForEnv();
199 continue;
200 }
201 if (!(*received_event)) {
202 LOG(DEBUG) << "Kernel log message channel closed";
203 break;
204 }
205
206 if (start != -1 && (*received_event)->event == start) {
207 if (!proxy) {
208 LOG(INFO) << "Start event (" << start << ") received. Starting proxy";
209 proxy = CF_EXPECT(StartProxyAsync(server, client));
210 }
211 continue;
212 }
213
214 if (stop != -1 && (*received_event)->event == stop) {
215 LOG(INFO) << "Stop event (" << start << ") received. Stopping proxy";
216 proxy.reset();
217 continue;
218 }
219 }
220
221 return {};
222 }
223
Main()224 Result<void> Main() {
225 auto server = BuildServer();
226 auto client = BuildClient();
227
228 if (FLAGS_events_fd != -1) {
229 CF_EXPECT(FLAGS_start_event_id != -1, "start_event_id is required if events_fd is provided");
230
231 const monitor::Event start_event = static_cast<monitor::Event>(FLAGS_start_event_id);
232 const monitor::Event stop_event = static_cast<monitor::Event>(FLAGS_stop_event_id);
233
234 CF_EXPECT(ListenEventsAndProxy(FLAGS_events_fd, start_event, stop_event,
235 *server, *client));
236 } else {
237 LOG(DEBUG) << "Starting proxy";
238 Proxy(CF_EXPECT(server->Start()), [&client] { return client->Start(); });
239 }
240
241 return {};
242 }
243
244 }
245 }
246 }
247
main(int argc,char * argv[])248 int main(int argc, char* argv[]) {
249 signal(SIGPIPE, SIG_IGN);
250
251 #ifdef CUTTLEFISH_HOST
252 cuttlefish::DefaultSubprocessLogging(argv, cuttlefish::MetadataLevel::TAG_AND_MESSAGE);
253 #else
254 ::android::base::InitLogging(argv, android::base::LogdLogger(android::base::SYSTEM));
255 #endif
256 google::ParseCommandLineFlags(&argc, &argv, true);
257
258 if (!FLAGS_label.empty()) {
259 android::base::SetDefaultTag("proxy_" + FLAGS_label);
260 }
261
262 auto result = cuttlefish::socket_proxy::Main();
263 if (!result.ok()) {
264 LOG(FATAL) << "Failed to proxy: " << result.error().FormatForEnv();
265 }
266
267 return 0;
268 }
269