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