1 /*
2  * Copyright (C) 2022 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 "host/libs/command_util/util.h"
18 
19 #include "sys/time.h"
20 #include "sys/types.h"
21 
22 #include <optional>
23 #include <string>
24 
25 #include "common/libs/fs/shared_buf.h"
26 #include "common/libs/fs/shared_fd.h"
27 #include "common/libs/fs/shared_select.h"
28 #include "common/libs/utils/result.h"
29 #include "host/libs/command_util/runner/defs.h"
30 #include "host/libs/config/cuttlefish_config.h"
31 
32 namespace cuttlefish {
33 namespace {
34 
IsShortAction(const LauncherAction action)35 bool IsShortAction(const LauncherAction action) {
36   switch (action) {
37     case LauncherAction::kFail:
38     case LauncherAction::kPowerwash:
39     case LauncherAction::kRestart:
40     case LauncherAction::kStatus:
41     case LauncherAction::kStop:
42       return true;
43     default:
44       return false;
45   };
46 }
47 
48 template <typename T>
WriteAllBinaryResult(const SharedFD & fd,const T * t)49 static Result<void> WriteAllBinaryResult(const SharedFD& fd, const T* t) {
50   ssize_t n = WriteAllBinary(fd, t);
51   CF_EXPECTF(n > 0, "Write error: {}", fd->StrError());
52   CF_EXPECT(n == sizeof(*t), "Unexpected EOF on write");
53   return {};
54 }
55 
56 // Rerturns true if something was read, false if the file descriptor reached
57 // EOF.
58 template <typename T>
ReadExactBinaryResult(const SharedFD & fd,T * t)59 static Result<bool> ReadExactBinaryResult(const SharedFD& fd, T* t) {
60   ssize_t n = ReadExactBinary(fd, t);
61   if (n == 0) {
62     return false;
63   }
64   CF_EXPECTF(n > 0, "Read error: {}", fd->StrError());
65   CF_EXPECT(n == sizeof(*t), "Unexpected EOF on read");
66   return true;
67 }
68 
69 }  // namespace
70 
ReadExitCode(SharedFD monitor_socket)71 Result<RunnerExitCodes> ReadExitCode(SharedFD monitor_socket) {
72   RunnerExitCodes exit_codes;
73   CF_EXPECT(ReadExactBinaryResult(monitor_socket, &exit_codes),
74             "Error reading RunnerExitCodes");
75   return exit_codes;
76 }
77 
GetLauncherMonitorFromInstance(const CuttlefishConfig::InstanceSpecific & instance_config,const int timeout_seconds)78 Result<SharedFD> GetLauncherMonitorFromInstance(
79     const CuttlefishConfig::InstanceSpecific& instance_config,
80     const int timeout_seconds) {
81   std::string monitor_path = instance_config.launcher_monitor_socket_path();
82   CF_EXPECT(!monitor_path.empty(), "No path to launcher monitor found");
83 
84   SharedFD monitor_socket = SharedFD::SocketLocalClient(
85       monitor_path.c_str(), false, SOCK_STREAM, timeout_seconds);
86   CF_EXPECT(monitor_socket->IsOpen(),
87             "Unable to connect to launcher monitor at "
88                 << monitor_path << ":" << monitor_socket->StrError());
89   return monitor_socket;
90 }
91 
GetLauncherMonitor(const CuttlefishConfig & config,const int instance_num,const int timeout_seconds)92 Result<SharedFD> GetLauncherMonitor(const CuttlefishConfig& config,
93                                     const int instance_num,
94                                     const int timeout_seconds) {
95   auto instance_config = config.ForInstance(instance_num);
96   return GetLauncherMonitorFromInstance(instance_config, timeout_seconds);
97 }
98 
ReadLauncherActionFromFd(SharedFD monitor_socket)99 Result<std::optional<LauncherActionInfo>> ReadLauncherActionFromFd(SharedFD monitor_socket) {
100   LauncherAction action;
101   auto read_something = CF_EXPECT(ReadExactBinaryResult(monitor_socket, &action),
102             "Error reading LauncherAction");
103   if (!read_something) {
104     return std::nullopt;
105   }
106   if (IsShortAction(action)) {
107     return LauncherActionInfo{
108         .action = action,
109         .extended_action = {},
110     };
111   }
112   std::uint32_t length = 0;
113   CF_EXPECT(ReadExactBinaryResult(monitor_socket, &length),
114             "Error reading proto length");
115   if (length == 0) {
116     return LauncherActionInfo{
117         .action = action,
118         .extended_action = {},
119     };
120   }
121   std::string serialized_data(length, 0);
122   ssize_t n =
123       ReadExact(monitor_socket, serialized_data.data(), serialized_data.size());
124   CF_EXPECTF(n > 0, "Read error: {}", monitor_socket->StrError());
125   CF_EXPECT(n == serialized_data.size(), "Unexpected EOF on read");
126 
127   run_cvd::ExtendedLauncherAction extended_action;
128   CF_EXPECT(extended_action.ParseFromString(serialized_data),
129             "Failed to parse ExtendedLauncherAction proto");
130 
131   return LauncherActionInfo{
132       .action = action,
133       .extended_action = std::move(extended_action),
134   };
135 }
136 
WaitForRead(SharedFD monitor_socket,const int timeout_seconds)137 Result<void> WaitForRead(SharedFD monitor_socket, const int timeout_seconds) {
138   // Perform a select with a timeout to guard against launcher hanging
139   SharedFDSet read_set;
140   read_set.Set(monitor_socket);
141   struct timeval timeout = {timeout_seconds, 0};
142   int select_result = Select(&read_set, nullptr, nullptr,
143                              timeout_seconds <= 0 ? nullptr : &timeout);
144   CF_EXPECT(select_result != 0,
145             "Timeout expired waiting for launcher monitor to respond");
146   CF_EXPECT(
147       select_result > 0,
148       "Failed communication with the launcher monitor: " << strerror(errno));
149   return {};
150 }
151 
RunLauncherAction(SharedFD monitor_socket,LauncherAction action,std::optional<int> timeout_seconds)152 Result<void> RunLauncherAction(SharedFD monitor_socket, LauncherAction action,
153                                std::optional<int> timeout_seconds) {
154   CF_EXPECTF(IsShortAction(action),
155              "PerformActionRequest doesn't support extended action \"{}\"",
156              static_cast<const char>(action));
157   CF_EXPECT(WriteAllBinaryResult(monitor_socket, &action),
158             "Error writing LauncherAction");
159 
160   if (timeout_seconds.has_value()) {
161     CF_EXPECT(WaitForRead(monitor_socket, timeout_seconds.value()));
162   }
163   LauncherResponse response;
164   CF_EXPECT(ReadExactBinaryResult(monitor_socket, &response),
165             "Error reading LauncherResponse");
166   CF_EXPECT_EQ((int)response, (int)LauncherResponse::kSuccess);
167   return {};
168 }
169 
RunLauncherAction(SharedFD monitor_socket,const run_cvd::ExtendedLauncherAction & extended_action,std::optional<int> timeout_seconds)170 Result<void> RunLauncherAction(
171     SharedFD monitor_socket,
172     const run_cvd::ExtendedLauncherAction& extended_action,
173     std::optional<int> timeout_seconds) {
174   const std::string serialized_data = extended_action.SerializeAsString();
175   CF_EXPECT(!serialized_data.empty(), "failed to serialize proto");
176 
177   const LauncherAction action = LauncherAction::kExtended;
178   CF_EXPECT(WriteAllBinaryResult(monitor_socket, &action),
179             "Error writing LauncherAction");
180   const std::uint32_t length = serialized_data.size();
181   CF_EXPECT(WriteAllBinaryResult(monitor_socket, &length),
182             "Error writing proto length");
183   if (!serialized_data.empty()) {
184     ssize_t n = WriteAll(monitor_socket, serialized_data.data(),
185                          serialized_data.size());
186     CF_EXPECTF(n > 0, "Write error: {}", monitor_socket->StrError());
187     CF_EXPECT(n == serialized_data.size(), "Unexpected EOF on write");
188   }
189 
190   if (timeout_seconds.has_value()) {
191     CF_EXPECT(WaitForRead(monitor_socket, timeout_seconds.value()));
192   }
193   LauncherResponse response;
194   CF_EXPECT(ReadExactBinaryResult(monitor_socket, &response),
195             "Error reading LauncherResponse");
196   CF_EXPECT_EQ((int)response, (int)LauncherResponse::kSuccess);
197   return {};
198 }
199 
200 }  // namespace cuttlefish
201