| /** @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/QUICAckFrameCreator.h" |
| |
| TEST_CASE("QUICAckFrameManager", "[quic]") |
| { |
| QUICAckFrameManager ack_manager; |
| QUICEncryptionLevel level = QUICEncryptionLevel::INITIAL; |
| uint8_t frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; |
| |
| // Initial state |
| QUICFrame *ack_frame = ack_manager.generate_frame(frame_buf, level, UINT16_MAX, UINT16_MAX, 0, 0); |
| QUICAckFrame *frame = static_cast<QUICAckFrame *>(ack_frame); |
| CHECK(frame == nullptr); |
| |
| // One packet |
| ack_manager.update(level, 1, 1, false); |
| ack_frame = ack_manager.generate_frame(frame_buf, level, UINT16_MAX, UINT16_MAX, 0, 0); |
| frame = static_cast<QUICAckFrame *>(ack_frame); |
| CHECK(frame != nullptr); |
| CHECK(frame->ack_block_count() == 0); |
| CHECK(frame->largest_acknowledged() == 1); |
| CHECK(frame->ack_block_section()->first_ack_block() == 0); |
| ack_frame->~QUICFrame(); |
| |
| // retry |
| CHECK(ack_manager.will_generate_frame(level, 0, true, 0) == false); |
| |
| // Not sequential |
| ack_manager.update(level, 2, 1, false); |
| ack_manager.update(level, 5, 1, false); |
| ack_manager.update(level, 3, 1, false); |
| ack_manager.update(level, 4, 1, false); |
| ack_frame = ack_manager.generate_frame(frame_buf, level, UINT16_MAX, UINT16_MAX, 0, 0); |
| frame = static_cast<QUICAckFrame *>(ack_frame); |
| CHECK(frame != nullptr); |
| CHECK(frame->ack_block_count() == 0); |
| CHECK(frame->largest_acknowledged() == 5); |
| CHECK(frame->ack_block_section()->first_ack_block() == 4); |
| ack_frame->~QUICFrame(); |
| |
| // Loss |
| ack_manager.update(level, 6, 1, false); |
| ack_manager.update(level, 7, 1, false); |
| ack_manager.update(level, 10, 1, false); |
| ack_frame = ack_manager.generate_frame(frame_buf, level, UINT16_MAX, UINT16_MAX, 0, 0); |
| frame = static_cast<QUICAckFrame *>(ack_frame); |
| CHECK(frame != nullptr); |
| CHECK(frame->ack_block_count() == 1); |
| CHECK(frame->largest_acknowledged() == 10); |
| CHECK(frame->ack_block_section()->first_ack_block() == 0); |
| CHECK(frame->ack_block_section()->begin()->gap() == 1); |
| ack_frame->~QUICFrame(); |
| |
| // on frame acked |
| ack_manager.on_frame_acked(frame->id()); |
| |
| CHECK(ack_manager.will_generate_frame(level, 0, true, 0) == false); |
| ack_frame = ack_manager.generate_frame(frame_buf, level, UINT16_MAX, UINT16_MAX, 0, 0); |
| CHECK(ack_frame == nullptr); |
| |
| ack_manager.update(level, 11, 1, false); |
| ack_manager.update(level, 12, 1, false); |
| ack_manager.update(level, 13, 1, false); |
| ack_frame = ack_manager.generate_frame(frame_buf, level, UINT16_MAX, UINT16_MAX, 0, 0); |
| frame = static_cast<QUICAckFrame *>(ack_frame); |
| CHECK(frame != nullptr); |
| CHECK(frame->ack_block_count() == 0); |
| CHECK(frame->largest_acknowledged() == 13); |
| CHECK(frame->ack_block_section()->first_ack_block() == 2); |
| CHECK(frame->ack_block_section()->begin()->gap() == 0); |
| ack_frame->~QUICFrame(); |
| |
| ack_manager.on_frame_acked(frame->id()); |
| |
| // ack-only |
| ack_manager.update(level, 14, 1, true); |
| ack_manager.update(level, 15, 1, true); |
| ack_manager.update(level, 16, 1, true); |
| CHECK(ack_manager.will_generate_frame(level, 0, true, 0) == false); |
| ack_frame = ack_manager.generate_frame(frame_buf, level, UINT16_MAX, UINT16_MAX, 0, 0); |
| |
| ack_manager.update(level, 17, 1, false); |
| ack_frame = ack_manager.generate_frame(frame_buf, level, UINT16_MAX, UINT16_MAX, 0, 0); |
| frame = static_cast<QUICAckFrame *>(ack_frame); |
| CHECK(frame != nullptr); |
| CHECK(frame->ack_block_count() == 0); |
| CHECK(frame->largest_acknowledged() == 17); |
| CHECK(frame->ack_block_section()->first_ack_block() == 3); |
| CHECK(frame->ack_block_section()->begin()->gap() == 0); |
| ack_frame->~QUICFrame(); |
| } |
| |
| TEST_CASE("QUICAckFrameManager should send", "[quic]") |
| { |
| SECTION("QUIC unorder packet", "[quic]") |
| { |
| QUICAckFrameManager ack_manager; |
| |
| QUICEncryptionLevel level = QUICEncryptionLevel::ONE_RTT; |
| ack_manager.update(level, 2, 1, false); |
| CHECK(ack_manager.will_generate_frame(level, 0, true, 0) == true); |
| } |
| |
| SECTION("QUIC delay ack and unorder packet", "[quic]") |
| { |
| QUICAckFrameManager ack_manager; |
| |
| QUICEncryptionLevel level = QUICEncryptionLevel::ONE_RTT; |
| ack_manager.update(level, 0, 1, false); |
| CHECK(ack_manager.will_generate_frame(level, 0, true, 0) == false); |
| |
| ack_manager.update(level, 1, 1, false); |
| CHECK(ack_manager.will_generate_frame(level, 0, true, 0) == false); |
| |
| ack_manager.update(level, 3, 1, false); |
| CHECK(ack_manager.will_generate_frame(level, 0, true, 0) == true); |
| } |
| |
| SECTION("QUIC delay too much time", "[quic]") |
| { |
| Thread::get_hrtime_updated(); |
| QUICAckFrameManager ack_manager; |
| |
| QUICEncryptionLevel level = QUICEncryptionLevel::ONE_RTT; |
| ack_manager.update(level, 0, 1, false); |
| CHECK(ack_manager.will_generate_frame(level, 0, true, 0) == false); |
| |
| sleep(1); |
| Thread::get_hrtime_updated(); |
| ack_manager.update(level, 1, 1, false); |
| CHECK(ack_manager.will_generate_frame(level, 0, true, 0) == true); |
| } |
| |
| SECTION("QUIC intial packet", "[quic]") |
| { |
| QUICAckFrameManager ack_manager; |
| |
| QUICEncryptionLevel level = QUICEncryptionLevel::INITIAL; |
| ack_manager.update(level, 0, 1, false); |
| CHECK(ack_manager.will_generate_frame(level, 0, true, 0) == true); |
| } |
| |
| SECTION("QUIC handshake packet", "[quic]") |
| { |
| QUICAckFrameManager ack_manager; |
| |
| QUICEncryptionLevel level = QUICEncryptionLevel::HANDSHAKE; |
| ack_manager.update(level, 0, 1, false); |
| CHECK(ack_manager.will_generate_frame(level, 0, true, 0) == true); |
| } |
| |
| SECTION("QUIC frame fired", "[quic]") |
| { |
| QUICAckFrameManager ack_manager; |
| QUICEncryptionLevel level = QUICEncryptionLevel::ONE_RTT; |
| |
| ack_manager.update(level, 0, 1, false); |
| CHECK(ack_manager.will_generate_frame(level, 0, true, 0) == false); |
| |
| sleep(1); |
| Thread::get_hrtime_updated(); |
| CHECK(ack_manager.will_generate_frame(level, 0, true, 0) == true); |
| } |
| |
| SECTION("QUIC refresh frame", "[quic]") |
| { |
| QUICAckFrameManager ack_manager; |
| QUICEncryptionLevel level = QUICEncryptionLevel::ONE_RTT; |
| |
| uint8_t frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; |
| QUICFrame *ack_frame = ack_manager.generate_frame(frame_buf, level, UINT16_MAX, UINT16_MAX, 0, 0); |
| QUICAckFrame *frame = static_cast<QUICAckFrame *>(ack_frame); |
| CHECK(frame == nullptr); |
| |
| // unorder frame should sent immediately |
| ack_manager.update(level, 1, 1, false); |
| CHECK(ack_manager.will_generate_frame(level, 0, true, 0) == true); |
| |
| ack_manager.update(level, 2, 1, false); |
| |
| // Delay due to some reason, the frame is not valued any more, but still valued |
| sleep(1); |
| Thread::get_hrtime_updated(); |
| CHECK(ack_manager.will_generate_frame(level, 0, true, 0) == true); |
| ack_frame = ack_manager.generate_frame(frame_buf, level, UINT16_MAX, UINT16_MAX, 0, 0); |
| frame = static_cast<QUICAckFrame *>(ack_frame); |
| |
| CHECK(frame->ack_block_count() == 0); |
| CHECK(frame->largest_acknowledged() == 2); |
| CHECK(frame->ack_block_section()->first_ack_block() == 1); |
| CHECK(frame->ack_block_section()->begin()->gap() == 0); |
| ack_frame->~QUICFrame(); |
| } |
| } |
| |
| TEST_CASE("QUICAckFrameManager_loss_recover", "[quic]") |
| { |
| QUICAckFrameManager ack_manager; |
| QUICEncryptionLevel level = QUICEncryptionLevel::INITIAL; |
| |
| // Initial state |
| uint8_t frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; |
| QUICFrame *ack_frame = ack_manager.generate_frame(frame_buf, level, UINT16_MAX, UINT16_MAX, 0, 0); |
| QUICAckFrame *frame = static_cast<QUICAckFrame *>(ack_frame); |
| CHECK(frame == nullptr); |
| |
| ack_manager.update(level, 2, 1, false); |
| ack_manager.update(level, 5, 1, false); |
| ack_manager.update(level, 6, 1, false); |
| ack_manager.update(level, 8, 1, false); |
| ack_manager.update(level, 9, 1, false); |
| |
| ack_frame = ack_manager.generate_frame(frame_buf, level, UINT16_MAX, UINT16_MAX, 0, 0); |
| frame = static_cast<QUICAckFrame *>(ack_frame); |
| CHECK(frame != nullptr); |
| CHECK(frame->ack_block_count() == 2); |
| CHECK(frame->largest_acknowledged() == 9); |
| CHECK(frame->ack_block_section()->first_ack_block() == 1); |
| CHECK(frame->ack_block_section()->begin()->gap() == 0); |
| ack_frame->~QUICFrame(); |
| |
| CHECK(ack_manager.will_generate_frame(level, 0, true, 0) == false); |
| |
| ack_manager.update(level, 7, 1, false); |
| ack_manager.update(level, 4, 1, false); |
| ack_frame = ack_manager.generate_frame(frame_buf, level, UINT16_MAX, UINT16_MAX, 0, 0); |
| frame = static_cast<QUICAckFrame *>(ack_frame); |
| CHECK(frame != nullptr); |
| CHECK(frame->ack_block_count() == 1); |
| CHECK(frame->largest_acknowledged() == 9); |
| CHECK(frame->ack_block_section()->first_ack_block() == 5); |
| CHECK(frame->ack_block_section()->begin()->gap() == 0); |
| ack_frame->~QUICFrame(); |
| } |
| |
| TEST_CASE("QUICAckFrameManager_QUICAckFrameCreator", "[quic]") |
| { |
| QUICAckFrameManager ack_manager; |
| QUICAckFrameManager::QUICAckFrameCreator packet_numbers(QUICPacketNumberSpace::Initial, &ack_manager); |
| |
| CHECK(packet_numbers.size() == 0); |
| CHECK(packet_numbers.largest_ack_number() == 0); |
| CHECK(packet_numbers.largest_ack_received_time() == 0); |
| |
| Thread::get_hrtime_updated(); |
| |
| packet_numbers.push_back(3, 2, false); |
| CHECK(packet_numbers.size() == 1); |
| CHECK(packet_numbers.largest_ack_number() == 3); |
| |
| ink_hrtime ti = packet_numbers.largest_ack_received_time(); |
| CHECK(packet_numbers.largest_ack_received_time() != 0); |
| |
| Thread::get_hrtime_updated(); |
| |
| packet_numbers.push_back(2, 2, false); |
| CHECK(packet_numbers.size() == 2); |
| CHECK(packet_numbers.largest_ack_number() == 3); |
| CHECK(packet_numbers.largest_ack_received_time() == ti); |
| |
| Thread::get_hrtime_updated(); |
| |
| packet_numbers.push_back(10, 2, false); |
| CHECK(packet_numbers.size() == 3); |
| CHECK(packet_numbers.largest_ack_number() == 10); |
| CHECK(packet_numbers.largest_ack_received_time() > ti); |
| |
| Thread::get_hrtime_updated(); |
| |
| packet_numbers.clear(); |
| CHECK(packet_numbers.size() == 0); |
| CHECK(packet_numbers.largest_ack_number() == 0); |
| CHECK(packet_numbers.largest_ack_received_time() == 0); |
| } |
| |
| TEST_CASE("QUICAckFrameManager lost_frame", "[quic]") |
| { |
| QUICAckFrameManager ack_manager; |
| QUICEncryptionLevel level = QUICEncryptionLevel::INITIAL; |
| uint8_t frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; |
| |
| // Initial state |
| QUICFrame *ack_frame = ack_manager.generate_frame(frame_buf, level, UINT16_MAX, UINT16_MAX, 0, 0); |
| QUICAckFrame *frame = static_cast<QUICAckFrame *>(ack_frame); |
| CHECK(frame == nullptr); |
| |
| ack_manager.update(level, 2, 1, false); |
| ack_manager.update(level, 5, 1, false); |
| ack_manager.update(level, 6, 1, false); |
| ack_manager.update(level, 8, 1, false); |
| ack_manager.update(level, 9, 1, false); |
| |
| ack_frame = ack_manager.generate_frame(frame_buf, level, UINT16_MAX, UINT16_MAX, 0, 0); |
| frame = static_cast<QUICAckFrame *>(ack_frame); |
| CHECK(frame != nullptr); |
| CHECK(frame->ack_block_count() == 2); |
| CHECK(frame->largest_acknowledged() == 9); |
| CHECK(frame->ack_block_section()->first_ack_block() == 1); |
| CHECK(frame->ack_block_section()->begin()->gap() == 0); |
| ack_frame->~QUICFrame(); |
| |
| ack_manager.on_frame_lost(frame->id()); |
| CHECK(ack_manager.will_generate_frame(level, 0, true, 0) == true); |
| ack_frame = ack_manager.generate_frame(frame_buf, level, UINT16_MAX, UINT16_MAX, 0, 0); |
| frame = static_cast<QUICAckFrame *>(ack_frame); |
| CHECK(frame != nullptr); |
| CHECK(frame->ack_block_count() == 2); |
| CHECK(frame->largest_acknowledged() == 9); |
| CHECK(frame->ack_block_section()->first_ack_block() == 1); |
| CHECK(frame->ack_block_section()->begin()->gap() == 0); |
| ack_frame->~QUICFrame(); |
| |
| CHECK(ack_manager.will_generate_frame(level, 0, true, 0) == false); |
| ack_manager.on_frame_lost(frame->id()); |
| CHECK(ack_manager.will_generate_frame(level, 0, true, 0) == true); |
| ack_manager.update(level, 7, 1, false); |
| ack_manager.update(level, 4, 1, false); |
| |
| ack_frame = ack_manager.generate_frame(frame_buf, level, UINT16_MAX, UINT16_MAX, 0, 0); |
| frame = static_cast<QUICAckFrame *>(ack_frame); |
| CHECK(frame != nullptr); |
| CHECK(frame->ack_block_count() == 1); |
| CHECK(frame->largest_acknowledged() == 9); |
| CHECK(frame->ack_block_section()->first_ack_block() == 5); |
| CHECK(frame->ack_block_section()->begin()->gap() == 0); |
| ack_frame->~QUICFrame(); |
| |
| CHECK(ack_manager.will_generate_frame(level, 0, true, 0) == false); |
| } |
| |
| TEST_CASE("QUICAckFrameManager ack only packet", "[quic]") |
| { |
| SECTION("INITIAL") |
| { |
| QUICAckFrameManager ack_manager; |
| QUICEncryptionLevel level = QUICEncryptionLevel::INITIAL; |
| uint8_t frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; |
| |
| // Initial state |
| QUICFrame *ack_frame = ack_manager.generate_frame(frame_buf, level, UINT16_MAX, UINT16_MAX, 0, 0); |
| QUICAckFrame *frame = static_cast<QUICAckFrame *>(ack_frame); |
| CHECK(frame == nullptr); |
| |
| ack_manager.update(level, 1, 1, false); |
| ack_manager.update(level, 2, 1, false); |
| ack_manager.update(level, 3, 1, false); |
| ack_manager.update(level, 4, 1, false); |
| ack_manager.update(level, 5, 1, false); |
| |
| CHECK(ack_manager.will_generate_frame(level, 0, true, 0) == true); |
| |
| ack_frame = ack_manager.generate_frame(frame_buf, level, UINT16_MAX, UINT16_MAX, 0, 0); |
| frame = static_cast<QUICAckFrame *>(ack_frame); |
| CHECK(frame != nullptr); |
| CHECK(frame->ack_block_count() == 0); |
| CHECK(frame->largest_acknowledged() == 5); |
| CHECK(frame->ack_block_section()->first_ack_block() == 4); |
| CHECK(frame->ack_block_section()->begin()->gap() == 0); |
| ack_frame->~QUICFrame(); |
| |
| ack_manager.update(level, 6, 1, true); |
| ack_manager.update(level, 7, 1, true); |
| CHECK(ack_manager.will_generate_frame(level, 0, true, 0) == false); |
| } |
| |
| SECTION("ONE_RTT") |
| { |
| QUICAckFrameManager ack_manager; |
| QUICEncryptionLevel level = QUICEncryptionLevel::ONE_RTT; |
| uint8_t frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; |
| |
| // Initial state |
| QUICFrame *ack_frame = ack_manager.generate_frame(frame_buf, level, UINT16_MAX, UINT16_MAX, 0, 0); |
| QUICAckFrame *frame = static_cast<QUICAckFrame *>(ack_frame); |
| CHECK(frame == nullptr); |
| |
| ack_manager.update(level, 1, 1, false); |
| ack_manager.update(level, 2, 1, false); |
| ack_manager.update(level, 3, 1, false); |
| ack_manager.update(level, 4, 1, false); |
| ack_manager.update(level, 5, 1, false); |
| |
| CHECK(ack_manager.will_generate_frame(level, 0, true, 0) == true); |
| |
| ack_frame = ack_manager.generate_frame(frame_buf, level, UINT16_MAX, UINT16_MAX, 0, 0); |
| frame = static_cast<QUICAckFrame *>(ack_frame); |
| CHECK(frame != nullptr); |
| CHECK(frame->ack_block_count() == 0); |
| CHECK(frame->largest_acknowledged() == 5); |
| CHECK(frame->ack_block_section()->first_ack_block() == 4); |
| CHECK(frame->ack_block_section()->begin()->gap() == 0); |
| ack_frame->~QUICFrame(); |
| |
| ack_manager.update(level, 6, 1, true); |
| ack_manager.update(level, 7, 1, true); |
| CHECK(ack_manager.will_generate_frame(level, 0, true, 0) == false); |
| } |
| } |