1*3f982cf4SFabien Sanglard // Copyright 2019 The Chromium Authors. All rights reserved.
2*3f982cf4SFabien Sanglard // Use of this source code is governed by a BSD-style license that can be
3*3f982cf4SFabien Sanglard // found in the LICENSE file.
4*3f982cf4SFabien Sanglard
5*3f982cf4SFabien Sanglard #include "discovery/mdns/mdns_probe.h"
6*3f982cf4SFabien Sanglard
7*3f982cf4SFabien Sanglard #include <utility>
8*3f982cf4SFabien Sanglard
9*3f982cf4SFabien Sanglard #include "discovery/mdns/mdns_random.h"
10*3f982cf4SFabien Sanglard #include "discovery/mdns/mdns_sender.h"
11*3f982cf4SFabien Sanglard #include "discovery/mdns/public/mdns_constants.h"
12*3f982cf4SFabien Sanglard #include "platform/api/task_runner.h"
13*3f982cf4SFabien Sanglard #include "platform/api/time.h"
14*3f982cf4SFabien Sanglard
15*3f982cf4SFabien Sanglard namespace openscreen {
16*3f982cf4SFabien Sanglard namespace discovery {
17*3f982cf4SFabien Sanglard
MdnsProbe(DomainName target_name,IPAddress address)18*3f982cf4SFabien Sanglard MdnsProbe::MdnsProbe(DomainName target_name, IPAddress address)
19*3f982cf4SFabien Sanglard : target_name_(std::move(target_name)),
20*3f982cf4SFabien Sanglard address_(std::move(address)),
21*3f982cf4SFabien Sanglard address_record_(CreateAddressRecord(target_name_, address_)) {}
22*3f982cf4SFabien Sanglard
23*3f982cf4SFabien Sanglard MdnsProbe::~MdnsProbe() = default;
24*3f982cf4SFabien Sanglard
25*3f982cf4SFabien Sanglard MdnsProbeImpl::Observer::~Observer() = default;
26*3f982cf4SFabien Sanglard
MdnsProbeImpl(MdnsSender * sender,MdnsReceiver * receiver,MdnsRandom * random_delay,TaskRunner * task_runner,ClockNowFunctionPtr now_function,Observer * observer,DomainName target_name,IPAddress address)27*3f982cf4SFabien Sanglard MdnsProbeImpl::MdnsProbeImpl(MdnsSender* sender,
28*3f982cf4SFabien Sanglard MdnsReceiver* receiver,
29*3f982cf4SFabien Sanglard MdnsRandom* random_delay,
30*3f982cf4SFabien Sanglard TaskRunner* task_runner,
31*3f982cf4SFabien Sanglard ClockNowFunctionPtr now_function,
32*3f982cf4SFabien Sanglard Observer* observer,
33*3f982cf4SFabien Sanglard DomainName target_name,
34*3f982cf4SFabien Sanglard IPAddress address)
35*3f982cf4SFabien Sanglard : MdnsProbe(std::move(target_name), std::move(address)),
36*3f982cf4SFabien Sanglard random_delay_(random_delay),
37*3f982cf4SFabien Sanglard task_runner_(task_runner),
38*3f982cf4SFabien Sanglard now_function_(now_function),
39*3f982cf4SFabien Sanglard alarm_(now_function_, task_runner_),
40*3f982cf4SFabien Sanglard sender_(sender),
41*3f982cf4SFabien Sanglard receiver_(receiver),
42*3f982cf4SFabien Sanglard observer_(observer) {
43*3f982cf4SFabien Sanglard OSP_DCHECK(sender_);
44*3f982cf4SFabien Sanglard OSP_DCHECK(receiver_);
45*3f982cf4SFabien Sanglard OSP_DCHECK(random_delay_);
46*3f982cf4SFabien Sanglard OSP_DCHECK(task_runner_);
47*3f982cf4SFabien Sanglard OSP_DCHECK(observer_);
48*3f982cf4SFabien Sanglard
49*3f982cf4SFabien Sanglard receiver_->AddResponseCallback(this);
50*3f982cf4SFabien Sanglard alarm_.ScheduleFromNow([this]() { ProbeOnce(); },
51*3f982cf4SFabien Sanglard random_delay_->GetInitialProbeDelay());
52*3f982cf4SFabien Sanglard }
53*3f982cf4SFabien Sanglard
~MdnsProbeImpl()54*3f982cf4SFabien Sanglard MdnsProbeImpl::~MdnsProbeImpl() {
55*3f982cf4SFabien Sanglard OSP_DCHECK(task_runner_->IsRunningOnTaskRunner());
56*3f982cf4SFabien Sanglard
57*3f982cf4SFabien Sanglard Stop();
58*3f982cf4SFabien Sanglard }
59*3f982cf4SFabien Sanglard
ProbeOnce()60*3f982cf4SFabien Sanglard void MdnsProbeImpl::ProbeOnce() {
61*3f982cf4SFabien Sanglard OSP_DCHECK(task_runner_->IsRunningOnTaskRunner());
62*3f982cf4SFabien Sanglard
63*3f982cf4SFabien Sanglard if (successful_probe_queries_++ < kProbeIterationCountBeforeSuccess) {
64*3f982cf4SFabien Sanglard // MdnsQuerier cannot be used, because probe queries cannot use the cache,
65*3f982cf4SFabien Sanglard // so instead directly send the query through the MdnsSender.
66*3f982cf4SFabien Sanglard MdnsMessage probe_query(CreateMessageId(), MessageType::Query);
67*3f982cf4SFabien Sanglard MdnsQuestion probe_question(target_name(), DnsType::kANY, DnsClass::kIN,
68*3f982cf4SFabien Sanglard ResponseType::kUnicast);
69*3f982cf4SFabien Sanglard probe_query.AddQuestion(probe_question);
70*3f982cf4SFabien Sanglard probe_query.AddAuthorityRecord(address_record());
71*3f982cf4SFabien Sanglard sender_->SendMulticast(probe_query);
72*3f982cf4SFabien Sanglard
73*3f982cf4SFabien Sanglard alarm_.ScheduleFromNow([this]() { ProbeOnce(); },
74*3f982cf4SFabien Sanglard kDelayBetweenProbeQueries);
75*3f982cf4SFabien Sanglard } else {
76*3f982cf4SFabien Sanglard Stop();
77*3f982cf4SFabien Sanglard observer_->OnProbeSuccess(this);
78*3f982cf4SFabien Sanglard }
79*3f982cf4SFabien Sanglard }
80*3f982cf4SFabien Sanglard
Stop()81*3f982cf4SFabien Sanglard void MdnsProbeImpl::Stop() {
82*3f982cf4SFabien Sanglard OSP_DCHECK(task_runner_->IsRunningOnTaskRunner());
83*3f982cf4SFabien Sanglard
84*3f982cf4SFabien Sanglard if (is_running_) {
85*3f982cf4SFabien Sanglard alarm_.Cancel();
86*3f982cf4SFabien Sanglard receiver_->RemoveResponseCallback(this);
87*3f982cf4SFabien Sanglard is_running_ = false;
88*3f982cf4SFabien Sanglard }
89*3f982cf4SFabien Sanglard }
90*3f982cf4SFabien Sanglard
Postpone(std::chrono::seconds delay)91*3f982cf4SFabien Sanglard void MdnsProbeImpl::Postpone(std::chrono::seconds delay) {
92*3f982cf4SFabien Sanglard OSP_DCHECK(task_runner_->IsRunningOnTaskRunner());
93*3f982cf4SFabien Sanglard
94*3f982cf4SFabien Sanglard successful_probe_queries_ = 0;
95*3f982cf4SFabien Sanglard alarm_.Cancel();
96*3f982cf4SFabien Sanglard alarm_.ScheduleFromNow([this]() { ProbeOnce(); }, Clock::to_duration(delay));
97*3f982cf4SFabien Sanglard }
98*3f982cf4SFabien Sanglard
OnMessageReceived(const MdnsMessage & message)99*3f982cf4SFabien Sanglard void MdnsProbeImpl::OnMessageReceived(const MdnsMessage& message) {
100*3f982cf4SFabien Sanglard OSP_DCHECK(task_runner_->IsRunningOnTaskRunner());
101*3f982cf4SFabien Sanglard OSP_DCHECK(message.type() == MessageType::Response);
102*3f982cf4SFabien Sanglard
103*3f982cf4SFabien Sanglard for (const auto& record : message.answers()) {
104*3f982cf4SFabien Sanglard if (record.name() == target_name()) {
105*3f982cf4SFabien Sanglard Stop();
106*3f982cf4SFabien Sanglard observer_->OnProbeFailure(this);
107*3f982cf4SFabien Sanglard }
108*3f982cf4SFabien Sanglard }
109*3f982cf4SFabien Sanglard }
110*3f982cf4SFabien Sanglard
111*3f982cf4SFabien Sanglard } // namespace discovery
112*3f982cf4SFabien Sanglard } // namespace openscreen
113