| // Copyright 2019 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 "discovery/mdns/mdns_service_impl.h" |
| |
| #include <memory> |
| #include <utility> |
| #include <vector> |
| |
| #include "discovery/common/reporting_client.h" |
| #include "discovery/mdns/mdns_records.h" |
| #include "discovery/mdns/public/mdns_constants.h" |
| |
| namespace openscreen { |
| namespace discovery { |
| |
| // static |
| std::unique_ptr<MdnsService> MdnsService::Create( |
| TaskRunner* task_runner, |
| ReportingClient* reporting_client, |
| const Config& config, |
| const Config::NetworkInfo& network_info) { |
| return std::make_unique<MdnsServiceImpl>( |
| task_runner, Clock::now, reporting_client, config, network_info); |
| } |
| |
| MdnsServiceImpl::MdnsServiceImpl(TaskRunner* task_runner, |
| ClockNowFunctionPtr now_function, |
| ReportingClient* reporting_client, |
| const Config& config, |
| const Config::NetworkInfo& network_info) |
| : task_runner_(task_runner), |
| now_function_(now_function), |
| reporting_client_(reporting_client), |
| receiver_(config), |
| interface_(network_info.interface.index) { |
| OSP_DCHECK(task_runner_); |
| OSP_DCHECK(reporting_client_); |
| OSP_DCHECK(network_info.supported_address_families); |
| |
| // Create all UDP sockets needed for this object. They should not yet be bound |
| // so that they do not send or receive data until the objects on which their |
| // callback depends is initialized. |
| // NOTE: we bind to the Any addresses here because traffic is filtered by |
| // the multicast join calls. |
| if (network_info.supported_address_families & Config::NetworkInfo::kUseIpV4) { |
| ErrorOr<std::unique_ptr<UdpSocket>> socket = UdpSocket::Create( |
| task_runner, this, |
| IPEndpoint{IPAddress::kAnyV4(), kDefaultMulticastPort}); |
| OSP_DCHECK(!socket.is_error()); |
| OSP_DCHECK(socket.value().get()); |
| OSP_DCHECK(socket.value()->IsIPv4()); |
| |
| socket_v4_ = std::move(socket.value()); |
| } |
| |
| if (network_info.supported_address_families & Config::NetworkInfo::kUseIpV6) { |
| ErrorOr<std::unique_ptr<UdpSocket>> socket = UdpSocket::Create( |
| task_runner, this, |
| IPEndpoint{IPAddress::kAnyV6(), kDefaultMulticastPort}); |
| OSP_DCHECK(!socket.is_error()); |
| OSP_DCHECK(socket.value().get()); |
| OSP_DCHECK(socket.value()->IsIPv6()); |
| |
| socket_v6_ = std::move(socket.value()); |
| } |
| |
| // Initialize objects which depend on the above sockets. |
| UdpSocket* socket_ptr = |
| socket_v4_.get() ? socket_v4_.get() : socket_v6_.get(); |
| OSP_DCHECK(socket_ptr); |
| sender_ = std::make_unique<MdnsSender>(socket_ptr); |
| if (config.enable_querying) { |
| querier_ = std::make_unique<MdnsQuerier>( |
| sender_.get(), &receiver_, task_runner_, now_function_, &random_delay_, |
| reporting_client_, config); |
| } |
| if (config.enable_publication) { |
| probe_manager_ = std::make_unique<MdnsProbeManagerImpl>( |
| sender_.get(), &receiver_, &random_delay_, task_runner_, now_function_); |
| publisher_ = |
| std::make_unique<MdnsPublisher>(sender_.get(), probe_manager_.get(), |
| task_runner_, now_function_, config); |
| responder_ = std::make_unique<MdnsResponder>( |
| publisher_.get(), probe_manager_.get(), sender_.get(), &receiver_, |
| task_runner_, now_function_, &random_delay_, config); |
| } |
| |
| receiver_.Start(); |
| |
| // Initialize all sockets to start sending/receiving data. Now that the above |
| // objects have all been created, it they should be able to safely do so. |
| // NOTE: Although only one of these sockets is used for sending, both will be |
| // used for reading on the mDNS v4 and v6 addresses and ports. |
| if (socket_v4_) { |
| socket_v4_->Bind(); |
| } |
| if (socket_v6_) { |
| socket_v6_->Bind(); |
| } |
| } |
| |
| MdnsServiceImpl::~MdnsServiceImpl() = default; |
| |
| void MdnsServiceImpl::StartQuery(const DomainName& name, |
| DnsType dns_type, |
| DnsClass dns_class, |
| MdnsRecordChangedCallback* callback) { |
| return querier_->StartQuery(name, dns_type, dns_class, callback); |
| } |
| |
| void MdnsServiceImpl::StopQuery(const DomainName& name, |
| DnsType dns_type, |
| DnsClass dns_class, |
| MdnsRecordChangedCallback* callback) { |
| return querier_->StopQuery(name, dns_type, dns_class, callback); |
| } |
| |
| void MdnsServiceImpl::ReinitializeQueries(const DomainName& name) { |
| querier_->ReinitializeQueries(name); |
| } |
| |
| Error MdnsServiceImpl::StartProbe(MdnsDomainConfirmedProvider* callback, |
| DomainName requested_name, |
| IPAddress address) { |
| return probe_manager_->StartProbe(callback, std::move(requested_name), |
| std::move(address)); |
| } |
| |
| Error MdnsServiceImpl::RegisterRecord(const MdnsRecord& record) { |
| return publisher_->RegisterRecord(record); |
| } |
| |
| Error MdnsServiceImpl::UpdateRegisteredRecord(const MdnsRecord& old_record, |
| const MdnsRecord& new_record) { |
| return publisher_->UpdateRegisteredRecord(old_record, new_record); |
| } |
| |
| Error MdnsServiceImpl::UnregisterRecord(const MdnsRecord& record) { |
| return publisher_->UnregisterRecord(record); |
| } |
| |
| void MdnsServiceImpl::OnError(UdpSocket* socket, Error error) { |
| reporting_client_->OnFatalError(error); |
| } |
| |
| void MdnsServiceImpl::OnSendError(UdpSocket* socket, Error error) { |
| sender_->OnSendError(socket, error); |
| } |
| |
| void MdnsServiceImpl::OnRead(UdpSocket* socket, ErrorOr<UdpPacket> packet) { |
| receiver_.OnRead(socket, std::move(packet)); |
| } |
| |
| void MdnsServiceImpl::OnBound(UdpSocket* socket) { |
| // Socket configuration must occur after the socket has been bound |
| // successfully. |
| if (socket == socket_v4_.get()) { |
| socket_v4_->SetMulticastOutboundInterface(interface_); |
| socket_v4_->JoinMulticastGroup(kDefaultMulticastGroupIPv4, interface_); |
| socket_v4_->JoinMulticastGroup(kDefaultSiteLocalGroupIPv4, interface_); |
| } else if (socket == socket_v6_.get()) { |
| socket_v6_->SetMulticastOutboundInterface(interface_); |
| socket_v6_->JoinMulticastGroup(kDefaultMulticastGroupIPv6, interface_); |
| socket_v6_->JoinMulticastGroup(kDefaultSiteLocalGroupIPv6, interface_); |
| } else { |
| // Sanity check: we shouldn't be called for sockets we haven't subscribed |
| // to. |
| OSP_NOTREACHED(); |
| } |
| } |
| |
| } // namespace discovery |
| } // namespace openscreen |