blob: e2dc6f54716f851b483bd2a5961b7821521ac27f [file] [log] [blame]
/*
*
* 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/minimal_mdns/core/BytesRange.h>
#include <lib/dnssd/minimal_mdns/core/DnsHeader.h>
namespace mdns {
namespace Minimal {
/// 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 Minimal
} // namespace mdns