| /* | |
| * | |
| * Copyright (c) 2020 Project CHIP Authors | |
| * | |
| * Licensed under the Apache License, Version 2.0 (the "License"); | |
| * you may not use this file except in compliance with the License. | |
| * You may obtain a copy of the License at | |
| * | |
| * http://www.apache.org/licenses/LICENSE-2.0 | |
| * | |
| * Unless required by applicable law or agreed to in writing, software | |
| * distributed under the License is distributed on an "AS IS" BASIS, | |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| * See the License for the specific language governing permissions and | |
| * limitations under the License. | |
| */ | |
| #pragma once | |
| #include <string.h> | |
| #include <array> | |
| #include <cstddef> | |
| #include <cstdint> | |
| #include <utility> | |
| #include <lib/core/CHIPEncoding.h> | |
| #include <lib/support/BufferWriter.h> | |
| #include <lib/dnssd/wire/BytesRange.h> | |
| #include <lib/dnssd/wire/DnsHeader.h> | |
| namespace chip { | |
| namespace Dnssd { | |
| /// A QName part is a null-terminated string | |
| using QNamePart = const char *; | |
| /// A list of QNames that is simple to pass around | |
| /// | |
| /// As the struct may be copied, the lifetime of 'names' has to extend beyond | |
| /// the objects that use this struct. | |
| struct FullQName | |
| { | |
| const QNamePart * names; | |
| size_t nameCount; | |
| FullQName() : names(nullptr), nameCount(0) {} | |
| FullQName(const FullQName &) = default; | |
| FullQName & operator=(const FullQName &) = default; | |
| template <size_t N> | |
| FullQName(const QNamePart (&data)[N]) : names(data), nameCount(N) | |
| {} | |
| bool operator==(const FullQName & other) const; | |
| bool operator!=(const FullQName & other) const { return !(*this == other); } | |
| }; | |
| /// A serialized QNAME is comprised of | |
| /// - length-prefixed parts | |
| /// - Ends in a 0-length item | |
| /// - May contain pointers to previous data (for efficient transmission) | |
| /// | |
| /// This class allows iterating over such parts while validating | |
| /// that the parts are within a valid range | |
| class SerializedQNameIterator | |
| { | |
| public: | |
| SerializedQNameIterator() : mLookBehindMax(0), mCurrentPosition(nullptr), mIsValid(false) {} | |
| SerializedQNameIterator(const SerializedQNameIterator &) = default; | |
| SerializedQNameIterator & operator=(const SerializedQNameIterator &) = default; | |
| SerializedQNameIterator(const BytesRange validData, const uint8_t * position) : | |
| mValidData(validData), mLookBehindMax(static_cast<size_t>(position - validData.Start())), mCurrentPosition(position) | |
| {} | |
| /// Advances to the next element in the sequence | |
| /// Returns true if new data was available | |
| bool Next(); | |
| /// Find out if the data parsing is ok. | |
| /// If invalid data is encountered during a [Next] call, this will | |
| /// return false. Check this after Next returns false. | |
| bool IsValid() const { return mIsValid; } | |
| /// Valid IFF Next() returned true. | |
| /// Next has to be called after construction | |
| QNamePart Value() const { return mValue; } | |
| /// Get the end of the sequence *without* following any | |
| /// backwards pointers. Changes iterator state. | |
| /// | |
| /// returs nullptr on error (invalid data) | |
| const uint8_t * FindDataEnd(); | |
| bool operator==(const FullQName & other) const; | |
| bool operator!=(const FullQName & other) const { return !(*this == other); } | |
| bool operator==(const SerializedQNameIterator & other) const; | |
| bool operator!=(const SerializedQNameIterator & other) const { return !(*this == other); } | |
| size_t OffsetInCurrentValidData() const { return static_cast<size_t>(mCurrentPosition - mValidData.Start()); } | |
| private: | |
| static constexpr size_t kMaxValueSize = 63; | |
| static constexpr uint8_t kPtrMask = 0xC0; | |
| BytesRange mValidData; | |
| size_t mLookBehindMax; // avoid loops by limiting lookbehind | |
| const uint8_t * mCurrentPosition; | |
| bool mIsValid = true; | |
| char mValue[kMaxValueSize + 1] = { 0 }; | |
| // Advances to the next element in the sequence | |
| bool Next(bool followIndirectPointers); | |
| }; | |
| } // namespace Dnssd | |
| } // namespace chip |