blob: 848c0e03d082edf8cda60186b1dff444b8f055cb [file] [log] [blame]
// Copyright 2022 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/connectivity/network/mdns/service/agents/host_name_requestor.h"
#include <lib/syslog/cpp/macros.h>
#include <lib/zx/time.h>
#include <algorithm>
#include "src/connectivity/network/mdns/service/common/mdns_names.h"
namespace mdns {
HostNameRequestor::HostNameRequestor(MdnsAgent::Owner* owner, const std::string& host_name,
Media media, IpVersions ip_versions, bool include_local,
bool include_local_proxies)
: MdnsAgent(owner),
host_name_(host_name),
host_full_name_(MdnsNames::HostFullName(host_name)),
media_(media),
ip_versions_(ip_versions),
include_local_(include_local),
include_local_proxies_(include_local_proxies) {}
HostNameRequestor::~HostNameRequestor() {}
void HostNameRequestor::AddSubscriber(Mdns::HostNameSubscriber* subscriber) {
subscribers_.insert(subscriber);
if (started() && !prev_addresses_.empty()) {
subscriber->AddressesChanged(prev_addresses());
}
}
void HostNameRequestor::RemoveSubscriber(Mdns::HostNameSubscriber* subscriber) {
subscribers_.erase(subscriber);
if (subscribers_.empty()) {
RemoveSelf();
}
}
void HostNameRequestor::Start(const std::string& local_host_full_name) {
// Note that |host_full_name_| is the name we're trying to resolve, not the
// name of the local host, which is the parameter to this method.
local_host_full_name_ = local_host_full_name;
MdnsAgent::Start(local_host_full_name);
if (include_local_ && host_full_name_ == local_host_full_name_) {
// Respond with local addresses.
OnLocalHostAddressesChanged();
return;
}
SendQuestion(std::make_shared<DnsQuestion>(host_full_name_, DnsType::kA),
ReplyAddress::Multicast(media_, ip_versions_));
SendQuestion(std::make_shared<DnsQuestion>(host_full_name_, DnsType::kAaaa),
ReplyAddress::Multicast(media_, ip_versions_));
}
void HostNameRequestor::ReceiveResource(const DnsResource& resource, MdnsResourceSection section,
ReplyAddress sender_address) {
if (!sender_address.Matches(media_) || !sender_address.Matches(ip_versions_) ||
resource.name_.dotted_string_ != host_full_name_) {
return;
}
if (include_local_ && host_full_name_ == local_host_full_name_) {
return;
}
HostAddress address;
if (resource.type_ == DnsType::kA) {
address = HostAddress(resource.a_.address_.address_, sender_address.interface_id(),
zx::sec(resource.time_to_live_));
} else if (resource.type_ == DnsType::kAaaa) {
address = HostAddress(resource.aaaa_.address_.address_, sender_address.interface_id(),
zx::sec(resource.time_to_live_));
}
if (section == MdnsResourceSection::kExpired) {
if (prev_addresses_.count(address) == 0) {
return;
}
if (addresses_.empty()) {
addresses_ = prev_addresses_;
}
addresses_.erase(address);
if (addresses_.empty()) {
SendAddressesChanged();
}
return;
}
// Add an address.
addresses_.insert(std::move(address));
Renew(resource, media_, ip_versions_);
}
void HostNameRequestor::EndOfMessage() {
if (addresses_.empty()) {
return;
}
if (addresses_ == prev_addresses_) {
addresses_.clear();
return;
}
SendAddressesChanged();
}
void HostNameRequestor::OnAddProxyHost(const std::string& host_full_name,
const std::vector<HostAddress>& addresses) {
if (!include_local_proxies_ || host_full_name != host_full_name_) {
return;
}
addresses_.clear();
for (auto& address : addresses) {
addresses_.insert(address);
}
if (addresses_ == prev_addresses_) {
addresses_.clear();
return;
}
SendAddressesChanged();
}
void HostNameRequestor::OnRemoveProxyHost(const std::string& host_full_name) {
if (!include_local_proxies_ || host_full_name != host_full_name_) {
return;
}
addresses_.clear();
SendAddressesChanged();
}
void HostNameRequestor::OnLocalHostAddressesChanged() {
if (!include_local_ || host_full_name_ != local_host_full_name_) {
return;
}
auto addresses = local_host_addresses();
std::unordered_set<HostAddress, HostAddress::Hash> addresses_set(addresses.begin(),
addresses.end());
if (addresses_set == addresses_) {
return;
}
addresses_ = addresses_set;
SendAddressesChanged();
}
void HostNameRequestor::SendAddressesChanged() {
for (auto subscriber : subscribers_) {
subscriber->AddressesChanged(addresses());
}
prev_addresses_ = std::move(addresses_);
}
} // namespace mdns