blob: 0356f7e4b2643eafd162ce80d163c67ee4c8d66e [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 <lib/core/CHIPEncoding.h>
#include <lib/core/Optional.h>
#include <lib/dnssd/minimal_mdns/core/QName.h>
#include <lib/support/BufferWriter.h>
namespace mdns {
namespace Minimal {
/**
* Handles writing into mdns packets.
*
* Generally the same as a binary data writer, but can handle qname writing with
* compression.
*/
class RecordWriter
{
public:
RecordWriter(chip::Encoding::BigEndian::BufferWriter * output) : mOutput(output) { Reset(); }
void Reset()
{
for (size_t i = 0; i < kMaxCachedReferences; i++)
{
mPreviousQNames[i] = kInvalidOffset;
}
}
chip::Encoding::BigEndian::BufferWriter & Writer() { return *mOutput; }
/// Writes the given qname into the underlying buffer, applying
/// compression if possible
RecordWriter & WriteQName(const FullQName & qname);
/// Writes the given qname into the underlying buffer, applying
/// compression if possible
RecordWriter & WriteQName(const SerializedQNameIterator & qname);
inline RecordWriter & Put8(uint8_t value)
{
mOutput->Put8(value);
return *this;
}
inline RecordWriter & Put16(uint16_t value)
{
mOutput->Put16(value);
return *this;
}
inline RecordWriter & Put32(uint32_t value)
{
mOutput->Put32(value);
return *this;
}
inline RecordWriter & PutString(const char * value)
{
mOutput->Put(value);
return *this;
}
inline RecordWriter & Put(const BytesRange & range)
{
mOutput->Put(range.Start(), range.Size());
return *this;
}
inline bool Fit() const { return mOutput->Fit(); }
private:
// How many paths to remember as 'previously written'
// and make use of them
static constexpr size_t kMaxCachedReferences = 8;
static constexpr uint16_t kInvalidOffset = 0xFFFF;
static constexpr uint16_t kMaxReuseOffset = 0x3FFF;
// Where the data is being outputted
chip::Encoding::BigEndian::BufferWriter * mOutput;
uint16_t mPreviousQNames[kMaxCachedReferences];
/// Find the offset at which this qname was previously seen (if any)
/// works with QName and SerializedQNameIterator
template <class T>
chip::Optional<uint16_t> FindPreviousName(const T & name) const
{
for (size_t i = 0; i < kMaxCachedReferences; i++)
{
SerializedQNameIterator previous = PreviousName(i);
// Any of the sub-segments may match
while (previous.IsValid())
{
if (previous == name)
{
return chip::Optional<uint16_t>::Value(previous.OffsetInCurrentValidData());
}
if (!previous.Next())
{
break;
}
}
}
return chip::Optional<uint16_t>::Missing();
}
/// Gets the iterator corresponding to the previous name
/// with the given index.
///
/// Will return an iterator that is not valid if
/// lookbehind index is not valid
SerializedQNameIterator PreviousName(size_t index) const;
/// Keep track that a qname was written at the given offset
void RememberWrittenQnameOffset(size_t offset);
};
} // namespace Minimal
} // namespace mdns