blob: e5cde0787f8b364ed0cf3cb83c88aca76073f6a9 [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
Sharon Yanga7939252019-09-19 17:22:237#include <lib/sys/cpp/component_context.h>
Kevin Marshall3e89fd72018-06-05 21:29:108#include <algorithm>
9#include <string>
10#include <utility>
11#include <vector>
12
Sebastien Marchand6d0558fd2019-01-25 16:49:3713#include "base/bind.h"
Jeremy Manson18f6ea32018-11-13 21:12:2714#include "base/fuchsia/fuchsia_logging.h"
Sharon Yangb2ff20e2020-06-19 12:54:0115#include "base/fuchsia/process_context.h"
Kevin Marshall3e89fd72018-06-05 21:29:1016#include "base/optional.h"
17#include "base/run_loop.h"
18#include "net/base/network_interfaces.h"
19#include "net/base/network_interfaces_fuchsia.h"
20
21namespace net {
Kevin Marshall3e89fd72018-06-05 21:29:1022
Aidan Wolterd89b7542019-01-24 11:01:2123NetworkChangeNotifierFuchsia::NetworkChangeNotifierFuchsia(
24 uint32_t required_features)
Sharon Yangb2ff20e2020-06-19 12:54:0125 : NetworkChangeNotifierFuchsia(base::ComponentContextForProcess()
26 ->svc()
27 ->Connect<fuchsia::netstack::Netstack>(),
28 required_features) {}
Kevin Marshall3e89fd72018-06-05 21:29:1029
30NetworkChangeNotifierFuchsia::NetworkChangeNotifierFuchsia(
Aidan Wolterd89b7542019-01-24 11:01:2131 fuchsia::netstack::NetstackPtr netstack,
Eric Orthc398f1e2019-07-09 21:54:5532 uint32_t required_features,
33 SystemDnsConfigChangeNotifier* system_dns_config_notifier)
34 : NetworkChangeNotifier(NetworkChangeCalculatorParams(),
35 system_dns_config_notifier),
36 required_features_(required_features) {
Wezec6e7f12019-05-17 23:02:0937 DCHECK(netstack);
Kevin Marshall3e89fd72018-06-05 21:29:1038
Wezec6e7f12019-05-17 23:02:0939 // Temporarily re-wrap our Netstack channel so we can query the interfaces
40 // and routing table synchronously to populate the initial state.
41 fuchsia::netstack::NetstackSyncPtr sync_netstack;
42 sync_netstack.Bind(netstack.Unbind());
Wezadb2dd70c2019-06-01 00:16:4443 DCHECK(sync_netstack);
Wezec6e7f12019-05-17 23:02:0944
45 // Manually fetch the interfaces and routes.
46 std::vector<fuchsia::netstack::NetInterface> interfaces;
47 zx_status_t status = sync_netstack->GetInterfaces(&interfaces);
48 ZX_CHECK(status == ZX_OK, status) << "synchronous GetInterfaces()";
49 std::vector<fuchsia::netstack::RouteTableEntry> routes;
50 status = sync_netstack->GetRouteTable(&routes);
51 ZX_CHECK(status == ZX_OK, status) << "synchronous GetInterfaces()";
Haines Sy2eb17bcb2019-10-26 17:48:1852 // This will Notify internal observers like the NetworkChangeCalculator
53 // to be properly updated.
54 OnRouteTableReceived(std::move(interfaces), std::move(routes));
Wezec6e7f12019-05-17 23:02:0955
56 // Re-wrap Netstack back into an asynchronous pointer.
57 netstack_.Bind(sync_netstack.Unbind());
Wezadb2dd70c2019-06-01 00:16:4458 DCHECK(netstack_);
Jeremy Manson18f6ea32018-11-13 21:12:2759 netstack_.set_error_handler([](zx_status_t status) {
Aidan Wolter002daa92019-03-02 06:21:3960 // TODO(https://crbug.com/901092): Unit tests that use NetworkService are
61 // crashing because NetworkService does not clean up properly, and the
62 // netstack connection is cancelled, causing this fatal error.
63 // When the NetworkService cleanup is fixed, we should make this log FATAL.
64 ZX_LOG(ERROR, status) << "Lost connection to netstack.";
Jeremy Manson18f6ea32018-11-13 21:12:2765 });
Wez84ac6fe2019-02-28 03:45:5466 netstack_.events().OnInterfacesChanged = fit::bind_member(
67 this, &NetworkChangeNotifierFuchsia::ProcessInterfaceList);
Kevin Marshall3e89fd72018-06-05 21:29:1068}
69
70NetworkChangeNotifierFuchsia::~NetworkChangeNotifierFuchsia() {
71 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
Paul Jensen61a51a12019-05-23 23:12:4972 ClearGlobalPointer();
Kevin Marshall3e89fd72018-06-05 21:29:1073}
74
75NetworkChangeNotifier::ConnectionType
76NetworkChangeNotifierFuchsia::GetCurrentConnectionType() const {
77 ConnectionType type = static_cast<ConnectionType>(
78 base::subtle::Acquire_Load(&cached_connection_type_));
79 return type;
80}
81
Kevin Marshall3e89fd72018-06-05 21:29:1082void NetworkChangeNotifierFuchsia::ProcessInterfaceList(
Wez3a12771b2019-01-13 06:49:5083 std::vector<fuchsia::netstack::NetInterface> interfaces) {
Wez84ac6fe2019-02-28 03:45:5484 netstack_->GetRouteTable(
85 [this, interfaces = std::move(interfaces)](
86 std::vector<fuchsia::netstack::RouteTableEntry> route_table) mutable {
Haines Sy2eb17bcb2019-10-26 17:48:1887 OnRouteTableReceived(std::move(interfaces), std::move(route_table));
Wez84ac6fe2019-02-28 03:45:5488 });
Kevin Marshall3e89fd72018-06-05 21:29:1089}
90
91void NetworkChangeNotifierFuchsia::OnRouteTableReceived(
Wez3a12771b2019-01-13 06:49:5092 std::vector<fuchsia::netstack::NetInterface> interfaces,
Haines Sy2eb17bcb2019-10-26 17:48:1893 std::vector<fuchsia::netstack::RouteTableEntry> route_table) {
Aidan Wolterd89b7542019-01-24 11:01:2194 // Create a set of NICs that have default routes (ie 0.0.0.0).
95 base::flat_set<uint32_t> default_route_ids;
96 for (const auto& route : route_table) {
97 if (MaskPrefixLength(
98 internal::FuchsiaIpAddressToIPAddress(route.netmask)) == 0) {
99 default_route_ids.insert(route.nicid);
Kevin Marshall3e89fd72018-06-05 21:29:10100 }
101 }
102
Moe Ahmadi5bc177452019-01-23 18:48:59103 ConnectionType connection_type = CONNECTION_NONE;
Aidan Wolterd89b7542019-01-24 11:01:21104 base::flat_set<IPAddress> addresses;
105 for (auto& interface : interfaces) {
106 // Filter out loopback and invalid connection types.
107 if ((internal::ConvertConnectionType(interface) ==
108 NetworkChangeNotifier::CONNECTION_NONE) ||
109 (interface.features &
110 fuchsia::hardware::ethernet::INFO_FEATURE_LOOPBACK)) {
111 continue;
112 }
113
114 // Filter out interfaces that do not meet the |required_features_|.
115 if ((interface.features & required_features_) != required_features_) {
116 continue;
117 }
118
119 // Filter out interfaces with non-default routes.
120 if (!default_route_ids.contains(interface.id)) {
121 continue;
122 }
123
Kevin Marshall3e89fd72018-06-05 21:29:10124 std::vector<NetworkInterface> flattened_interfaces =
Aidan Wolterd89b7542019-01-24 11:01:21125 internal::NetInterfaceToNetworkInterfaces(interface);
126 if (flattened_interfaces.empty()) {
127 continue;
128 }
129
130 // Add the addresses from this interface to the list of all addresses.
Kevin Marshall3e89fd72018-06-05 21:29:10131 std::transform(
132 flattened_interfaces.begin(), flattened_interfaces.end(),
133 std::inserter(addresses, addresses.begin()),
134 [](const NetworkInterface& interface) { return interface.address; });
Aidan Wolterd89b7542019-01-24 11:01:21135
136 // Set the default connection to the first interface connection found.
137 if (connection_type == CONNECTION_NONE) {
Kevin Marshall3e89fd72018-06-05 21:29:10138 connection_type = flattened_interfaces.front().type;
139 }
Kevin Marshall3e89fd72018-06-05 21:29:10140 }
141
Kevin Marshall3e89fd72018-06-05 21:29:10142 if (addresses != cached_addresses_) {
143 std::swap(cached_addresses_, addresses);
Haines Sy2eb17bcb2019-10-26 17:48:18144 NotifyObserversOfIPAddressChange();
Kevin Marshall3e89fd72018-06-05 21:29:10145 }
146
Wezec6e7f12019-05-17 23:02:09147 if (connection_type != cached_connection_type_) {
148 base::subtle::Release_Store(&cached_connection_type_, connection_type);
Haines Sy2eb17bcb2019-10-26 17:48:18149 NotifyObserversOfConnectionTypeChange();
Kevin Marshall3e89fd72018-06-05 21:29:10150 }
Kevin Marshall3e89fd72018-06-05 21:29:10151}
152
153} // namespace net