Line data Source code
1 : /* 2 : * 3 : * Copyright (c) 2020 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 : 18 : #pragma once 19 : 20 : #include <inttypes.h> 21 : 22 : #include <lib/core/CHIPError.h> 23 : #include <lib/dnssd/minimal_mdns/core/FlatAllocatedQName.h> 24 : #include <lib/dnssd/minimal_mdns/core/QName.h> 25 : #include <lib/dnssd/minimal_mdns/responders/IP.h> 26 : #include <lib/dnssd/minimal_mdns/responders/Ptr.h> 27 : #include <lib/dnssd/minimal_mdns/responders/QueryResponder.h> 28 : #include <lib/dnssd/minimal_mdns/responders/RecordResponder.h> 29 : #include <lib/dnssd/minimal_mdns/responders/Srv.h> 30 : #include <lib/dnssd/minimal_mdns/responders/Txt.h> 31 : #include <lib/support/CHIPMem.h> 32 : #include <lib/support/logging/CHIPLogging.h> 33 : 34 : namespace chip { 35 : namespace Dnssd { 36 : 37 : template <size_t kMaxRecords> 38 : class QueryResponderAllocator 39 : { 40 : public: 41 11 : QueryResponderAllocator() 42 11 : { 43 97 : for (auto & responder : mAllocatedResponders) 44 : { 45 86 : responder = nullptr; 46 : } 47 363 : for (auto & name : mAllocatedQNameParts) 48 : { 49 352 : name = nullptr; 50 : } 51 11 : } 52 11 : ~QueryResponderAllocator() { Clear(); } 53 : 54 : /// Appends another responder to the internal replies. 55 : template <typename ResponderType, typename... Args> 56 157 : mdns::Minimal::QueryResponderSettings AddResponder(Args &&... args) 57 : { 58 157 : return AddAllocatedResponder(chip::Platform::New<ResponderType>(std::forward<Args>(args)...)); 59 : } 60 : 61 : template <typename... Args> 62 117 : mdns::Minimal::FullQName AllocateQName(Args &&... names) 63 : { 64 117 : void * storage = AllocateQNameSpace(mdns::Minimal::FlatAllocatedQName::RequiredStorageSize(std::forward<Args>(names)...)); 65 117 : if (storage == nullptr) 66 : { 67 0 : return mdns::Minimal::FullQName(); 68 : } 69 117 : return mdns::Minimal::FlatAllocatedQName::Build(storage, std::forward<Args>(names)...); 70 : } 71 : 72 20 : mdns::Minimal::FullQName AllocateQNameFromArray(char const * const * names, size_t num) 73 : { 74 20 : void * storage = AllocateQNameSpace(mdns::Minimal::FlatAllocatedQName::RequiredStorageSizeFromArray(names, num)); 75 20 : if (storage == nullptr) 76 : { 77 0 : return mdns::Minimal::FullQName(); 78 : } 79 20 : return mdns::Minimal::FlatAllocatedQName::BuildFromArray(storage, names, num); 80 : } 81 : 82 : /// Sets the query responder to a blank state and frees up any 83 : /// allocated memory. 84 73 : void Clear() 85 : { 86 : // Init clears all responders, so that data can be freed 87 73 : mQueryResponder.Init(); 88 : 89 : // Free all allocated data 90 801 : for (auto & responder : mAllocatedResponders) 91 : { 92 728 : if (responder != nullptr) 93 : { 94 157 : chip::Platform::Delete(responder); 95 157 : responder = nullptr; 96 : } 97 : } 98 : 99 2409 : for (auto & name : mAllocatedQNameParts) 100 : { 101 2336 : if (name != nullptr) 102 : { 103 137 : chip::Platform::MemoryFree(name); 104 137 : name = nullptr; 105 : } 106 : } 107 73 : } 108 444 : mdns::Minimal::QueryResponder<kMaxRecords + 1> * GetQueryResponder() { return &mQueryResponder; } 109 12 : const mdns::Minimal::RecordResponder * GetResponder(const mdns::Minimal::QType & qtype, 110 : const mdns::Minimal::FullQName & qname) const 111 : { 112 79 : for (auto & responder : mAllocatedResponders) 113 : { 114 68 : if (responder != nullptr && responder->GetQType() == qtype && responder->GetQName() == qname) 115 : { 116 1 : return responder; 117 : } 118 : } 119 11 : return nullptr; 120 : } 121 : bool IsEmpty() const 122 : { 123 : for (auto & responder : mAllocatedResponders) 124 : { 125 : if (responder != nullptr) 126 : { 127 : return false; 128 : } 129 : } 130 : for (auto & name : mAllocatedQNameParts) 131 : { 132 : if (name != nullptr) 133 : { 134 : return false; 135 : } 136 : } 137 : return true; 138 : } 139 : 140 : protected: 141 : // For testing. 142 : size_t GetMaxAllocatedQNames() { return kMaxAllocatedQNameData; } 143 : void * GetQNamePart(size_t idx) { return mAllocatedQNameParts[idx]; } 144 : mdns::Minimal::RecordResponder * GetRecordResponder(size_t idx) { return mAllocatedResponders[idx]; } 145 : 146 : private: 147 : static constexpr size_t kMaxAllocatedQNameData = 32; 148 : // dynamically allocated items 149 : mdns::Minimal::RecordResponder * mAllocatedResponders[kMaxRecords]; 150 : void * mAllocatedQNameParts[kMaxAllocatedQNameData]; 151 : // The QueryResponder needs 1 extra space to hold the record for itself. 152 : mdns::Minimal::QueryResponder<kMaxRecords + 1> mQueryResponder; 153 : 154 157 : mdns::Minimal::QueryResponderSettings AddAllocatedResponder(mdns::Minimal::RecordResponder * newResponder) 155 : { 156 157 : if (newResponder == nullptr) 157 : { 158 0 : ChipLogError(Discovery, "Responder memory allocation failed"); 159 0 : return mdns::Minimal::QueryResponderSettings(); // failed 160 : } 161 : 162 721 : for (auto & responder : mAllocatedResponders) 163 : { 164 721 : if (responder != nullptr) 165 : { 166 564 : continue; 167 : } 168 : 169 157 : responder = newResponder; 170 157 : return mQueryResponder.AddResponder(responder); 171 : } 172 : 173 0 : Platform::Delete(newResponder); 174 0 : ChipLogError(Discovery, "Failed to find free slot for adding a responder"); 175 0 : return mdns::Minimal::QueryResponderSettings(); 176 : } 177 : 178 137 : void * AllocateQNameSpace(size_t size) 179 : { 180 564 : for (auto & name : mAllocatedQNameParts) 181 : { 182 564 : if (name != nullptr) 183 : { 184 427 : continue; 185 : } 186 : 187 137 : name = chip::Platform::MemoryAlloc(size); 188 137 : if (name == nullptr) 189 : { 190 0 : ChipLogError(Discovery, "QName memory allocation failed"); 191 : } 192 137 : return name; 193 : } 194 0 : ChipLogError(Discovery, "Failed to find free slot for adding a qname"); 195 0 : return nullptr; 196 : } 197 : }; 198 : 199 : } // namespace Dnssd 200 : } // namespace chip