blob: 575a55019f80786c5cc0c4ff51d9fc6fa52f7508 [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.
#ifndef SRC_CONNECTIVITY_NETWORK_MDNS_SERVICE_AGENTS_INSTANCE_REQUESTOR_H_
#define SRC_CONNECTIVITY_NETWORK_MDNS_SERVICE_AGENTS_INSTANCE_REQUESTOR_H_
#include <lib/zx/time.h>
#include <algorithm>
#include <memory>
#include <queue>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include "src/connectivity/network/mdns/service/agents/mdns_agent.h"
#include "src/connectivity/network/mdns/service/mdns.h"
#include "src/lib/inet/socket_address.h"
namespace mdns {
// Searches for instances of a service type.
class InstanceRequestor : public MdnsAgent {
public:
// Creates an |InstanceRequestor|.
InstanceRequestor(MdnsAgent::Owner* owner, const std::string& service_name, Media media,
IpVersions ip_versions, bool include_local, bool include_local_proxies);
// Creates an |InstanceRequestor| requesting all services.
InstanceRequestor(MdnsAgent::Owner* owner, Media media, IpVersions ip_versions,
bool include_local, bool include_local_proxies);
~InstanceRequestor() override = default;
// Adds the subscriber.
void AddSubscriber(Mdns::Subscriber* subscriber);
// Removes the subscriber. If it's the last subscriber, this
// |InstanceRequestor| is destroyed.
void RemoveSubscriber(Mdns::Subscriber* subscriber);
// MdnsAgent overrides.
void Start(const std::string& local_host_full_name) override;
void ReceiveResource(const DnsResource& resource, MdnsResourceSection section,
ReplyAddress sender_address) override;
void EndOfMessage() override;
void OnAddLocalServiceInstance(const Mdns::ServiceInstance& instance, bool from_proxy) override;
void OnChangeLocalServiceInstance(const Mdns::ServiceInstance& instance,
bool from_proxy) override;
void OnRemoveLocalServiceInstance(const std::string& service_name,
const std::string& instance_name, bool from_proxy) override;
private:
// Set of socket addresses associated with a target.
class TargetAddressSet {
public:
TargetAddressSet() = default;
~TargetAddressSet() = default;
// Indicates whether the set is empty.
bool empty() const { return insert_times_by_address_.empty(); }
// Erases |address| from the set. Returns true if the address was in the set, false if not.
bool erase(inet::SocketAddress address) { return insert_times_by_address_.erase(address); }
// Inserts |address| into the set if it isn't already there. The age of the address is zeroed
// regardless. Returns true if the address was added, false if it was already there.
bool insert(inet::SocketAddress address) {
auto now = zx::clock::get_monotonic();
auto [iter, inserted] = insert_times_by_address_.emplace(address, now);
if (!inserted) {
iter->second = now;
}
return inserted;
}
// Replaces all addresses in the set with |from| and returns true, unless this set already
// contains exactly the addresses in |from|, in which case changes nothing and returns false.
// This is used only for local instances and does not assign meaningful insert times.
bool Replace(const std::vector<inet::SocketAddress>& from);
// Erases all IPv4 addresses that are older than one second.
void EraseV4AddressesOlderThanOneSecond();
// Erases all IPv6 addresses that are older than one second.
void EraseV6AddressesOlderThanOneSecond();
// Returns a list of the contained addresses each with its port number replaced with |port|.
std::vector<inet::SocketAddress> AddressesWithPort(inet::IpPort port);
private:
std::unordered_map<inet::SocketAddress, zx::time> insert_times_by_address_;
};
// Describes a service instance.
struct InstanceInfo {
std::string service_name_;
std::string instance_name_;
std::string target_;
std::string target_full_name_;
inet::IpPort port_;
std::vector<std::vector<uint8_t>> text_;
uint16_t srv_priority_ = 0;
uint16_t srv_weight_ = 0;
bool new_ = true;
bool dirty_ = true;
bool srv_queried_ = false;
bool txt_received_ = false;
bool txt_queried_ = false;
};
// Describes a target. We use |inet::SocketAddress| because it has scope_id. The port numbers
// aren't used. |InstanceInfo| provides the service instance's port number.
struct TargetInfo {
TargetAddressSet addresses_;
bool keep_ = false;
bool dirty_ = false;
bool addresses_queried_ = false;
};
// Report all known instances to the indicated subscriber.
void ReportAllDiscoveries(Mdns::Subscriber* subscriber);
// Sends a query for instances and schedules the next query, as appropriate.
void SendQuery();
void ReceivePtrResource(const DnsResource& resource, MdnsResourceSection section);
void ReceiveSrvResource(const DnsResource& resource, MdnsResourceSection section,
InstanceInfo* instance_info);
void ReceiveTxtResource(const DnsResource& resource, MdnsResourceSection section,
InstanceInfo* instance_info);
void ReceiveAResource(const DnsResource& resource, MdnsResourceSection section,
TargetInfo* target_info, uint32_t scope_id);
void ReceiveAaaaResource(const DnsResource& resource, MdnsResourceSection section,
TargetInfo* target_info, uint32_t scope_id);
void RemoveInstance(const std::string& instance_full_name);
std::string service_name_;
std::string service_full_name_;
Media media_;
IpVersions ip_versions_;
bool include_local_;
bool include_local_proxies_;
std::unordered_set<Mdns::Subscriber*> subscribers_;
std::unordered_map<std::string, InstanceInfo> instance_infos_by_full_name_;
std::unordered_map<std::string, TargetInfo> target_infos_by_full_name_;
zx::duration query_delay_;
std::shared_ptr<DnsQuestion> question_;
public:
// Disallow copy, assign and move.
InstanceRequestor(const InstanceRequestor&) = delete;
InstanceRequestor(InstanceRequestor&&) = delete;
InstanceRequestor& operator=(const InstanceRequestor&) = delete;
InstanceRequestor& operator=(InstanceRequestor&&) = delete;
};
} // namespace mdns
#endif // SRC_CONNECTIVITY_NETWORK_MDNS_SERVICE_AGENTS_INSTANCE_REQUESTOR_H_