blob: 61bb652ab1c19ec2e7cc33b5a70e5b4c0668c18f [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 "catch.hpp"
#include "quic/QUICFlowController.h"
#include "quic/Mock.h"
#include <memory>
static constexpr int DEFAULT_RTT = 1 * HRTIME_SECOND;
class MockRTTProvider : public QUICRTTProvider
{
public:
ink_hrtime
smoothed_rtt() const override
{
return this->_smoothed_rtt;
}
MockRTTProvider(ink_hrtime rtt) : _smoothed_rtt(rtt) {}
void
set_smoothed_rtt(ink_hrtime rtt)
{
this->_smoothed_rtt = rtt;
}
ink_hrtime
latest_rtt() const override
{
return HRTIME_MSECONDS(1);
}
ink_hrtime
rttvar() const override
{
return HRTIME_MSECONDS(1);
}
ink_hrtime
congestion_period(uint32_t period) const override
{
return HRTIME_MSECONDS(1);
}
private:
ink_hrtime _smoothed_rtt = 0;
};
TEST_CASE("QUICFlowController_Local_Connection", "[quic]")
{
int ret = 0;
uint8_t frame_buf[QUICFrame::MAX_INSTANCE_SIZE];
MockRTTProvider rp(DEFAULT_RTT);
QUICLocalConnectionFlowController fc(&rp, 1024);
// Check initial state
CHECK(fc.current_offset() == 0);
CHECK(fc.current_limit() == 1024);
ret = fc.update(256);
CHECK(fc.current_offset() == 256);
CHECK(fc.current_limit() == 1024);
CHECK(ret == 0);
ret = fc.update(512);
CHECK(fc.current_offset() == 512);
CHECK(fc.current_limit() == 1024);
CHECK(ret == 0);
// Retransmit
ret = fc.update(512);
CHECK(fc.current_offset() == 512);
CHECK(fc.current_limit() == 1024);
CHECK(ret == 0);
ret = fc.update(1024);
CHECK(fc.current_offset() == 1024);
CHECK(fc.current_limit() == 1024);
CHECK(ret == 0);
// Delay
ret = fc.update(512);
CHECK(fc.current_offset() == 1024);
CHECK(fc.current_limit() == 1024);
CHECK(ret == 0);
Thread::get_hrtime_updated();
// Exceed limit
ret = fc.update(1280);
CHECK(fc.current_offset() == 1024);
CHECK(fc.current_limit() == 1024);
CHECK(ret != 0);
// MAX_STREAM_DATA
fc.forward_limit(2048);
CHECK(fc.current_offset() == 1024);
CHECK(fc.current_limit() == 2048);
QUICFrame *frame = fc.generate_frame(frame_buf, QUICEncryptionLevel::ONE_RTT, 0, 1024, 0, 0);
CHECK(frame);
CHECK(frame->type() == QUICFrameType::MAX_DATA);
ret = fc.update(1280);
CHECK(fc.current_offset() == 1280);
CHECK(fc.current_limit() == 2048);
CHECK(ret == 0);
}
TEST_CASE("QUICFlowController_Remote_Connection", "[quic]")
{
int ret = 0;
uint8_t frame_buf[QUICFrame::MAX_INSTANCE_SIZE];
QUICRemoteConnectionFlowController fc(1024);
// Check initial state
CHECK(fc.current_offset() == 0);
CHECK(fc.current_limit() == 1024);
ret = fc.update(256);
CHECK(fc.current_offset() == 256);
CHECK(fc.current_limit() == 1024);
CHECK(ret == 0);
ret = fc.update(512);
CHECK(fc.current_offset() == 512);
CHECK(fc.current_limit() == 1024);
CHECK(ret == 0);
// Retransmit
ret = fc.update(512);
CHECK(fc.current_offset() == 512);
CHECK(fc.current_limit() == 1024);
CHECK(ret == 0);
ret = fc.update(1000);
CHECK(fc.current_offset() == 1000);
CHECK(fc.current_limit() == 1024);
CHECK(ret == 0);
// Delay
ret = fc.update(512);
CHECK(fc.current_offset() == 1000);
CHECK(fc.current_limit() == 1024);
CHECK(ret == 0);
// Exceed limit
ret = fc.update(1280);
CHECK(fc.current_offset() == 1000);
CHECK(fc.current_limit() == 1024);
CHECK(ret != 0);
QUICFrame *frame = fc.generate_frame(frame_buf, QUICEncryptionLevel::ONE_RTT, 0, 1024, 0, 0);
CHECK(frame);
CHECK(frame->type() == QUICFrameType::DATA_BLOCKED);
// MAX_STREAM_DATA
fc.forward_limit(2048);
CHECK(fc.current_offset() == 1000);
CHECK(fc.current_limit() == 2048);
ret = fc.update(1280);
CHECK(fc.current_offset() == 1280);
CHECK(fc.current_limit() == 2048);
CHECK(ret == 0);
}
TEST_CASE("QUICFlowController_Remote_Connection_ZERO_Credit", "[quic]")
{
int ret = 0;
uint8_t frame_buf[QUICFrame::MAX_INSTANCE_SIZE];
QUICRemoteConnectionFlowController fc(1024);
// Check initial state
CHECK(fc.current_offset() == 0);
CHECK(fc.current_limit() == 1024);
// Zero credit
ret = fc.update(1024);
CHECK(fc.current_offset() == 1024);
CHECK(fc.current_limit() == 1024);
CHECK(ret == 0);
CHECK(fc.will_generate_frame(QUICEncryptionLevel::ONE_RTT, 0, true, 0));
// if there're anything to send
QUICFrame *frame = fc.generate_frame(frame_buf, QUICEncryptionLevel::ONE_RTT, 0, 1024, 0, 0);
CHECK(frame);
CHECK(frame->type() == QUICFrameType::DATA_BLOCKED);
// MAX_STREAM_DATA
fc.forward_limit(2048);
CHECK(fc.current_offset() == 1024);
CHECK(fc.current_limit() == 2048);
ret = fc.update(1280);
CHECK(fc.current_offset() == 1280);
CHECK(fc.current_limit() == 2048);
CHECK(ret == 0);
}
TEST_CASE("QUICFlowController_Local_Stream", "[quic]")
{
int ret = 0;
uint8_t frame_buf[QUICFrame::MAX_INSTANCE_SIZE];
MockRTTProvider rp(DEFAULT_RTT);
QUICLocalStreamFlowController fc(&rp, 1024, 0);
// Check initial state
CHECK(fc.current_offset() == 0);
CHECK(fc.current_limit() == 1024);
ret = fc.update(256);
CHECK(fc.current_offset() == 256);
CHECK(fc.current_limit() == 1024);
CHECK(ret == 0);
ret = fc.update(512);
CHECK(fc.current_offset() == 512);
CHECK(fc.current_limit() == 1024);
CHECK(ret == 0);
// Retransmit
ret = fc.update(512);
CHECK(fc.current_offset() == 512);
CHECK(fc.current_limit() == 1024);
CHECK(ret == 0);
ret = fc.update(1024);
CHECK(fc.current_offset() == 1024);
CHECK(fc.current_limit() == 1024);
CHECK(ret == 0);
// Delay
ret = fc.update(512);
CHECK(fc.current_offset() == 1024);
CHECK(fc.current_limit() == 1024);
CHECK(ret == 0);
Thread::get_hrtime_updated();
// Exceed limit
ret = fc.update(1280);
CHECK(fc.current_offset() == 1024);
CHECK(fc.current_limit() == 1024);
CHECK(ret != 0);
// MAX_STREAM_DATA
fc.forward_limit(2048);
CHECK(fc.current_offset() == 1024);
CHECK(fc.current_limit() == 2048);
QUICFrame *frame = fc.generate_frame(frame_buf, QUICEncryptionLevel::ONE_RTT, 0, 1024, 0, 0);
CHECK(frame);
CHECK(frame->type() == QUICFrameType::MAX_STREAM_DATA);
ret = fc.update(1280);
CHECK(fc.current_offset() == 1280);
CHECK(fc.current_limit() == 2048);
CHECK(ret == 0);
}
TEST_CASE("QUICFlowController_Remote_Stream", "[quic]")
{
int ret = 0;
QUICRemoteStreamFlowController fc(1024, 0);
// Check initial state
CHECK(fc.current_offset() == 0);
CHECK(fc.current_limit() == 1024);
ret = fc.update(256);
CHECK(fc.current_offset() == 256);
CHECK(fc.current_limit() == 1024);
CHECK(ret == 0);
ret = fc.update(512);
CHECK(fc.current_offset() == 512);
CHECK(fc.current_limit() == 1024);
CHECK(ret == 0);
// Retransmit
ret = fc.update(512);
CHECK(fc.current_offset() == 512);
CHECK(fc.current_limit() == 1024);
CHECK(ret == 0);
ret = fc.update(1024);
CHECK(fc.current_offset() == 1024);
CHECK(fc.current_limit() == 1024);
CHECK(ret == 0);
CHECK(fc.credit() == 0);
CHECK(fc.will_generate_frame(QUICEncryptionLevel::ONE_RTT, 0, true, 0));
// Delay
ret = fc.update(512);
CHECK(fc.current_offset() == 1024);
CHECK(fc.current_limit() == 1024);
CHECK(ret == 0);
// Exceed limit
ret = fc.update(1280);
CHECK(fc.current_offset() == 1024);
CHECK(fc.current_limit() == 1024);
CHECK(ret != 0);
// MAX_STREAM_DATA
fc.forward_limit(2048);
CHECK(fc.current_offset() == 1024);
CHECK(fc.current_limit() == 2048);
ret = fc.update(1280);
CHECK(fc.current_offset() == 1280);
CHECK(fc.current_limit() == 2048);
CHECK(ret == 0);
}
TEST_CASE("Frame retransmission", "[quic]")
{
QUICEncryptionLevel level = QUICEncryptionLevel::ONE_RTT;
SECTION("BLOCKED frame")
{
int ret = 0;
uint8_t frame_buf[QUICFrame::MAX_INSTANCE_SIZE];
QUICRemoteConnectionFlowController fc(1024);
// Check initial state
auto frame = fc.generate_frame(frame_buf, level, 1024, 1024, 0, 0);
CHECK(!frame);
ret = fc.update(1024);
CHECK(ret == 0);
frame = fc.generate_frame(frame_buf, level, 1024, 1024, 0, 0);
REQUIRE(frame);
CHECK(static_cast<QUICDataBlockedFrame *>(frame)->offset() == 1024);
QUICFrameId id = frame->id();
// Don't retransmit unless the frame is lost
frame = fc.generate_frame(frame_buf, level, 1024, 1024, 0, 0);
REQUIRE(!frame);
// Retransmit
fc.on_frame_lost(id);
frame = fc.generate_frame(frame_buf, level, 1024, 1024, 0, 0);
REQUIRE(frame);
CHECK(static_cast<QUICDataBlockedFrame *>(frame)->offset() == 1024);
// Don't send if it was not blocked
fc.on_frame_lost(frame->id());
fc.forward_limit(2048);
ret = fc.update(1536);
frame = fc.generate_frame(frame_buf, level, 1024, 1024, 0, 0);
CHECK(!frame);
// This should not be retransmition
ret = fc.update(2048);
frame = fc.generate_frame(frame_buf, level, 1024, 1024, 0, 0);
REQUIRE(frame);
CHECK(static_cast<QUICDataBlockedFrame *>(frame)->offset() == 2048);
}
SECTION("STREAM_DATA_BLOCKED frame")
{
int ret = 0;
uint8_t frame_buf[QUICFrame::MAX_INSTANCE_SIZE];
QUICRemoteStreamFlowController fc(1024, 0);
// Check initial state
auto frame = fc.generate_frame(frame_buf, level, 1024, 1024, 0, 0);
CHECK(!frame);
ret = fc.update(1024);
CHECK(ret == 0);
frame = fc.generate_frame(frame_buf, level, 1024, 1024, 0, 0);
REQUIRE(frame);
CHECK(static_cast<QUICStreamDataBlockedFrame *>(frame)->offset() == 1024);
QUICFrameId id = frame->id();
// Don't retransmit unless the frame is lost
frame = fc.generate_frame(frame_buf, level, 1024, 1024, 0, 0);
REQUIRE(!frame);
// Retransmit
fc.on_frame_lost(id);
frame = fc.generate_frame(frame_buf, level, 1024, 1024, 0, 0);
REQUIRE(frame);
CHECK(static_cast<QUICStreamDataBlockedFrame *>(frame)->offset() == 1024);
// Don't send if it was not blocked
fc.on_frame_lost(frame->id());
fc.forward_limit(2048);
ret = fc.update(1536);
frame = fc.generate_frame(frame_buf, level, 1024, 1024, 0, 0);
CHECK(!frame);
// This should not be retransmition
ret = fc.update(2048);
frame = fc.generate_frame(frame_buf, level, 1024, 1024, 0, 0);
REQUIRE(frame);
CHECK(static_cast<QUICStreamDataBlockedFrame *>(frame)->offset() == 2048);
}
SECTION("MAX_DATA frame")
{
uint8_t frame_buf[QUICFrame::MAX_INSTANCE_SIZE];
MockRTTProvider rp(DEFAULT_RTT);
QUICLocalConnectionFlowController fc(&rp, 1024);
// Check initial state
auto frame = fc.generate_frame(frame_buf, level, 1024, 1024, 0, 0);
CHECK(!frame);
fc.update(1024);
fc.forward_limit(1024);
frame = fc.generate_frame(frame_buf, level, 1024, 1024, 0, 0);
REQUIRE(frame);
CHECK(static_cast<QUICMaxDataFrame *>(frame)->maximum_data() == 1024);
QUICFrameId id = frame->id();
// Don't retransmit unless the frame is lost
frame = fc.generate_frame(frame_buf, level, 1024, 1024, 0, 0);
REQUIRE(!frame);
// Retransmit
fc.on_frame_lost(id);
frame = fc.generate_frame(frame_buf, level, 1024, 1024, 0, 0);
REQUIRE(frame);
CHECK(static_cast<QUICMaxDataFrame *>(frame)->maximum_data() == 1024);
// Send new one if it was updated
fc.on_frame_lost(id);
fc.forward_limit(2048);
fc.update(2048);
frame = fc.generate_frame(frame_buf, level, 1024, 1024, 0, 0);
REQUIRE(frame);
CHECK(static_cast<QUICMaxDataFrame *>(frame)->maximum_data() == 2048);
}
SECTION("MAX_STREAM_DATA frame")
{
uint8_t frame_buf[QUICFrame::MAX_INSTANCE_SIZE];
MockRTTProvider rp(DEFAULT_RTT);
QUICLocalStreamFlowController fc(&rp, 1024, 0);
// Check initial state
auto frame = fc.generate_frame(frame_buf, level, 1024, 1024, 0, 0);
CHECK(!frame);
fc.update(1024);
fc.forward_limit(1024);
frame = fc.generate_frame(frame_buf, level, 1024, 1024, 0, 0);
REQUIRE(frame);
CHECK(static_cast<QUICMaxStreamDataFrame *>(frame)->maximum_stream_data() == 1024);
QUICFrameId id = frame->id();
// Don't retransmit unless the frame is lost
frame = fc.generate_frame(frame_buf, level, 1024, 1024, 0, 0);
REQUIRE(!frame);
// Retransmit
fc.on_frame_lost(id);
frame = fc.generate_frame(frame_buf, level, 1024, 1024, 0, 0);
REQUIRE(frame);
CHECK(static_cast<QUICMaxStreamDataFrame *>(frame)->maximum_stream_data() == 1024);
// Send new one if it was updated
fc.on_frame_lost(id);
fc.forward_limit(2048);
fc.update(2048);
frame = fc.generate_frame(frame_buf, level, 1024, 1024, 0, 0);
REQUIRE(frame);
CHECK(static_cast<QUICMaxStreamDataFrame *>(frame)->maximum_stream_data() == 2048);
}
}