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