blob: 2e802cacbf4a05c6bd0d7d26c3c4776d17b0294e [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
Sebastien Marchand6d0558fd2019-01-25 16:49:3712#include "base/bind.h"
Jeremy Manson18f6ea32018-11-13 21:12:2713#include "base/fuchsia/fuchsia_logging.h"
Wezb10b9bb2019-02-07 00:15:4114#include "base/fuchsia/service_directory_client.h"
Kevin Marshall3e89fd72018-06-05 21:29:1015#include "base/optional.h"
16#include "base/run_loop.h"
17#include "net/base/network_interfaces.h"
18#include "net/base/network_interfaces_fuchsia.h"
19
20namespace net {
Kevin Marshall3e89fd72018-06-05 21:29:1021
Aidan Wolterd89b7542019-01-24 11:01:2122NetworkChangeNotifierFuchsia::NetworkChangeNotifierFuchsia(
23 uint32_t required_features)
Kevin Marshall3e89fd72018-06-05 21:29:1024 : NetworkChangeNotifierFuchsia(
Wezb10b9bb2019-02-07 00:15:4125 base::fuchsia::ServiceDirectoryClient::ForCurrentProcess()
Aidan Wolterd89b7542019-01-24 11:01:2126 ->ConnectToService<fuchsia::netstack::Netstack>(),
27 required_features) {}
Kevin Marshall3e89fd72018-06-05 21:29:1028
29NetworkChangeNotifierFuchsia::NetworkChangeNotifierFuchsia(
Aidan Wolterd89b7542019-01-24 11:01:2130 fuchsia::netstack::NetstackPtr netstack,
31 uint32_t required_features)
Wezec6e7f12019-05-17 23:02:0932 : required_features_(required_features) {
33 DCHECK(netstack);
Kevin Marshall3e89fd72018-06-05 21:29:1034
Wezec6e7f12019-05-17 23:02:0935 // Temporarily re-wrap our Netstack channel so we can query the interfaces
36 // and routing table synchronously to populate the initial state.
37 fuchsia::netstack::NetstackSyncPtr sync_netstack;
38 sync_netstack.Bind(netstack.Unbind());
39
40 // Manually fetch the interfaces and routes.
41 std::vector<fuchsia::netstack::NetInterface> interfaces;
42 zx_status_t status = sync_netstack->GetInterfaces(&interfaces);
43 ZX_CHECK(status == ZX_OK, status) << "synchronous GetInterfaces()";
44 std::vector<fuchsia::netstack::RouteTableEntry> routes;
45 status = sync_netstack->GetRouteTable(&routes);
46 ZX_CHECK(status == ZX_OK, status) << "synchronous GetInterfaces()";
47 OnRouteTableReceived(std::move(interfaces), std::move(routes), false);
48
49 // Re-wrap Netstack back into an asynchronous pointer.
50 netstack_.Bind(sync_netstack.Unbind());
Jeremy Manson18f6ea32018-11-13 21:12:2751 netstack_.set_error_handler([](zx_status_t status) {
Aidan Wolter002daa92019-03-02 06:21:3952 // TODO(https://crbug.com/901092): Unit tests that use NetworkService are
53 // crashing because NetworkService does not clean up properly, and the
54 // netstack connection is cancelled, causing this fatal error.
55 // When the NetworkService cleanup is fixed, we should make this log FATAL.
56 ZX_LOG(ERROR, status) << "Lost connection to netstack.";
Jeremy Manson18f6ea32018-11-13 21:12:2757 });
Wez84ac6fe2019-02-28 03:45:5458 netstack_.events().OnInterfacesChanged = fit::bind_member(
59 this, &NetworkChangeNotifierFuchsia::ProcessInterfaceList);
Kevin Marshall3e89fd72018-06-05 21:29:1060}
61
62NetworkChangeNotifierFuchsia::~NetworkChangeNotifierFuchsia() {
63 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
64}
65
66NetworkChangeNotifier::ConnectionType
67NetworkChangeNotifierFuchsia::GetCurrentConnectionType() const {
68 ConnectionType type = static_cast<ConnectionType>(
69 base::subtle::Acquire_Load(&cached_connection_type_));
70 return type;
71}
72
Kevin Marshall3e89fd72018-06-05 21:29:1073void NetworkChangeNotifierFuchsia::ProcessInterfaceList(
Wez3a12771b2019-01-13 06:49:5074 std::vector<fuchsia::netstack::NetInterface> interfaces) {
Wez84ac6fe2019-02-28 03:45:5475 netstack_->GetRouteTable(
76 [this, interfaces = std::move(interfaces)](
77 std::vector<fuchsia::netstack::RouteTableEntry> route_table) mutable {
Wezec6e7f12019-05-17 23:02:0978 OnRouteTableReceived(std::move(interfaces), std::move(route_table),
79 true);
Wez84ac6fe2019-02-28 03:45:5480 });
Kevin Marshall3e89fd72018-06-05 21:29:1081}
82
83void NetworkChangeNotifierFuchsia::OnRouteTableReceived(
Wez3a12771b2019-01-13 06:49:5084 std::vector<fuchsia::netstack::NetInterface> interfaces,
Wezec6e7f12019-05-17 23:02:0985 std::vector<fuchsia::netstack::RouteTableEntry> route_table,
86 bool notify_observers) {
Aidan Wolterd89b7542019-01-24 11:01:2187 // Create a set of NICs that have default routes (ie 0.0.0.0).
88 base::flat_set<uint32_t> default_route_ids;
89 for (const auto& route : route_table) {
90 if (MaskPrefixLength(
91 internal::FuchsiaIpAddressToIPAddress(route.netmask)) == 0) {
92 default_route_ids.insert(route.nicid);
Kevin Marshall3e89fd72018-06-05 21:29:1093 }
94 }
95
Moe Ahmadi5bc177452019-01-23 18:48:5996 ConnectionType connection_type = CONNECTION_NONE;
Aidan Wolterd89b7542019-01-24 11:01:2197 base::flat_set<IPAddress> addresses;
98 for (auto& interface : interfaces) {
99 // Filter out loopback and invalid connection types.
100 if ((internal::ConvertConnectionType(interface) ==
101 NetworkChangeNotifier::CONNECTION_NONE) ||
102 (interface.features &
103 fuchsia::hardware::ethernet::INFO_FEATURE_LOOPBACK)) {
104 continue;
105 }
106
107 // Filter out interfaces that do not meet the |required_features_|.
108 if ((interface.features & required_features_) != required_features_) {
109 continue;
110 }
111
112 // Filter out interfaces with non-default routes.
113 if (!default_route_ids.contains(interface.id)) {
114 continue;
115 }
116
Kevin Marshall3e89fd72018-06-05 21:29:10117 std::vector<NetworkInterface> flattened_interfaces =
Aidan Wolterd89b7542019-01-24 11:01:21118 internal::NetInterfaceToNetworkInterfaces(interface);
119 if (flattened_interfaces.empty()) {
120 continue;
121 }
122
123 // Add the addresses from this interface to the list of all addresses.
Kevin Marshall3e89fd72018-06-05 21:29:10124 std::transform(
125 flattened_interfaces.begin(), flattened_interfaces.end(),
126 std::inserter(addresses, addresses.begin()),
127 [](const NetworkInterface& interface) { return interface.address; });
Aidan Wolterd89b7542019-01-24 11:01:21128
129 // Set the default connection to the first interface connection found.
130 if (connection_type == CONNECTION_NONE) {
Kevin Marshall3e89fd72018-06-05 21:29:10131 connection_type = flattened_interfaces.front().type;
132 }
Kevin Marshall3e89fd72018-06-05 21:29:10133 }
134
Kevin Marshall3e89fd72018-06-05 21:29:10135 if (addresses != cached_addresses_) {
136 std::swap(cached_addresses_, addresses);
Wezec6e7f12019-05-17 23:02:09137 if (notify_observers)
138 NotifyObserversOfIPAddressChange();
Kevin Marshall3e89fd72018-06-05 21:29:10139 }
140
Wezec6e7f12019-05-17 23:02:09141 if (connection_type != cached_connection_type_) {
142 base::subtle::Release_Store(&cached_connection_type_, connection_type);
143 if (notify_observers)
144 NotifyObserversOfConnectionTypeChange();
Kevin Marshall3e89fd72018-06-05 21:29:10145 }
Kevin Marshall3e89fd72018-06-05 21:29:10146}
147
148} // namespace net