Line data Source code
1 : /*
2 : *
3 : * Copyright (c) 2022 Project CHIP Authors
4 : *
5 : * Licensed under the Apache License, Version 2.0 (the "License");
6 : * you may not use this file except in compliance with the License.
7 : * You may obtain a copy of the License at
8 : *
9 : * http://www.apache.org/licenses/LICENSE-2.0
10 : *
11 : * Unless required by applicable law or agreed to in writing, software
12 : * distributed under the License is distributed on an "AS IS" BASIS,
13 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 : * See the License for the specific language governing permissions and
15 : * limitations under the License.
16 : */
17 : #pragma once
18 :
19 : #include <lib/dnssd/Resolver.h>
20 : #include <lib/dnssd/Types.h>
21 : #include <lib/dnssd/minimal_mdns/Parser.h>
22 : #include <lib/dnssd/minimal_mdns/RecordData.h>
23 : #include <lib/dnssd/minimal_mdns/core/QName.h>
24 : #include <lib/support/BitFlags.h>
25 : #include <lib/support/Variant.h>
26 :
27 : namespace chip {
28 : namespace Dnssd {
29 :
30 : /// Allows storing and retrieving of a SerializedQName for later recall.
31 : ///
32 : /// This is a convenience storage as MDNS generally provides data as QNames
33 : /// and comparisons between QNames is more convenient than replacing them with
34 : /// null-terminated character strings.
35 : class StoredServerName
36 : {
37 : public:
38 670 : StoredServerName() {}
39 :
40 26 : void Clear() { memset(mNameBuffer, 0, sizeof(mNameBuffer)); }
41 :
42 : /// Set the underlying value. Will return CHIP_ERROR_NO_MEMORY
43 : /// on insufficient storage space.
44 : ///
45 : /// If insufficient space, buffer will be cleared.
46 : CHIP_ERROR Set(mdns::Minimal::SerializedQNameIterator value);
47 :
48 : /// Return the underlying value in this object.
49 : ///
50 : /// Value valid as long as this object is valid and underlying Set() is
51 : /// not called.
52 : mdns::Minimal::SerializedQNameIterator Get() const;
53 :
54 : private:
55 : // Try to have space for at least:
56 : // L1234._sub._matterc._udp.local => 30 chars
57 : // <fabric>-<node>._matter._tcp.local => 52 chars
58 : // <hostname>.local (where hostname is kHostNameMaxLength == 16)
59 : //
60 : // This does not try to optimize out ".local" suffix which is always expected
61 : // since comparisons are easier when suffix is still present.
62 : static constexpr size_t kMaxStoredNameLength = 64;
63 :
64 : uint8_t mNameBuffer[kMaxStoredNameLength] = {};
65 : };
66 :
67 : /// Incrementally accumulates data from DNSSD packets. It is geared twoards
68 : /// resource-constrained dns-sd querier implementations.
69 : ///
70 : /// It all starts with processing SRV records which define the type of record
71 : /// (could be operational, commissionable or commissioner), after which the
72 : /// additional data is accumulated, specifically TXT information and A/AAAA
73 : ///
74 : /// Class can also be used to determine what additional data is missing from a
75 : /// record so that additional DNSSD queries can be made recursively (e.g. if
76 : /// only a SRV/TXT records are available, ask for AAAA records).
77 : class IncrementalResolver
78 : {
79 : public:
80 : // Elements that the incremental resolve still needs
81 : enum class RequiredInformationBitFlags : uint8_t
82 : {
83 : kSrvInitialization = (1 << 0), // server being initialized
84 : kIpAddress = (1 << 1), // IP address missing
85 : };
86 : using RequiredInformationFlags = BitFlags<RequiredInformationBitFlags>;
87 :
88 : // Type of service name that is contained in this resolver
89 : enum class ServiceNameType
90 : {
91 : kInvalid, // not a matter service name
92 : kOperational,
93 : kCommissioner,
94 : kCommissionable,
95 : };
96 :
97 334 : IncrementalResolver() = default;
98 :
99 : /// Checks if object has been initialized using the `InitializeParsing`
100 : /// method.
101 256 : bool IsActive() const { return mSpecificResolutionData.Valid(); }
102 :
103 34 : bool IsActiveCommissionParse() const { return mSpecificResolutionData.Is<CommissionNodeData>(); }
104 8 : bool IsActiveOperationalParse() const { return mSpecificResolutionData.Is<OperationalNodeData>(); }
105 :
106 8 : ServiceNameType GetCurrentType() const { return mServiceNameType; }
107 :
108 0 : PeerId OperationalParsePeerId() const
109 : {
110 0 : VerifyOrReturnValue(IsActiveOperationalParse(), PeerId());
111 0 : return mSpecificResolutionData.Get<OperationalNodeData>().peerId;
112 : }
113 :
114 : /// Start parsing a new record. SRV records are the records we are mainly
115 : /// interested on, after which TXT and A/AAAA are looked for.
116 : ///
117 : /// Returns CHIP_ERROR_UNSUPPORTED_DNSSD_SERVICE_NAME for non-matter service names.
118 : ///
119 : /// If this function returns with error, the object will be in an inactive state.
120 : CHIP_ERROR InitializeParsing(mdns::Minimal::SerializedQNameIterator name, const uint64_t ttl,
121 : const mdns::Minimal::SrvRecord & srv);
122 :
123 : /// Notify that a new record is being processed.
124 : /// Will handle filtering and processing of data to determine if the entry is relevant for
125 : /// the current resolver.
126 : ///
127 : /// Providing a data that is not relevant to the current parser is not considered and error,
128 : /// however if the resource fails parsing completely an error will be returned.
129 : ///
130 : ///
131 : /// [data] represents the record received via [interface] and [packetRange] represents the range
132 : /// of valid bytes within the packet for the purpose of QName parsing
133 : CHIP_ERROR OnRecord(Inet::InterfaceId interface, const mdns::Minimal::ResourceData & data,
134 : mdns::Minimal::BytesRange packetRange);
135 :
136 : /// Return what additional data is required until the object can be extracted
137 : ///
138 : /// If `!GetREquiredInformation().HasAny()` the parsed information is ready
139 : /// to be processed.
140 : RequiredInformationFlags GetMissingRequiredInformation() const;
141 :
142 : /// Fetch the target host name set by `InitializeParsing`
143 : ///
144 : /// VALIDITY: Data references internal storage of this object and is valid as long
145 : /// as this object is valid and InitializeParsing is not called again.
146 5 : mdns::Minimal::SerializedQNameIterator GetTargetHostName() const { return mTargetHostName.Get(); }
147 :
148 : /// Fetch the record name set by `InitializeParsing`.
149 : ///
150 : /// VALIDITY: Data references internal storage of this object and is valid as long
151 : /// as this object is valid and InitializeParsing is not called again.
152 0 : mdns::Minimal::SerializedQNameIterator GetRecordName() const { return mRecordName.Get(); }
153 :
154 : /// Take the current value of the object and clear it once returned.
155 : ///
156 : /// Object must be in `IsActive()` for this to succeed.
157 : /// Data will be returned (and cleared) even if not yet complete based
158 : /// on `GetMissingRequiredInformation()`. This method takes as much data as
159 : /// it was parsed so far.
160 : CHIP_ERROR Take(DiscoveredNodeData & outputData);
161 :
162 : /// Take the current value of the object and clear it once returned.
163 : ///
164 : /// Object must be in `IsActiveOperationalParse()` for this to succeed.
165 : /// Data will be returned (and cleared) even if not yet complete based
166 : /// on `GetMissingRequiredInformation()`. This method takes as much data as
167 : /// it was parsed so far.
168 : CHIP_ERROR Take(ResolvedNodeData & outputData);
169 :
170 : /// Clears current state, setting as inactive
171 12 : void ResetToInactive()
172 : {
173 12 : mCommonResolutionData.Reset();
174 12 : mSpecificResolutionData = ParsedRecordSpecificData();
175 12 : }
176 :
177 : private:
178 : /// Notify that a PTR record can be parsed.
179 : ///
180 : /// Input data MUST have GetType() == QType::TXT
181 : CHIP_ERROR OnTxtRecord(const mdns::Minimal::ResourceData & data, mdns::Minimal::BytesRange packetRange);
182 :
183 : /// Notify that a new IP address has been found.
184 : ///
185 : /// This is to be called on both A (if IPv4 support is enabled) and AAAA
186 : /// addresses.
187 : ///
188 : /// Prerequisite: IP address belongs to the right nost name
189 : CHIP_ERROR OnIpAddress(Inet::InterfaceId interface, const Inet::IPAddress & addr);
190 :
191 : using ParsedRecordSpecificData = Variant<OperationalNodeData, CommissionNodeData>;
192 :
193 : StoredServerName mRecordName; // Record name for what is parsed (SRV/PTR/TXT)
194 : StoredServerName mTargetHostName; // `Target` for the SRV record
195 : ServiceNameType mServiceNameType = ServiceNameType::kInvalid;
196 : CommonResolutionData mCommonResolutionData;
197 : ParsedRecordSpecificData mSpecificResolutionData;
198 : };
199 :
200 : } // namespace Dnssd
201 : } // namespace chip
|