blob: 373d0093123fdaffbb3d157079e3552da545b34b [file] [log] [blame]
/** @file
*
* A brief file description
*
* @section license License
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
#include "QUICIncomingFrameBuffer.h"
//
// QUICIncomingFrameBuffer
//
QUICIncomingFrameBuffer::~QUICIncomingFrameBuffer()
{
this->clear();
}
void
QUICIncomingFrameBuffer::clear()
{
for (auto ite : this->_out_of_order_queue) {
delete ite.second;
}
this->_out_of_order_queue.clear();
while (!this->_recv_buffer.empty()) {
delete this->_recv_buffer.front();
this->_recv_buffer.pop();
}
this->_recv_offset = 0;
}
bool
QUICIncomingFrameBuffer::empty()
{
return this->_out_of_order_queue.empty() && this->_recv_buffer.empty();
}
//
// QUICIncomingStreamFrameBuffer
//
QUICIncomingStreamFrameBuffer::~QUICIncomingStreamFrameBuffer()
{
this->clear();
}
const QUICFrame *
QUICIncomingStreamFrameBuffer::pop()
{
if (this->_recv_buffer.empty()) {
auto elem = this->_out_of_order_queue.find(this->_recv_offset);
while (elem != this->_out_of_order_queue.end()) {
const QUICStreamFrame *frame = static_cast<const QUICStreamFrame *>(elem->second);
this->_recv_buffer.push(frame);
this->_recv_offset += frame->data_length();
this->_out_of_order_queue.erase(elem);
elem = this->_out_of_order_queue.find(this->_recv_offset);
}
}
if (!this->_recv_buffer.empty()) {
auto frame = this->_recv_buffer.front();
this->_recv_buffer.pop();
return frame;
}
return nullptr;
}
QUICConnectionErrorUPtr
QUICIncomingStreamFrameBuffer::insert(const QUICFrame *frame)
{
const QUICStreamFrame *stream_frame = static_cast<const QUICStreamFrame *>(frame);
QUICOffset offset = stream_frame->offset();
size_t len = stream_frame->data_length();
QUICConnectionErrorUPtr err = this->_check_and_set_fin_flag(offset, len, stream_frame->has_fin_flag());
if (err != nullptr) {
delete frame;
return err;
}
// Ignore empty stream frame except pure fin stream frame
if (len == 0 && !stream_frame->has_fin_flag()) {
delete frame;
return nullptr;
}
if (this->_recv_offset > offset) {
// dup frame;
delete frame;
return nullptr;
} else if (this->_recv_offset == offset) {
this->_recv_offset = offset + len;
this->_recv_buffer.push(stream_frame);
} else {
auto result = this->_out_of_order_queue.insert(std::make_pair(offset, stream_frame));
if (!result.second) {
// Duplicate frame doesn't need to be inserted
delete stream_frame;
}
}
return nullptr;
}
void
QUICIncomingStreamFrameBuffer::clear()
{
this->_fin_offset = UINT64_MAX;
this->_max_offset = 0;
super::clear();
}
QUICConnectionErrorUPtr
QUICIncomingStreamFrameBuffer::_check_and_set_fin_flag(QUICOffset offset, size_t len, bool fin_flag)
{
// stream with fin flag {11.3. Stream Final Offset}
// Once a final offset for a stream is known, it cannot change.
// If a RESET_STREAM or STREAM frame causes the final offset to change for a stream,
// an endpoint SHOULD respond with a FINAL_SIZE_ERROR error (see Section 12).
// A receiver SHOULD treat receipt of data at or beyond the final offset as a
// FINAL_SIZE_ERROR error, even after a stream is closed.
// {11.3. Stream Final Offset}
// A receiver SHOULD treat receipt of data at or beyond the final offset as a
// FINAL_SIZE_ERROR error, even after a stream is closed.
if (fin_flag) {
if (this->_fin_offset != UINT64_MAX) {
if (this->_fin_offset == offset + len) {
// dup fin frame
return nullptr;
}
return std::make_unique<QUICConnectionError>(QUICTransErrorCode::FINAL_SIZE_ERROR);
}
this->_fin_offset = offset + len;
if (this->_max_offset > this->_fin_offset) {
return std::make_unique<QUICConnectionError>(QUICTransErrorCode::FINAL_SIZE_ERROR);
}
} else if (this->_fin_offset != UINT64_MAX && this->_fin_offset <= offset) {
return std::make_unique<QUICConnectionError>(QUICTransErrorCode::FINAL_SIZE_ERROR);
}
this->_max_offset = std::max(offset + len, this->_max_offset);
return nullptr;
}
bool
QUICIncomingStreamFrameBuffer::is_transfer_goal_set() const
{
return this->_fin_offset != UINT64_MAX;
}
uint64_t
QUICIncomingStreamFrameBuffer::transfer_progress() const
{
return this->_max_offset;
}
uint64_t
QUICIncomingStreamFrameBuffer::transfer_goal() const
{
return this->_fin_offset;
}
bool
QUICIncomingStreamFrameBuffer::is_cancelled() const
{
return false;
}
//
// QUICIncomingCryptoFrameBuffer
//
QUICIncomingCryptoFrameBuffer::~QUICIncomingCryptoFrameBuffer()
{
super::clear();
}
const QUICFrame *
QUICIncomingCryptoFrameBuffer::pop()
{
if (this->_recv_buffer.empty()) {
auto elem = this->_out_of_order_queue.find(this->_recv_offset);
while (elem != this->_out_of_order_queue.end()) {
const QUICCryptoFrame *frame = static_cast<const QUICCryptoFrame *>(elem->second);
this->_recv_buffer.push(frame);
this->_recv_offset += frame->data_length();
this->_out_of_order_queue.erase(elem);
elem = this->_out_of_order_queue.find(this->_recv_offset);
}
}
if (!this->_recv_buffer.empty()) {
auto frame = this->_recv_buffer.front();
this->_recv_buffer.pop();
return frame;
}
return nullptr;
}
QUICConnectionErrorUPtr
QUICIncomingCryptoFrameBuffer::insert(const QUICFrame *frame)
{
const QUICCryptoFrame *crypto_frame = static_cast<const QUICCryptoFrame *>(frame);
QUICOffset offset = crypto_frame->offset();
size_t len = crypto_frame->data_length();
// Ignore empty stream frame
if (len == 0) {
delete frame;
return nullptr;
}
if (this->_recv_offset > offset) {
// dup frame;
delete frame;
return nullptr;
} else if (this->_recv_offset == offset) {
this->_recv_offset = offset + len;
this->_recv_buffer.push(crypto_frame);
} else {
auto result = this->_out_of_order_queue.insert(std::make_pair(offset, crypto_frame));
if (!result.second) {
// Duplicate frame doesn't need to be inserted
delete crypto_frame;
}
}
return nullptr;
}