|  | // 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_MDNS_H_ | 
|  | #define SRC_CONNECTIVITY_NETWORK_MDNS_SERVICE_MDNS_H_ | 
|  |  | 
|  | #include <fuchsia/net/interfaces/cpp/fidl.h> | 
|  | #include <fuchsia/net/mdns/cpp/fidl.h> | 
|  | #include <lib/async/dispatcher.h> | 
|  | #include <lib/fit/function.h> | 
|  | #include <lib/zx/clock.h> | 
|  |  | 
|  | #include <memory> | 
|  | #include <queue> | 
|  | #include <string> | 
|  | #include <unordered_map> | 
|  | #include <unordered_set> | 
|  | #include <vector> | 
|  |  | 
|  | #include "src/connectivity/network/mdns/service/agents/address_prober.h" | 
|  | #include "src/connectivity/network/mdns/service/agents/address_responder.h" | 
|  | #include "src/connectivity/network/mdns/service/agents/mdns_agent.h" | 
|  | #include "src/connectivity/network/mdns/service/common/service_instance.h" | 
|  | #include "src/connectivity/network/mdns/service/encoding/dns_message.h" | 
|  | #include "src/connectivity/network/mdns/service/transport/mdns_interface_transceiver.h" | 
|  | #include "src/lib/inet/socket_address.h" | 
|  |  | 
|  | namespace mdns { | 
|  |  | 
|  | class HostNameRequestor; | 
|  | class InstanceProber; | 
|  | class InstanceRequestor; | 
|  | class InstanceResponder; | 
|  | class ResourceRenewer; | 
|  |  | 
|  | // Implements mDNS. | 
|  | class Mdns : public MdnsAgent::Owner { | 
|  | public: | 
|  | // Abstract base class for message transceiver. | 
|  | class Transceiver { | 
|  | public: | 
|  | using InboundMessageCallback = | 
|  | fit::function<void(std::unique_ptr<DnsMessage>, const ReplyAddress&)>; | 
|  | using InterfaceTransceiverCreateFunction = | 
|  | fit::function<std::unique_ptr<MdnsInterfaceTransceiver>(inet::IpAddress, const std::string&, | 
|  | uint32_t, Media)>; | 
|  |  | 
|  | virtual ~Transceiver() {} | 
|  |  | 
|  | // Starts the transceiver. | 
|  | virtual void Start(fuchsia::net::interfaces::WatcherPtr watcher, | 
|  | fit::closure link_change_callback, | 
|  | InboundMessageCallback inbound_message_callback, | 
|  | InterfaceTransceiverCreateFunction transceiver_factory) = 0; | 
|  |  | 
|  | // Stops the transceiver. | 
|  | virtual void Stop() = 0; | 
|  |  | 
|  | // Determines if this transceiver has interfaces. | 
|  | virtual bool HasInterfaces() = 0; | 
|  |  | 
|  | // Sends a message to the specified address. A V6 interface will send to | 
|  | // |MdnsAddresses::V6Multicast| if |reply_address.socket_address()| is | 
|  | // |MdnsAddresses::V4Multicast|. | 
|  | virtual void SendMessage(const DnsMessage& message, const ReplyAddress& reply_address) = 0; | 
|  |  | 
|  | // Writes log messages describing lifetime traffic. | 
|  | virtual void LogTraffic() = 0; | 
|  |  | 
|  | // Gets the list of addresses for the local host. | 
|  | virtual std::vector<HostAddress> LocalHostAddresses() = 0; | 
|  | }; | 
|  |  | 
|  | // Describes an initial instance publication or query response. | 
|  | struct Publication { | 
|  | static std::unique_ptr<Publication> Create( | 
|  | inet::IpPort port, | 
|  | const std::vector<std::vector<uint8_t>>& text = std::vector<std::vector<uint8_t>>(), | 
|  | uint16_t srv_priority = 0, uint16_t srv_weight = 0); | 
|  |  | 
|  | std::unique_ptr<Publication> Clone() const; | 
|  |  | 
|  | inet::IpPort port_; | 
|  | std::vector<std::vector<uint8_t>> text_; | 
|  | uint16_t srv_priority_ = 0; | 
|  | uint16_t srv_weight_ = 0; | 
|  | uint32_t ptr_ttl_seconds_ = 120;   // default 2 minutes | 
|  | uint32_t srv_ttl_seconds_ = 120;   // default 2 minutes | 
|  | uint32_t txt_ttl_seconds_ = 4500;  // default 75 minutes | 
|  | }; | 
|  |  | 
|  | using ServiceInstance = ServiceInstance; | 
|  |  | 
|  | // Abstract base class for client-supplied subscriber. | 
|  | class HostNameSubscriber { | 
|  | public: | 
|  | virtual ~HostNameSubscriber(); | 
|  |  | 
|  | // Unsubscribes from the host name. If this |Subscriber| is already | 
|  | // unsubscribed, this method does nothing. | 
|  | void Unsubscribe(); | 
|  |  | 
|  | // Called when addresses associated with the host name are changed. | 
|  | virtual void AddressesChanged(std::vector<HostAddress> addresses) = 0; | 
|  |  | 
|  | protected: | 
|  | HostNameSubscriber() = default; | 
|  |  | 
|  | private: | 
|  | void Connect(std::shared_ptr<HostNameRequestor> host_name_requestor); | 
|  |  | 
|  | std::shared_ptr<HostNameRequestor> host_name_requestor_; | 
|  |  | 
|  | friend class Mdns; | 
|  | }; | 
|  |  | 
|  | // Abstract base class for client-supplied subscriber. | 
|  | class Subscriber { | 
|  | public: | 
|  | virtual ~Subscriber(); | 
|  |  | 
|  | // Unsubscribes from the service. If this |Subscriber| is already | 
|  | // unsubscribed, this method does nothing. | 
|  | void Unsubscribe(); | 
|  |  | 
|  | // Called when a new instance is discovered. | 
|  | virtual void InstanceDiscovered(const std::string& service, const std::string& instance, | 
|  | const std::vector<inet::SocketAddress>& addresses, | 
|  | const std::vector<std::vector<uint8_t>>& text, | 
|  | uint16_t srv_priority, uint16_t srv_weight, | 
|  | const std::string& target) = 0; | 
|  |  | 
|  | // Called when a previously discovered instance changes addresses or text. | 
|  | virtual void InstanceChanged(const std::string& service, const std::string& instance, | 
|  | const std::vector<inet::SocketAddress>& addresses, | 
|  | const std::vector<std::vector<uint8_t>>& text, | 
|  | uint16_t srv_priority, uint16_t srv_weight, | 
|  | const std::string& target) = 0; | 
|  |  | 
|  | // Called when an instance is lost. | 
|  | virtual void InstanceLost(const std::string& service, const std::string& instance) = 0; | 
|  |  | 
|  | // Called when a query is sent. | 
|  | virtual void Query(DnsType type_queried) = 0; | 
|  |  | 
|  | protected: | 
|  | Subscriber() {} | 
|  |  | 
|  | private: | 
|  | void Connect(std::shared_ptr<InstanceRequestor> instance_requestor); | 
|  |  | 
|  | std::shared_ptr<InstanceRequestor> instance_requestor_; | 
|  |  | 
|  | friend class Mdns; | 
|  | }; | 
|  |  | 
|  | // Abstract base class for client-supplied publisher. | 
|  | class Publisher { | 
|  | public: | 
|  | using GetPublicationCallback = fit::function<void(std::unique_ptr<Publication>)>; | 
|  |  | 
|  | virtual ~Publisher(); | 
|  |  | 
|  | // Sets subtypes for the service instance.  If this |Publisher| is | 
|  | // unpublished, this method does nothing. | 
|  | void SetSubtypes(std::vector<std::string> subtypes); | 
|  |  | 
|  | // Initiates announcement of the service instance.  If this |Publisher| is | 
|  | // unpublished, this method does nothing. | 
|  | void Reannounce(); | 
|  |  | 
|  | // Unpublishes the service instance. If this |Publisher| is already | 
|  | // unpublished, this method does nothing. | 
|  | void Unpublish(); | 
|  |  | 
|  | // Reports whether the publication attempt was successful. Publication can | 
|  | // fail if the service instance is currently be published by another device | 
|  | // on the subnet. | 
|  | virtual void ReportSuccess(bool success) = 0; | 
|  |  | 
|  | // Provides instance information for initial announcements and query | 
|  | // responses relating to the service instance specified in |PublishServiceInstance|. | 
|  | // |pubication_type| indicates whether data is requested for an initial announcement | 
|  | // or in response to a multicast or unicast query. If the publication relates to | 
|  | // a subtype of the service, |subtype| contains the subtype, otherwise it is | 
|  | // empty. |source_addresses| supplies the source addresses of the queries that | 
|  | // caused this publication. If the publication provided by the callback is null, no | 
|  | // announcement or response is transmitted. | 
|  | virtual void GetPublication(PublicationCause pubication_type, const std::string& subtype, | 
|  | const std::vector<inet::SocketAddress>& source_addresses, | 
|  | GetPublicationCallback callback) = 0; | 
|  |  | 
|  | protected: | 
|  | Publisher() {} | 
|  |  | 
|  | private: | 
|  | void Connect(std::shared_ptr<InstanceResponder> instance_responder); | 
|  |  | 
|  | void ConnectProber(std::shared_ptr<InstanceProber> instance_prober); | 
|  |  | 
|  | void DisconnectProber(); | 
|  |  | 
|  | std::shared_ptr<InstanceResponder> instance_responder_; | 
|  | std::shared_ptr<InstanceProber> instance_prober_; | 
|  |  | 
|  | friend class Mdns; | 
|  | }; | 
|  |  | 
|  | // Abstract base class for client-supplied host publisher. | 
|  | class HostPublisher { | 
|  | public: | 
|  | virtual ~HostPublisher(); | 
|  |  | 
|  | // Unpublishes the service instance. If this |Publisher| is already | 
|  | // unpublished, this method does nothing. | 
|  | void Unpublish(); | 
|  |  | 
|  | // Reports whether the publication attempt was successful. Publication can | 
|  | // fail if the service instance is currently being published by another device | 
|  | // on the subnet. | 
|  | virtual void ReportSuccess(bool success) = 0; | 
|  |  | 
|  | protected: | 
|  | HostPublisher() = default; | 
|  |  | 
|  | private: | 
|  | void Connect(std::shared_ptr<AddressResponder> address_responder); | 
|  |  | 
|  | void ConnectProber(std::shared_ptr<AddressProber> address_prober); | 
|  |  | 
|  | void DisconnectProber(); | 
|  |  | 
|  | std::shared_ptr<AddressResponder> address_responder_; | 
|  | std::shared_ptr<AddressProber> address_prober_; | 
|  |  | 
|  | friend class Mdns; | 
|  | }; | 
|  |  | 
|  | using ResolveHostNameCallback = | 
|  | fit::function<void(const std::string& host_name, std::vector<HostAddress> addresses)>; | 
|  |  | 
|  | using ResolveServiceInstanceCallback = fit::function<void(fuchsia::net::mdns::ServiceInstance)>; | 
|  |  | 
|  | // |transceiver| must live as long as this |Mdns| object. | 
|  | Mdns(Transceiver& transceiver); | 
|  |  | 
|  | virtual ~Mdns() override; | 
|  |  | 
|  | // Determines whether message traffic will be logged. | 
|  | void SetVerbose(bool verbose); | 
|  |  | 
|  | // Starts the transceiver. |ready_callback| is called once we're is ready for | 
|  | // calls to |ResolveHostName|, |SubscribeToService| and | 
|  | // |PublishServiceInstance|. | 
|  | void Start(fuchsia::net::interfaces::WatcherPtr, const std::string& local_host_name, | 
|  | bool perform_address_probe, fit::closure ready_callback, | 
|  | std::vector<std::string> alt_services); | 
|  |  | 
|  | // Stops the transceiver. | 
|  | void Stop(); | 
|  |  | 
|  | // Returns the local host name currently in use. May be different than the host name | 
|  | // passed in to |Start| if address probing detected conflicts. | 
|  | std::string local_host_name() { return local_host_name_; } | 
|  |  | 
|  | // Resolves |host_name| to |IpAddress|es. Must not be called before |Start|'s ready callback is | 
|  | // called. | 
|  | void ResolveHostName(const std::string& host_name, zx::duration timeout, Media media, | 
|  | IpVersions ip_versions, bool include_local, bool include_local_proxies, | 
|  | ResolveHostNameCallback callback); | 
|  |  | 
|  | // Subscribes to the specified host name. Must not be called before | 
|  | // |Start|'s ready callback is called. The subscription is cancelled when | 
|  | // the subscriber is deleted or its |Unsubscribe| method is called. | 
|  | // Multiple subscriptions may be created for a given host name. | 
|  | void SubscribeToHostName(const std::string& host_name, Media media, IpVersions ip_versions, | 
|  | bool include_local, bool include_local_proxies, | 
|  | HostNameSubscriber* subscriber); | 
|  |  | 
|  | // Resolves |service+instance| to a node, i.e sends an SRV query and gets | 
|  | // a valid response if the service instance exists/is active. | 
|  | void ResolveServiceInstance(const std::string& service, const std::string& instance, | 
|  | zx::time timeout, Media media, IpVersions ip_versions, | 
|  | bool include_local, bool include_local_proxies, | 
|  | ResolveServiceInstanceCallback callback); | 
|  |  | 
|  | // Subscribes to the specified service. The subscription is cancelled when | 
|  | // the subscriber is deleted or its |Unsubscribe| method is called. | 
|  | // Multiple subscriptions may be created for a given service name. Must not be | 
|  | // called before |Start|'s ready callback is called. | 
|  | void SubscribeToService(const std::string& service_name, Media media, IpVersions ip_versions, | 
|  | bool include_local, bool include_local_proxies, Subscriber* subscriber); | 
|  |  | 
|  | // Subscribes to all services. The subscription is cancelled when the subscriber is deleted or its | 
|  | // |Unsubscribe| method is called. Multiple subscriptions may be created for a all services. Must | 
|  | // not be called before |Start|'s ready callback is called. | 
|  | void SubscribeToAllServices(Media media, IpVersions ip_versions, bool include_local, | 
|  | bool include_local_proxies, Subscriber* subscriber); | 
|  |  | 
|  | // Publishes a service instance. Returns false if and only if the instance was | 
|  | // already published locally. The instance is unpublished when the publisher | 
|  | // is deleted or its |Unpublish| method is called. Must not be called before | 
|  | // |Start|'s ready callback is called. | 
|  | bool PublishServiceInstance(std::string service_name, std::string instance_name, Media media, | 
|  | IpVersions ip_versions, bool perform_probe, Publisher* publisher) { | 
|  | return PublishServiceInstance("", {}, std::move(service_name), std::move(instance_name), media, | 
|  | ip_versions, perform_probe, publisher); | 
|  | } | 
|  |  | 
|  | // Publishes a service instance for a host identified by |host_name| and |addresses|. Returns | 
|  | // false if and only if the instance was already published locally. The instance is unpublished | 
|  | // when the publisher is deleted or its |Unpublish| method is called. Must not be called before | 
|  | // |Start|'s ready callback is called. | 
|  | bool PublishServiceInstance(std::string host_name, std::vector<inet::IpAddress> addresses, | 
|  | std::string service_name, std::string instance_name, Media media, | 
|  | IpVersions ip_versions, bool perform_probe, Publisher* publisher); | 
|  |  | 
|  | // Publishes a host. Returns false if and only if the host was already published locally. The | 
|  | // host is unpublished when the publisher is deleted or its |Unpublish| method is called. Must | 
|  | // not be called for |Start|'s ready callback is called. | 
|  | bool PublishHost(std::string host_name, std::vector<inet::IpAddress> addresses, Media media, | 
|  | IpVersions ip_versions, bool perform_probe, HostPublisher* publisher); | 
|  |  | 
|  | // Writes log messages describing lifetime traffic. | 
|  | void LogTraffic(); | 
|  |  | 
|  | private: | 
|  | enum class State { | 
|  | kNotStarted, | 
|  | kWaitingForInterfaces, | 
|  | kAddressProbeInProgress, | 
|  | kActive, | 
|  | }; | 
|  |  | 
|  | struct TaskQueueEntry { | 
|  | TaskQueueEntry(MdnsAgent* agent, fit::closure task, zx::time time) | 
|  | : agent_(agent), task_(std::move(task)), time_(time) {} | 
|  |  | 
|  | MdnsAgent* agent_; | 
|  | // mutable because std::priority_queue doesn't provide a non-const accessor | 
|  | // for its contents which makes it otherwise impossible to move the closure | 
|  | // out of the queue when it is time to dispatch the task | 
|  | mutable fit::closure task_; | 
|  | zx::time time_; | 
|  |  | 
|  | bool operator<(const TaskQueueEntry& other) const { return time_ > other.time_; } | 
|  | }; | 
|  |  | 
|  | struct ReplyAddressHash { | 
|  | std::size_t operator()(const ReplyAddress& reply_address) const noexcept { | 
|  | return std::hash<inet::SocketAddress>{}(reply_address.socket_address()) ^ | 
|  | (std::hash<inet::IpAddress>{}(reply_address.interface_address()) << 1) ^ | 
|  | (std::hash<uint32_t>{}(reply_address.interface_id()) << 2) ^ | 
|  | (std::hash<Media>{}(reply_address.media()) << 3) ^ | 
|  | (std::hash<IpVersions>{}(reply_address.ip_versions()) << 4); | 
|  | } | 
|  | }; | 
|  |  | 
|  | struct ResourceHash { | 
|  | std::size_t operator()(std::shared_ptr<DnsResource> resource) const noexcept { | 
|  | return resource ? std::hash<DnsResource>{}(*resource) : 0; | 
|  | } | 
|  | }; | 
|  |  | 
|  | struct ResourceEqual { | 
|  | bool operator()(std::shared_ptr<DnsResource> a, std::shared_ptr<DnsResource> b) const noexcept { | 
|  | return a ? (b ? *a == *b : false) : !b; | 
|  | } | 
|  | }; | 
|  |  | 
|  | struct RequestorKey { | 
|  | RequestorKey() = default; | 
|  |  | 
|  | RequestorKey(std::string name, Media media, IpVersions ip_versions) | 
|  | : name_(std::move(name)), media_(media), ip_versions_(ip_versions) {} | 
|  |  | 
|  | bool operator==(const RequestorKey& other) const { | 
|  | return name_ == other.name_ && media_ == other.media_ && ip_versions_ == other.ip_versions_; | 
|  | } | 
|  |  | 
|  | std::string name_; | 
|  | Media media_; | 
|  | IpVersions ip_versions_; | 
|  | }; | 
|  |  | 
|  | struct RequestorKeyHash { | 
|  | std::size_t operator()(const RequestorKey& value) const noexcept { | 
|  | return std::hash<std::string>{}(value.name_) ^ (std::hash<Media>{}(value.media_) << 1) ^ | 
|  | (std::hash<IpVersions>{}(value.ip_versions_) << 2); | 
|  | } | 
|  | }; | 
|  |  | 
|  | class DnsMessageBuilder { | 
|  | public: | 
|  | void AddQuestion(std::shared_ptr<DnsQuestion> question) { questions_.push_back(question); } | 
|  |  | 
|  | void AddResource(std::shared_ptr<DnsResource> resource, MdnsResourceSection section) { | 
|  | switch (section) { | 
|  | case MdnsResourceSection::kAnswer: | 
|  | answers_.insert(resource); | 
|  | break; | 
|  | case MdnsResourceSection::kAuthority: | 
|  | authorities_.insert(resource); | 
|  | break; | 
|  | case MdnsResourceSection::kAdditional: | 
|  | additionals_.insert(resource); | 
|  | break; | 
|  | case MdnsResourceSection::kExpired: | 
|  | FX_DCHECK(false); | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | void Build(DnsMessage& message_out) const { | 
|  | if (questions_.empty()) { | 
|  | message_out.header_.SetResponse(true); | 
|  | message_out.header_.SetAuthoritativeAnswer(true); | 
|  | } else { | 
|  | message_out.questions_ = std::move(questions_); | 
|  | } | 
|  |  | 
|  | message_out.answers_ = | 
|  | std::vector<std::shared_ptr<DnsResource>>(answers_.begin(), answers_.end()); | 
|  | message_out.authorities_ = | 
|  | std::vector<std::shared_ptr<DnsResource>>(authorities_.begin(), authorities_.end()); | 
|  | message_out.additionals_ = | 
|  | std::vector<std::shared_ptr<DnsResource>>(additionals_.begin(), additionals_.end()); | 
|  |  | 
|  | message_out.UpdateCounts(); | 
|  | } | 
|  |  | 
|  | private: | 
|  | std::vector<std::shared_ptr<DnsQuestion>> questions_; | 
|  | std::unordered_set<std::shared_ptr<DnsResource>, ResourceHash, ResourceEqual> answers_; | 
|  | std::unordered_set<std::shared_ptr<DnsResource>, ResourceHash, ResourceEqual> authorities_; | 
|  | std::unordered_set<std::shared_ptr<DnsResource>, ResourceHash, ResourceEqual> additionals_; | 
|  | }; | 
|  |  | 
|  | // Starts the address probe or transitions to ready state, depending on | 
|  | // |perform_address_probe|. This method is called the first time a transceiver | 
|  | // becomes ready. | 
|  | void OnInterfacesStarted(const std::string& local_host_name, bool perform_address_probe); | 
|  |  | 
|  | // Starts a probe for a conflicting host name. If a conflict is detected, a | 
|  | // new name is generated and this method is called again. If no conflict is | 
|  | // detected, |local_host_full_name_| gets set and the service is ready to start | 
|  | // other agents. | 
|  | void StartAddressProbe(const std::string& local_host_name); | 
|  |  | 
|  | // Sets |local_host_name_|, |local_host_name_full_name_| and |address_placeholder_|. | 
|  | void RegisterLocalHostName(const std::string& local_host_name); | 
|  |  | 
|  | // Starts agents and calls the ready callback. This method is called when | 
|  | // at least one transceiver is ready and a unique host name has been | 
|  | // established. | 
|  | void OnReady(); | 
|  |  | 
|  | // Call |agent->OnAddProxyHost| for each agent in |agents_|. | 
|  | void OnAddProxyHost(const std::string& host_full_name, const std::vector<HostAddress>& addresses); | 
|  |  | 
|  | // Call |agent->OnRemoveProxyHost| for each agent in |agents_|. | 
|  | void OnRemoveProxyHost(const std::string& host_full_name); | 
|  |  | 
|  | // Call |agent->OnAddLocalServiceInstance| for each agent in |agents_|. | 
|  | void OnAddLocalServiceInstance(const ServiceInstance& service_instance, bool from_proxy); | 
|  |  | 
|  | // Call |agent->OnChangeLocalServiceInstance| for each agent in |agents_|. | 
|  | void OnChangeLocalServiceInstance(const ServiceInstance& service_instance, bool from_proxy); | 
|  |  | 
|  | // Call |agent->OnRemoveLocalServiceInstance| for each agent in |agents_|. | 
|  | void OnRemoveLocalServiceInstance(const std::string& service_name, | 
|  | const std::string& instance_name, bool from_proxy); | 
|  |  | 
|  | // Determines what host name to try next after a conflict is detected and | 
|  | // calls |StartAddressProbe| with that name. | 
|  | void OnHostNameConflict(); | 
|  |  | 
|  | // MdnsAgent::Owner implementation. | 
|  | zx::time now() override; | 
|  |  | 
|  | void PostTaskForTime(MdnsAgent* agent, fit::closure task, zx::time target_time) override; | 
|  |  | 
|  | void SendQuestion(std::shared_ptr<DnsQuestion> question, ReplyAddress reply_address) override; | 
|  |  | 
|  | void SendResource(std::shared_ptr<DnsResource> resource, MdnsResourceSection section, | 
|  | const ReplyAddress& reply_address) override; | 
|  |  | 
|  | void SendAddresses(MdnsResourceSection section, const ReplyAddress& reply_address) override; | 
|  |  | 
|  | void Renew(const DnsResource& resource, Media media, IpVersions ip_versions) override; | 
|  |  | 
|  | void Query(DnsType type, const std::string& name, Media media, IpVersions ip_versions, | 
|  | zx::time initial_query_time, zx::duration interval, uint32_t interval_multiplier, | 
|  | uint32_t max_queries, bool request_unicast_response) override; | 
|  |  | 
|  | void RemoveAgent(std::shared_ptr<MdnsAgent> agent) override; | 
|  |  | 
|  | void FlushSentItems() override; | 
|  |  | 
|  | void AddLocalServiceInstance(const ServiceInstance& instance, bool from_proxy) override; | 
|  |  | 
|  | void ChangeLocalServiceInstance(const ServiceInstance& instance, bool from_proxy) override; | 
|  |  | 
|  | std::vector<HostAddress> LocalHostAddresses() override; | 
|  |  | 
|  | // Adds an agent and, if |started_|, starts it. | 
|  | void AddAgent(std::shared_ptr<MdnsAgent> agent); | 
|  |  | 
|  | // Sends any messages found in |outbound_messages_by_reply_address_| and | 
|  | // clears |outbound_messages_by_reply_address_|. | 
|  | void SendMessages(); | 
|  |  | 
|  | // Distributes questions to all the agents except the resource renewer. | 
|  | void ReceiveQuestion(const DnsQuestion& question, const ReplyAddress& reply_address, | 
|  | const ReplyAddress& sender_address); | 
|  |  | 
|  | // Distributes resources to all the agents, starting with the resource | 
|  | // renewer. | 
|  | void ReceiveResource(const DnsResource& resource, MdnsResourceSection section, | 
|  | ReplyAddress sender_address); | 
|  |  | 
|  | // Runs tasks in |task_queue_| using |dispatcher_|. | 
|  | void PostTask(); | 
|  |  | 
|  | async_dispatcher_t* dispatcher_; | 
|  | Transceiver& transceiver_; | 
|  | std::string original_local_host_name_; | 
|  | fit::closure ready_callback_; | 
|  | std::vector<std::string> alt_services_; | 
|  | uint32_t next_local_host_name_deduplicator_ = 2; | 
|  | std::string local_host_name_; | 
|  | std::string local_host_full_name_; | 
|  | State state_ = State::kNotStarted; | 
|  | std::priority_queue<TaskQueueEntry> task_queue_; | 
|  | zx::time posted_task_time_ = zx::time::infinite(); | 
|  | std::unordered_map<ReplyAddress, DnsMessageBuilder, ReplyAddressHash> | 
|  | outbound_message_builders_by_reply_address_; | 
|  | std::vector<std::shared_ptr<MdnsAgent>> agents_awaiting_start_; | 
|  | std::unordered_set<std::shared_ptr<MdnsAgent>> agents_; | 
|  | std::unordered_map<RequestorKey, std::shared_ptr<HostNameRequestor>, RequestorKeyHash> | 
|  | host_name_requestors_by_key_; | 
|  | std::unordered_map<RequestorKey, std::shared_ptr<InstanceRequestor>, RequestorKeyHash> | 
|  | instance_requestors_by_key_; | 
|  | std::unordered_map<std::string, std::shared_ptr<InstanceResponder>> | 
|  | instance_responders_by_instance_full_name_; | 
|  | std::unordered_map<std::string, std::shared_ptr<AddressResponder>> | 
|  | address_responders_by_host_full_name_; | 
|  | std::shared_ptr<DnsResource> address_placeholder_; | 
|  | #ifdef MDNS_TRACE | 
|  | // Because |verbose_| defaults to true, traffic will be logged as long as the | 
|  | // enable_mdns_trace gn arg is set to true. This is preferred, as there is no | 
|  | // way (currently) to set |verbose_| to true at runtime. | 
|  | bool verbose_ = true; | 
|  | #endif  // MDNS_TRACE | 
|  | std::shared_ptr<ResourceRenewer> resource_renewer_; | 
|  | bool prohibit_agent_removal_ = false; | 
|  | bool defer_flush_ = false; | 
|  |  | 
|  | #ifdef NDEBUG | 
|  | #define DPROHIBIT_AGENT_REMOVAL() ((void)0) | 
|  | #define DALLOW_AGENT_REMOVAL() ((void)0) | 
|  | #else | 
|  | #define DPROHIBIT_AGENT_REMOVAL() (prohibit_agent_removal_ = true) | 
|  | #define DALLOW_AGENT_REMOVAL() (prohibit_agent_removal_ = false) | 
|  | #endif  // NDEBUG | 
|  |  | 
|  | public: | 
|  | // Disallow copy, assign and move. | 
|  | Mdns(const Mdns&) = delete; | 
|  | Mdns(Mdns&&) = delete; | 
|  | Mdns& operator=(const Mdns&) = delete; | 
|  | Mdns& operator=(Mdns&&) = delete; | 
|  | }; | 
|  |  | 
|  | }  // namespace mdns | 
|  |  | 
|  | #endif  // SRC_CONNECTIVITY_NETWORK_MDNS_SERVICE_MDNS_H_ |