/* * Copyright (c) 2021 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "net/dcsctp/rx/data_tracker.h" #include #include #include #include "absl/types/optional.h" #include "api/array_view.h" #include "net/dcsctp/packet/chunk/sack_chunk.h" #include "net/dcsctp/timer/fake_timeout.h" #include "net/dcsctp/timer/timer.h" #include "rtc_base/gunit.h" #include "test/gmock.h" namespace dcsctp { namespace { using ::testing::ElementsAre; using ::testing::IsEmpty; constexpr size_t kArwnd = 10000; constexpr TSN kInitialTSN(11); class DataTrackerTest : public testing::Test { protected: DataTrackerTest() : timeout_manager_([this]() { return now_; }), timer_manager_([this]() { return timeout_manager_.CreateTimeout(); }), timer_(timer_manager_.CreateTimer( "test/delayed_ack", []() { return absl::nullopt; }, TimerOptions(DurationMs(0)))), buf_("log: ", timer_.get(), kInitialTSN) {} void Observer(std::initializer_list tsns) { for (const uint32_t tsn : tsns) { buf_.Observe(TSN(tsn), AnyDataChunk::ImmediateAckFlag(false)); } } TimeMs now_ = TimeMs(0); FakeTimeoutManager timeout_manager_; TimerManager timer_manager_; std::unique_ptr timer_; DataTracker buf_; }; TEST_F(DataTrackerTest, Empty) { SackChunk sack = buf_.CreateSelectiveAck(kArwnd); EXPECT_EQ(sack.cumulative_tsn_ack(), TSN(10)); EXPECT_THAT(sack.gap_ack_blocks(), IsEmpty()); EXPECT_THAT(sack.duplicate_tsns(), IsEmpty()); } TEST_F(DataTrackerTest, ObserverSingleInOrderPacket) { Observer({11}); SackChunk sack = buf_.CreateSelectiveAck(kArwnd); EXPECT_EQ(sack.cumulative_tsn_ack(), TSN(11)); EXPECT_THAT(sack.gap_ack_blocks(), IsEmpty()); EXPECT_THAT(sack.duplicate_tsns(), IsEmpty()); } TEST_F(DataTrackerTest, ObserverManyInOrderMovesCumulativeTsnAck) { Observer({11, 12, 13}); SackChunk sack = buf_.CreateSelectiveAck(kArwnd); EXPECT_EQ(sack.cumulative_tsn_ack(), TSN(13)); EXPECT_THAT(sack.gap_ack_blocks(), IsEmpty()); EXPECT_THAT(sack.duplicate_tsns(), IsEmpty()); } TEST_F(DataTrackerTest, ObserveOutOfOrderMovesCumulativeTsnAck) { Observer({12, 13, 14, 11}); SackChunk sack = buf_.CreateSelectiveAck(kArwnd); EXPECT_EQ(sack.cumulative_tsn_ack(), TSN(14)); EXPECT_THAT(sack.gap_ack_blocks(), IsEmpty()); EXPECT_THAT(sack.duplicate_tsns(), IsEmpty()); } TEST_F(DataTrackerTest, SingleGap) { Observer({12}); SackChunk sack = buf_.CreateSelectiveAck(kArwnd); EXPECT_EQ(sack.cumulative_tsn_ack(), TSN(10)); EXPECT_THAT(sack.gap_ack_blocks(), ElementsAre(SackChunk::GapAckBlock(2, 2))); EXPECT_THAT(sack.duplicate_tsns(), IsEmpty()); } TEST_F(DataTrackerTest, ExampleFromRFC4960Section334) { Observer({11, 12, 14, 15, 17}); SackChunk sack = buf_.CreateSelectiveAck(kArwnd); EXPECT_EQ(sack.cumulative_tsn_ack(), TSN(12)); EXPECT_THAT(sack.gap_ack_blocks(), ElementsAre(SackChunk::GapAckBlock(2, 3), SackChunk::GapAckBlock(5, 5))); EXPECT_THAT(sack.duplicate_tsns(), IsEmpty()); } TEST_F(DataTrackerTest, AckAlreadyReceivedChunk) { Observer({11}); SackChunk sack1 = buf_.CreateSelectiveAck(kArwnd); EXPECT_EQ(sack1.cumulative_tsn_ack(), TSN(11)); EXPECT_THAT(sack1.gap_ack_blocks(), IsEmpty()); // Receive old chunk Observer({8}); SackChunk sack2 = buf_.CreateSelectiveAck(kArwnd); EXPECT_EQ(sack2.cumulative_tsn_ack(), TSN(11)); EXPECT_THAT(sack2.gap_ack_blocks(), IsEmpty()); } TEST_F(DataTrackerTest, DoubleSendRetransmittedChunk) { Observer({11, 13, 14, 15}); SackChunk sack1 = buf_.CreateSelectiveAck(kArwnd); EXPECT_EQ(sack1.cumulative_tsn_ack(), TSN(11)); EXPECT_THAT(sack1.gap_ack_blocks(), ElementsAre(SackChunk::GapAckBlock(2, 4))); // Fill in the hole. Observer({12, 16, 17, 18}); SackChunk sack2 = buf_.CreateSelectiveAck(kArwnd); EXPECT_EQ(sack2.cumulative_tsn_ack(), TSN(18)); EXPECT_THAT(sack2.gap_ack_blocks(), IsEmpty()); // Receive chunk 12 again. Observer({12, 19, 20, 21}); SackChunk sack3 = buf_.CreateSelectiveAck(kArwnd); EXPECT_EQ(sack3.cumulative_tsn_ack(), TSN(21)); EXPECT_THAT(sack3.gap_ack_blocks(), IsEmpty()); } TEST_F(DataTrackerTest, ForwardTsnSimple) { // Messages (11, 12, 13), (14, 15) - first message expires. Observer({11, 12, 15}); buf_.HandleForwardTsn(TSN(13)); SackChunk sack = buf_.CreateSelectiveAck(kArwnd); EXPECT_EQ(sack.cumulative_tsn_ack(), TSN(13)); EXPECT_THAT(sack.gap_ack_blocks(), ElementsAre(SackChunk::GapAckBlock(2, 2))); } TEST_F(DataTrackerTest, ForwardTsnSkipsFromGapBlock) { // Messages (11, 12, 13), (14, 15) - first message expires. Observer({11, 12, 14}); buf_.HandleForwardTsn(TSN(13)); SackChunk sack = buf_.CreateSelectiveAck(kArwnd); EXPECT_EQ(sack.cumulative_tsn_ack(), TSN(14)); EXPECT_THAT(sack.gap_ack_blocks(), IsEmpty()); } TEST_F(DataTrackerTest, ExampleFromRFC3758) { buf_.HandleForwardTsn(TSN(102)); Observer({102, 104, 105, 107}); buf_.HandleForwardTsn(TSN(103)); SackChunk sack = buf_.CreateSelectiveAck(kArwnd); EXPECT_EQ(sack.cumulative_tsn_ack(), TSN(105)); EXPECT_THAT(sack.gap_ack_blocks(), ElementsAre(SackChunk::GapAckBlock(2, 2))); } TEST_F(DataTrackerTest, EmptyAllAcks) { Observer({11, 13, 14, 15}); buf_.HandleForwardTsn(TSN(100)); SackChunk sack = buf_.CreateSelectiveAck(kArwnd); EXPECT_EQ(sack.cumulative_tsn_ack(), TSN(100)); EXPECT_THAT(sack.gap_ack_blocks(), IsEmpty()); } TEST_F(DataTrackerTest, SetsArwndCorrectly) { SackChunk sack1 = buf_.CreateSelectiveAck(/*a_rwnd=*/100); EXPECT_EQ(sack1.a_rwnd(), 100u); SackChunk sack2 = buf_.CreateSelectiveAck(/*a_rwnd=*/101); EXPECT_EQ(sack2.a_rwnd(), 101u); } TEST_F(DataTrackerTest, WillIncreaseCumAckTsn) { EXPECT_EQ(buf_.last_cumulative_acked_tsn(), TSN(10)); EXPECT_FALSE(buf_.will_increase_cum_ack_tsn(TSN(10))); EXPECT_TRUE(buf_.will_increase_cum_ack_tsn(TSN(11))); EXPECT_FALSE(buf_.will_increase_cum_ack_tsn(TSN(12))); Observer({11, 12, 13, 14, 15}); EXPECT_EQ(buf_.last_cumulative_acked_tsn(), TSN(15)); EXPECT_FALSE(buf_.will_increase_cum_ack_tsn(TSN(15))); EXPECT_TRUE(buf_.will_increase_cum_ack_tsn(TSN(16))); EXPECT_FALSE(buf_.will_increase_cum_ack_tsn(TSN(17))); } TEST_F(DataTrackerTest, ForceShouldSendSackImmediately) { EXPECT_FALSE(buf_.ShouldSendAck()); buf_.ForceImmediateSack(); EXPECT_TRUE(buf_.ShouldSendAck()); } TEST_F(DataTrackerTest, WillAcceptValidTSNs) { // The initial TSN is always one more than the last, which is our base. TSN last_tsn = TSN(*kInitialTSN - 1); int limit = static_cast(DataTracker::kMaxAcceptedOutstandingFragments); for (int i = -limit; i <= limit; ++i) { EXPECT_TRUE(buf_.IsTSNValid(TSN(*last_tsn + i))); } } TEST_F(DataTrackerTest, WillNotAcceptInvalidTSNs) { // The initial TSN is always one more than the last, which is our base. TSN last_tsn = TSN(*kInitialTSN - 1); size_t limit = DataTracker::kMaxAcceptedOutstandingFragments; EXPECT_FALSE(buf_.IsTSNValid(TSN(*last_tsn + limit + 1))); EXPECT_FALSE(buf_.IsTSNValid(TSN(*last_tsn - (limit + 1)))); EXPECT_FALSE(buf_.IsTSNValid(TSN(*last_tsn + 65536))); EXPECT_FALSE(buf_.IsTSNValid(TSN(*last_tsn - 65536))); EXPECT_FALSE(buf_.IsTSNValid(TSN(*last_tsn + 0x8000000))); EXPECT_FALSE(buf_.IsTSNValid(TSN(*last_tsn - 0x8000000))); } } // namespace } // namespace dcsctp