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 13 : QueryResponderAllocator()
42 13 : {
43 121 : for (auto & responder : mAllocatedResponders)
44 : {
45 108 : responder = nullptr;
46 : }
47 429 : for (auto & name : mAllocatedQNameParts)
48 : {
49 416 : name = nullptr;
50 : }
51 13 : }
52 13 : ~QueryResponderAllocator() { Clear(); }
53 :
54 : /// Appends another responder to the internal replies.
55 : template <typename ResponderType, typename... Args>
56 148 : mdns::Minimal::QueryResponderSettings AddResponder(Args &&... args)
57 : {
58 148 : return AddAllocatedResponder(chip::Platform::New<ResponderType>(std::forward<Args>(args)...));
59 : }
60 :
61 : template <typename... Args>
62 110 : mdns::Minimal::FullQName AllocateQName(Args &&... names)
63 : {
64 110 : void * storage = AllocateQNameSpace(mdns::Minimal::FlatAllocatedQName::RequiredStorageSize(std::forward<Args>(names)...));
65 110 : if (storage == nullptr)
66 : {
67 0 : return mdns::Minimal::FullQName();
68 : }
69 110 : return mdns::Minimal::FlatAllocatedQName::Build(storage, std::forward<Args>(names)...);
70 : }
71 :
72 19 : mdns::Minimal::FullQName AllocateQNameFromArray(char const * const * names, size_t num)
73 : {
74 19 : void * storage = AllocateQNameSpace(mdns::Minimal::FlatAllocatedQName::RequiredStorageSizeFromArray(names, num));
75 19 : if (storage == nullptr)
76 : {
77 0 : return mdns::Minimal::FullQName();
78 : }
79 19 : 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 70 : void Clear()
85 : {
86 : // Init clears all responders, so that data can be freed
87 70 : mQueryResponder.Init();
88 :
89 : // Free all allocated data
90 765 : for (auto & responder : mAllocatedResponders)
91 : {
92 695 : if (responder != nullptr)
93 : {
94 148 : chip::Platform::Delete(responder);
95 148 : responder = nullptr;
96 : }
97 : }
98 :
99 2310 : for (auto & name : mAllocatedQNameParts)
100 : {
101 2240 : if (name != nullptr)
102 : {
103 129 : chip::Platform::MemoryFree(name);
104 129 : name = nullptr;
105 : }
106 : }
107 70 : }
108 404 : 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 148 : mdns::Minimal::QueryResponderSettings AddAllocatedResponder(mdns::Minimal::RecordResponder * newResponder)
155 : {
156 148 : if (newResponder == nullptr)
157 : {
158 0 : ChipLogError(Discovery, "Responder memory allocation failed");
159 0 : return mdns::Minimal::QueryResponderSettings(); // failed
160 : }
161 :
162 676 : for (auto & responder : mAllocatedResponders)
163 : {
164 676 : if (responder != nullptr)
165 : {
166 528 : continue;
167 : }
168 :
169 148 : responder = newResponder;
170 148 : 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 129 : void * AllocateQNameSpace(size_t size)
179 : {
180 528 : for (auto & name : mAllocatedQNameParts)
181 : {
182 528 : if (name != nullptr)
183 : {
184 399 : continue;
185 : }
186 :
187 129 : name = chip::Platform::MemoryAlloc(size);
188 129 : if (name == nullptr)
189 : {
190 0 : ChipLogError(Discovery, "QName memory allocation failed");
191 : }
192 129 : 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
|