blob: 28f86cecf9290a1321a2be50b09f5dc1c9edc820 [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_MDNS_AGENT_H_
#define SRC_CONNECTIVITY_NETWORK_MDNS_SERVICE_AGENTS_MDNS_AGENT_H_
#include <lib/fit/function.h>
#include <lib/syslog/cpp/macros.h>
#include <lib/zx/time.h>
#include <memory>
#include "src/connectivity/network/mdns/service/common/reply_address.h"
#include "src/connectivity/network/mdns/service/common/service_instance.h"
#include "src/connectivity/network/mdns/service/encoding/dns_message.h"
#include "src/lib/inet/socket_address.h"
namespace mdns {
// Base class for objects that drive mDNS question and record traffic.
//
// Agents that have been 'started' receive all inbound questions and resource records via their
// |ReceiveQuestion| and |ReceiveResource| methods. When the agent owner receives an inbound
// message, it calls those methods for each question and resource in the message. When that's
// done, the owner calls |EndOfMessage| on each agent.
//
// Agents may call any of the protected 'Send' methods (|SendQuestion|, |SendResource| and
// |SendAddresses|) at any time. The owner accumulates the questions and resources and sends
// them in messages. Typically, agents don't have to worry about sending messages. Messages
// are sent for accumulated questions and resources:
//
// 1) after |Start| is called on any agent,
// 2) after an inbound message is processed and all agents have gotten their |EndOfMessage| calls,
// 3) after an agent is removed (in case it wants to say goodbye),
// 4) after the completion of any task posted using |PostTaskForTime|.
//
// If an agent wants a message sent asynchronously with respect to agent start, inbound message
// arrival, agent removal and posted tasks, the agent should call |FlushSentItems|. Calling
// |FlushSentItems| synchronously with those operations isn't harmful.
//
class MdnsAgent : public std::enable_shared_from_this<MdnsAgent> {
public:
class Owner {
public:
virtual ~Owner() = default;
// Gets the current time.
virtual zx::time now() = 0;
// Posts a task to be executed at the specified time. Scheduled tasks posted
// by agents that have since been removed are not executed.
virtual void PostTaskForTime(MdnsAgent* agent, fit::closure task, zx::time target_time) = 0;
// Sends a question to the multicast address.
virtual void SendQuestion(std::shared_ptr<DnsQuestion> question,
ReplyAddress reply_address) = 0;
// Sends a resource to the specified address. The default |reply_address|
// |kV4MulticastReply| sends the resource to the V4 or V6
// multicast address.
virtual void SendResource(std::shared_ptr<DnsResource> resource, MdnsResourceSection section,
const ReplyAddress& reply_address) = 0;
// Sends address resources to the specified address. The default
// |reply_address| |kV4MulticastReply| sends the addresses to the V4 or V6
// multicast address.
virtual void SendAddresses(MdnsResourceSection section, const ReplyAddress& reply_address) = 0;
// Registers the resource for renewal. See |MdnsAgent::Renew| below.
virtual void Renew(const DnsResource& resource, Media media, IpVersions ip_versions) = 0;
// Registers the resource for repeated queries. See |MdnsAgent::Request| below.
virtual 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) = 0;
// Removes the specified agent.
virtual void RemoveAgent(std::shared_ptr<MdnsAgent> agent) = 0;
// Flushes sent questions and resources by sending the appropriate messages.
virtual void FlushSentItems() = 0;
// Notifies all agents of the addition of a local service instance.|from_proxy| indicates
// whether the instance is published by the local host (false) or a local proxy host (true).
virtual void AddLocalServiceInstance(const ServiceInstance& instance, bool from_proxy) = 0;
// Notifies all agents of a change to a previously-added local service instance.|from_proxy|
// indicates whether the instance is published by the local host (false) or a local proxy host
// (true).
virtual void ChangeLocalServiceInstance(const ServiceInstance& instance, bool from_proxy) = 0;
// Returns the addresses for the local host.
virtual std::vector<HostAddress> LocalHostAddresses() = 0;
};
virtual ~MdnsAgent() {}
// Starts the agent. This method is never called before a shared pointer to
// the agent is created, so |shared_from_this| is safe to call.
// Specializations should call this method first.
virtual void Start(const std::string& local_host_full_name) { started_ = true; }
// Presents a received question. |sender_address| identifies the sender of the question. If
// the question is not marked for unicast response, |reply_address| is the multicast placeholder
// address with |Media::kBoth| and |IpVersions::kBoth|. If the question is marked for unicast
// response, |reply_address| is the same as |sender_address|. This agent must not call
// |RemoveSelf| during a call to this method.
virtual void ReceiveQuestion(const DnsQuestion& question, const ReplyAddress& reply_address,
const ReplyAddress& sender_address) {}
// Presents a received resource. |sender_address| identifies the sender of the resource. This
// agent must not call |RemoveSelf| during a call to this method.
virtual void ReceiveResource(const DnsResource& resource, MdnsResourceSection section,
ReplyAddress sender_address) {}
// Signals the end of a message. This agent must not call |RemoveSelf| during
// a call to this method.
virtual void EndOfMessage() {}
// Notifies the agent of the addition of a proxy host.
virtual void OnAddProxyHost(const std::string& host_full_name,
const std::vector<HostAddress>& addresses) {}
// Notifies the agent of the removal of a proxy host.
virtual void OnRemoveProxyHost(const std::string& host_full_name) {}
// Notifies the agent of the addition of a local or local proxy service instance. |target|
// and |addresses| are empty for local service instances and non-empty for local proxy service
// instances. |from_proxy| indicates whether the instance is published by the local host (false)
// or a local proxy host (true).
virtual void OnAddLocalServiceInstance(const ServiceInstance& instance, bool from_proxy) {}
// Notifies the agent of a change to a local or local proxy service instance. |target| and
// |addresses| are empty for local service instances and non-empty for local proxy service
// instances.|from_proxy| indicates whether the instance is published by the local host (false)
// or a local proxy host (true).
virtual void OnChangeLocalServiceInstance(const ServiceInstance& instance, bool from_proxy) {}
// Notifies the agent of the removal of local or local proxy service instance. |from_proxy|
// indicates whether the instance is published by the local host (false) or a local proxy host
// (true).
virtual void OnRemoveLocalServiceInstance(const std::string& service_name,
const std::string& instance_name, bool from_proxy) {}
// Notifies the agent that local host addresses have changed.
virtual void OnLocalHostAddressesChanged() {}
// Tells the agent to quit. Any overrides should call this base implementation.
virtual void Quit() {
RemoveSelf();
if (on_quit_) {
on_quit_();
on_quit_ = nullptr;
}
}
// Sets the 'on quit' callback that's called when the agent quits. May be called once at most
// for a given agent.
void SetOnQuitCallback(fit::closure on_quit) {
FX_DCHECK(on_quit);
FX_DCHECK(!on_quit_);
on_quit_ = std::move(on_quit);
}
protected:
explicit MdnsAgent(Owner* owner) : owner_(owner) { FX_DCHECK(owner_); }
bool started() const { return started_; }
// Gets the current time.
zx::time now() { return owner_->now(); }
// Posts a task to be executed at the specified time. Scheduled tasks posted
// by agents that have since been removed are not executed.
void PostTaskForTime(fit::closure task, zx::time target_time) {
owner_->PostTaskForTime(this, std::move(task), target_time);
}
// Returns the addresses for the local host.
std::vector<HostAddress> local_host_addresses() { return owner_->LocalHostAddresses(); }
// Sends a question to the specified address.
void SendQuestion(std::shared_ptr<DnsQuestion> question,
const ReplyAddress& reply_address) const {
owner_->SendQuestion(std::move(question), reply_address);
}
// Sends a resource to the specified address.
void SendResource(std::shared_ptr<DnsResource> resource, MdnsResourceSection section,
const ReplyAddress& reply_address) const {
owner_->SendResource(std::move(resource), section, reply_address);
}
// Sends address resources to the specified address.
void SendAddresses(MdnsResourceSection section, const ReplyAddress& reply_address) const {
owner_->SendAddresses(section, reply_address);
}
// Flushes sent questions and resources by sending the appropriate messages. This method is only
// needed when questions or resources need to be sent asynchronously with respect to |Start|,
// |ReceiveQuestion|, |ReceiveResource|, |EndOfMessage|, |Quit| or a task posted using
// |PostTaskForTime|. See the discussion at the top of the file.
void FlushSentItems() { owner_->FlushSentItems(); }
// Notifies all agents of the addition of a local service instance.
void AddLocalServiceInstance(const ServiceInstance& instance, bool from_proxy) {
owner_->AddLocalServiceInstance(instance, from_proxy);
}
// Notifies all agents of a change to a previously-added local service instance.
void ChangeLocalServiceInstance(const ServiceInstance& instance, bool from_proxy) {
owner_->ChangeLocalServiceInstance(instance, from_proxy);
}
// Registers the resource for renewal. Before the resource's TTL expires,
// an attempt will be made to renew the resource by issuing queries for it.
// If the renewal is successful, the agent will receive the renewed resource
// (via |ReceiveResource|) and may choose to renew the resource again.
// If the renewal fails, the agent will receive a resource record with the
// same name and type but with a TTL of zero. The section parameter
// accompanying that resource record will be kExpired.
//
// The effect of this call is transient, and there is no way to cancel the
// renewal. When an agent loses interest in a particular resource, it should
// simply refrain from renewing the incoming records.
void Renew(const DnsResource& resource, Media media, IpVersions ip_versions) const {
owner_->Renew(resource, media, ip_versions);
}
// Registers a resource for repeated queries. At |initial_query_time|, queries for the resource
// will be sent until the resource is received or |max_queries| are sent without receiving the
// resource. The first interval between queries will be |interval|, with the interval multiplied
// by |interval_multiplier| after each query. If the resource is not received, an expiration for
// the resource (TTL of zero) will be distributed to all agents.
//
// If all parameters but that last two are the same for two or more calls made consecutively
// (without yielding the thread), the queries will be sent in the same message.
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) {
owner_->Query(type, name, media, ip_versions, initial_query_time, interval, interval_multiplier,
max_queries);
}
// Removes this agent.
void RemoveSelf() { owner_->RemoveAgent(shared_from_this()); }
private:
Owner* owner_;
bool started_ = false;
fit::closure on_quit_;
};
} // namespace mdns
#endif // SRC_CONNECTIVITY_NETWORK_MDNS_SERVICE_AGENTS_MDNS_AGENT_H_