blob: 47bf9c12b53e5555d41f8aeabf3045434e32fd32 [file] [log] [blame]
// Copyright 2020 The Fuchsia 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 "src/developer/forensics/crash_reports/network_watcher.h"
#include <lib/syslog/cpp/macros.h>
namespace forensics {
namespace crash_reports {
NetworkWatcher::NetworkWatcher(async_dispatcher_t* dispatcher,
std::shared_ptr<sys::ServiceDirectory> services)
: dispatcher_(dispatcher),
services_(std::move(services)),
netstack_(),
backoff_(/*initial_delay=*/zx::min(1), /*retry_factor=*/2u,
/*max_delay=*/zx::hour(1)),
callbacks_() {
netstack_.set_error_handler([this](const zx_status_t status) {
FX_PLOGS(WARNING, status) << "Lost connection to " << fuchsia::netstack::Netstack::Name_;
watch_task_.PostDelayed(dispatcher_, backoff_.GetNext());
});
Watch();
}
void NetworkWatcher::Register(fit::function<void(bool)> on_reachable) {
callbacks_.push_back(std::move(on_reachable));
}
void NetworkWatcher::Watch() {
if (!netstack_.is_bound()) {
services_->Connect(netstack_.NewRequest(dispatcher_));
}
auto IsReachable = [](const fuchsia::netstack::NetInterface& interface) {
if ((interface.flags & fuchsia::netstack::Flags::UP) != fuchsia::netstack::Flags::UP) {
return false;
}
if ((interface.flags & fuchsia::netstack::Flags::DHCP) != fuchsia::netstack::Flags::DHCP) {
return false;
}
auto isZero = [](const uint8_t octet) { return octet == 0; };
switch (interface.addr.Which()) {
case fuchsia::net::IpAddress::Tag::kIpv4: {
const auto& octets = interface.addr.ipv4().addr;
return !std::all_of(octets.cbegin(), octets.cend(), isZero);
}
case fuchsia::net::IpAddress::Tag::kIpv6: {
const auto& octets = interface.addr.ipv6().addr;
return !std::all_of(octets.cbegin(), octets.cend(), isZero);
}
case fuchsia::net::IpAddress::Tag::Invalid: {
FX_LOGS(ERROR) << "Network interface " << interface.name << " has malformed IP address";
return false;
}
}
};
netstack_.events().OnInterfacesChanged =
[this, IsReachable](std::vector<fuchsia::netstack::NetInterface> interfaces) {
backoff_.Reset();
const bool reachable = std::any_of(interfaces.cbegin(), interfaces.cend(), IsReachable);
for (const auto& on_reachable : callbacks_) {
on_reachable(reachable);
}
};
}
} // namespace crash_reports
} // namespace forensics