1 // Copyright 2020 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_DNSSD_IMPL_DNS_DATA_GRAPH_H_ 6 #define DISCOVERY_DNSSD_IMPL_DNS_DATA_GRAPH_H_ 7 8 #include <functional> 9 #include <map> 10 #include <memory> 11 #include <vector> 12 13 #include "absl/types/optional.h" 14 #include "discovery/dnssd/impl/constants.h" 15 #include "discovery/dnssd/public/dns_sd_instance_endpoint.h" 16 #include "discovery/mdns/mdns_record_changed_callback.h" 17 #include "discovery/mdns/mdns_records.h" 18 19 namespace openscreen { 20 namespace discovery { 21 22 /* 23 Per RFC 6763, the following mappings exist between the domains of the called 24 out mDNS records: 25 26 -------------- 27 | PTR Record | 28 -------------- 29 /\ 30 / \ 31 / \ 32 / \ 33 / \ 34 -------------- -------------- 35 | SRV Record | | TXT Record | 36 -------------- -------------- 37 /\ 38 / \ 39 / \ 40 / \ 41 / \ 42 / \ 43 -------------- --------------- 44 | A Record | | AAAA Record | 45 -------------- --------------- 46 47 Such that PTR records point to the domain of SRV and TXT records, and SRV 48 records point to the domain of A and AAAA records. Below, these 3 separate 49 sets are referred to as "Domain Groups". 50 51 Though it is frequently the case that each A or AAAA record will only be 52 pointed to by one SRV record domain, this is not a requirement for DNS-SD and 53 in the wild this case does come up. On the other hand, it is expected that 54 each PTR record domain will point to multiple SRV records. 55 56 To represent this data, a multigraph structure has been used. 57 - Each node of the graph represents a specific domain name 58 - Each edge represents a parent-child relationship, such that node A is a 59 parent of node B iff there exists some record x in A such that x points to 60 the domain represented by B. 61 In practice, it is expected that no more than one edge will ever exist 62 between two nodes. A multigraph is used despite this to simplify the code and 63 avoid a number of tricky edge cases (both literally and figuratively). 64 65 Note the following: 66 - This definition allows for cycles in the multigraph (which are unexpected 67 but allowed by the RFC). 68 - This definition allows for self loops (which are expected when a SRV record 69 points to address records with the same domain). 70 - The memory requirement for this graph is bounded due to a bound on the 71 number of tracked records in the mDNS layer as part of 72 discovery/mdns/mdns_querier.h. 73 */ 74 class DnsDataGraph { 75 public: 76 // The set of valid groups of domains, as called out in the hierarchy 77 // described above. 78 enum class DomainGroup { kNone = 0, kPtr, kSrvAndTxt, kAddress }; 79 80 // Get the domain group associated with the provided object. 81 static DomainGroup GetDomainGroup(DnsType type); 82 static DomainGroup GetDomainGroup(const MdnsRecord record); 83 84 // Creates a new DnsDataGraph. 85 static std::unique_ptr<DnsDataGraph> Create( 86 NetworkInterfaceIndex network_index); 87 88 // Callback to use when a domain change occurs. 89 using DomainChangeCallback = std::function<void(DomainName)>; 90 91 virtual ~DnsDataGraph(); 92 93 // Manually starts or stops tracking the provided domain. These methods should 94 // only be called for top-level PTR domains. 95 virtual void StartTracking(const DomainName& domain, 96 DomainChangeCallback on_start_tracking) = 0; 97 virtual void StopTracking(const DomainName& domain, 98 DomainChangeCallback on_stop_tracking) = 0; 99 100 // Attempts to create all DnsSdInstanceEndpoint objects with |name| associated 101 // with the provided |domain_group|. If all required data for one such 102 // endpoint has been received, and an error occurs while parsing this data, 103 // then an error is returned in place of that endpoint. 104 virtual std::vector<ErrorOr<DnsSdInstanceEndpoint>> CreateEndpoints( 105 DomainGroup domain_group, 106 const DomainName& name) const = 0; 107 108 // Modifies this entity with the provided DnsRecord. If called with a valid 109 // record type, the provided change will only be applied if the provided event 110 // is valid at the time of calling. The returned result will be an error if 111 // the change does not make sense from our current data state, and 112 // Error::None() otherwise. Valid record types with which this method can be 113 // called are PTR, SRV, TXT, A, and AAAA record types. 114 // 115 // TODO(issuetracker.google.com/157822423): Allow for duplicate records of 116 // non-PTR types. 117 virtual Error ApplyDataRecordChange( 118 MdnsRecord record, 119 RecordChangedEvent event, 120 DomainChangeCallback on_start_tracking, 121 DomainChangeCallback on_stop_tracking) = 0; 122 123 virtual size_t GetTrackedDomainCount() const = 0; 124 125 // Returns whether the provided domain is tracked or not. This may either be 126 // due to a direct call to StartTracking() or due to the result of a received 127 // record. 128 virtual bool IsTracked(const DomainName& name) const = 0; 129 }; 130 131 } // namespace discovery 132 } // namespace openscreen 133 134 #endif // DISCOVERY_DNSSD_IMPL_DNS_DATA_GRAPH_H_ 135