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