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 #ifndef DISCOVERY_MDNS_MDNS_PUBLISHER_H_
6 #define DISCOVERY_MDNS_MDNS_PUBLISHER_H_
7 
8 #include <map>
9 #include <memory>
10 #include <utility>
11 #include <vector>
12 
13 #include "absl/types/optional.h"
14 #include "discovery/mdns/mdns_records.h"
15 #include "discovery/mdns/mdns_responder.h"
16 #include "util/alarm.h"
17 
18 namespace openscreen {
19 
20 class TaskRunner;
21 
22 namespace discovery {
23 
24 struct Config;
25 class MdnsProbeManager;
26 class MdnsRandom;
27 class MdnsSender;
28 class MdnsQuerier;
29 
30 // This class is responsible for both tracking what records have been registered
31 // to mDNS as well as publishing new mDNS records to the network.
32 // When a new record is published, it will be announced 8 times, starting at an
33 // interval of 1 second, with the interval doubling each successive
34 // announcement. This same announcement process is followed when an existing
35 // record is updated. When it is removed, a Goodbye message must be sent if the
36 // record is unique.
37 //
38 // Prior to publishing a record, the domain name for this service instance must
39 // be claimed using the ClaimExclusiveOwnership() function. This function probes
40 // the network to determine whether the chosen name exists, modifying the
41 // chosen name as described in RFC 6762 if a collision is found.
42 //
43 // NOTE: All MdnsPublisher instances must be run on the same task runner thread,
44 // due to the shared announce + goodbye message queue.
45 class MdnsPublisher : public MdnsResponder::RecordHandler {
46  public:
47   // |sender|, |ownership_manager|, and  |task_runner| must all persist for the
48   // duration of this object's lifetime
49   MdnsPublisher(MdnsSender* sender,
50                 MdnsProbeManager* ownership_manager,
51                 TaskRunner* task_runner,
52                 ClockNowFunctionPtr now_function,
53                 const Config& config);
54   ~MdnsPublisher() override;
55 
56   // Registers a new mDNS record for advertisement by this service. For A, AAAA,
57   // SRV, and TXT records, the domain name must have already been claimed by the
58   // ClaimExclusiveOwnership() method and for PTR records the name being pointed
59   // to must have been claimed in the same fashion, but the domain name in the
60   // top-level MdnsRecord entity does not.
61   // NOTE: This call is only valid for |dns_type| values:
62   // - DnsType::kA
63   // - DnsType::kPTR
64   // - DnsType::kTXT
65   // - DnsType::kAAAA
66   // - DnsType::kSRV
67   // - DnsType::kANY
68   Error RegisterRecord(const MdnsRecord& record);
69 
70   // Updates the existing record with name matching the name of the new record.
71   // NOTE: This method is not valid for PTR records.
72   Error UpdateRegisteredRecord(const MdnsRecord& old_record,
73                                const MdnsRecord& new_record);
74 
75   // Stops advertising the provided record.
76   Error UnregisterRecord(const MdnsRecord& record);
77 
78   // Returns the total number of records currently registered;
79   size_t GetRecordCount() const;
80 
81   OSP_DISALLOW_COPY_AND_ASSIGN(MdnsPublisher);
82 
83  private:
84   // Class responsible for sending announcement and goodbye messages for
85   // MdnsRecord instances when they are published, updated, or unpublished. The
86   // announcement messages will be sent |target_announcement_attempts| times,
87   // first at an interval of 1 second apart, and then with delay increasing by a
88   // factor of 2 with each successive announcement.
89   // NOTE: |publisher| must be the MdnsPublisher instance from which this
90   // instance was created.
91   class RecordAnnouncer {
92    public:
93     RecordAnnouncer(MdnsRecord record,
94                     MdnsPublisher* publisher,
95                     TaskRunner* task_runner,
96                     ClockNowFunctionPtr now_function,
97                     int max_announcement_attempts);
98     RecordAnnouncer(const RecordAnnouncer& other) = delete;
99     RecordAnnouncer(RecordAnnouncer&& other) noexcept = delete;
100     ~RecordAnnouncer();
101 
102     RecordAnnouncer& operator=(const RecordAnnouncer& other) = delete;
103     RecordAnnouncer& operator=(RecordAnnouncer&& other) noexcept = delete;
104 
record()105     const MdnsRecord& record() const { return record_; }
106 
107     // Specifies whether goodbye messages should not be sent when this announcer
108     // is destroyed. This should only be called as part of the 'Update' flow,
109     // for records which should not send this message.
DisableGoodbyeMessageTransmission()110     void DisableGoodbyeMessageTransmission() {
111       should_send_goodbye_message_ = false;
112     }
113 
114    private:
115     // Gets the delay required before the next announcement message is sent.
116     Clock::duration GetNextAnnounceDelay();
117 
118     // When announce + goodbye messages are ready to be sent, they are queued
119     // up. Every 20ms, if there are any messages to send out, these records are
120     // batched up and sent out.
121     void QueueGoodbye();
122     void QueueAnnouncement();
123 
124     MdnsPublisher* const publisher_;
125     TaskRunner* const task_runner_;
126     const ClockNowFunctionPtr now_function_;
127 
128     // Whether or not goodbye messages should be sent.
129     bool should_send_goodbye_message_ = true;
130 
131     // Record to send.
132     const MdnsRecord record_;
133 
134     // Alarm used to cancel future resend attempts if this object is deleted.
135     Alarm alarm_;
136 
137     // Number of attempts at sending this record which have occurred so far.
138     int attempts_ = 0;
139 
140     // Number of times to announce a newly published record.
141     const int target_announcement_attempts_;
142   };
143 
144   using RecordAnnouncerPtr = std::unique_ptr<RecordAnnouncer>;
145 
146   friend class MdnsPublisherTesting;
147 
148   // Creates a new published from the provided record.
CreateAnnouncer(MdnsRecord record)149   RecordAnnouncerPtr CreateAnnouncer(MdnsRecord record) {
150     return std::make_unique<RecordAnnouncer>(std::move(record), this,
151                                              task_runner_, now_function_,
152                                              max_announcement_attempts_);
153   }
154 
155   // Removes the given record from the |records_| map. A goodbye record is only
156   // sent for this removal if |should_announce_deletion| is true.
157   Error RemoveRecord(const MdnsRecord& record, bool should_announce_deletion);
158 
159   // Returns whether the provided record has had its name claimed so far.
160   bool IsRecordNameClaimed(const MdnsRecord& record) const;
161 
162   // Processes the |records_to_send_| queue, sending out the records together as
163   // a single MdnsMessage.
164   void ProcessRecordQueue();
165 
166   // Adds a new record to the |records_to_send_| queue or ensures that the
167   // record with lower ttl is present if it differs from an existing record by
168   // only that one field.
169   void QueueRecord(MdnsRecord record);
170 
171   // MdnsResponder::RecordHandler overrides.
172   bool HasRecords(const DomainName& name,
173                   DnsType type,
174                   DnsClass clazz) override;
175   std::vector<MdnsRecord::ConstRef> GetRecords(const DomainName& name,
176                                                DnsType type,
177                                                DnsClass clazz) override;
178   std::vector<MdnsRecord::ConstRef> GetPtrRecords(DnsClass clazz) override;
179 
180   MdnsSender* const sender_;
181   MdnsProbeManager* const ownership_manager_;
182   TaskRunner* const task_runner_;
183   ClockNowFunctionPtr now_function_;
184 
185   // Alarm to cancel batching of records when this class is destroyed, and
186   // instead send them immediately. Variable is only set when it is in use.
187   absl::optional<Alarm> batch_records_alarm_;
188 
189   // Number of times to announce a newly published record.
190   const int max_announcement_attempts_;
191 
192   // The queue for announce and goodbye records to be sent periodically.
193   std::vector<MdnsRecord> records_to_send_;
194 
195   // Stores mDNS records that have been published. The keys here are domain
196   // names for valid mDNS Records, and the values are the RecordAnnouncer
197   // entities associated with all published MdnsRecords for the keyed domain.
198   // These are responsible for publishing a specific MdnsRecord, announcing it
199   // when its created and sending a goodbye record when it's deleted.
200   std::map<DomainName, std::vector<RecordAnnouncerPtr>> records_;
201 };
202 
203 }  // namespace discovery
204 }  // namespace openscreen
205 
206 #endif  // DISCOVERY_MDNS_MDNS_PUBLISHER_H_
207