blob: ddcd0dbd669ff10f686e3a96b2c1e253064b7e30 [file] [log] [blame]
// Copyright 2018 The Chromium 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 <array>
#include <map>
#include <memory>
#include <set>
#include <string>
#include <vector>
#include "osp/impl/discovery/mdns/mdns_responder_adapter.h"
#include "osp/impl/mdns_platform_service.h"
#include "osp/impl/service_listener_impl.h"
#include "osp/impl/service_publisher_impl.h"
#include "platform/api/network_interface.h"
#include "platform/api/task_runner.h"
#include "platform/api/time.h"
#include "platform/base/ip_address.h"
#include "util/alarm.h"
namespace openscreen {
namespace osp {
class MdnsResponderAdapterFactory {
virtual ~MdnsResponderAdapterFactory() = default;
virtual std::unique_ptr<MdnsResponderAdapter> Create() = 0;
class MdnsResponderService : public ServiceListenerImpl::Delegate,
public ServicePublisherImpl::Delegate,
public UdpSocket::Client {
ClockNowFunctionPtr now_function,
TaskRunner* task_runner,
const std::string& service_name,
const std::string& service_protocol,
std::unique_ptr<MdnsResponderAdapterFactory> mdns_responder_factory,
std::unique_ptr<MdnsPlatformService> platform);
~MdnsResponderService() override;
void SetServiceConfig(const std::string& hostname,
const std::string& instance,
uint16_t port,
const std::vector<NetworkInterfaceIndex> allowlist,
const std::map<std::string, std::string>& txt_data);
// UdpSocket::Client overrides.
void OnRead(UdpSocket* socket, ErrorOr<UdpPacket> packet) override;
void OnSendError(UdpSocket* socket, Error error) override;
void OnError(UdpSocket* socket, Error error) override;
// ServiceListenerImpl::Delegate overrides.
void StartListener() override;
void StartAndSuspendListener() override;
void StopListener() override;
void SuspendListener() override;
void ResumeListener() override;
void SearchNow(ServiceListener::State from) override;
// ServicePublisherImpl::Delegate overrides.
void StartPublisher() override;
void StartAndSuspendPublisher() override;
void StopPublisher() override;
void SuspendPublisher() override;
void ResumePublisher() override;
void HandleMdnsEvents();
std::unique_ptr<MdnsResponderAdapter> mdns_responder_;
// Create internal versions of all public methods. These are used to push all
// calls to these methods to the task runner.
// TODO(rwkeane): Clean up these methods. Some result in multiple pushes to
// the task runner when just one would suffice.
// ServiceListenerImpl::Delegate overrides.
void StartListenerInternal();
void StartAndSuspendListenerInternal();
void StopListenerInternal();
void SuspendListenerInternal();
void ResumeListenerInternal();
void SearchNowInternal(ServiceListener::State from);
void StartPublisherInternal();
void StartAndSuspendPublisherInternal();
void StopPublisherInternal();
void SuspendPublisherInternal();
void ResumePublisherInternal();
// NOTE: service_instance implicit in map key.
struct ServiceInstance {
UdpSocket* ptr_socket = nullptr;
DomainName domain_name;
uint16_t port = 0;
bool has_ptr_record = false;
std::vector<std::string> txt_info;
// |port| == 0 signals that we have no SRV record.
bool has_srv() const { return port != 0; }
// NOTE: hostname implicit in map key.
struct HostInfo {
std::vector<ServiceInstance*> services;
IPAddress v4_address;
IPAddress v6_address;
struct NetworkScopedDomainName {
UdpSocket* socket;
DomainName domain_name;
struct NetworkScopedDomainNameComparator {
bool operator()(const NetworkScopedDomainName& a,
const NetworkScopedDomainName& b) const;
using InstanceNameSet = std::set<DomainName, DomainNameComparator>;
void StartListening();
void StopListening();
void StartService();
void StopService();
void StopMdnsResponder();
void UpdatePendingServiceInfoSet(InstanceNameSet* modified_instance_names,
const DomainName& domain_name);
void RemoveAllReceivers();
// NOTE: |modified_instance_names| is used to track which service instances
// are modified by the record events. See HandleMdnsEvents for more details.
bool HandlePtrEvent(const PtrEvent& ptr_event,
InstanceNameSet* modified_instance_names);
bool HandleSrvEvent(const SrvEvent& srv_event,
InstanceNameSet* modified_instance_names);
bool HandleTxtEvent(const TxtEvent& txt_event,
InstanceNameSet* modified_instance_names);
bool HandleAddressEvent(UdpSocket* socket,
QueryEventHeader::Type response_type,
const DomainName& domain_name,
bool a_event,
const IPAddress& address,
InstanceNameSet* modified_instance_names);
bool HandleAEvent(const AEvent& a_event,
InstanceNameSet* modified_instance_names);
bool HandleAaaaEvent(const AaaaEvent& aaaa_event,
InstanceNameSet* modified_instance_names);
HostInfo* AddOrGetHostInfo(UdpSocket* socket, const DomainName& domain_name);
HostInfo* GetHostInfo(UdpSocket* socket, const DomainName& domain_name);
bool IsServiceReady(const ServiceInstance& instance, HostInfo* host) const;
NetworkInterfaceIndex GetNetworkInterfaceIndexFromSocket(
const UdpSocket* socket) const;
// Runs background tasks to manage the internal mDNS state.
void RunBackgroundTasks();
// Service type separated as service name and service protocol for both
// listening and publishing (e.g. {"_openscreen", "_udp"}).
std::array<std::string, 2> service_type_;
// The following variables all relate to what MdnsResponderService publishes,
// if anything.
std::string service_hostname_;
std::string service_instance_name_;
uint16_t service_port_;
std::vector<NetworkInterfaceIndex> interface_index_allowlist_;
std::map<std::string, std::string> service_txt_data_;
std::unique_ptr<MdnsResponderAdapterFactory> mdns_responder_factory_;
std::unique_ptr<MdnsPlatformService> platform_;
std::vector<MdnsPlatformService::BoundInterface> bound_interfaces_;
// A map of service information collected from PTR, SRV, and TXT records. It
// is keyed by service instance names.
std::map<DomainName, std::unique_ptr<ServiceInstance>, DomainNameComparator>
// The map key is a combination of the interface to which the address records
// belong and the hostname of the address records. The values are IPAddresses
// for the given hostname on the given network and pointers to dependent
// service instances. The service instance pointers act as a reference count
// to keep the A/AAAA queries alive, when more than one service refers to the
// same hostname. This is not currently used by openscreen, but is used by
// Cast, so may be supported in openscreen in the future.
std::map<NetworkScopedDomainName, HostInfo, NetworkScopedDomainNameComparator>
std::map<std::string, ServiceInfo> receiver_info_;
TaskRunner* const task_runner_;
// Scheduled to run periodic background tasks.
Alarm background_tasks_alarm_;
friend class TestingMdnsResponderService;
} // namespace osp
} // namespace openscreen