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 64546 : bool SerializedQNameIterator::Next()
26 : {
27 64546 : return mIsValid && Next(true);
28 : }
29 :
30 65350 : bool SerializedQNameIterator::Next(bool followIndirectPointers)
31 : {
32 65350 : if (!mIsValid)
33 : {
34 0 : return false;
35 : }
36 :
37 : while (true)
38 : {
39 76268 : assert(mValidData.Contains(mCurrentPosition));
40 :
41 76268 : const uint8_t length = *mCurrentPosition;
42 76268 : if (*mCurrentPosition == 0)
43 : {
44 : // Done with all items
45 13029 : return false;
46 : }
47 :
48 63239 : if ((length & kPtrMask) == kPtrMask)
49 : {
50 11187 : if (!followIndirectPointers)
51 : {
52 : // Stop at first indirect pointer
53 263 : return false;
54 : }
55 :
56 : // PTR contains 2 bytes
57 10924 : if (!mValidData.Contains(mCurrentPosition + 1))
58 : {
59 2 : mIsValid = false;
60 2 : return false;
61 : }
62 :
63 10922 : size_t offset = static_cast<size_t>(((*mCurrentPosition & 0x3F) << 8) | *(mCurrentPosition + 1));
64 : // Look behind has to keep going backwards to avoid potential infinite recursion.
65 : // mLookBehindMax starts out <= mValidData.Size() and only decreases;
66 : // mLookBehindMax <= mCurrentPosition - mValidData.Start() remains true throughout.
67 10922 : if (offset >= mLookBehindMax)
68 : {
69 4 : mIsValid = false;
70 4 : return false;
71 : }
72 :
73 10918 : mLookBehindMax = offset;
74 10918 : mCurrentPosition = mValidData.Start() + offset;
75 : }
76 : else
77 : {
78 : // This branch handles non-pointer data. This will be string of size [length].
79 52052 : if (length > kMaxValueSize)
80 : {
81 : // value is too large (larger than RFC limit)
82 0 : mIsValid = false;
83 0 : return false;
84 : }
85 :
86 52052 : if (!mValidData.Contains(mCurrentPosition + 1 + length))
87 : {
88 : // string outside valid data
89 7 : mIsValid = false;
90 7 : return false;
91 : }
92 :
93 52045 : memcpy(mValue, mCurrentPosition + 1, length);
94 52045 : mValue[length] = '\0';
95 52045 : mCurrentPosition = mCurrentPosition + length + 1;
96 52045 : return true;
97 : }
98 10918 : }
99 : }
100 :
101 361 : const uint8_t * SerializedQNameIterator::FindDataEnd()
102 : {
103 805 : while (Next(false))
104 : {
105 : // nothing to do, just advance
106 : }
107 :
108 361 : if (!IsValid())
109 : {
110 0 : return nullptr;
111 : }
112 :
113 : // normal end
114 361 : if (*mCurrentPosition == 0)
115 : {
116 : // mCurrentPosition MUST already be valid
117 98 : return mCurrentPosition + 1;
118 : }
119 :
120 : // ends with a dataptr
121 263 : if ((*mCurrentPosition & kPtrMask) == kPtrMask)
122 : {
123 263 : if (!mValidData.Contains(mCurrentPosition + 1))
124 : {
125 0 : return nullptr;
126 : }
127 263 : return mCurrentPosition + 2;
128 : }
129 :
130 : // invalid data
131 0 : return nullptr;
132 : }
133 :
134 29430 : bool SerializedQNameIterator::operator==(const FullQName & other) const
135 : {
136 29430 : SerializedQNameIterator self = *this; // allow iteration
137 29430 : size_t idx = 0;
138 :
139 36012 : while ((idx < other.nameCount) && self.Next())
140 : {
141 28660 : if (strcasecmp(self.Value(), other.names[idx]) != 0)
142 : {
143 22078 : return false;
144 : }
145 6582 : idx++;
146 : }
147 :
148 7352 : return ((idx == other.nameCount) && !self.Next());
149 : }
150 :
151 74 : bool SerializedQNameIterator::operator==(const SerializedQNameIterator & other) const
152 : {
153 74 : SerializedQNameIterator a = *this; // allow iteration
154 74 : SerializedQNameIterator b = other;
155 :
156 : while (true)
157 : {
158 248 : bool hasA = a.Next();
159 248 : bool hasB = b.Next();
160 :
161 248 : if (hasA ^ hasB)
162 : {
163 6 : return false; /// one is longer than the other
164 : }
165 :
166 242 : if (!a.IsValid() || !b.IsValid())
167 : {
168 0 : return false; // invalid data
169 : }
170 :
171 242 : if (!hasA || !hasB)
172 : {
173 : break;
174 : }
175 :
176 191 : if (strcasecmp(a.Value(), b.Value()) != 0)
177 : {
178 17 : return false;
179 : }
180 174 : }
181 :
182 51 : return a.IsValid() && b.IsValid();
183 : }
184 :
185 7049 : bool FullQName::operator==(const FullQName & other) const
186 : {
187 7049 : if (nameCount != other.nameCount)
188 : {
189 5475 : return false;
190 : }
191 4978 : for (size_t i = 0; i < nameCount; i++)
192 : {
193 3985 : if (strcasecmp(names[i], other.names[i]) != 0)
194 : {
195 581 : return false;
196 : }
197 : }
198 993 : return true;
199 : }
200 :
201 : } // namespace Minimal
202 : } // namespace mdns
|