Fix for x86_64 build fail
[platform/upstream/connectedhomeip.git] / src / lib / mdns / minimal / Parser.cpp
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 #include "Parser.h"
19
20 #include "Query.h"
21
22 #include <stdio.h>
23
24 namespace mdns {
25 namespace Minimal {
26
27 bool QueryData::Parse(const BytesRange & validData, const uint8_t ** start)
28 {
29     // Structure is:
30     //    QNAME
31     //    TYPE
32     //    CLASS (plus a flag for unicast)
33
34     if (!validData.Contains(*start))
35     {
36         return false;
37     }
38
39     const uint8_t * nameEnd = nullptr;
40     {
41         SerializedQNameIterator it(validData, *start);
42         nameEnd = it.FindDataEnd();
43     }
44     if (nameEnd == nullptr)
45     {
46         return false;
47     }
48
49     if (!validData.Contains(nameEnd + 3))
50     {
51         return false;
52     }
53
54     // TODO: should there be checks for valid mType/class?
55
56     mType = static_cast<QType>(chip::Encoding::BigEndian::Read16(nameEnd));
57
58     uint16_t klass = chip::Encoding::BigEndian::Read16(nameEnd);
59
60     mAnswerViaUnicast = (klass & kQClassUnicastAnswerFlag) != 0;
61     mClass            = static_cast<QClass>(klass & ~kQClassUnicastAnswerFlag);
62     mNameIterator     = SerializedQNameIterator(validData, *start);
63
64     *start = nameEnd;
65
66     return true;
67 }
68
69 bool QueryData::Append(HeaderRef & hdr, chip::Encoding::BigEndian::BufferWriter & out) const
70 {
71     if ((hdr.GetAdditionalCount() != 0) || (hdr.GetAnswerCount() != 0) || (hdr.GetAuthorityCount() != 0))
72     {
73         return false;
74     }
75
76     GetName().Put(out);
77     out.Put16(static_cast<uint16_t>(mType));
78     out.Put16(static_cast<uint16_t>(mClass) | (mAnswerViaUnicast ? kQClassUnicastAnswerFlag : 0));
79
80     if (out.Fit())
81     {
82         hdr.SetQueryCount(static_cast<uint16_t>(hdr.GetQueryCount() + 1));
83     }
84
85     return out.Fit();
86 }
87
88 bool ResourceData::Parse(const BytesRange & validData, const uint8_t ** start)
89 {
90     // Structure is:
91     //    QNAME
92     //    TYPE      (16 bit)
93     //    CLASS     (16 bit)
94     //    TTL       (32 bit)
95     //    RDLENGTH  (16 bit)
96     //    <DATA>    (RDLENGTH bytes)
97     if (!validData.Contains(*start))
98     {
99         return false;
100     }
101
102     const uint8_t * nameEnd = nullptr;
103
104     {
105         SerializedQNameIterator it(validData, *start);
106         nameEnd = it.FindDataEnd();
107     }
108     if (nameEnd == nullptr)
109     {
110         return false;
111     }
112
113     // need 3*u16 + u32
114     if (!validData.Contains(nameEnd + 9))
115     {
116         return false;
117     }
118
119     mType  = static_cast<QType>(chip::Encoding::BigEndian::Read16(nameEnd));
120     mClass = static_cast<QClass>(chip::Encoding::BigEndian::Read16(nameEnd));
121     mTtl   = chip::Encoding::BigEndian::Read32(nameEnd);
122
123     uint16_t dataLen = chip::Encoding::BigEndian::Read16(nameEnd); // resource data
124
125     if (!validData.Contains(nameEnd + dataLen - 1))
126     {
127         return false; // no space for RDATA
128     }
129     mData = BytesRange(nameEnd, nameEnd + dataLen);
130
131     mNameIterator = SerializedQNameIterator(validData, *start);
132
133     *start = nameEnd + dataLen;
134
135     return true;
136 }
137
138 bool ParsePacket(const BytesRange & packetData, ParserDelegate * delegate)
139 {
140     if (packetData.Size() < static_cast<ptrdiff_t>(HeaderRef::kSizeBytes))
141     {
142         return false;
143     }
144
145     // header is used as const, so cast is safe
146     ConstHeaderRef header(packetData.Start());
147
148     if (!header.GetFlags().IsValidMdns())
149     {
150         return false;
151     }
152
153     delegate->OnHeader(header);
154
155     const uint8_t * data = packetData.Start() + HeaderRef::kSizeBytes;
156
157     {
158         QueryData queryData;
159         for (uint16_t i = 0; i < header.GetQueryCount(); i++)
160         {
161             if (!queryData.Parse(packetData, &data))
162             {
163                 return false;
164             }
165
166             delegate->OnQuery(queryData);
167         }
168     }
169
170     {
171         ResourceData resourceData;
172         for (uint16_t i = 0; i < header.GetAnswerCount(); i++)
173         {
174             if (!resourceData.Parse(packetData, &data))
175             {
176                 return false;
177             }
178
179             delegate->OnResource(ResourceType::kAnswer, resourceData);
180         }
181
182         for (uint16_t i = 0; i < header.GetAuthorityCount(); i++)
183         {
184             if (!resourceData.Parse(packetData, &data))
185             {
186                 return false;
187             }
188
189             delegate->OnResource(ResourceType::kAuthority, resourceData);
190         }
191
192         for (uint16_t i = 0; i < header.GetAdditionalCount(); i++)
193         {
194             if (!resourceData.Parse(packetData, &data))
195             {
196                 return false;
197             }
198
199             delegate->OnResource(ResourceType::kAdditional, resourceData);
200         }
201     }
202
203     return true;
204 }
205
206 } // namespace Minimal
207 } // namespace mdns