blob: efdc637c6ff25a333d24b7f6cd42ba4a92a6c530 [file] [log] [blame]
// Copyright 2018 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 "garnet/bin/mdns/service/fidl_interface_monitor.h"
#include "garnet/bin/mdns/service/mdns_fidl_util.h"
#include "lib/fxl/logging.h"
namespace mdns {
// static
std::unique_ptr<InterfaceMonitor> FidlInterfaceMonitor::Create(
fuchsia::sys::StartupContext* startup_context) {
return std::unique_ptr<InterfaceMonitor>(
new FidlInterfaceMonitor(startup_context));
}
FidlInterfaceMonitor::FidlInterfaceMonitor(
fuchsia::sys::StartupContext* startup_context)
: binding_(this) {
netstack_ = startup_context
->ConnectToEnvironmentService<fuchsia::netstack::Netstack>();
fidl::InterfaceHandle<fuchsia::netstack::NotificationListener>
listener_handle;
binding_.Bind(listener_handle.NewRequest());
binding_.set_error_handler([this]() {
binding_.set_error_handler(nullptr);
binding_.Unbind();
FXL_LOG(ERROR) << "Connection to netstack dropped.";
});
netstack_->RegisterListener(std::move(listener_handle));
netstack_->GetInterfaces(
[this](fidl::VectorPtr<fuchsia::netstack::NetInterface> interfaces) {
OnInterfacesChanged(std::move(interfaces));
});
}
FidlInterfaceMonitor::~FidlInterfaceMonitor() {
if (binding_.is_bound()) {
binding_.set_error_handler(nullptr);
binding_.Unbind();
}
}
void FidlInterfaceMonitor::RegisterLinkChangeCallback(fit::closure callback) {
link_change_callback_ = std::move(callback);
}
const std::vector<std::unique_ptr<InterfaceDescriptor>>&
FidlInterfaceMonitor::GetInterfaces() {
return interfaces_;
}
void FidlInterfaceMonitor::OnInterfacesChanged(
fidl::VectorPtr<fuchsia::netstack::NetInterface> interfaces) {
bool link_change = false;
for (const auto& if_info : *interfaces) {
IpAddress address = MdnsFidlUtil::IpAddressFrom(&if_info.addr);
if (!address.is_valid() || address.is_loopback() ||
(if_info.flags & fuchsia::netstack::NetInterfaceFlagUp) == 0) {
if (interfaces_.size() > if_info.id &&
interfaces_[if_info.id] != nullptr) {
// Interface went away.
interfaces_[if_info.id] = nullptr;
link_change = true;
}
continue;
}
// Make sure the |interfaces_| array is big enough.
if (interfaces_.size() <= if_info.id) {
interfaces_.resize(if_info.id + 1);
}
InterfaceDescriptor* existing = interfaces_[if_info.id].get();
if (existing == nullptr) {
// We don't have an |InterfaceDescriptor| for this interface yet. Add one.
interfaces_[if_info.id].reset(
new InterfaceDescriptor(address, if_info.name));
link_change = true;
} else if (existing->address_ != address ||
existing->name_ != if_info.name) {
// We have an |InterfaceDescriptor| for this interface, but it's
// out-of-date. Update it.
existing->address_ = address;
existing->name_ = if_info.name;
link_change = true;
}
}
if (link_change && link_change_callback_) {
link_change_callback_();
}
}
} // namespace mdns