You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
210 lines
7.6 KiB
210 lines
7.6 KiB
// 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.
|
|
|
|
#ifndef OSP_IMPL_MDNS_RESPONDER_SERVICE_H_
|
|
#define OSP_IMPL_MDNS_RESPONDER_SERVICE_H_
|
|
|
|
#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 {
|
|
public:
|
|
virtual ~MdnsResponderAdapterFactory() = default;
|
|
|
|
virtual std::unique_ptr<MdnsResponderAdapter> Create() = 0;
|
|
};
|
|
|
|
class MdnsResponderService : public ServiceListenerImpl::Delegate,
|
|
public ServicePublisherImpl::Delegate,
|
|
public UdpSocket::Client {
|
|
public:
|
|
MdnsResponderService(
|
|
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;
|
|
|
|
protected:
|
|
void HandleMdnsEvents();
|
|
|
|
std::unique_ptr<MdnsResponderAdapter> mdns_responder_;
|
|
|
|
private:
|
|
// 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>
|
|
service_by_name_;
|
|
|
|
// 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>
|
|
network_scoped_domain_to_host_;
|
|
|
|
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
|
|
|
|
#endif // OSP_IMPL_MDNS_RESPONDER_SERVICE_H_
|