blob: d93bf8d5ecc1153ba8a5a3767d470de576a4e8b9 [file] [log] [blame]
// Copyright 2017 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/address_responder.h"
#include <lib/syslog/cpp/macros.h>
#include "src/connectivity/network/mdns/service/common/mdns_names.h"
#include "src/connectivity/network/mdns/service/common/type_converters.h"
namespace mdns {
AddressResponder::AddressResponder(MdnsAgent::Owner* owner, Media media, IpVersions ip_versions)
: MdnsAgent(owner), media_(media), ip_versions_(ip_versions) {}
AddressResponder::AddressResponder(MdnsAgent::Owner* owner, std::string host_full_name,
std::vector<inet::IpAddress> addresses, Media media,
IpVersions ip_versions)
: MdnsAgent(owner),
host_full_name_(std::move(host_full_name)),
addresses_(std::move(addresses)),
media_(media),
ip_versions_(ip_versions) {
FX_DCHECK(!host_full_name_.empty());
// TODO(https://fxbug.dev/42065146): Restore this check when alt_services is no longer needed.
// FX_DCHECK(!addresses_.empty());
}
AddressResponder::~AddressResponder() {}
std::vector<HostAddress> AddressResponder::addresses() const {
return fidl::To<std::vector<HostAddress>>(addresses_);
}
void AddressResponder::Start(const std::string& local_host_full_name) {
FX_DCHECK(!local_host_full_name.empty());
MdnsAgent::Start(local_host_full_name);
if (host_full_name_.empty()) {
host_full_name_ = local_host_full_name;
}
}
void AddressResponder::ReceiveQuestion(const DnsQuestion& question,
const ReplyAddress& reply_address,
const ReplyAddress& sender_address) {
if (sender_address.Matches(media_) && sender_address.Matches(ip_versions_) &&
(question.type_ == DnsType::kA || question.type_ == DnsType::kAaaa ||
question.type_ == DnsType::kAny) &&
question.name_.dotted_string_ == host_full_name_) {
MaybeSendAddresses(reply_address);
}
}
void AddressResponder::MaybeSendAddresses(ReplyAddress reply_address) {
// We only throttle multicast sends. A V4 multicast reply address indicates V4 and V6 multicast.
if (reply_address.is_multicast_placeholder()) {
// Replace the general multicast placeholder with one that's restricted to the desired |Media|
// and |IpVersions|.
reply_address = ReplyAddress::Multicast(media_, ip_versions_);
if (throttle_state_ == kThrottleStatePending) {
// The send is already happening.
return;
}
if (throttle_state_ + kMinMulticastInterval > now()) {
// A send happened less than a second ago, and no send is currently scheduled. We need to
// schedule a multicast send for one second after the previous one.
PostTaskForTime(
[this, reply_address]() {
SendAddressResources(reply_address);
throttle_state_ = now();
},
throttle_state_ + kMinMulticastInterval);
throttle_state_ = kThrottleStatePending;
return;
}
}
SendAddressResources(reply_address);
throttle_state_ = now();
}
void AddressResponder::SendAddressResources(ReplyAddress reply_address) {
if (addresses_.empty()) {
// Send local addresses. The address value in the resource is invalid, which tells the interface
// transceivers to send their own addresses.
SendResource(std::make_shared<DnsResource>(host_full_name_, DnsType::kA),
MdnsResourceSection::kAnswer, reply_address);
} else {
// Send addresses that were provided in the constructor.
for (const auto& address : addresses_) {
SendResource(std::make_shared<DnsResource>(host_full_name_, address),
MdnsResourceSection::kAnswer, reply_address);
}
}
}
} // namespace mdns