blob: 5f0674dd3e676f8b956be0d39dc35fefe42d9635 [file] [log] [blame]
Garrick Evans08843932019-09-17 14:41:08 +09001// Copyright 2016 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "arc/network/client.h"
6
7#include <base/logging.h>
8#include <chromeos/dbus/service_constants.h>
9#include <dbus/message.h>
10#include <dbus/object_path.h>
11
12namespace patchpanel {
13
14// static
15std::unique_ptr<Client> Client::New() {
16 dbus::Bus::Options opts;
17 opts.bus_type = dbus::Bus::SYSTEM;
18 scoped_refptr<dbus::Bus> bus(new dbus::Bus(std::move(opts)));
19
20 if (!bus->Connect()) {
21 LOG(ERROR) << "Failed to connect to system bus";
22 return nullptr;
23 }
24
25 dbus::ObjectProxy* proxy = bus->GetObjectProxy(
26 kPatchPanelServiceName, dbus::ObjectPath(kPatchPanelServicePath));
27 if (!proxy) {
28 LOG(ERROR) << "Unable to get dbus proxy for " << kPatchPanelServiceName;
29 return nullptr;
30 }
31
Garrick Evans93a83fc2020-03-31 15:16:55 +090032 return std::make_unique<Client>(std::move(bus), proxy);
33}
34
35Client::~Client() {
36 if (bus_)
37 bus_->ShutdownAndBlock();
Garrick Evans08843932019-09-17 14:41:08 +090038}
39
40bool Client::NotifyArcStartup(pid_t pid) {
41 dbus::MethodCall method_call(kPatchPanelInterface, kArcStartupMethod);
42 dbus::MessageWriter writer(&method_call);
43
44 ArcStartupRequest request;
45 request.set_pid(static_cast<uint32_t>(pid));
46
47 if (!writer.AppendProtoAsArrayOfBytes(request)) {
48 LOG(ERROR) << "Failed to encode ArcStartupRequest proto";
49 return false;
50 }
51
52 std::unique_ptr<dbus::Response> dbus_response = proxy_->CallMethodAndBlock(
53 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
54 if (!dbus_response) {
55 LOG(ERROR) << "Failed to send dbus message to patchpanel service";
56 return false;
57 }
58
59 dbus::MessageReader reader(dbus_response.get());
60 ArcStartupResponse response;
61 if (!reader.PopArrayOfBytesAsProto(&response)) {
62 LOG(ERROR) << "Failed to parse response proto";
63 return false;
64 }
65
66 return true;
67}
68
Garrick Evansca2b41b2019-12-02 09:06:11 +090069bool Client::NotifyArcShutdown() {
Garrick Evans08843932019-09-17 14:41:08 +090070 dbus::MethodCall method_call(kPatchPanelInterface, kArcShutdownMethod);
71 dbus::MessageWriter writer(&method_call);
72
73 ArcShutdownRequest request;
Garrick Evans08843932019-09-17 14:41:08 +090074 if (!writer.AppendProtoAsArrayOfBytes(request)) {
75 LOG(ERROR) << "Failed to encode ArcShutdownRequest proto";
76 return false;
77 }
78
79 std::unique_ptr<dbus::Response> dbus_response = proxy_->CallMethodAndBlock(
80 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
81 if (!dbus_response) {
82 LOG(ERROR) << "Failed to send dbus message to patchpanel service";
83 return false;
84 }
85
86 dbus::MessageReader reader(dbus_response.get());
87 ArcShutdownResponse response;
88 if (!reader.PopArrayOfBytesAsProto(&response)) {
89 LOG(ERROR) << "Failed to parse response proto";
90 return false;
91 }
92
93 return true;
94}
95
Garrick Evans0a189372020-02-07 08:55:27 +090096std::vector<patchpanel::Device> Client::NotifyArcVmStartup(uint32_t cid) {
Garrick Evans08843932019-09-17 14:41:08 +090097 dbus::MethodCall method_call(kPatchPanelInterface, kArcVmStartupMethod);
98 dbus::MessageWriter writer(&method_call);
99
100 ArcVmStartupRequest request;
Garrick Evans0a189372020-02-07 08:55:27 +0900101 request.set_cid(cid);
Garrick Evans08843932019-09-17 14:41:08 +0900102
103 if (!writer.AppendProtoAsArrayOfBytes(request)) {
104 LOG(ERROR) << "Failed to encode ArcVmStartupRequest proto";
105 return {};
106 }
107
108 std::unique_ptr<dbus::Response> dbus_response = proxy_->CallMethodAndBlock(
109 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
110 if (!dbus_response) {
111 LOG(ERROR) << "Failed to send dbus message to patchpanel service";
112 return {};
113 }
114
115 dbus::MessageReader reader(dbus_response.get());
116 ArcVmStartupResponse response;
117 if (!reader.PopArrayOfBytesAsProto(&response)) {
118 LOG(ERROR) << "Failed to parse response proto";
119 return {};
120 }
121
122 std::vector<patchpanel::Device> devices;
123 for (const auto& d : response.devices()) {
124 devices.emplace_back(d);
125 }
126 return devices;
127}
128
Garrick Evans0a189372020-02-07 08:55:27 +0900129bool Client::NotifyArcVmShutdown(uint32_t cid) {
Garrick Evans08843932019-09-17 14:41:08 +0900130 dbus::MethodCall method_call(kPatchPanelInterface, kArcVmShutdownMethod);
131 dbus::MessageWriter writer(&method_call);
132
133 ArcVmShutdownRequest request;
Garrick Evans0a189372020-02-07 08:55:27 +0900134 request.set_cid(cid);
Garrick Evans08843932019-09-17 14:41:08 +0900135
136 if (!writer.AppendProtoAsArrayOfBytes(request)) {
137 LOG(ERROR) << "Failed to encode ArcVmShutdownRequest proto";
138 return false;
139 }
140
141 std::unique_ptr<dbus::Response> dbus_response = proxy_->CallMethodAndBlock(
142 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
143 if (!dbus_response) {
144 LOG(ERROR) << "Failed to send dbus message to patchpanel service";
145 return false;
146 }
147
148 dbus::MessageReader reader(dbus_response.get());
149 ArcVmShutdownResponse response;
150 if (!reader.PopArrayOfBytesAsProto(&response)) {
151 LOG(ERROR) << "Failed to parse response proto";
152 return false;
153 }
154
155 return true;
156}
157
Garrick Evans0a189372020-02-07 08:55:27 +0900158bool Client::NotifyTerminaVmStartup(uint32_t cid,
Garrick Evans27b74032019-11-19 13:33:47 +0900159 patchpanel::Device* device,
160 patchpanel::IPv4Subnet* container_subnet) {
161 dbus::MethodCall method_call(kPatchPanelInterface, kTerminaVmStartupMethod);
162 dbus::MessageWriter writer(&method_call);
163
164 TerminaVmStartupRequest request;
Garrick Evans0a189372020-02-07 08:55:27 +0900165 request.set_cid(cid);
Garrick Evans27b74032019-11-19 13:33:47 +0900166
167 if (!writer.AppendProtoAsArrayOfBytes(request)) {
168 LOG(ERROR) << "Failed to encode TerminaVmStartupRequest proto";
169 return false;
170 }
171
172 std::unique_ptr<dbus::Response> dbus_response = proxy_->CallMethodAndBlock(
173 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
174 if (!dbus_response) {
175 LOG(ERROR) << "Failed to send dbus message to patchpanel service";
176 return false;
177 }
178
179 dbus::MessageReader reader(dbus_response.get());
180 TerminaVmStartupResponse response;
181 if (!reader.PopArrayOfBytesAsProto(&response)) {
182 LOG(ERROR) << "Failed to parse response proto";
183 return false;
184 }
185
186 if (!response.has_device()) {
187 LOG(ERROR) << "No device found";
188 return false;
189 }
190 *device = response.device();
191
192 if (response.has_container_subnet()) {
193 *container_subnet = response.container_subnet();
194 } else {
195 LOG(WARNING) << "No container subnet found";
196 }
197
198 return true;
199}
200
Garrick Evans0a189372020-02-07 08:55:27 +0900201bool Client::NotifyTerminaVmShutdown(uint32_t cid) {
Garrick Evans27b74032019-11-19 13:33:47 +0900202 dbus::MethodCall method_call(kPatchPanelInterface, kTerminaVmShutdownMethod);
203 dbus::MessageWriter writer(&method_call);
204
205 TerminaVmShutdownRequest request;
Garrick Evans0a189372020-02-07 08:55:27 +0900206 request.set_cid(cid);
Garrick Evans27b74032019-11-19 13:33:47 +0900207
208 if (!writer.AppendProtoAsArrayOfBytes(request)) {
209 LOG(ERROR) << "Failed to encode TerminaVmShutdownRequest proto";
210 return false;
211 }
212
213 std::unique_ptr<dbus::Response> dbus_response = proxy_->CallMethodAndBlock(
214 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
215 if (!dbus_response) {
216 LOG(ERROR) << "Failed to send dbus message to patchpanel service";
217 return false;
218 }
219
220 dbus::MessageReader reader(dbus_response.get());
221 TerminaVmShutdownResponse response;
222 if (!reader.PopArrayOfBytesAsProto(&response)) {
223 LOG(ERROR) << "Failed to parse response proto";
224 return false;
225 }
226
227 return true;
228}
229
Garrick Evans376f0672020-01-07 15:31:50 +0900230bool Client::NotifyPluginVmStartup(uint64_t vm_id,
231 int subnet_index,
232 patchpanel::Device* device) {
233 dbus::MethodCall method_call(kPatchPanelInterface, kPluginVmStartupMethod);
234 dbus::MessageWriter writer(&method_call);
235
236 PluginVmStartupRequest request;
237 request.set_id(vm_id);
238 request.set_subnet_index(subnet_index);
239
240 if (!writer.AppendProtoAsArrayOfBytes(request)) {
241 LOG(ERROR) << "Failed to encode PluginVmStartupRequest proto";
242 return false;
243 }
244
245 std::unique_ptr<dbus::Response> dbus_response = proxy_->CallMethodAndBlock(
246 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
247 if (!dbus_response) {
248 LOG(ERROR) << "Failed to send dbus message to patchpanel service";
249 return false;
250 }
251
252 dbus::MessageReader reader(dbus_response.get());
253 PluginVmStartupResponse response;
254 if (!reader.PopArrayOfBytesAsProto(&response)) {
255 LOG(ERROR) << "Failed to parse response proto";
256 return false;
257 }
258
259 if (!response.has_device()) {
260 LOG(ERROR) << "No device found";
261 return false;
262 }
263 *device = response.device();
264
265 return true;
266}
267
268bool Client::NotifyPluginVmShutdown(uint64_t vm_id) {
269 dbus::MethodCall method_call(kPatchPanelInterface, kPluginVmShutdownMethod);
270 dbus::MessageWriter writer(&method_call);
271
272 PluginVmShutdownRequest request;
273 request.set_id(vm_id);
274
275 if (!writer.AppendProtoAsArrayOfBytes(request)) {
276 LOG(ERROR) << "Failed to encode PluginVmShutdownRequest proto";
277 return false;
278 }
279
280 std::unique_ptr<dbus::Response> dbus_response = proxy_->CallMethodAndBlock(
281 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
282 if (!dbus_response) {
283 LOG(ERROR) << "Failed to send dbus message to patchpanel service";
284 return false;
285 }
286
287 dbus::MessageReader reader(dbus_response.get());
Garrick Evans9751a1e2020-02-20 11:02:10 +0900288 PluginVmShutdownResponse response;
Garrick Evans376f0672020-01-07 15:31:50 +0900289 if (!reader.PopArrayOfBytesAsProto(&response)) {
290 LOG(ERROR) << "Failed to parse response proto";
291 return false;
292 }
293
294 return true;
295}
296
Hugo Benichi7d9d8db2020-03-30 15:56:56 +0900297bool Client::DefaultVpnRouting(int socket) {
298 return SendSetVpnIntentRequest(socket, SetVpnIntentRequest::DEFAULT_ROUTING);
299}
300
301bool Client::RouteOnVpn(int socket) {
302 return SendSetVpnIntentRequest(socket, SetVpnIntentRequest::ROUTE_ON_VPN);
303}
304
305bool Client::BypassVpn(int socket) {
306 return SendSetVpnIntentRequest(socket, SetVpnIntentRequest::BYPASS_VPN);
307}
308
309bool Client::SendSetVpnIntentRequest(
310 int socket, SetVpnIntentRequest::VpnRoutingPolicy policy) {
311 dbus::MethodCall method_call(kPatchPanelInterface, kSetVpnIntentMethod);
312 dbus::MessageWriter writer(&method_call);
313
314 SetVpnIntentRequest request;
315 SetVpnIntentResponse response;
316 request.set_policy(policy);
317
318 if (!writer.AppendProtoAsArrayOfBytes(request)) {
319 LOG(ERROR) << "Failed to encode SetVpnIntentRequest proto";
320 return false;
321 }
322 writer.AppendFileDescriptor(socket);
323
324 std::unique_ptr<dbus::Response> dbus_response = proxy_->CallMethodAndBlock(
325 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
326 if (!dbus_response) {
327 LOG(ERROR)
328 << "Failed to send SetVpnIntentRequest message to patchpanel service";
329 return false;
330 }
331
332 dbus::MessageReader reader(dbus_response.get());
333 if (!reader.PopArrayOfBytesAsProto(&response)) {
334 LOG(ERROR) << "Failed to parse SetVpnIntentResponse proto";
335 return false;
336 }
337
338 if (!response.success()) {
339 LOG(ERROR) << "SetVpnIntentRequest failed";
340 return false;
341 }
342 return true;
343}
344
Garrick Evans08843932019-09-17 14:41:08 +0900345} // namespace patchpanel