blob: 1136e05a3131610f808f38617a15f17f00f30eba [file] [log] [blame]
Kevin Marshall3e89fd72018-06-05 21:29:101// Copyright 2018 The Chromium 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 "net/base/network_change_notifier_fuchsia.h"
6
7#include <algorithm>
8#include <string>
9#include <utility>
10#include <vector>
11
12#include "base/fuchsia/component_context.h"
Jeremy Manson18f6ea32018-11-13 21:12:2713#include "base/fuchsia/fuchsia_logging.h"
Kevin Marshall3e89fd72018-06-05 21:29:1014#include "base/optional.h"
15#include "base/run_loop.h"
16#include "net/base/network_interfaces.h"
17#include "net/base/network_interfaces_fuchsia.h"
18
19namespace net {
20namespace {
21
22using ConnectionType = NetworkChangeNotifier::ConnectionType;
23
24// Adapts a base::RepeatingCallback to a std::function object.
25// Useful when binding callbacks to asynchronous FIDL calls, because
26// it allows the caller to reference in-scope move-only objects as well as use
27// Chromium's ownership signifiers such as base::Passed, base::Unretained, etc.
28//
29// Note that the function takes a RepeatingCallback because it is copyable, but
30// in practice the callback will only be executed once by the FIDL system.
31template <typename R, typename... Args>
32std::function<R(Args...)> WrapCallbackAsFunction(
33 base::RepeatingCallback<R(Args...)> callback) {
34 return
35 [callback](Args... args) { callback.Run(std::forward<Args>(args)...); };
36}
37
38} // namespace
39
40NetworkChangeNotifierFuchsia::NetworkChangeNotifierFuchsia()
41 : NetworkChangeNotifierFuchsia(
42 base::fuchsia::ComponentContext::GetDefault()
43 ->ConnectToService<fuchsia::netstack::Netstack>()) {}
44
45NetworkChangeNotifierFuchsia::NetworkChangeNotifierFuchsia(
46 fuchsia::netstack::NetstackPtr netstack)
Wez9691382f2018-08-03 18:28:1647 : netstack_(std::move(netstack)) {
Kevin Marshall3e89fd72018-06-05 21:29:1048 DCHECK(netstack_);
49
Jeremy Manson18f6ea32018-11-13 21:12:2750 netstack_.set_error_handler([](zx_status_t status) {
51 ZX_LOG(ERROR, status) << "Lost connection to netstack.";
52 });
Wez9691382f2018-08-03 18:28:1653 netstack_.events().OnInterfacesChanged =
Wez3a12771b2019-01-13 06:49:5054 [this](std::vector<fuchsia::netstack::NetInterface> interfaces) {
Wez9691382f2018-08-03 18:28:1655 ProcessInterfaceList(base::OnceClosure(), std::move(interfaces));
56 };
Kevin Marshall3e89fd72018-06-05 21:29:1057
Wez9691382f2018-08-03 18:28:1658 // Fetch the interface list synchronously, so that an initial ConnectionType
59 // is available before we return.
60 base::RunLoop wait_for_interfaces;
Wez3a12771b2019-01-13 06:49:5061 netstack_->GetInterfaces(
62 [this, quit_closure = wait_for_interfaces.QuitClosure()](
63 std::vector<fuchsia::netstack::NetInterface> interfaces) {
64 ProcessInterfaceList(quit_closure, std::move(interfaces));
65 });
Wez9691382f2018-08-03 18:28:1666 wait_for_interfaces.Run();
Kevin Marshall3e89fd72018-06-05 21:29:1067}
68
69NetworkChangeNotifierFuchsia::~NetworkChangeNotifierFuchsia() {
70 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
71}
72
73NetworkChangeNotifier::ConnectionType
74NetworkChangeNotifierFuchsia::GetCurrentConnectionType() const {
75 ConnectionType type = static_cast<ConnectionType>(
76 base::subtle::Acquire_Load(&cached_connection_type_));
77 return type;
78}
79
Kevin Marshall3e89fd72018-06-05 21:29:1080void NetworkChangeNotifierFuchsia::ProcessInterfaceList(
81 base::OnceClosure on_initialized_cb,
Wez3a12771b2019-01-13 06:49:5082 std::vector<fuchsia::netstack::NetInterface> interfaces) {
Kevin Marshall3e89fd72018-06-05 21:29:1083 netstack_->GetRouteTable(WrapCallbackAsFunction(base::BindRepeating(
84 &NetworkChangeNotifierFuchsia::OnRouteTableReceived,
85 base::Unretained(this), base::Passed(std::move(on_initialized_cb)),
86 base::Passed(std::move(interfaces)))));
87}
88
89void NetworkChangeNotifierFuchsia::OnRouteTableReceived(
90 base::OnceClosure on_initialized_cb,
Wez3a12771b2019-01-13 06:49:5091 std::vector<fuchsia::netstack::NetInterface> interfaces,
92 std::vector<fuchsia::netstack::RouteTableEntry> route_table) {
Kevin Marshall3e89fd72018-06-05 21:29:1093 // Find the default interface in the routing table.
94 auto default_route_interface = std::find_if(
Wez3a12771b2019-01-13 06:49:5095 route_table.begin(), route_table.end(),
Kevin Marshall3e89fd72018-06-05 21:29:1096 [](const fuchsia::netstack::RouteTableEntry& rt) {
Sergey Ulanovcac547192018-12-10 22:11:5197 return MaskPrefixLength(
98 internal::FuchsiaIpAddressToIPAddress(rt.netmask)) == 0;
Kevin Marshall3e89fd72018-06-05 21:29:1099 });
100
101 // Find the default interface in the NetInterface list.
102 const fuchsia::netstack::NetInterface* default_interface = nullptr;
Wez3a12771b2019-01-13 06:49:50103 if (default_route_interface != route_table.end()) {
104 for (const auto& cur_interface : interfaces) {
Kevin Marshall3e89fd72018-06-05 21:29:10105 if (cur_interface.id == default_route_interface->nicid) {
106 default_interface = &cur_interface;
107 }
108 }
109 }
110
111 base::flat_set<IPAddress> addresses;
112 std::string ssid;
113 ConnectionType connection_type = CONNECTION_NONE;
114 if (default_interface) {
115 std::vector<NetworkInterface> flattened_interfaces =
116 internal::NetInterfaceToNetworkInterfaces(*default_interface);
117 std::transform(
118 flattened_interfaces.begin(), flattened_interfaces.end(),
119 std::inserter(addresses, addresses.begin()),
120 [](const NetworkInterface& interface) { return interface.address; });
121 if (!flattened_interfaces.empty()) {
122 connection_type = flattened_interfaces.front().type;
123 }
124
125 // TODO(https://crbug.com/848355): Treat SSID changes as IP address changes.
126 }
127
128 bool connection_type_changed = false;
129 if (connection_type != cached_connection_type_) {
130 base::subtle::Release_Store(&cached_connection_type_, connection_type);
131 connection_type_changed = true;
132 }
133
134 if (addresses != cached_addresses_) {
135 std::swap(cached_addresses_, addresses);
136 if (on_initialized_cb.is_null()) {
137 NotifyObserversOfIPAddressChange();
138 }
139 connection_type_changed = true;
140 }
141
142 if (on_initialized_cb.is_null() && connection_type_changed) {
143 NotifyObserversOfConnectionTypeChange();
144 }
145
146 if (!on_initialized_cb.is_null()) {
147 std::move(on_initialized_cb).Run();
148 }
149}
150
151} // namespace net