mirror of
https://github.com/klzgrad/naiveproxy.git
synced 2024-12-01 01:36:09 +03:00
150 lines
5.2 KiB
C++
150 lines
5.2 KiB
C++
// Copyright 2018 The Chromium Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#include "net/base/network_change_notifier_fuchsia.h"
|
|
|
|
#include <algorithm>
|
|
#include <string>
|
|
#include <utility>
|
|
#include <vector>
|
|
|
|
#include "base/fuchsia/component_context.h"
|
|
#include "base/optional.h"
|
|
#include "base/run_loop.h"
|
|
#include "net/base/network_interfaces.h"
|
|
#include "net/base/network_interfaces_fuchsia.h"
|
|
|
|
namespace net {
|
|
namespace {
|
|
|
|
using ConnectionType = NetworkChangeNotifier::ConnectionType;
|
|
|
|
// Adapts a base::RepeatingCallback to a std::function object.
|
|
// Useful when binding callbacks to asynchronous FIDL calls, because
|
|
// it allows the caller to reference in-scope move-only objects as well as use
|
|
// Chromium's ownership signifiers such as base::Passed, base::Unretained, etc.
|
|
//
|
|
// Note that the function takes a RepeatingCallback because it is copyable, but
|
|
// in practice the callback will only be executed once by the FIDL system.
|
|
template <typename R, typename... Args>
|
|
std::function<R(Args...)> WrapCallbackAsFunction(
|
|
base::RepeatingCallback<R(Args...)> callback) {
|
|
return
|
|
[callback](Args... args) { callback.Run(std::forward<Args>(args)...); };
|
|
}
|
|
|
|
} // namespace
|
|
|
|
NetworkChangeNotifierFuchsia::NetworkChangeNotifierFuchsia()
|
|
: NetworkChangeNotifierFuchsia(
|
|
base::fuchsia::ComponentContext::GetDefault()
|
|
->ConnectToService<fuchsia::netstack::Netstack>()) {}
|
|
|
|
NetworkChangeNotifierFuchsia::NetworkChangeNotifierFuchsia(
|
|
fuchsia::netstack::NetstackPtr netstack)
|
|
: netstack_(std::move(netstack)) {
|
|
DCHECK(netstack_);
|
|
|
|
netstack_.set_error_handler(
|
|
[this]() { LOG(ERROR) << "Lost connection to netstack."; });
|
|
netstack_.events().OnInterfacesChanged =
|
|
[this](fidl::VectorPtr<fuchsia::netstack::NetInterface> interfaces) {
|
|
ProcessInterfaceList(base::OnceClosure(), std::move(interfaces));
|
|
};
|
|
|
|
// Fetch the interface list synchronously, so that an initial ConnectionType
|
|
// is available before we return.
|
|
base::RunLoop wait_for_interfaces;
|
|
netstack_->GetInterfaces([
|
|
this, quit_closure = wait_for_interfaces.QuitClosure()
|
|
](fidl::VectorPtr<fuchsia::netstack::NetInterface> interfaces) {
|
|
ProcessInterfaceList(quit_closure, std::move(interfaces));
|
|
});
|
|
wait_for_interfaces.Run();
|
|
}
|
|
|
|
NetworkChangeNotifierFuchsia::~NetworkChangeNotifierFuchsia() {
|
|
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
|
|
}
|
|
|
|
NetworkChangeNotifier::ConnectionType
|
|
NetworkChangeNotifierFuchsia::GetCurrentConnectionType() const {
|
|
ConnectionType type = static_cast<ConnectionType>(
|
|
base::subtle::Acquire_Load(&cached_connection_type_));
|
|
return type;
|
|
}
|
|
|
|
void NetworkChangeNotifierFuchsia::ProcessInterfaceList(
|
|
base::OnceClosure on_initialized_cb,
|
|
fidl::VectorPtr<fuchsia::netstack::NetInterface> interfaces) {
|
|
netstack_->GetRouteTable(WrapCallbackAsFunction(base::BindRepeating(
|
|
&NetworkChangeNotifierFuchsia::OnRouteTableReceived,
|
|
base::Unretained(this), base::Passed(std::move(on_initialized_cb)),
|
|
base::Passed(std::move(interfaces)))));
|
|
}
|
|
|
|
void NetworkChangeNotifierFuchsia::OnRouteTableReceived(
|
|
base::OnceClosure on_initialized_cb,
|
|
fidl::VectorPtr<fuchsia::netstack::NetInterface> interfaces,
|
|
fidl::VectorPtr<fuchsia::netstack::RouteTableEntry> route_table) {
|
|
// Find the default interface in the routing table.
|
|
auto default_route_interface = std::find_if(
|
|
route_table->begin(), route_table->end(),
|
|
[](const fuchsia::netstack::RouteTableEntry& rt) {
|
|
return MaskPrefixLength(internal::NetAddressToIPAddress(rt.netmask)) ==
|
|
0;
|
|
});
|
|
|
|
// Find the default interface in the NetInterface list.
|
|
const fuchsia::netstack::NetInterface* default_interface = nullptr;
|
|
if (default_route_interface != route_table->end()) {
|
|
for (const auto& cur_interface : *interfaces) {
|
|
if (cur_interface.id == default_route_interface->nicid) {
|
|
default_interface = &cur_interface;
|
|
}
|
|
}
|
|
}
|
|
|
|
base::flat_set<IPAddress> addresses;
|
|
std::string ssid;
|
|
ConnectionType connection_type = CONNECTION_NONE;
|
|
if (default_interface) {
|
|
std::vector<NetworkInterface> flattened_interfaces =
|
|
internal::NetInterfaceToNetworkInterfaces(*default_interface);
|
|
std::transform(
|
|
flattened_interfaces.begin(), flattened_interfaces.end(),
|
|
std::inserter(addresses, addresses.begin()),
|
|
[](const NetworkInterface& interface) { return interface.address; });
|
|
if (!flattened_interfaces.empty()) {
|
|
connection_type = flattened_interfaces.front().type;
|
|
}
|
|
|
|
// TODO(https://crbug.com/848355): Treat SSID changes as IP address changes.
|
|
}
|
|
|
|
bool connection_type_changed = false;
|
|
if (connection_type != cached_connection_type_) {
|
|
base::subtle::Release_Store(&cached_connection_type_, connection_type);
|
|
connection_type_changed = true;
|
|
}
|
|
|
|
if (addresses != cached_addresses_) {
|
|
std::swap(cached_addresses_, addresses);
|
|
if (on_initialized_cb.is_null()) {
|
|
NotifyObserversOfIPAddressChange();
|
|
}
|
|
connection_type_changed = true;
|
|
}
|
|
|
|
if (on_initialized_cb.is_null() && connection_type_changed) {
|
|
NotifyObserversOfConnectionTypeChange();
|
|
}
|
|
|
|
if (!on_initialized_cb.is_null()) {
|
|
std::move(on_initialized_cb).Run();
|
|
}
|
|
}
|
|
|
|
} // namespace net
|