blob: e3f5eed68cef95819e8a12ee1523708c7a1f4638 [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
Jason Jeremy Imanadffbcb2020-08-31 13:21:36 +09005#include "patchpanel/dbus/client.h"
Garrick Evans08843932019-09-17 14:41:08 +09006
Hugo Benichicc6850f2020-01-17 13:26:06 +09007#include <fcntl.h>
8
Jie Jiang0a70acf2020-10-02 11:57:32 +09009#include <base/bind.h>
Garrick Evans08843932019-09-17 14:41:08 +090010#include <base/logging.h>
11#include <chromeos/dbus/service_constants.h>
12#include <dbus/message.h>
13#include <dbus/object_path.h>
14
Garrick Evans3388a032020-03-24 11:25:55 +090015#include "patchpanel/net_util.h"
Hugo Benichicc6850f2020-01-17 13:26:06 +090016
Garrick Evans08843932019-09-17 14:41:08 +090017namespace patchpanel {
18
Jason Jeremy Iman6f1f3e72020-07-06 13:04:03 +090019namespace {
20
21std::ostream& operator<<(std::ostream& stream,
22 const ModifyPortRuleRequest& request) {
23 stream << "{ operation: "
24 << ModifyPortRuleRequest::Operation_Name(request.op())
25 << ", rule type: "
26 << ModifyPortRuleRequest::RuleType_Name(request.type())
27 << ", protocol: "
28 << ModifyPortRuleRequest::Protocol_Name(request.proto());
29 if (!request.input_ifname().empty()) {
30 stream << ", input interface name: " << request.input_ifname();
31 }
32 if (!request.input_dst_ip().empty()) {
33 stream << ", input destination IP: " << request.input_dst_ip();
34 }
35 stream << ", input destination port: " << request.input_dst_port();
36 if (!request.dst_ip().empty()) {
37 stream << ", destination IP: " << request.dst_ip();
38 }
39 if (request.dst_port() != 0) {
40 stream << ", destination port: " << request.dst_port();
41 }
42 stream << " }";
43 return stream;
44}
45
Jie Jiang0a70acf2020-10-02 11:57:32 +090046void OnGetTrafficCountersDBusResponse(
47 Client::GetTrafficCountersCallback callback,
48 dbus::Response* dbus_response) {
49 if (!dbus_response) {
50 LOG(ERROR) << "Failed to send TrafficCountersRequest message to patchpanel "
51 "service";
52 std::move(callback).Run({});
53 return;
54 }
55
56 TrafficCountersResponse response;
57 dbus::MessageReader reader(dbus_response);
58 if (!reader.PopArrayOfBytesAsProto(&response)) {
59 LOG(ERROR) << "Failed to parse TrafficCountersResponse proto";
60 std::move(callback).Run({});
61 return;
62 }
63
64 std::move(callback).Run(
65 {response.counters().begin(), response.counters().end()});
66}
67
Jie Jiange2e4c0b2020-09-16 18:48:43 +090068void OnNeighborConnectedStateChangedSignal(
69 const Client::NeighborConnectedStateChangedHandler& handler,
70 dbus::Signal* signal) {
71 dbus::MessageReader reader(signal);
72 NeighborConnectedStateChangedSignal proto;
73 if (!reader.PopArrayOfBytesAsProto(&proto)) {
74 LOG(ERROR) << "Failed to parse NeighborConnectedStateChangedSignal proto";
75 return;
76 }
77
78 handler.Run(proto);
79}
80
81void OnSignalConnectedCallback(const std::string& interface_name,
82 const std::string& signal_name,
83 bool success) {
84 if (!success)
85 LOG(ERROR) << "Failed to connect to " << signal_name;
86}
87
Jie Jiang81c84db2020-09-29 17:40:16 +090088class ClientImpl : public Client {
89 public:
90 ClientImpl(const scoped_refptr<dbus::Bus>& bus, dbus::ObjectProxy* proxy)
91 : bus_(std::move(bus)), proxy_(proxy) {}
92 ~ClientImpl();
Jason Jeremy Iman6f1f3e72020-07-06 13:04:03 +090093
Jie Jiang81c84db2020-09-29 17:40:16 +090094 bool NotifyArcStartup(pid_t pid) override;
95 bool NotifyArcShutdown() override;
Garrick Evans08843932019-09-17 14:41:08 +090096
Jie Jiang81c84db2020-09-29 17:40:16 +090097 std::vector<NetworkDevice> NotifyArcVmStartup(uint32_t cid) override;
98 bool NotifyArcVmShutdown(uint32_t cid) override;
Garrick Evans08843932019-09-17 14:41:08 +090099
Jie Jiang81c84db2020-09-29 17:40:16 +0900100 bool NotifyTerminaVmStartup(uint32_t cid,
101 NetworkDevice* device,
102 IPv4Subnet* container_subnet) override;
103 bool NotifyTerminaVmShutdown(uint32_t cid) override;
Garrick Evans08843932019-09-17 14:41:08 +0900104
Jie Jiang81c84db2020-09-29 17:40:16 +0900105 bool NotifyPluginVmStartup(uint64_t vm_id,
106 int subnet_index,
107 NetworkDevice* device) override;
108 bool NotifyPluginVmShutdown(uint64_t vm_id) override;
Garrick Evans93a83fc2020-03-31 15:16:55 +0900109
Jie Jiang81c84db2020-09-29 17:40:16 +0900110 bool DefaultVpnRouting(int socket) override;
111
112 bool RouteOnVpn(int socket) override;
113
114 bool BypassVpn(int socket) override;
115
116 std::pair<base::ScopedFD, patchpanel::ConnectNamespaceResponse>
117 ConnectNamespace(pid_t pid,
118 const std::string& outbound_ifname,
119 bool forward_user_traffic) override;
120
121 void GetTrafficCounters(const std::set<std::string>& devices,
122 GetTrafficCountersCallback callback) override;
123
124 bool ModifyPortRule(patchpanel::ModifyPortRuleRequest::Operation op,
125 patchpanel::ModifyPortRuleRequest::RuleType type,
126 patchpanel::ModifyPortRuleRequest::Protocol proto,
127 const std::string& input_ifname,
128 const std::string& input_dst_ip,
129 uint32_t input_dst_port,
130 const std::string& dst_ip,
131 uint32_t dst_port) override;
132
133 void RegisterNeighborConnectedStateChangedHandler(
134 NeighborConnectedStateChangedHandler handler) override;
135
136 private:
137 scoped_refptr<dbus::Bus> bus_;
138 dbus::ObjectProxy* proxy_ = nullptr; // owned by bus_
139
140 bool SendSetVpnIntentRequest(int socket,
141 SetVpnIntentRequest::VpnRoutingPolicy policy);
142
143 DISALLOW_COPY_AND_ASSIGN(ClientImpl);
144};
145
146ClientImpl::~ClientImpl() {
Garrick Evans93a83fc2020-03-31 15:16:55 +0900147 if (bus_)
148 bus_->ShutdownAndBlock();
Garrick Evans08843932019-09-17 14:41:08 +0900149}
150
Jie Jiang81c84db2020-09-29 17:40:16 +0900151bool ClientImpl::NotifyArcStartup(pid_t pid) {
Garrick Evans08843932019-09-17 14:41:08 +0900152 dbus::MethodCall method_call(kPatchPanelInterface, kArcStartupMethod);
153 dbus::MessageWriter writer(&method_call);
154
155 ArcStartupRequest request;
156 request.set_pid(static_cast<uint32_t>(pid));
157
158 if (!writer.AppendProtoAsArrayOfBytes(request)) {
159 LOG(ERROR) << "Failed to encode ArcStartupRequest proto";
160 return false;
161 }
162
163 std::unique_ptr<dbus::Response> dbus_response = proxy_->CallMethodAndBlock(
164 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
165 if (!dbus_response) {
166 LOG(ERROR) << "Failed to send dbus message to patchpanel service";
167 return false;
168 }
169
170 dbus::MessageReader reader(dbus_response.get());
171 ArcStartupResponse response;
172 if (!reader.PopArrayOfBytesAsProto(&response)) {
173 LOG(ERROR) << "Failed to parse response proto";
174 return false;
175 }
176
177 return true;
178}
179
Jie Jiang81c84db2020-09-29 17:40:16 +0900180bool ClientImpl::NotifyArcShutdown() {
Garrick Evans08843932019-09-17 14:41:08 +0900181 dbus::MethodCall method_call(kPatchPanelInterface, kArcShutdownMethod);
182 dbus::MessageWriter writer(&method_call);
183
184 ArcShutdownRequest request;
Garrick Evans08843932019-09-17 14:41:08 +0900185 if (!writer.AppendProtoAsArrayOfBytes(request)) {
186 LOG(ERROR) << "Failed to encode ArcShutdownRequest proto";
187 return false;
188 }
189
190 std::unique_ptr<dbus::Response> dbus_response = proxy_->CallMethodAndBlock(
191 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
192 if (!dbus_response) {
193 LOG(ERROR) << "Failed to send dbus message to patchpanel service";
194 return false;
195 }
196
197 dbus::MessageReader reader(dbus_response.get());
198 ArcShutdownResponse response;
199 if (!reader.PopArrayOfBytesAsProto(&response)) {
200 LOG(ERROR) << "Failed to parse response proto";
201 return false;
202 }
203
204 return true;
205}
206
Jie Jiang81c84db2020-09-29 17:40:16 +0900207std::vector<NetworkDevice> ClientImpl::NotifyArcVmStartup(uint32_t cid) {
Garrick Evans08843932019-09-17 14:41:08 +0900208 dbus::MethodCall method_call(kPatchPanelInterface, kArcVmStartupMethod);
209 dbus::MessageWriter writer(&method_call);
210
211 ArcVmStartupRequest request;
Garrick Evans0a189372020-02-07 08:55:27 +0900212 request.set_cid(cid);
Garrick Evans08843932019-09-17 14:41:08 +0900213
214 if (!writer.AppendProtoAsArrayOfBytes(request)) {
215 LOG(ERROR) << "Failed to encode ArcVmStartupRequest proto";
216 return {};
217 }
218
219 std::unique_ptr<dbus::Response> dbus_response = proxy_->CallMethodAndBlock(
220 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
221 if (!dbus_response) {
222 LOG(ERROR) << "Failed to send dbus message to patchpanel service";
223 return {};
224 }
225
226 dbus::MessageReader reader(dbus_response.get());
227 ArcVmStartupResponse response;
228 if (!reader.PopArrayOfBytesAsProto(&response)) {
229 LOG(ERROR) << "Failed to parse response proto";
230 return {};
231 }
232
Garrick Evans3388a032020-03-24 11:25:55 +0900233 std::vector<NetworkDevice> devices;
Garrick Evans08843932019-09-17 14:41:08 +0900234 for (const auto& d : response.devices()) {
235 devices.emplace_back(d);
236 }
237 return devices;
238}
239
Jie Jiang81c84db2020-09-29 17:40:16 +0900240bool ClientImpl::NotifyArcVmShutdown(uint32_t cid) {
Garrick Evans08843932019-09-17 14:41:08 +0900241 dbus::MethodCall method_call(kPatchPanelInterface, kArcVmShutdownMethod);
242 dbus::MessageWriter writer(&method_call);
243
244 ArcVmShutdownRequest request;
Garrick Evans0a189372020-02-07 08:55:27 +0900245 request.set_cid(cid);
Garrick Evans08843932019-09-17 14:41:08 +0900246
247 if (!writer.AppendProtoAsArrayOfBytes(request)) {
248 LOG(ERROR) << "Failed to encode ArcVmShutdownRequest proto";
249 return false;
250 }
251
252 std::unique_ptr<dbus::Response> dbus_response = proxy_->CallMethodAndBlock(
253 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
254 if (!dbus_response) {
255 LOG(ERROR) << "Failed to send dbus message to patchpanel service";
256 return false;
257 }
258
259 dbus::MessageReader reader(dbus_response.get());
260 ArcVmShutdownResponse response;
261 if (!reader.PopArrayOfBytesAsProto(&response)) {
262 LOG(ERROR) << "Failed to parse response proto";
263 return false;
264 }
265
266 return true;
267}
268
Jie Jiang81c84db2020-09-29 17:40:16 +0900269bool ClientImpl::NotifyTerminaVmStartup(uint32_t cid,
270 NetworkDevice* device,
271 IPv4Subnet* container_subnet) {
Garrick Evans27b74032019-11-19 13:33:47 +0900272 dbus::MethodCall method_call(kPatchPanelInterface, kTerminaVmStartupMethod);
273 dbus::MessageWriter writer(&method_call);
274
275 TerminaVmStartupRequest request;
Garrick Evans0a189372020-02-07 08:55:27 +0900276 request.set_cid(cid);
Garrick Evans27b74032019-11-19 13:33:47 +0900277
278 if (!writer.AppendProtoAsArrayOfBytes(request)) {
279 LOG(ERROR) << "Failed to encode TerminaVmStartupRequest proto";
280 return false;
281 }
282
283 std::unique_ptr<dbus::Response> dbus_response = proxy_->CallMethodAndBlock(
284 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
285 if (!dbus_response) {
286 LOG(ERROR) << "Failed to send dbus message to patchpanel service";
287 return false;
288 }
289
290 dbus::MessageReader reader(dbus_response.get());
291 TerminaVmStartupResponse response;
292 if (!reader.PopArrayOfBytesAsProto(&response)) {
293 LOG(ERROR) << "Failed to parse response proto";
294 return false;
295 }
296
297 if (!response.has_device()) {
298 LOG(ERROR) << "No device found";
299 return false;
300 }
301 *device = response.device();
302
303 if (response.has_container_subnet()) {
304 *container_subnet = response.container_subnet();
305 } else {
306 LOG(WARNING) << "No container subnet found";
307 }
308
309 return true;
310}
311
Jie Jiang81c84db2020-09-29 17:40:16 +0900312bool ClientImpl::NotifyTerminaVmShutdown(uint32_t cid) {
Garrick Evans27b74032019-11-19 13:33:47 +0900313 dbus::MethodCall method_call(kPatchPanelInterface, kTerminaVmShutdownMethod);
314 dbus::MessageWriter writer(&method_call);
315
316 TerminaVmShutdownRequest request;
Garrick Evans0a189372020-02-07 08:55:27 +0900317 request.set_cid(cid);
Garrick Evans27b74032019-11-19 13:33:47 +0900318
319 if (!writer.AppendProtoAsArrayOfBytes(request)) {
320 LOG(ERROR) << "Failed to encode TerminaVmShutdownRequest proto";
321 return false;
322 }
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) << "Failed to send dbus message to patchpanel service";
328 return false;
329 }
330
331 dbus::MessageReader reader(dbus_response.get());
332 TerminaVmShutdownResponse response;
333 if (!reader.PopArrayOfBytesAsProto(&response)) {
334 LOG(ERROR) << "Failed to parse response proto";
335 return false;
336 }
337
338 return true;
339}
340
Jie Jiang81c84db2020-09-29 17:40:16 +0900341bool ClientImpl::NotifyPluginVmStartup(uint64_t vm_id,
342 int subnet_index,
343 NetworkDevice* device) {
Garrick Evans376f0672020-01-07 15:31:50 +0900344 dbus::MethodCall method_call(kPatchPanelInterface, kPluginVmStartupMethod);
345 dbus::MessageWriter writer(&method_call);
346
347 PluginVmStartupRequest request;
348 request.set_id(vm_id);
349 request.set_subnet_index(subnet_index);
350
351 if (!writer.AppendProtoAsArrayOfBytes(request)) {
352 LOG(ERROR) << "Failed to encode PluginVmStartupRequest proto";
353 return false;
354 }
355
356 std::unique_ptr<dbus::Response> dbus_response = proxy_->CallMethodAndBlock(
357 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
358 if (!dbus_response) {
359 LOG(ERROR) << "Failed to send dbus message to patchpanel service";
360 return false;
361 }
362
363 dbus::MessageReader reader(dbus_response.get());
364 PluginVmStartupResponse response;
365 if (!reader.PopArrayOfBytesAsProto(&response)) {
366 LOG(ERROR) << "Failed to parse response proto";
367 return false;
368 }
369
370 if (!response.has_device()) {
371 LOG(ERROR) << "No device found";
372 return false;
373 }
374 *device = response.device();
375
376 return true;
377}
378
Jie Jiang81c84db2020-09-29 17:40:16 +0900379bool ClientImpl::NotifyPluginVmShutdown(uint64_t vm_id) {
Garrick Evans376f0672020-01-07 15:31:50 +0900380 dbus::MethodCall method_call(kPatchPanelInterface, kPluginVmShutdownMethod);
381 dbus::MessageWriter writer(&method_call);
382
383 PluginVmShutdownRequest request;
384 request.set_id(vm_id);
385
386 if (!writer.AppendProtoAsArrayOfBytes(request)) {
387 LOG(ERROR) << "Failed to encode PluginVmShutdownRequest proto";
388 return false;
389 }
390
391 std::unique_ptr<dbus::Response> dbus_response = proxy_->CallMethodAndBlock(
392 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
393 if (!dbus_response) {
394 LOG(ERROR) << "Failed to send dbus message to patchpanel service";
395 return false;
396 }
397
398 dbus::MessageReader reader(dbus_response.get());
Garrick Evans9751a1e2020-02-20 11:02:10 +0900399 PluginVmShutdownResponse response;
Garrick Evans376f0672020-01-07 15:31:50 +0900400 if (!reader.PopArrayOfBytesAsProto(&response)) {
401 LOG(ERROR) << "Failed to parse response proto";
402 return false;
403 }
404
405 return true;
406}
407
Jie Jiang81c84db2020-09-29 17:40:16 +0900408bool ClientImpl::DefaultVpnRouting(int socket) {
Hugo Benichi7d9d8db2020-03-30 15:56:56 +0900409 return SendSetVpnIntentRequest(socket, SetVpnIntentRequest::DEFAULT_ROUTING);
410}
411
Jie Jiang81c84db2020-09-29 17:40:16 +0900412bool ClientImpl::RouteOnVpn(int socket) {
Hugo Benichi7d9d8db2020-03-30 15:56:56 +0900413 return SendSetVpnIntentRequest(socket, SetVpnIntentRequest::ROUTE_ON_VPN);
414}
415
Jie Jiang81c84db2020-09-29 17:40:16 +0900416bool ClientImpl::BypassVpn(int socket) {
Hugo Benichi7d9d8db2020-03-30 15:56:56 +0900417 return SendSetVpnIntentRequest(socket, SetVpnIntentRequest::BYPASS_VPN);
418}
419
Jie Jiang81c84db2020-09-29 17:40:16 +0900420bool ClientImpl::SendSetVpnIntentRequest(
Hugo Benichi7d9d8db2020-03-30 15:56:56 +0900421 int socket, SetVpnIntentRequest::VpnRoutingPolicy policy) {
422 dbus::MethodCall method_call(kPatchPanelInterface, kSetVpnIntentMethod);
423 dbus::MessageWriter writer(&method_call);
424
425 SetVpnIntentRequest request;
426 SetVpnIntentResponse response;
427 request.set_policy(policy);
428
429 if (!writer.AppendProtoAsArrayOfBytes(request)) {
430 LOG(ERROR) << "Failed to encode SetVpnIntentRequest proto";
431 return false;
432 }
433 writer.AppendFileDescriptor(socket);
434
435 std::unique_ptr<dbus::Response> dbus_response = proxy_->CallMethodAndBlock(
436 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
437 if (!dbus_response) {
438 LOG(ERROR)
439 << "Failed to send SetVpnIntentRequest message to patchpanel service";
440 return false;
441 }
442
443 dbus::MessageReader reader(dbus_response.get());
444 if (!reader.PopArrayOfBytesAsProto(&response)) {
445 LOG(ERROR) << "Failed to parse SetVpnIntentResponse proto";
446 return false;
447 }
448
449 if (!response.success()) {
450 LOG(ERROR) << "SetVpnIntentRequest failed";
451 return false;
452 }
453 return true;
454}
455
Hugo Benichicc6850f2020-01-17 13:26:06 +0900456std::pair<base::ScopedFD, patchpanel::ConnectNamespaceResponse>
Jie Jiang81c84db2020-09-29 17:40:16 +0900457ClientImpl::ConnectNamespace(pid_t pid,
458 const std::string& outbound_ifname,
459 bool forward_user_traffic) {
Hugo Benichicc6850f2020-01-17 13:26:06 +0900460 // Prepare and serialize the request proto.
461 ConnectNamespaceRequest request;
462 request.set_pid(static_cast<int32_t>(pid));
463 request.set_outbound_physical_device(outbound_ifname);
464 request.set_allow_user_traffic(forward_user_traffic);
465
466 dbus::MethodCall method_call(kPatchPanelInterface, kConnectNamespaceMethod);
467 dbus::MessageWriter writer(&method_call);
468 if (!writer.AppendProtoAsArrayOfBytes(request)) {
469 LOG(ERROR) << "Failed to encode ConnectNamespaceRequest proto";
470 return {};
471 }
472
473 // Prepare an fd pair and append one fd directly after the serialized request.
474 int pipe_fds[2] = {-1, -1};
475 if (pipe2(pipe_fds, O_CLOEXEC) < 0) {
476 PLOG(ERROR) << "Failed to create a pair of fds with pipe2()";
477 return {};
478 }
479 base::ScopedFD fd_local(pipe_fds[0]);
480 // MessageWriter::AppendFileDescriptor duplicates the fd, so use ScopeFD to
481 // make sure the original fd is closed eventually.
482 base::ScopedFD fd_remote(pipe_fds[1]);
483 writer.AppendFileDescriptor(pipe_fds[1]);
484
485 std::unique_ptr<dbus::Response> dbus_response = proxy_->CallMethodAndBlock(
486 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
487 if (!dbus_response) {
488 LOG(ERROR) << "Failed to send ConnectNamespace message to patchpanel";
489 return {};
490 }
491
492 dbus::MessageReader reader(dbus_response.get());
493 ConnectNamespaceResponse response;
494 if (!reader.PopArrayOfBytesAsProto(&response)) {
495 LOG(ERROR) << "Failed to parse ConnectNamespaceResponse proto";
496 return {};
497 }
498
Hugo Benichi2fd0c6e2020-04-17 16:12:05 +0900499 if (response.peer_ifname().empty() || response.host_ifname().empty()) {
Hugo Benichicc6850f2020-01-17 13:26:06 +0900500 LOG(ERROR) << "ConnectNamespace for netns pid " << pid << " failed";
501 return {};
502 }
503
Garrick Evans3388a032020-03-24 11:25:55 +0900504 std::string subnet_info = IPv4AddressToCidrString(
Hugo Benichicc6850f2020-01-17 13:26:06 +0900505 response.ipv4_subnet().base_addr(), response.ipv4_subnet().prefix_len());
506 LOG(INFO) << "ConnectNamespace for netns pid " << pid
Hugo Benichi2fd0c6e2020-04-17 16:12:05 +0900507 << " succeeded: peer_ifname=" << response.peer_ifname()
508 << " peer_ipv4_address="
509 << IPv4AddressToString(response.peer_ipv4_address())
510 << " host_ifname=" << response.host_ifname()
511 << " host_ipv4_address="
512 << IPv4AddressToString(response.host_ipv4_address())
Hugo Benichicc6850f2020-01-17 13:26:06 +0900513 << " subnet=" << subnet_info;
514
515 return std::make_pair(std::move(fd_local), std::move(response));
516}
517
Jie Jiang81c84db2020-09-29 17:40:16 +0900518void ClientImpl::GetTrafficCounters(const std::set<std::string>& devices,
519 GetTrafficCountersCallback callback) {
Jie Jiange02d1202020-07-27 16:57:04 +0900520 dbus::MethodCall method_call(kPatchPanelInterface, kGetTrafficCountersMethod);
521 dbus::MessageWriter writer(&method_call);
522
523 TrafficCountersRequest request;
524 for (const auto& device : devices) {
525 request.add_devices(device);
526 }
527
528 if (!writer.AppendProtoAsArrayOfBytes(request)) {
529 LOG(ERROR) << "Failed to encode TrafficCountersRequest proto";
Jie Jiang0a70acf2020-10-02 11:57:32 +0900530 std::move(callback).Run({});
531 return;
Jie Jiange02d1202020-07-27 16:57:04 +0900532 }
533
Jie Jiang0a70acf2020-10-02 11:57:32 +0900534 proxy_->CallMethod(
535 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
536 base::BindOnce(&OnGetTrafficCountersDBusResponse, std::move(callback)));
Jie Jiange02d1202020-07-27 16:57:04 +0900537}
538
Jie Jiang81c84db2020-09-29 17:40:16 +0900539bool ClientImpl::ModifyPortRule(ModifyPortRuleRequest::Operation op,
540 ModifyPortRuleRequest::RuleType type,
541 ModifyPortRuleRequest::Protocol proto,
542 const std::string& input_ifname,
543 const std::string& input_dst_ip,
544 uint32_t input_dst_port,
545 const std::string& dst_ip,
546 uint32_t dst_port) {
Jason Jeremy Iman6f1f3e72020-07-06 13:04:03 +0900547 dbus::MethodCall method_call(kPatchPanelInterface, kModifyPortRuleMethod);
548 dbus::MessageWriter writer(&method_call);
549
550 ModifyPortRuleRequest request;
551 ModifyPortRuleResponse response;
552
553 request.set_op(op);
554 request.set_type(type);
555 request.set_proto(proto);
556 request.set_input_ifname(input_ifname);
557 request.set_input_dst_ip(input_dst_ip);
558 request.set_input_dst_port(input_dst_port);
559 request.set_dst_ip(dst_ip);
560 request.set_dst_port(dst_port);
561
562 if (!writer.AppendProtoAsArrayOfBytes(request)) {
563 LOG(ERROR) << "Failed to encode ModifyPortRuleRequest proto " << request;
564 return false;
565 }
566
567 std::unique_ptr<dbus::Response> dbus_response = proxy_->CallMethodAndBlock(
568 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
569 if (!dbus_response) {
570 LOG(ERROR)
571 << "Failed to send ModifyPortRuleRequest message to patchpanel service "
572 << request;
573 return false;
574 }
575
576 dbus::MessageReader reader(dbus_response.get());
577 if (!reader.PopArrayOfBytesAsProto(&response)) {
578 LOG(ERROR) << "Failed to parse ModifyPortRuleResponse proto " << request;
579 return false;
580 }
581
582 if (!response.success()) {
583 LOG(ERROR) << "ModifyPortRuleRequest failed " << request;
584 return false;
585 }
586 return true;
587}
588
Jie Jiang81c84db2020-09-29 17:40:16 +0900589void ClientImpl::RegisterNeighborConnectedStateChangedHandler(
Jie Jiange2e4c0b2020-09-16 18:48:43 +0900590 NeighborConnectedStateChangedHandler handler) {
591 proxy_->ConnectToSignal(
592 kPatchPanelInterface, kNeighborConnectedStateChangedSignal,
593 base::BindRepeating(OnNeighborConnectedStateChangedSignal, handler),
594 base::BindOnce(OnSignalConnectedCallback));
595}
596
Jie Jiang81c84db2020-09-29 17:40:16 +0900597} // namespace
598
599// static
600std::unique_ptr<Client> Client::New() {
601 dbus::Bus::Options opts;
602 opts.bus_type = dbus::Bus::SYSTEM;
603 scoped_refptr<dbus::Bus> bus(new dbus::Bus(std::move(opts)));
604
605 if (!bus->Connect()) {
606 LOG(ERROR) << "Failed to connect to system bus";
607 return nullptr;
608 }
609
610 dbus::ObjectProxy* proxy = bus->GetObjectProxy(
611 kPatchPanelServiceName, dbus::ObjectPath(kPatchPanelServicePath));
612 if (!proxy) {
613 LOG(ERROR) << "Unable to get dbus proxy for " << kPatchPanelServiceName;
614 return nullptr;
615 }
616
617 return std::make_unique<ClientImpl>(std::move(bus), proxy);
618}
619
620std::unique_ptr<Client> Client::New(const scoped_refptr<dbus::Bus>& bus,
621 dbus::ObjectProxy* proxy) {
622 return std::make_unique<ClientImpl>(std::move(bus), proxy);
623}
624
Garrick Evans08843932019-09-17 14:41:08 +0900625} // namespace patchpanel