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 : #pragma once 18 : 19 : #include <lib/core/CHIPEncoding.h> 20 : #include <lib/core/Optional.h> 21 : #include <lib/dnssd/minimal_mdns/core/QName.h> 22 : #include <lib/support/BufferWriter.h> 23 : 24 : namespace mdns { 25 : namespace Minimal { 26 : 27 : /** 28 : * Handles writing into mdns packets. 29 : * 30 : * Generally the same as a binary data writer, but can handle qname writing with 31 : * compression. 32 : */ 33 : class RecordWriter 34 : { 35 : public: 36 65 : RecordWriter(chip::Encoding::BigEndian::BufferWriter * output) : mOutput(output) { Reset(); } 37 : 38 113 : void Reset() 39 : { 40 1017 : for (size_t i = 0; i < kMaxCachedReferences; i++) 41 : { 42 904 : mPreviousQNames[i] = kInvalidOffset; 43 : } 44 113 : } 45 : 46 2714 : chip::Encoding::BigEndian::BufferWriter & Writer() { return *mOutput; } 47 : 48 : /// Writes the given qname into the underlying buffer, applying 49 : /// compression if possible 50 : RecordWriter & WriteQName(const FullQName & qname); 51 : 52 : /// Writes the given qname into the underlying buffer, applying 53 : /// compression if possible 54 : RecordWriter & WriteQName(const SerializedQNameIterator & qname); 55 : 56 240 : inline RecordWriter & Put8(uint8_t value) 57 : { 58 240 : mOutput->Put8(value); 59 240 : return *this; 60 : } 61 : 62 646 : inline RecordWriter & Put16(uint16_t value) 63 : { 64 646 : mOutput->Put16(value); 65 646 : return *this; 66 : } 67 : 68 : inline RecordWriter & Put32(uint32_t value) 69 : { 70 : mOutput->Put32(value); 71 : return *this; 72 : } 73 : 74 240 : inline RecordWriter & PutString(const char * value) 75 : { 76 240 : mOutput->Put(value); 77 240 : return *this; 78 : } 79 : 80 157 : inline RecordWriter & Put(const BytesRange & range) 81 : { 82 157 : mOutput->Put(range.Start(), range.Size()); 83 157 : return *this; 84 : } 85 : 86 1372 : inline bool Fit() const { return mOutput->Fit(); } 87 : 88 : private: 89 : // How many paths to remember as 'previously written' 90 : // and make use of them 91 : static constexpr size_t kMaxCachedReferences = 8; 92 : static constexpr uint16_t kInvalidOffset = 0xFFFF; 93 : static constexpr uint16_t kMaxReuseOffset = 0x3FFF; 94 : 95 : // Where the data is being outputted 96 : chip::Encoding::BigEndian::BufferWriter * mOutput; 97 : uint16_t mPreviousQNames[kMaxCachedReferences]; 98 : 99 : /// Find the offset at which this qname was previously seen (if any) 100 : /// works with QName and SerializedQNameIterator 101 : template <class T> 102 3837 : chip::Optional<uint16_t> FindPreviousName(const T & name) const 103 : { 104 24499 : for (size_t i = 0; i < kMaxCachedReferences; i++) 105 : { 106 22197 : SerializedQNameIterator previous = PreviousName(i); 107 : 108 : // Any of the sub-segments may match 109 42268 : while (previous.IsValid()) 110 : { 111 26507 : if (previous == name) 112 : { 113 1535 : return chip::MakeOptional(static_cast<uint16_t>(previous.OffsetInCurrentValidData())); 114 : } 115 : 116 24972 : if (!previous.Next()) 117 : { 118 4901 : break; 119 : } 120 : } 121 : } 122 : 123 2302 : return chip::Optional<uint16_t>::Missing(); 124 : } 125 : 126 : /// Gets the iterator corresponding to the previous name 127 : /// with the given index. 128 : /// 129 : /// Will return an iterator that is not valid if 130 : /// lookbehind index is not valid 131 : SerializedQNameIterator PreviousName(size_t index) const; 132 : 133 : /// Keep track that a qname was written at the given offset 134 : void RememberWrittenQnameOffset(size_t offset); 135 : }; 136 : 137 : } // namespace Minimal 138 : } // namespace mdns