123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216 |
- // 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 <iterator>
- #include <string>
- #include <utility>
- #include <vector>
- #include "base/bind.h"
- #include "base/fuchsia/fuchsia_logging.h"
- #include "base/strings/stringprintf.h"
- #include "third_party/abseil-cpp/absl/types/optional.h"
- namespace net {
- NetworkChangeNotifierFuchsia::NetworkChangeNotifierFuchsia(bool require_wlan)
- : NetworkChangeNotifierFuchsia(internal::ConnectInterfacesWatcher(),
- require_wlan) {}
- NetworkChangeNotifierFuchsia::NetworkChangeNotifierFuchsia(
- fidl::InterfaceHandle<fuchsia::net::interfaces::Watcher> handle,
- bool require_wlan,
- SystemDnsConfigChangeNotifier* system_dns_config_notifier)
- : NetworkChangeNotifier(NetworkChangeCalculatorParams(),
- system_dns_config_notifier),
- require_wlan_(require_wlan) {
- DCHECK(handle);
- watcher_.set_error_handler(base::LogFidlErrorAndExitProcess(
- FROM_HERE, "fuchsia.net.interfaces.Watcher"));
- fuchsia::net::interfaces::WatcherSyncPtr watcher = handle.BindSync();
- absl::optional<internal::ExistingInterfaceProperties> interfaces =
- internal::GetExistingInterfaces(watcher);
- if (!interfaces)
- return;
- handle = watcher.Unbind();
- bool notify_ip_address_changed = false;
- for (const auto& interface_entry : *interfaces) {
- notify_ip_address_changed |=
- CanReachExternalNetwork(interface_entry.second);
- }
- interface_cache_ = InterfacePropertiesMap(std::move(*interfaces));
- UpdateConnectionType();
- if (notify_ip_address_changed) {
- NotifyObserversOfIPAddressChange();
- }
- // Bind to the dispatcher for the thread's MessagePump.
- zx_status_t status = watcher_.Bind(std::move(handle));
- ZX_CHECK(status == ZX_OK, status) << "Bind()";
- watcher_->Watch(
- fit::bind_member(this, &NetworkChangeNotifierFuchsia::OnInterfacesEvent));
- }
- NetworkChangeNotifierFuchsia::~NetworkChangeNotifierFuchsia() {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- ClearGlobalPointer();
- }
- NetworkChangeNotifier::ConnectionType
- NetworkChangeNotifierFuchsia::GetCurrentConnectionType() const {
- ConnectionType type = static_cast<ConnectionType>(
- base::subtle::Acquire_Load(&cached_connection_type_));
- return type;
- }
- void NetworkChangeNotifierFuchsia::OnInterfacesEvent(
- fuchsia::net::interfaces::Event event) {
- // Immediately trigger the next watch, which will happen asynchronously. If
- // event processing encounters an error it'll close the watcher channel which
- // will cancel any pending callbacks.
- watcher_->Watch(
- fit::bind_member(this, &NetworkChangeNotifierFuchsia::OnInterfacesEvent));
- switch (event.Which()) {
- case fuchsia::net::interfaces::Event::kAdded:
- OnInterfaceAdded(std::move(event.added()));
- break;
- case fuchsia::net::interfaces::Event::kRemoved:
- OnInterfaceRemoved(event.removed());
- break;
- case fuchsia::net::interfaces::Event::kChanged:
- OnInterfaceChanged(std::move(event.changed()));
- break;
- case fuchsia::net::interfaces::Event::kExisting:
- case fuchsia::net::interfaces::Event::kIdle:
- OnWatcherError(base::StringPrintf(
- "OnInterfaceEvent: unexpected event %lu.", event.Which()));
- break;
- case fuchsia::net::interfaces::Event::Invalid:
- LOG(WARNING)
- << "Invalid event received from fuchsia.net.interfaces/Watcher";
- break;
- }
- }
- void NetworkChangeNotifierFuchsia::OnInterfaceAdded(
- fuchsia::net::interfaces::Properties properties) {
- uint64_t id = properties.id();
- absl::optional<internal::InterfaceProperties> cache_entry =
- internal::InterfaceProperties::VerifyAndCreate(std::move(properties));
- if (!cache_entry) {
- OnWatcherError("OnInterfaceAdded: incomplete interface properties.");
- return;
- }
- if (interface_cache_.find(id) != interface_cache_.end()) {
- OnWatcherError(base::StringPrintf(
- "OnInterfaceAdded: duplicate interface ID %lu.", id));
- return;
- }
- const bool can_reach = CanReachExternalNetwork(*cache_entry);
- interface_cache_.emplace(id, std::move(*cache_entry));
- UpdateConnectionType();
- if (can_reach) {
- NotifyObserversOfIPAddressChange();
- }
- }
- void NetworkChangeNotifierFuchsia::OnInterfaceRemoved(uint64_t interface_id) {
- InterfacePropertiesMap::iterator cache_entry =
- interface_cache_.find(interface_id);
- if (cache_entry == interface_cache_.end()) {
- OnWatcherError(base::StringPrintf(
- "OnInterfaceRemoved: unknown interface ID %lu.", interface_id));
- return;
- }
- const bool can_reach = CanReachExternalNetwork(cache_entry->second);
- interface_cache_.erase(cache_entry);
- UpdateConnectionType();
- if (can_reach) {
- NotifyObserversOfIPAddressChange();
- }
- }
- void NetworkChangeNotifierFuchsia::OnInterfaceChanged(
- fuchsia::net::interfaces::Properties properties) {
- if (!properties.has_id()) {
- OnWatcherError("OnInterfaceChanged: no interface ID.");
- return;
- }
- const uint64_t id = properties.id();
- InterfacePropertiesMap::iterator cache_entry = interface_cache_.find(id);
- if (cache_entry == interface_cache_.end()) {
- OnWatcherError(base::StringPrintf(
- "OnInterfaceChanged: unknown interface ID %lu.", id));
- return;
- }
- const bool old_can_reach = CanReachExternalNetwork(cache_entry->second);
- const bool has_addresses = properties.has_addresses();
- if (!cache_entry->second.Update(std::move(properties))) {
- OnWatcherError("OnInterfaceChanged: update failed.");
- return;
- }
- UpdateConnectionType();
- const bool can_reach = CanReachExternalNetwork(cache_entry->second);
- if (has_addresses || old_can_reach != can_reach) {
- NotifyObserversOfIPAddressChange();
- }
- }
- void NetworkChangeNotifierFuchsia::OnWatcherError(
- base::StringPiece error_message) {
- LOG(ERROR) << error_message;
- watcher_.Unbind();
- ResetConnectionType();
- }
- void NetworkChangeNotifierFuchsia::UpdateConnectionType() {
- ConnectionType connection_type = ConnectionType::CONNECTION_NONE;
- for (const auto& interface : interface_cache_) {
- if (CanReachExternalNetwork(interface.second)) {
- connection_type = GetEffectiveConnectionType(interface.second);
- break;
- }
- }
- if (connection_type != GetCurrentConnectionType()) {
- base::subtle::Release_Store(&cached_connection_type_, connection_type);
- NotifyObserversOfConnectionTypeChange();
- }
- }
- void NetworkChangeNotifierFuchsia::ResetConnectionType() {
- base::subtle::Release_Store(&cached_connection_type_,
- ConnectionType::CONNECTION_UNKNOWN);
- }
- NetworkChangeNotifier::ConnectionType
- NetworkChangeNotifierFuchsia::GetEffectiveConnectionType(
- const internal::InterfaceProperties& properties) {
- if (!properties.IsPubliclyRoutable())
- return NetworkChangeNotifier::CONNECTION_NONE;
- NetworkChangeNotifier::ConnectionType connection_type =
- internal::ConvertConnectionType(properties.device_class());
- if (require_wlan_ &&
- connection_type != NetworkChangeNotifier::CONNECTION_WIFI) {
- return NetworkChangeNotifier::CONNECTION_NONE;
- }
- return connection_type;
- }
- bool NetworkChangeNotifierFuchsia::CanReachExternalNetwork(
- const internal::InterfaceProperties& properties) {
- return GetEffectiveConnectionType(properties) !=
- NetworkChangeNotifier::CONNECTION_NONE;
- }
- } // namespace net
|