webrtc/net/dcsctp/packet/chunk_validators_test.cc
Victor Boivie 0b0afaa81a dcsctp: Add Chunk Validators
The SCTP RFCs aren't very strict in specifying when a chunk or parameter
is invalid, so most chunks and/or parameters must be accepted but they
may need some cleaning to avoid a lot of error handling deeper in the
chunk handling code.

Bug: webrtc:12614
Change-Id: I723f08cbdc26e1a1b78463b6137340e638089037
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/214966
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Commit-Queue: Victor Boivie <boivie@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#33788}
2021-04-20 13:37:22 +00:00

161 lines
5 KiB
C++

/*
* 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/packet/chunk_validators.h"
#include <utility>
#include "rtc_base/gunit.h"
#include "test/gmock.h"
namespace dcsctp {
namespace {
using ::testing::ElementsAre;
using ::testing::IsEmpty;
TEST(ChunkValidatorsTest, NoGapAckBlocksAreValid) {
SackChunk sack(TSN(123), /*a_rwnd=*/456,
/*gap_ack_blocks=*/{}, {});
EXPECT_TRUE(ChunkValidators::Validate(sack));
SackChunk clean = ChunkValidators::Clean(std::move(sack));
EXPECT_THAT(clean.gap_ack_blocks(), IsEmpty());
}
TEST(ChunkValidatorsTest, OneValidAckBlock) {
SackChunk sack(TSN(123), /*a_rwnd=*/456, {SackChunk::GapAckBlock(2, 3)}, {});
EXPECT_TRUE(ChunkValidators::Validate(sack));
SackChunk clean = ChunkValidators::Clean(std::move(sack));
EXPECT_THAT(clean.gap_ack_blocks(),
ElementsAre(SackChunk::GapAckBlock(2, 3)));
}
TEST(ChunkValidatorsTest, TwoValidAckBlocks) {
SackChunk sack(TSN(123), /*a_rwnd=*/456,
{SackChunk::GapAckBlock(2, 3), SackChunk::GapAckBlock(5, 6)},
{});
EXPECT_TRUE(ChunkValidators::Validate(sack));
SackChunk clean = ChunkValidators::Clean(std::move(sack));
EXPECT_THAT(
clean.gap_ack_blocks(),
ElementsAre(SackChunk::GapAckBlock(2, 3), SackChunk::GapAckBlock(5, 6)));
}
TEST(ChunkValidatorsTest, OneInvalidAckBlock) {
SackChunk sack(TSN(123), /*a_rwnd=*/456, {SackChunk::GapAckBlock(1, 2)}, {});
EXPECT_FALSE(ChunkValidators::Validate(sack));
// It's not strictly valid, but due to the renegable nature of gap ack blocks,
// the cum_ack_tsn can't simply be moved.
SackChunk clean = ChunkValidators::Clean(std::move(sack));
EXPECT_THAT(clean.gap_ack_blocks(),
ElementsAre(SackChunk::GapAckBlock(1, 2)));
}
TEST(ChunkValidatorsTest, RemovesInvalidGapAckBlockFromSack) {
SackChunk sack(TSN(123), /*a_rwnd=*/456,
{SackChunk::GapAckBlock(2, 3), SackChunk::GapAckBlock(6, 4)},
{});
EXPECT_FALSE(ChunkValidators::Validate(sack));
SackChunk clean = ChunkValidators::Clean(std::move(sack));
EXPECT_THAT(clean.gap_ack_blocks(),
ElementsAre(SackChunk::GapAckBlock(2, 3)));
}
TEST(ChunkValidatorsTest, SortsGapAckBlocksInOrder) {
SackChunk sack(TSN(123), /*a_rwnd=*/456,
{SackChunk::GapAckBlock(6, 7), SackChunk::GapAckBlock(3, 4)},
{});
EXPECT_FALSE(ChunkValidators::Validate(sack));
SackChunk clean = ChunkValidators::Clean(std::move(sack));
EXPECT_THAT(
clean.gap_ack_blocks(),
ElementsAre(SackChunk::GapAckBlock(3, 4), SackChunk::GapAckBlock(6, 7)));
}
TEST(ChunkValidatorsTest, MergesAdjacentBlocks) {
SackChunk sack(TSN(123), /*a_rwnd=*/456,
{SackChunk::GapAckBlock(3, 4), SackChunk::GapAckBlock(5, 6)},
{});
EXPECT_FALSE(ChunkValidators::Validate(sack));
SackChunk clean = ChunkValidators::Clean(std::move(sack));
EXPECT_THAT(clean.gap_ack_blocks(),
ElementsAre(SackChunk::GapAckBlock(3, 6)));
}
TEST(ChunkValidatorsTest, MergesOverlappingByOne) {
SackChunk sack(TSN(123), /*a_rwnd=*/456,
{SackChunk::GapAckBlock(3, 4), SackChunk::GapAckBlock(4, 5)},
{});
SackChunk clean = ChunkValidators::Clean(std::move(sack));
EXPECT_FALSE(ChunkValidators::Validate(sack));
EXPECT_THAT(clean.gap_ack_blocks(),
ElementsAre(SackChunk::GapAckBlock(3, 5)));
}
TEST(ChunkValidatorsTest, MergesOverlappingByMore) {
SackChunk sack(TSN(123), /*a_rwnd=*/456,
{SackChunk::GapAckBlock(3, 10), SackChunk::GapAckBlock(4, 5)},
{});
EXPECT_FALSE(ChunkValidators::Validate(sack));
SackChunk clean = ChunkValidators::Clean(std::move(sack));
EXPECT_THAT(clean.gap_ack_blocks(),
ElementsAre(SackChunk::GapAckBlock(3, 10)));
}
TEST(ChunkValidatorsTest, MergesBlocksStartingWithSameStartOffset) {
SackChunk sack(TSN(123), /*a_rwnd=*/456,
{SackChunk::GapAckBlock(3, 7), SackChunk::GapAckBlock(3, 5),
SackChunk::GapAckBlock(3, 9)},
{});
EXPECT_FALSE(ChunkValidators::Validate(sack));
SackChunk clean = ChunkValidators::Clean(std::move(sack));
EXPECT_THAT(clean.gap_ack_blocks(),
ElementsAre(SackChunk::GapAckBlock(3, 9)));
}
TEST(ChunkValidatorsTest, MergesBlocksPartiallyOverlapping) {
SackChunk sack(TSN(123), /*a_rwnd=*/456,
{SackChunk::GapAckBlock(3, 7), SackChunk::GapAckBlock(5, 9)},
{});
EXPECT_FALSE(ChunkValidators::Validate(sack));
SackChunk clean = ChunkValidators::Clean(std::move(sack));
EXPECT_THAT(clean.gap_ack_blocks(),
ElementsAre(SackChunk::GapAckBlock(3, 9)));
}
} // namespace
} // namespace dcsctp