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