1 /** @file
2 *
3 * A brief file description
4 *
5 * @section license License
6 *
7 * Licensed to the Apache Software Foundation (ASF) under one
8 * or more contributor license agreements. See the NOTICE file
9 * distributed with this work for additional information
10 * regarding copyright ownership. The ASF licenses this file
11 * to you under the Apache License, Version 2.0 (the
12 * "License"); you may not use this file except in compliance
13 * with the License. You may obtain a copy of the License at
14 *
15 * http://www.apache.org/licenses/LICENSE-2.0
16 *
17 * Unless required by applicable law or agreed to in writing, software
18 * distributed under the License is distributed on an "AS IS" BASIS,
19 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 * See the License for the specific language governing permissions and
21 * limitations under the License.
22 */
23
24 #include "QUICIncomingFrameBuffer.h"
25
26 //
27 // QUICIncomingFrameBuffer
28 //
29
~QUICIncomingFrameBuffer()30 QUICIncomingFrameBuffer::~QUICIncomingFrameBuffer()
31 {
32 this->clear();
33 }
34
35 void
clear()36 QUICIncomingFrameBuffer::clear()
37 {
38 for (auto ite : this->_out_of_order_queue) {
39 delete ite.second;
40 }
41 this->_out_of_order_queue.clear();
42
43 while (!this->_recv_buffer.empty()) {
44 delete this->_recv_buffer.front();
45 this->_recv_buffer.pop();
46 }
47
48 this->_recv_offset = 0;
49 }
50
51 bool
empty()52 QUICIncomingFrameBuffer::empty()
53 {
54 return this->_out_of_order_queue.empty() && this->_recv_buffer.empty();
55 }
56
57 //
58 // QUICIncomingStreamFrameBuffer
59 //
~QUICIncomingStreamFrameBuffer()60 QUICIncomingStreamFrameBuffer::~QUICIncomingStreamFrameBuffer()
61 {
62 this->clear();
63 }
64
65 const QUICFrame *
pop()66 QUICIncomingStreamFrameBuffer::pop()
67 {
68 if (this->_recv_buffer.empty()) {
69 auto elem = this->_out_of_order_queue.find(this->_recv_offset);
70 while (elem != this->_out_of_order_queue.end()) {
71 const QUICStreamFrame *frame = static_cast<const QUICStreamFrame *>(elem->second);
72
73 this->_recv_buffer.push(frame);
74 this->_recv_offset += frame->data_length();
75 this->_out_of_order_queue.erase(elem);
76 elem = this->_out_of_order_queue.find(this->_recv_offset);
77 }
78 }
79
80 if (!this->_recv_buffer.empty()) {
81 auto frame = this->_recv_buffer.front();
82 this->_recv_buffer.pop();
83 return frame;
84 }
85 return nullptr;
86 }
87
88 QUICConnectionErrorUPtr
insert(const QUICFrame * frame)89 QUICIncomingStreamFrameBuffer::insert(const QUICFrame *frame)
90 {
91 const QUICStreamFrame *stream_frame = static_cast<const QUICStreamFrame *>(frame);
92
93 QUICOffset offset = stream_frame->offset();
94 size_t len = stream_frame->data_length();
95
96 QUICConnectionErrorUPtr err = this->_check_and_set_fin_flag(offset, len, stream_frame->has_fin_flag());
97 if (err != nullptr) {
98 delete frame;
99 return err;
100 }
101
102 // Ignore empty stream frame except pure fin stream frame
103 if (len == 0 && !stream_frame->has_fin_flag()) {
104 delete frame;
105 return nullptr;
106 }
107
108 if (this->_recv_offset > offset) {
109 // dup frame;
110 delete frame;
111 return nullptr;
112 } else if (this->_recv_offset == offset) {
113 this->_recv_offset = offset + len;
114 this->_recv_buffer.push(stream_frame);
115 } else {
116 auto result = this->_out_of_order_queue.insert(std::make_pair(offset, stream_frame));
117 if (!result.second) {
118 // Duplicate frame doesn't need to be inserted
119 delete stream_frame;
120 }
121 }
122
123 return nullptr;
124 }
125
126 void
clear()127 QUICIncomingStreamFrameBuffer::clear()
128 {
129 this->_fin_offset = UINT64_MAX;
130 this->_max_offset = 0;
131
132 super::clear();
133 }
134
135 QUICConnectionErrorUPtr
_check_and_set_fin_flag(QUICOffset offset,size_t len,bool fin_flag)136 QUICIncomingStreamFrameBuffer::_check_and_set_fin_flag(QUICOffset offset, size_t len, bool fin_flag)
137 {
138 // stream with fin flag {11.3. Stream Final Offset}
139 // Once a final offset for a stream is known, it cannot change.
140 // If a RESET_STREAM or STREAM frame causes the final offset to change for a stream,
141 // an endpoint SHOULD respond with a FINAL_SIZE_ERROR error (see Section 12).
142 // A receiver SHOULD treat receipt of data at or beyond the final offset as a
143 // FINAL_SIZE_ERROR error, even after a stream is closed.
144
145 // {11.3. Stream Final Offset}
146 // A receiver SHOULD treat receipt of data at or beyond the final offset as a
147 // FINAL_SIZE_ERROR error, even after a stream is closed.
148 if (fin_flag) {
149 if (this->_fin_offset != UINT64_MAX) {
150 if (this->_fin_offset == offset + len) {
151 // dup fin frame
152 return nullptr;
153 }
154 return std::make_unique<QUICConnectionError>(QUICTransErrorCode::FINAL_SIZE_ERROR);
155 }
156
157 this->_fin_offset = offset + len;
158
159 if (this->_max_offset > this->_fin_offset) {
160 return std::make_unique<QUICConnectionError>(QUICTransErrorCode::FINAL_SIZE_ERROR);
161 }
162
163 } else if (this->_fin_offset != UINT64_MAX && this->_fin_offset <= offset) {
164 return std::make_unique<QUICConnectionError>(QUICTransErrorCode::FINAL_SIZE_ERROR);
165 }
166 this->_max_offset = std::max(offset + len, this->_max_offset);
167
168 return nullptr;
169 }
170
171 bool
is_transfer_goal_set() const172 QUICIncomingStreamFrameBuffer::is_transfer_goal_set() const
173 {
174 return this->_fin_offset != UINT64_MAX;
175 }
176
177 uint64_t
transfer_progress() const178 QUICIncomingStreamFrameBuffer::transfer_progress() const
179 {
180 return this->_max_offset;
181 }
182
183 uint64_t
transfer_goal() const184 QUICIncomingStreamFrameBuffer::transfer_goal() const
185 {
186 return this->_fin_offset;
187 }
188
189 bool
is_cancelled() const190 QUICIncomingStreamFrameBuffer::is_cancelled() const
191 {
192 return false;
193 }
194
195 //
196 // QUICIncomingCryptoFrameBuffer
197 //
~QUICIncomingCryptoFrameBuffer()198 QUICIncomingCryptoFrameBuffer::~QUICIncomingCryptoFrameBuffer()
199 {
200 super::clear();
201 }
202
203 const QUICFrame *
pop()204 QUICIncomingCryptoFrameBuffer::pop()
205 {
206 if (this->_recv_buffer.empty()) {
207 auto elem = this->_out_of_order_queue.find(this->_recv_offset);
208 while (elem != this->_out_of_order_queue.end()) {
209 const QUICCryptoFrame *frame = static_cast<const QUICCryptoFrame *>(elem->second);
210
211 this->_recv_buffer.push(frame);
212 this->_recv_offset += frame->data_length();
213 this->_out_of_order_queue.erase(elem);
214 elem = this->_out_of_order_queue.find(this->_recv_offset);
215 }
216 }
217
218 if (!this->_recv_buffer.empty()) {
219 auto frame = this->_recv_buffer.front();
220 this->_recv_buffer.pop();
221 return frame;
222 }
223
224 return nullptr;
225 }
226
227 QUICConnectionErrorUPtr
insert(const QUICFrame * frame)228 QUICIncomingCryptoFrameBuffer::insert(const QUICFrame *frame)
229 {
230 const QUICCryptoFrame *crypto_frame = static_cast<const QUICCryptoFrame *>(frame);
231
232 QUICOffset offset = crypto_frame->offset();
233 size_t len = crypto_frame->data_length();
234
235 // Ignore empty stream frame
236 if (len == 0) {
237 delete frame;
238 return nullptr;
239 }
240
241 if (this->_recv_offset > offset) {
242 // dup frame;
243 delete frame;
244 return nullptr;
245 } else if (this->_recv_offset == offset) {
246 this->_recv_offset = offset + len;
247 this->_recv_buffer.push(crypto_frame);
248 } else {
249 auto result = this->_out_of_order_queue.insert(std::make_pair(offset, crypto_frame));
250 if (!result.second) {
251 // Duplicate frame doesn't need to be inserted
252 delete crypto_frame;
253 }
254 }
255
256 return nullptr;
257 }
258