• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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