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