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_QUERIER_H_ 6*3f982cf4SFabien Sanglard #define DISCOVERY_MDNS_MDNS_QUERIER_H_ 7*3f982cf4SFabien Sanglard 8*3f982cf4SFabien Sanglard #include <list> 9*3f982cf4SFabien Sanglard #include <map> 10*3f982cf4SFabien Sanglard #include <memory> 11*3f982cf4SFabien Sanglard #include <vector> 12*3f982cf4SFabien Sanglard 13*3f982cf4SFabien Sanglard #include "discovery/common/config.h" 14*3f982cf4SFabien Sanglard #include "discovery/mdns/mdns_receiver.h" 15*3f982cf4SFabien Sanglard #include "discovery/mdns/mdns_record_changed_callback.h" 16*3f982cf4SFabien Sanglard #include "discovery/mdns/mdns_records.h" 17*3f982cf4SFabien Sanglard #include "discovery/mdns/mdns_trackers.h" 18*3f982cf4SFabien Sanglard #include "platform/api/task_runner.h" 19*3f982cf4SFabien Sanglard 20*3f982cf4SFabien Sanglard namespace openscreen { 21*3f982cf4SFabien Sanglard namespace discovery { 22*3f982cf4SFabien Sanglard 23*3f982cf4SFabien Sanglard class MdnsRandom; 24*3f982cf4SFabien Sanglard class MdnsSender; 25*3f982cf4SFabien Sanglard class MdnsQuestionTracker; 26*3f982cf4SFabien Sanglard class MdnsRecordTracker; 27*3f982cf4SFabien Sanglard class ReportingClient; 28*3f982cf4SFabien Sanglard 29*3f982cf4SFabien Sanglard class MdnsQuerier : public MdnsReceiver::ResponseClient { 30*3f982cf4SFabien Sanglard public: 31*3f982cf4SFabien Sanglard MdnsQuerier(MdnsSender* sender, 32*3f982cf4SFabien Sanglard MdnsReceiver* receiver, 33*3f982cf4SFabien Sanglard TaskRunner* task_runner, 34*3f982cf4SFabien Sanglard ClockNowFunctionPtr now_function, 35*3f982cf4SFabien Sanglard MdnsRandom* random_delay, 36*3f982cf4SFabien Sanglard ReportingClient* reporting_client, 37*3f982cf4SFabien Sanglard Config config); 38*3f982cf4SFabien Sanglard MdnsQuerier(const MdnsQuerier& other) = delete; 39*3f982cf4SFabien Sanglard MdnsQuerier(MdnsQuerier&& other) noexcept = delete; 40*3f982cf4SFabien Sanglard MdnsQuerier& operator=(const MdnsQuerier& other) = delete; 41*3f982cf4SFabien Sanglard MdnsQuerier& operator=(MdnsQuerier&& other) noexcept = delete; 42*3f982cf4SFabien Sanglard ~MdnsQuerier() override; 43*3f982cf4SFabien Sanglard 44*3f982cf4SFabien Sanglard // Starts an mDNS query with the given name, DNS type, and DNS class. Updated 45*3f982cf4SFabien Sanglard // records are passed to |callback|. The caller must ensure |callback| 46*3f982cf4SFabien Sanglard // remains alive while it is registered with a query. 47*3f982cf4SFabien Sanglard // NOTE: This call is only valid for |dns_type| values: 48*3f982cf4SFabien Sanglard // - DnsType::kA 49*3f982cf4SFabien Sanglard // - DnsType::kPTR 50*3f982cf4SFabien Sanglard // - DnsType::kTXT 51*3f982cf4SFabien Sanglard // - DnsType::kAAAA 52*3f982cf4SFabien Sanglard // - DnsType::kSRV 53*3f982cf4SFabien Sanglard // - DnsType::kANY 54*3f982cf4SFabien Sanglard void StartQuery(const DomainName& name, 55*3f982cf4SFabien Sanglard DnsType dns_type, 56*3f982cf4SFabien Sanglard DnsClass dns_class, 57*3f982cf4SFabien Sanglard MdnsRecordChangedCallback* callback); 58*3f982cf4SFabien Sanglard 59*3f982cf4SFabien Sanglard // Stops an mDNS query with the given name, DNS type, and DNS class. 60*3f982cf4SFabien Sanglard // |callback| must be the same callback pointer that was previously passed to 61*3f982cf4SFabien Sanglard // StartQuery. 62*3f982cf4SFabien Sanglard void StopQuery(const DomainName& name, 63*3f982cf4SFabien Sanglard DnsType dns_type, 64*3f982cf4SFabien Sanglard DnsClass dns_class, 65*3f982cf4SFabien Sanglard MdnsRecordChangedCallback* callback); 66*3f982cf4SFabien Sanglard 67*3f982cf4SFabien Sanglard // Re-initializes the process of service discovery for the provided domain 68*3f982cf4SFabien Sanglard // name. All ongoing queries for this domain are restarted and any previously 69*3f982cf4SFabien Sanglard // received query results are discarded. 70*3f982cf4SFabien Sanglard void ReinitializeQueries(const DomainName& name); 71*3f982cf4SFabien Sanglard 72*3f982cf4SFabien Sanglard private: 73*3f982cf4SFabien Sanglard struct CallbackInfo { 74*3f982cf4SFabien Sanglard MdnsRecordChangedCallback* const callback; 75*3f982cf4SFabien Sanglard const DnsType dns_type; 76*3f982cf4SFabien Sanglard const DnsClass dns_class; 77*3f982cf4SFabien Sanglard }; 78*3f982cf4SFabien Sanglard 79*3f982cf4SFabien Sanglard // Represents a Least Recently Used cache of MdnsRecordTrackers. 80*3f982cf4SFabien Sanglard class RecordTrackerLruCache { 81*3f982cf4SFabien Sanglard public: 82*3f982cf4SFabien Sanglard using RecordTrackerConstRef = 83*3f982cf4SFabien Sanglard std::reference_wrapper<const MdnsRecordTracker>; 84*3f982cf4SFabien Sanglard using TrackerApplicableCheck = 85*3f982cf4SFabien Sanglard std::function<bool(const MdnsRecordTracker&)>; 86*3f982cf4SFabien Sanglard using TrackerChangeCallback = std::function<void(const MdnsRecordTracker&)>; 87*3f982cf4SFabien Sanglard 88*3f982cf4SFabien Sanglard RecordTrackerLruCache(MdnsQuerier* querier, 89*3f982cf4SFabien Sanglard MdnsSender* sender, 90*3f982cf4SFabien Sanglard MdnsRandom* random_delay, 91*3f982cf4SFabien Sanglard TaskRunner* task_runner, 92*3f982cf4SFabien Sanglard ClockNowFunctionPtr now_function, 93*3f982cf4SFabien Sanglard ReportingClient* reporting_client, 94*3f982cf4SFabien Sanglard const Config& config); 95*3f982cf4SFabien Sanglard 96*3f982cf4SFabien Sanglard // Returns all trackers with the associated |name| such that its type 97*3f982cf4SFabien Sanglard // represents a type corresponding to |dns_type| and class corresponding to 98*3f982cf4SFabien Sanglard // |dns_class|. 99*3f982cf4SFabien Sanglard std::vector<RecordTrackerConstRef> Find(const DomainName& name); 100*3f982cf4SFabien Sanglard std::vector<RecordTrackerConstRef> Find(const DomainName& name, 101*3f982cf4SFabien Sanglard DnsType dns_type, 102*3f982cf4SFabien Sanglard DnsClass dns_class); 103*3f982cf4SFabien Sanglard 104*3f982cf4SFabien Sanglard // Calls ExpireSoon on all record trackers in the provided domain which 105*3f982cf4SFabien Sanglard // match the provided applicability check. Returns the number of trackers 106*3f982cf4SFabien Sanglard // marked for expiry. 107*3f982cf4SFabien Sanglard int ExpireSoon(const DomainName& name, TrackerApplicableCheck check); 108*3f982cf4SFabien Sanglard 109*3f982cf4SFabien Sanglard // Erases all record trackers in the provided domain which match the 110*3f982cf4SFabien Sanglard // provided applicability check. Returns the number of trackers erased. 111*3f982cf4SFabien Sanglard int Erase(const DomainName& name, TrackerApplicableCheck check); 112*3f982cf4SFabien Sanglard 113*3f982cf4SFabien Sanglard // Updates all record trackers in the domain |record.name()| which match the 114*3f982cf4SFabien Sanglard // provided applicability check using the provided record. Returns the 115*3f982cf4SFabien Sanglard // number of records successfully updated. 116*3f982cf4SFabien Sanglard int Update(const MdnsRecord& record, TrackerApplicableCheck check); 117*3f982cf4SFabien Sanglard int Update(const MdnsRecord& record, 118*3f982cf4SFabien Sanglard TrackerApplicableCheck check, 119*3f982cf4SFabien Sanglard TrackerChangeCallback on_rdata_update); 120*3f982cf4SFabien Sanglard 121*3f982cf4SFabien Sanglard // Creates a record tracker of the given type associated with the provided 122*3f982cf4SFabien Sanglard // record. 123*3f982cf4SFabien Sanglard const MdnsRecordTracker& StartTracking(MdnsRecord record, DnsType type); 124*3f982cf4SFabien Sanglard size()125*3f982cf4SFabien Sanglard size_t size() { return records_.size(); } 126*3f982cf4SFabien Sanglard 127*3f982cf4SFabien Sanglard private: 128*3f982cf4SFabien Sanglard using LruList = std::list<MdnsRecordTracker>; 129*3f982cf4SFabien Sanglard using RecordMap = std::multimap<DomainName, LruList::iterator>; 130*3f982cf4SFabien Sanglard 131*3f982cf4SFabien Sanglard void MoveToBeginning(RecordMap::iterator iterator); 132*3f982cf4SFabien Sanglard void MoveToEnd(RecordMap::iterator iterator); 133*3f982cf4SFabien Sanglard 134*3f982cf4SFabien Sanglard MdnsQuerier* const querier_; 135*3f982cf4SFabien Sanglard MdnsSender* const sender_; 136*3f982cf4SFabien Sanglard MdnsRandom* const random_delay_; 137*3f982cf4SFabien Sanglard TaskRunner* const task_runner_; 138*3f982cf4SFabien Sanglard ClockNowFunctionPtr now_function_; 139*3f982cf4SFabien Sanglard ReportingClient* reporting_client_; 140*3f982cf4SFabien Sanglard const Config& config_; 141*3f982cf4SFabien Sanglard 142*3f982cf4SFabien Sanglard // List of RecordTracker instances used by this instance where the least 143*3f982cf4SFabien Sanglard // recently updated element (or next to be deleted element) appears at the 144*3f982cf4SFabien Sanglard // end of the list. 145*3f982cf4SFabien Sanglard LruList lru_order_; 146*3f982cf4SFabien Sanglard 147*3f982cf4SFabien Sanglard // A collection of active known record trackers, each is identified by 148*3f982cf4SFabien Sanglard // domain name, DNS record type, and DNS record class. Multimap key is 149*3f982cf4SFabien Sanglard // domain name only to allow easy support for wildcard processing for DNS 150*3f982cf4SFabien Sanglard // record type and class and allow storing shared records that differ only 151*3f982cf4SFabien Sanglard // in RDATA. 152*3f982cf4SFabien Sanglard // 153*3f982cf4SFabien Sanglard // MdnsRecordTracker instances are stored as unique_ptr so they are not 154*3f982cf4SFabien Sanglard // moved around in memory when the collection is modified. This allows 155*3f982cf4SFabien Sanglard // passing a pointer to MdnsQuestionTracker to a task running on the 156*3f982cf4SFabien Sanglard // TaskRunner. 157*3f982cf4SFabien Sanglard RecordMap records_; 158*3f982cf4SFabien Sanglard }; 159*3f982cf4SFabien Sanglard 160*3f982cf4SFabien Sanglard friend class MdnsQuerierTest; 161*3f982cf4SFabien Sanglard 162*3f982cf4SFabien Sanglard // MdnsReceiver::ResponseClient overrides. 163*3f982cf4SFabien Sanglard void OnMessageReceived(const MdnsMessage& message) override; 164*3f982cf4SFabien Sanglard 165*3f982cf4SFabien Sanglard // Expires the record tracker provided. This callback is passed to owned 166*3f982cf4SFabien Sanglard // MdnsRecordTracker instances in |records_|. 167*3f982cf4SFabien Sanglard void OnRecordExpired(const MdnsRecordTracker* tracker, 168*3f982cf4SFabien Sanglard const MdnsRecord& record); 169*3f982cf4SFabien Sanglard 170*3f982cf4SFabien Sanglard // Determines whether a record received by this querier should be processed 171*3f982cf4SFabien Sanglard // or dropped. 172*3f982cf4SFabien Sanglard bool ShouldAnswerRecordBeProcessed(const MdnsRecord& answer); 173*3f982cf4SFabien Sanglard 174*3f982cf4SFabien Sanglard // Processes any record update, calling into the below methods as needed. 175*3f982cf4SFabien Sanglard // NOTE: All records of type OPT are dropped, as they should not be cached per 176*3f982cf4SFabien Sanglard // RFC6891. 177*3f982cf4SFabien Sanglard void ProcessRecord(const MdnsRecord& records); 178*3f982cf4SFabien Sanglard 179*3f982cf4SFabien Sanglard // Processes a shared record update as a record of type |type|. 180*3f982cf4SFabien Sanglard void ProcessSharedRecord(const MdnsRecord& record, DnsType type); 181*3f982cf4SFabien Sanglard 182*3f982cf4SFabien Sanglard // Processes a unique record update as a record of type |type|. 183*3f982cf4SFabien Sanglard void ProcessUniqueRecord(const MdnsRecord& record, DnsType type); 184*3f982cf4SFabien Sanglard 185*3f982cf4SFabien Sanglard // Called when exactly one tracker is associated with a provided key. 186*3f982cf4SFabien Sanglard // Determines the type of update being executed by this update call, then 187*3f982cf4SFabien Sanglard // fires the appropriate callback. 188*3f982cf4SFabien Sanglard void ProcessSinglyTrackedUniqueRecord(const MdnsRecord& record, 189*3f982cf4SFabien Sanglard const MdnsRecordTracker& tracker); 190*3f982cf4SFabien Sanglard 191*3f982cf4SFabien Sanglard // Called when multiple records are associated with the same key. Expire all 192*3f982cf4SFabien Sanglard // record with non-matching RDATA. Update the record with the matching RDATA 193*3f982cf4SFabien Sanglard // if it exists, otherwise insert a new record. 194*3f982cf4SFabien Sanglard void ProcessMultiTrackedUniqueRecord(const MdnsRecord& record, 195*3f982cf4SFabien Sanglard DnsType dns_type); 196*3f982cf4SFabien Sanglard 197*3f982cf4SFabien Sanglard // Calls all callbacks associated with the provided record. 198*3f982cf4SFabien Sanglard void ProcessCallbacks(const MdnsRecord& record, RecordChangedEvent event); 199*3f982cf4SFabien Sanglard 200*3f982cf4SFabien Sanglard // Begins tracking the provided question. 201*3f982cf4SFabien Sanglard void AddQuestion(const MdnsQuestion& question); 202*3f982cf4SFabien Sanglard 203*3f982cf4SFabien Sanglard // Begins tracking the provided record. 204*3f982cf4SFabien Sanglard void AddRecord(const MdnsRecord& record, DnsType type); 205*3f982cf4SFabien Sanglard 206*3f982cf4SFabien Sanglard // Applies the supplied pending changes. 207*3f982cf4SFabien Sanglard void ApplyPendingChanges(std::vector<PendingQueryChange> pending_changes); 208*3f982cf4SFabien Sanglard 209*3f982cf4SFabien Sanglard MdnsSender* const sender_; 210*3f982cf4SFabien Sanglard MdnsReceiver* const receiver_; 211*3f982cf4SFabien Sanglard TaskRunner* const task_runner_; 212*3f982cf4SFabien Sanglard const ClockNowFunctionPtr now_function_; 213*3f982cf4SFabien Sanglard MdnsRandom* const random_delay_; 214*3f982cf4SFabien Sanglard ReportingClient* reporting_client_; 215*3f982cf4SFabien Sanglard Config config_; 216*3f982cf4SFabien Sanglard 217*3f982cf4SFabien Sanglard // A collection of active question trackers, each is uniquely identified by 218*3f982cf4SFabien Sanglard // domain name, DNS record type, and DNS record class. Multimap key is domain 219*3f982cf4SFabien Sanglard // name only to allow easy support for wildcard processing for DNS record type 220*3f982cf4SFabien Sanglard // and class. MdnsQuestionTracker instances are stored as unique_ptr so they 221*3f982cf4SFabien Sanglard // are not moved around in memory when the collection is modified. This allows 222*3f982cf4SFabien Sanglard // passing a pointer to MdnsQuestionTracker to a task running on the 223*3f982cf4SFabien Sanglard // TaskRunner. 224*3f982cf4SFabien Sanglard std::multimap<DomainName, std::unique_ptr<MdnsQuestionTracker>> questions_; 225*3f982cf4SFabien Sanglard 226*3f982cf4SFabien Sanglard // Set of records tracked by this querier. 227*3f982cf4SFabien Sanglard RecordTrackerLruCache records_; 228*3f982cf4SFabien Sanglard 229*3f982cf4SFabien Sanglard // A collection of callbacks passed to StartQuery method. Each is identified 230*3f982cf4SFabien Sanglard // by domain name, DNS record type, and DNS record class, but there can be 231*3f982cf4SFabien Sanglard // more than one callback for a particular query. Multimap key is domain name 232*3f982cf4SFabien Sanglard // only to allow easy matching of records against callbacks that have wildcard 233*3f982cf4SFabien Sanglard // DNS class and/or DNS type. 234*3f982cf4SFabien Sanglard std::multimap<DomainName, CallbackInfo> callbacks_; 235*3f982cf4SFabien Sanglard }; 236*3f982cf4SFabien Sanglard 237*3f982cf4SFabien Sanglard } // namespace discovery 238*3f982cf4SFabien Sanglard } // namespace openscreen 239*3f982cf4SFabien Sanglard 240*3f982cf4SFabien Sanglard #endif // DISCOVERY_MDNS_MDNS_QUERIER_H_ 241