blob: f1578ddd8375d913b48c27e72abaed1f56270ae5 [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
Tamir Dubersteinbf0a6a1d2020-08-03 18:44:117#include <lib/async-loop/cpp/loop.h>
Sharon Yanga7939252019-09-19 17:22:238#include <lib/sys/cpp/component_context.h>
Tamir Dubersteinbf0a6a1d2020-08-03 18:44:119
Kevin Marshall3e89fd72018-06-05 21:29:1010#include <algorithm>
11#include <string>
12#include <utility>
13#include <vector>
14
Sebastien Marchand6d0558fd2019-01-25 16:49:3715#include "base/bind.h"
Jeremy Manson18f6ea32018-11-13 21:12:2716#include "base/fuchsia/fuchsia_logging.h"
Sharon Yangb2ff20e2020-06-19 12:54:0117#include "base/fuchsia/process_context.h"
Kevin Marshall3e89fd72018-06-05 21:29:1018#include "base/optional.h"
19#include "base/run_loop.h"
20#include "net/base/network_interfaces.h"
21#include "net/base/network_interfaces_fuchsia.h"
22
23namespace net {
Kevin Marshall3e89fd72018-06-05 21:29:1024
Aidan Wolterd89b7542019-01-24 11:01:2125NetworkChangeNotifierFuchsia::NetworkChangeNotifierFuchsia(
26 uint32_t required_features)
Sharon Yangb2ff20e2020-06-19 12:54:0127 : NetworkChangeNotifierFuchsia(base::ComponentContextForProcess()
28 ->svc()
29 ->Connect<fuchsia::netstack::Netstack>(),
30 required_features) {}
Kevin Marshall3e89fd72018-06-05 21:29:1031
32NetworkChangeNotifierFuchsia::NetworkChangeNotifierFuchsia(
Tamir Dubersteinbf0a6a1d2020-08-03 18:44:1133 fidl::InterfaceHandle<fuchsia::netstack::Netstack> netstack,
Eric Orthc398f1e2019-07-09 21:54:5534 uint32_t required_features,
35 SystemDnsConfigChangeNotifier* system_dns_config_notifier)
36 : NetworkChangeNotifier(NetworkChangeCalculatorParams(),
37 system_dns_config_notifier),
38 required_features_(required_features) {
Wezec6e7f12019-05-17 23:02:0939 DCHECK(netstack);
Kevin Marshall3e89fd72018-06-05 21:29:1040
Jeremy Manson18f6ea32018-11-13 21:12:2741 netstack_.set_error_handler([](zx_status_t status) {
Tamir Dubersteinbf0a6a1d2020-08-03 18:44:1142 ZX_LOG(FATAL, status) << "Lost connection to netstack.";
Jeremy Manson18f6ea32018-11-13 21:12:2743 });
Tamir Dubersteinbf0a6a1d2020-08-03 18:44:1144
Wez84ac6fe2019-02-28 03:45:5445 netstack_.events().OnInterfacesChanged = fit::bind_member(
46 this, &NetworkChangeNotifierFuchsia::ProcessInterfaceList);
Tamir Dubersteinbf0a6a1d2020-08-03 18:44:1147
48 // Temporarily bind to a local dispatcher so we can synchronously wait for the
49 // synthetic event to populate the initial state.
50 async::Loop loop(&kAsyncLoopConfigNeverAttachToThread);
51 zx_status_t status = netstack_.Bind(std::move(netstack), loop.dispatcher());
52 ZX_CHECK(status == ZX_OK, status) << "Bind()";
53 on_initial_interfaces_received_ =
54 base::BindOnce(&async::Loop::Quit, base::Unretained(&loop));
55 status = loop.Run();
56 ZX_CHECK(status == ZX_ERR_CANCELED, status) << "loop.Run()";
57
58 // Bind to the dispatcher for the thread's MessagePump.
59 //
60 // Note this must be done before |loop| is destroyed, since that would close
61 // the interface handle underlying |netstack_|.
62 status = netstack_.Bind(netstack_.Unbind());
63 ZX_CHECK(status == ZX_OK, status) << "Bind()";
Kevin Marshall3e89fd72018-06-05 21:29:1064}
65
66NetworkChangeNotifierFuchsia::~NetworkChangeNotifierFuchsia() {
67 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
Paul Jensen61a51a12019-05-23 23:12:4968 ClearGlobalPointer();
Kevin Marshall3e89fd72018-06-05 21:29:1069}
70
71NetworkChangeNotifier::ConnectionType
72NetworkChangeNotifierFuchsia::GetCurrentConnectionType() const {
73 ConnectionType type = static_cast<ConnectionType>(
74 base::subtle::Acquire_Load(&cached_connection_type_));
75 return type;
76}
77
Kevin Marshall3e89fd72018-06-05 21:29:1078void NetworkChangeNotifierFuchsia::ProcessInterfaceList(
Wez3a12771b2019-01-13 06:49:5079 std::vector<fuchsia::netstack::NetInterface> interfaces) {
Wez84ac6fe2019-02-28 03:45:5480 netstack_->GetRouteTable(
81 [this, interfaces = std::move(interfaces)](
82 std::vector<fuchsia::netstack::RouteTableEntry> route_table) mutable {
Haines Sy2eb17bcb2019-10-26 17:48:1883 OnRouteTableReceived(std::move(interfaces), std::move(route_table));
Wez84ac6fe2019-02-28 03:45:5484 });
Kevin Marshall3e89fd72018-06-05 21:29:1085}
86
87void NetworkChangeNotifierFuchsia::OnRouteTableReceived(
Wez3a12771b2019-01-13 06:49:5088 std::vector<fuchsia::netstack::NetInterface> interfaces,
Haines Sy2eb17bcb2019-10-26 17:48:1889 std::vector<fuchsia::netstack::RouteTableEntry> route_table) {
Aidan Wolterd89b7542019-01-24 11:01:2190 // Create a set of NICs that have default routes (ie 0.0.0.0).
91 base::flat_set<uint32_t> default_route_ids;
92 for (const auto& route : route_table) {
93 if (MaskPrefixLength(
94 internal::FuchsiaIpAddressToIPAddress(route.netmask)) == 0) {
95 default_route_ids.insert(route.nicid);
Kevin Marshall3e89fd72018-06-05 21:29:1096 }
97 }
98
Moe Ahmadi5bc177452019-01-23 18:48:5999 ConnectionType connection_type = CONNECTION_NONE;
Aidan Wolterd89b7542019-01-24 11:01:21100 base::flat_set<IPAddress> addresses;
101 for (auto& interface : interfaces) {
102 // Filter out loopback and invalid connection types.
103 if ((internal::ConvertConnectionType(interface) ==
104 NetworkChangeNotifier::CONNECTION_NONE) ||
105 (interface.features &
106 fuchsia::hardware::ethernet::INFO_FEATURE_LOOPBACK)) {
107 continue;
108 }
109
110 // Filter out interfaces that do not meet the |required_features_|.
111 if ((interface.features & required_features_) != required_features_) {
112 continue;
113 }
114
115 // Filter out interfaces with non-default routes.
116 if (!default_route_ids.contains(interface.id)) {
117 continue;
118 }
119
Kevin Marshall3e89fd72018-06-05 21:29:10120 std::vector<NetworkInterface> flattened_interfaces =
Aidan Wolterd89b7542019-01-24 11:01:21121 internal::NetInterfaceToNetworkInterfaces(interface);
122 if (flattened_interfaces.empty()) {
123 continue;
124 }
125
126 // Add the addresses from this interface to the list of all addresses.
Kevin Marshall3e89fd72018-06-05 21:29:10127 std::transform(
128 flattened_interfaces.begin(), flattened_interfaces.end(),
129 std::inserter(addresses, addresses.begin()),
130 [](const NetworkInterface& interface) { return interface.address; });
Aidan Wolterd89b7542019-01-24 11:01:21131
132 // Set the default connection to the first interface connection found.
133 if (connection_type == CONNECTION_NONE) {
Kevin Marshall3e89fd72018-06-05 21:29:10134 connection_type = flattened_interfaces.front().type;
135 }
Kevin Marshall3e89fd72018-06-05 21:29:10136 }
137
Kevin Marshall3e89fd72018-06-05 21:29:10138 if (addresses != cached_addresses_) {
139 std::swap(cached_addresses_, addresses);
Haines Sy2eb17bcb2019-10-26 17:48:18140 NotifyObserversOfIPAddressChange();
Kevin Marshall3e89fd72018-06-05 21:29:10141 }
142
Wezec6e7f12019-05-17 23:02:09143 if (connection_type != cached_connection_type_) {
144 base::subtle::Release_Store(&cached_connection_type_, connection_type);
Haines Sy2eb17bcb2019-10-26 17:48:18145 NotifyObserversOfConnectionTypeChange();
Kevin Marshall3e89fd72018-06-05 21:29:10146 }
Tamir Dubersteinbf0a6a1d2020-08-03 18:44:11147
148 if (on_initial_interfaces_received_) {
149 std::move(on_initial_interfaces_received_).Run();
150 }
Kevin Marshall3e89fd72018-06-05 21:29:10151}
152
153} // namespace net