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 : #include <assert.h>
18 : #include <strings.h>
19 :
20 : #include "QName.h"
21 :
22 : namespace mdns {
23 : namespace Minimal {
24 :
25 56149 : bool SerializedQNameIterator::Next()
26 : {
27 56149 : return mIsValid && Next(true);
28 : }
29 :
30 56973 : bool SerializedQNameIterator::Next(bool followIndirectPointers)
31 : {
32 56973 : if (!mIsValid)
33 : {
34 0 : return false;
35 : }
36 :
37 : while (true)
38 : {
39 66806 : assert(mValidData.Contains(mCurrentPosition));
40 :
41 66806 : const uint8_t length = *mCurrentPosition;
42 66806 : if (*mCurrentPosition == 0)
43 : {
44 : // Done with all items
45 11313 : return false;
46 : }
47 :
48 55493 : if ((length & kPtrMask) == kPtrMask)
49 : {
50 10126 : if (!followIndirectPointers)
51 : {
52 : // Stop at first indirect pointer
53 287 : return false;
54 : }
55 :
56 : // PTR contains 2 bytes
57 9839 : if (!mValidData.Contains(mCurrentPosition + 1))
58 : {
59 2 : mIsValid = false;
60 2 : return false;
61 : }
62 :
63 9837 : size_t offset = static_cast<size_t>(((*mCurrentPosition & 0x3F) << 8) | *(mCurrentPosition + 1));
64 9837 : if (offset >= mLookBehindMax)
65 : {
66 : // Potential infinite recursion.
67 4 : mIsValid = false;
68 4 : return false;
69 : }
70 9833 : if (offset > mValidData.Size())
71 : {
72 : // offset too large
73 0 : mIsValid = false;
74 0 : return false;
75 : }
76 :
77 : // Look behind has to keep going backwards, otherwise we may
78 : // get into an infinite list
79 9833 : if (offset >= static_cast<size_t>(mCurrentPosition - mValidData.Start()))
80 : {
81 0 : mIsValid = false;
82 0 : return false;
83 : }
84 :
85 9833 : mLookBehindMax = offset;
86 9833 : mCurrentPosition = mValidData.Start() + offset;
87 : }
88 : else
89 : {
90 : // This branch handles non-pointer data. This will be string of size [length].
91 45367 : if (length > kMaxValueSize)
92 : {
93 : // value is too large (larger than RFC limit)
94 0 : mIsValid = false;
95 0 : return false;
96 : }
97 :
98 45367 : if (!mValidData.Contains(mCurrentPosition + 1 + length))
99 : {
100 : // string outside valid data
101 7 : mIsValid = false;
102 7 : return false;
103 : }
104 :
105 45360 : memcpy(mValue, mCurrentPosition + 1, length);
106 45360 : mValue[length] = '\0';
107 45360 : mCurrentPosition = mCurrentPosition + length + 1;
108 45360 : return true;
109 : }
110 9833 : }
111 : }
112 :
113 384 : const uint8_t * SerializedQNameIterator::FindDataEnd()
114 : {
115 824 : while (Next(false))
116 : {
117 : // nothing to do, just advance
118 : }
119 :
120 384 : if (!IsValid())
121 : {
122 0 : return nullptr;
123 : }
124 :
125 : // normal end
126 384 : if (*mCurrentPosition == 0)
127 : {
128 : // mCurrentPosition MUST already be valid
129 97 : return mCurrentPosition + 1;
130 : }
131 :
132 : // ends with a dataptr
133 287 : if ((*mCurrentPosition & kPtrMask) == kPtrMask)
134 : {
135 287 : if (!mValidData.Contains(mCurrentPosition + 1))
136 : {
137 0 : return nullptr;
138 : }
139 287 : return mCurrentPosition + 2;
140 : }
141 :
142 : // invalid data
143 0 : return nullptr;
144 : }
145 :
146 25566 : bool SerializedQNameIterator::operator==(const FullQName & other) const
147 : {
148 25566 : SerializedQNameIterator self = *this; // allow iteration
149 25566 : size_t idx = 0;
150 :
151 31151 : while ((idx < other.nameCount) && self.Next())
152 : {
153 24803 : if (strcasecmp(self.Value(), other.names[idx]) != 0)
154 : {
155 19218 : return false;
156 : }
157 5585 : idx++;
158 : }
159 :
160 6348 : return ((idx == other.nameCount) && !self.Next());
161 : }
162 :
163 86 : bool SerializedQNameIterator::operator==(const SerializedQNameIterator & other) const
164 : {
165 86 : SerializedQNameIterator a = *this; // allow iteration
166 86 : SerializedQNameIterator b = other;
167 :
168 : while (true)
169 : {
170 284 : bool hasA = a.Next();
171 284 : bool hasB = b.Next();
172 :
173 284 : if (hasA ^ hasB)
174 : {
175 6 : return false; /// one is longer than the other
176 : }
177 :
178 278 : if (!a.IsValid() || !b.IsValid())
179 : {
180 0 : return false; // invalid data
181 : }
182 :
183 278 : if (!hasA || !hasB)
184 : {
185 : break;
186 : }
187 :
188 215 : if (strcasecmp(a.Value(), b.Value()) != 0)
189 : {
190 17 : return false;
191 : }
192 198 : }
193 :
194 63 : return a.IsValid() && b.IsValid();
195 : }
196 :
197 5645 : bool FullQName::operator==(const FullQName & other) const
198 : {
199 5645 : if (nameCount != other.nameCount)
200 : {
201 4341 : return false;
202 : }
203 4072 : for (size_t i = 0; i < nameCount; i++)
204 : {
205 3229 : if (strcasecmp(names[i], other.names[i]) != 0)
206 : {
207 461 : return false;
208 : }
209 : }
210 843 : return true;
211 : }
212 :
213 : } // namespace Minimal
214 : } // namespace mdns
|