• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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