2021-04-03 20:33:43 +02:00
|
|
|
/*
|
|
|
|
|
* 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/reassembly_queue.h"
|
|
|
|
|
|
|
|
|
|
#include <stddef.h>
|
|
|
|
|
|
|
|
|
|
#include <algorithm>
|
|
|
|
|
#include <array>
|
|
|
|
|
#include <cstdint>
|
|
|
|
|
#include <iterator>
|
|
|
|
|
#include <vector>
|
|
|
|
|
|
|
|
|
|
#include "api/array_view.h"
|
2021-09-20 11:35:59 +02:00
|
|
|
#include "net/dcsctp/common/handover_testing.h"
|
2021-04-03 20:33:43 +02:00
|
|
|
#include "net/dcsctp/packet/chunk/forward_tsn_chunk.h"
|
|
|
|
|
#include "net/dcsctp/packet/chunk/forward_tsn_common.h"
|
|
|
|
|
#include "net/dcsctp/packet/chunk/iforward_tsn_chunk.h"
|
|
|
|
|
#include "net/dcsctp/packet/data.h"
|
|
|
|
|
#include "net/dcsctp/public/dcsctp_message.h"
|
|
|
|
|
#include "net/dcsctp/public/types.h"
|
|
|
|
|
#include "net/dcsctp/testing/data_generator.h"
|
|
|
|
|
#include "rtc_base/gunit.h"
|
|
|
|
|
#include "test/gmock.h"
|
|
|
|
|
|
|
|
|
|
namespace dcsctp {
|
|
|
|
|
namespace {
|
|
|
|
|
using ::testing::ElementsAre;
|
2021-09-15 11:59:17 +02:00
|
|
|
using ::testing::SizeIs;
|
2021-05-11 22:54:16 +02:00
|
|
|
using ::testing::UnorderedElementsAre;
|
dcsctp: Reset synchronously with incoming request
When a sender has requested a stream to be reset, and the last sender
assigned TSN hasn't been received yet, the receiver will enter deferred
reset mode, where it will store any data chunks received after that
given TSN, and replay those later, when the stream has been reset.
Before this CL, leaving deferred mode was done as soon as the sender's
last assigned TSN was received. That's actually not how the RFC
describes the process[1], but was done that way to properly handle some
sequences of RE-CONFIG and FORWARD-TSN. But after having read the RFCs
again, and realizing that whenever RFC6525 mention "any data arriving",
this also applies to any FORWARD-TSN[2] - it's better to reset streams
synchronously with the incoming requests, and defer not just DATA past
the sender last assigned TSN, but also any FORWARD-TSN after that TSN.
This mostly simplifies the code and is mostly a refactoring, but most
importantly aligns it with how the resetting procedure is explained in
the RFC. It also fixes two bugs:
* It defers FORWARD-TSN *as well as* DATA chunks with a TSN later
than the sender's last assigned TSN - see test case. The old
implementation tried to handle that by exiting the deferred reset
processing as soon as it reached the sender's last assigned TSN, but
it didn't manage to do that in all cases.
* It only defers DATA chunks for streams that are to be reset, not
all DATA chunks with a TSN > sender's last assigned TSN. This was
missed in the old implementation, but as it's now implemented
strictly according to the RFC, this was now done.
[1] https://datatracker.ietf.org/doc/html/rfc6525#section-5.2.2
[2] RFC6525 cover stream resetting, and RFC3758 cover FORWARD-TSN, and
the combination of these is not covered in the RFCs.
Bug: webrtc:14600
Change-Id: Ief878b755291b9c923aa6fb4317b0f5c00231df4
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/322623
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Commit-Queue: Victor Boivie <boivie@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#40889}
2023-09-27 18:01:18 +02:00
|
|
|
using SkippedStream = AnyForwardTsnChunk::SkippedStream;
|
2021-04-03 20:33:43 +02:00
|
|
|
|
|
|
|
|
// The default maximum size of the Reassembly Queue.
|
|
|
|
|
static constexpr size_t kBufferSize = 10000;
|
|
|
|
|
|
|
|
|
|
static constexpr StreamID kStreamID(1);
|
|
|
|
|
static constexpr SSN kSSN(0);
|
|
|
|
|
static constexpr MID kMID(0);
|
|
|
|
|
static constexpr FSN kFSN(0);
|
|
|
|
|
static constexpr PPID kPPID(53);
|
|
|
|
|
|
|
|
|
|
static constexpr std::array<uint8_t, 4> kShortPayload = {1, 2, 3, 4};
|
|
|
|
|
static constexpr std::array<uint8_t, 4> kMessage2Payload = {5, 6, 7, 8};
|
2021-05-11 22:54:16 +02:00
|
|
|
static constexpr std::array<uint8_t, 6> kSixBytePayload = {1, 2, 3, 4, 5, 6};
|
|
|
|
|
static constexpr std::array<uint8_t, 8> kMediumPayload1 = {1, 2, 3, 4,
|
|
|
|
|
5, 6, 7, 8};
|
|
|
|
|
static constexpr std::array<uint8_t, 8> kMediumPayload2 = {9, 10, 11, 12,
|
|
|
|
|
13, 14, 15, 16};
|
2021-04-03 20:33:43 +02:00
|
|
|
static constexpr std::array<uint8_t, 16> kLongPayload = {
|
|
|
|
|
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
|
|
|
|
|
|
|
|
|
|
MATCHER_P3(SctpMessageIs, stream_id, ppid, expected_payload, "") {
|
|
|
|
|
if (arg.stream_id() != stream_id) {
|
|
|
|
|
*result_listener << "the stream_id is " << *arg.stream_id();
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (arg.ppid() != ppid) {
|
|
|
|
|
*result_listener << "the ppid is " << *arg.ppid();
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (std::vector<uint8_t>(arg.payload().begin(), arg.payload().end()) !=
|
|
|
|
|
std::vector<uint8_t>(expected_payload.begin(), expected_payload.end())) {
|
|
|
|
|
*result_listener << "the payload is wrong";
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class ReassemblyQueueTest : public testing::Test {
|
|
|
|
|
protected:
|
|
|
|
|
ReassemblyQueueTest() {}
|
|
|
|
|
DataGenerator gen_;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
TEST_F(ReassemblyQueueTest, EmptyQueue) {
|
2024-04-04 12:57:24 +02:00
|
|
|
ReassemblyQueue reasm("log: ", kBufferSize);
|
2021-04-03 20:33:43 +02:00
|
|
|
EXPECT_FALSE(reasm.HasMessages());
|
|
|
|
|
EXPECT_EQ(reasm.queued_bytes(), 0u);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(ReassemblyQueueTest, SingleUnorderedChunkMessage) {
|
2024-04-04 12:57:24 +02:00
|
|
|
ReassemblyQueue reasm("log: ", kBufferSize);
|
2021-04-03 20:33:43 +02:00
|
|
|
reasm.Add(TSN(10), gen_.Unordered({1, 2, 3, 4}, "BE"));
|
|
|
|
|
EXPECT_TRUE(reasm.HasMessages());
|
|
|
|
|
EXPECT_THAT(reasm.FlushMessages(),
|
|
|
|
|
ElementsAre(SctpMessageIs(kStreamID, kPPID, kShortPayload)));
|
|
|
|
|
EXPECT_EQ(reasm.queued_bytes(), 0u);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(ReassemblyQueueTest, LargeUnorderedChunkAllPermutations) {
|
|
|
|
|
std::vector<uint32_t> tsns = {10, 11, 12, 13};
|
|
|
|
|
rtc::ArrayView<const uint8_t> payload(kLongPayload);
|
|
|
|
|
do {
|
2024-04-04 12:57:24 +02:00
|
|
|
ReassemblyQueue reasm("log: ", kBufferSize);
|
2021-04-03 20:33:43 +02:00
|
|
|
|
|
|
|
|
for (size_t i = 0; i < tsns.size(); i++) {
|
|
|
|
|
auto span = payload.subview((tsns[i] - 10) * 4, 4);
|
|
|
|
|
Data::IsBeginning is_beginning(tsns[i] == 10);
|
|
|
|
|
Data::IsEnd is_end(tsns[i] == 13);
|
|
|
|
|
|
2021-12-01 18:57:22 +00:00
|
|
|
reasm.Add(TSN(tsns[i]),
|
|
|
|
|
Data(kStreamID, kSSN, kMID, kFSN, kPPID,
|
|
|
|
|
std::vector<uint8_t>(span.begin(), span.end()),
|
|
|
|
|
is_beginning, is_end, IsUnordered(false)));
|
2021-04-03 20:33:43 +02:00
|
|
|
if (i < 3) {
|
|
|
|
|
EXPECT_FALSE(reasm.HasMessages());
|
|
|
|
|
} else {
|
|
|
|
|
EXPECT_TRUE(reasm.HasMessages());
|
|
|
|
|
EXPECT_THAT(reasm.FlushMessages(),
|
|
|
|
|
ElementsAre(SctpMessageIs(kStreamID, kPPID, kLongPayload)));
|
|
|
|
|
EXPECT_EQ(reasm.queued_bytes(), 0u);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} while (std::next_permutation(std::begin(tsns), std::end(tsns)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(ReassemblyQueueTest, SingleOrderedChunkMessage) {
|
2024-04-04 12:57:24 +02:00
|
|
|
ReassemblyQueue reasm("log: ", kBufferSize);
|
2021-04-03 20:33:43 +02:00
|
|
|
reasm.Add(TSN(10), gen_.Ordered({1, 2, 3, 4}, "BE"));
|
|
|
|
|
EXPECT_EQ(reasm.queued_bytes(), 0u);
|
|
|
|
|
EXPECT_TRUE(reasm.HasMessages());
|
|
|
|
|
EXPECT_THAT(reasm.FlushMessages(),
|
|
|
|
|
ElementsAre(SctpMessageIs(kStreamID, kPPID, kShortPayload)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(ReassemblyQueueTest, ManySmallOrderedMessages) {
|
|
|
|
|
std::vector<uint32_t> tsns = {10, 11, 12, 13};
|
|
|
|
|
rtc::ArrayView<const uint8_t> payload(kLongPayload);
|
|
|
|
|
do {
|
2024-04-04 12:57:24 +02:00
|
|
|
ReassemblyQueue reasm("log: ", kBufferSize);
|
2021-04-03 20:33:43 +02:00
|
|
|
for (size_t i = 0; i < tsns.size(); i++) {
|
|
|
|
|
auto span = payload.subview((tsns[i] - 10) * 4, 4);
|
|
|
|
|
Data::IsBeginning is_beginning(true);
|
|
|
|
|
Data::IsEnd is_end(true);
|
|
|
|
|
|
|
|
|
|
SSN ssn(static_cast<uint16_t>(tsns[i] - 10));
|
2021-12-01 18:57:22 +00:00
|
|
|
reasm.Add(TSN(tsns[i]),
|
|
|
|
|
Data(kStreamID, ssn, kMID, kFSN, kPPID,
|
|
|
|
|
std::vector<uint8_t>(span.begin(), span.end()),
|
|
|
|
|
is_beginning, is_end, IsUnordered(false)));
|
2021-04-03 20:33:43 +02:00
|
|
|
}
|
|
|
|
|
EXPECT_THAT(
|
|
|
|
|
reasm.FlushMessages(),
|
|
|
|
|
ElementsAre(SctpMessageIs(kStreamID, kPPID, payload.subview(0, 4)),
|
|
|
|
|
SctpMessageIs(kStreamID, kPPID, payload.subview(4, 4)),
|
|
|
|
|
SctpMessageIs(kStreamID, kPPID, payload.subview(8, 4)),
|
|
|
|
|
SctpMessageIs(kStreamID, kPPID, payload.subview(12, 4))));
|
|
|
|
|
EXPECT_EQ(reasm.queued_bytes(), 0u);
|
|
|
|
|
} while (std::next_permutation(std::begin(tsns), std::end(tsns)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(ReassemblyQueueTest, RetransmissionInLargeOrdered) {
|
2024-04-04 12:57:24 +02:00
|
|
|
ReassemblyQueue reasm("log: ", kBufferSize);
|
2021-04-03 20:33:43 +02:00
|
|
|
reasm.Add(TSN(10), gen_.Ordered({1}, "B"));
|
|
|
|
|
reasm.Add(TSN(12), gen_.Ordered({3}));
|
|
|
|
|
reasm.Add(TSN(13), gen_.Ordered({4}));
|
|
|
|
|
reasm.Add(TSN(14), gen_.Ordered({5}));
|
|
|
|
|
reasm.Add(TSN(15), gen_.Ordered({6}));
|
|
|
|
|
reasm.Add(TSN(16), gen_.Ordered({7}));
|
|
|
|
|
reasm.Add(TSN(17), gen_.Ordered({8}));
|
|
|
|
|
EXPECT_EQ(reasm.queued_bytes(), 7u);
|
|
|
|
|
|
|
|
|
|
// lost and retransmitted
|
|
|
|
|
reasm.Add(TSN(11), gen_.Ordered({2}));
|
|
|
|
|
reasm.Add(TSN(18), gen_.Ordered({9}));
|
|
|
|
|
reasm.Add(TSN(19), gen_.Ordered({10}));
|
|
|
|
|
EXPECT_EQ(reasm.queued_bytes(), 10u);
|
|
|
|
|
EXPECT_FALSE(reasm.HasMessages());
|
|
|
|
|
|
|
|
|
|
reasm.Add(TSN(20), gen_.Ordered({11, 12, 13, 14, 15, 16}, "E"));
|
|
|
|
|
EXPECT_TRUE(reasm.HasMessages());
|
|
|
|
|
EXPECT_THAT(reasm.FlushMessages(),
|
|
|
|
|
ElementsAre(SctpMessageIs(kStreamID, kPPID, kLongPayload)));
|
|
|
|
|
EXPECT_EQ(reasm.queued_bytes(), 0u);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(ReassemblyQueueTest, ForwardTSNRemoveUnordered) {
|
2024-04-04 12:57:24 +02:00
|
|
|
ReassemblyQueue reasm("log: ", kBufferSize);
|
2021-04-03 20:33:43 +02:00
|
|
|
reasm.Add(TSN(10), gen_.Unordered({1}, "B"));
|
|
|
|
|
reasm.Add(TSN(12), gen_.Unordered({3}));
|
|
|
|
|
reasm.Add(TSN(13), gen_.Unordered({4}, "E"));
|
|
|
|
|
|
|
|
|
|
reasm.Add(TSN(14), gen_.Unordered({5}, "B"));
|
|
|
|
|
reasm.Add(TSN(15), gen_.Unordered({6}));
|
|
|
|
|
reasm.Add(TSN(17), gen_.Unordered({8}, "E"));
|
|
|
|
|
EXPECT_EQ(reasm.queued_bytes(), 6u);
|
|
|
|
|
|
|
|
|
|
EXPECT_FALSE(reasm.HasMessages());
|
|
|
|
|
|
dcsctp: Reset synchronously with incoming request
When a sender has requested a stream to be reset, and the last sender
assigned TSN hasn't been received yet, the receiver will enter deferred
reset mode, where it will store any data chunks received after that
given TSN, and replay those later, when the stream has been reset.
Before this CL, leaving deferred mode was done as soon as the sender's
last assigned TSN was received. That's actually not how the RFC
describes the process[1], but was done that way to properly handle some
sequences of RE-CONFIG and FORWARD-TSN. But after having read the RFCs
again, and realizing that whenever RFC6525 mention "any data arriving",
this also applies to any FORWARD-TSN[2] - it's better to reset streams
synchronously with the incoming requests, and defer not just DATA past
the sender last assigned TSN, but also any FORWARD-TSN after that TSN.
This mostly simplifies the code and is mostly a refactoring, but most
importantly aligns it with how the resetting procedure is explained in
the RFC. It also fixes two bugs:
* It defers FORWARD-TSN *as well as* DATA chunks with a TSN later
than the sender's last assigned TSN - see test case. The old
implementation tried to handle that by exiting the deferred reset
processing as soon as it reached the sender's last assigned TSN, but
it didn't manage to do that in all cases.
* It only defers DATA chunks for streams that are to be reset, not
all DATA chunks with a TSN > sender's last assigned TSN. This was
missed in the old implementation, but as it's now implemented
strictly according to the RFC, this was now done.
[1] https://datatracker.ietf.org/doc/html/rfc6525#section-5.2.2
[2] RFC6525 cover stream resetting, and RFC3758 cover FORWARD-TSN, and
the combination of these is not covered in the RFCs.
Bug: webrtc:14600
Change-Id: Ief878b755291b9c923aa6fb4317b0f5c00231df4
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/322623
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Commit-Queue: Victor Boivie <boivie@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#40889}
2023-09-27 18:01:18 +02:00
|
|
|
reasm.HandleForwardTsn(TSN(13), std::vector<SkippedStream>());
|
2021-04-03 20:33:43 +02:00
|
|
|
EXPECT_EQ(reasm.queued_bytes(), 3u);
|
|
|
|
|
|
|
|
|
|
// The second lost chunk comes, message is assembled.
|
|
|
|
|
reasm.Add(TSN(16), gen_.Unordered({7}));
|
|
|
|
|
EXPECT_TRUE(reasm.HasMessages());
|
|
|
|
|
EXPECT_EQ(reasm.queued_bytes(), 0u);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(ReassemblyQueueTest, ForwardTSNRemoveOrdered) {
|
2024-04-04 12:57:24 +02:00
|
|
|
ReassemblyQueue reasm("log: ", kBufferSize);
|
2021-04-03 20:33:43 +02:00
|
|
|
reasm.Add(TSN(10), gen_.Ordered({1}, "B"));
|
|
|
|
|
reasm.Add(TSN(12), gen_.Ordered({3}));
|
|
|
|
|
reasm.Add(TSN(13), gen_.Ordered({4}, "E"));
|
|
|
|
|
|
|
|
|
|
reasm.Add(TSN(14), gen_.Ordered({5}, "B"));
|
|
|
|
|
reasm.Add(TSN(15), gen_.Ordered({6}));
|
|
|
|
|
reasm.Add(TSN(16), gen_.Ordered({7}));
|
|
|
|
|
reasm.Add(TSN(17), gen_.Ordered({8}, "E"));
|
|
|
|
|
EXPECT_EQ(reasm.queued_bytes(), 7u);
|
|
|
|
|
|
|
|
|
|
EXPECT_FALSE(reasm.HasMessages());
|
|
|
|
|
|
dcsctp: Reset synchronously with incoming request
When a sender has requested a stream to be reset, and the last sender
assigned TSN hasn't been received yet, the receiver will enter deferred
reset mode, where it will store any data chunks received after that
given TSN, and replay those later, when the stream has been reset.
Before this CL, leaving deferred mode was done as soon as the sender's
last assigned TSN was received. That's actually not how the RFC
describes the process[1], but was done that way to properly handle some
sequences of RE-CONFIG and FORWARD-TSN. But after having read the RFCs
again, and realizing that whenever RFC6525 mention "any data arriving",
this also applies to any FORWARD-TSN[2] - it's better to reset streams
synchronously with the incoming requests, and defer not just DATA past
the sender last assigned TSN, but also any FORWARD-TSN after that TSN.
This mostly simplifies the code and is mostly a refactoring, but most
importantly aligns it with how the resetting procedure is explained in
the RFC. It also fixes two bugs:
* It defers FORWARD-TSN *as well as* DATA chunks with a TSN later
than the sender's last assigned TSN - see test case. The old
implementation tried to handle that by exiting the deferred reset
processing as soon as it reached the sender's last assigned TSN, but
it didn't manage to do that in all cases.
* It only defers DATA chunks for streams that are to be reset, not
all DATA chunks with a TSN > sender's last assigned TSN. This was
missed in the old implementation, but as it's now implemented
strictly according to the RFC, this was now done.
[1] https://datatracker.ietf.org/doc/html/rfc6525#section-5.2.2
[2] RFC6525 cover stream resetting, and RFC3758 cover FORWARD-TSN, and
the combination of these is not covered in the RFCs.
Bug: webrtc:14600
Change-Id: Ief878b755291b9c923aa6fb4317b0f5c00231df4
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/322623
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Commit-Queue: Victor Boivie <boivie@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#40889}
2023-09-27 18:01:18 +02:00
|
|
|
reasm.HandleForwardTsn(
|
|
|
|
|
TSN(13), std::vector<SkippedStream>({SkippedStream(kStreamID, kSSN)}));
|
2021-04-03 20:33:43 +02:00
|
|
|
EXPECT_EQ(reasm.queued_bytes(), 0u);
|
|
|
|
|
|
|
|
|
|
// The lost chunk comes, but too late.
|
|
|
|
|
EXPECT_TRUE(reasm.HasMessages());
|
|
|
|
|
EXPECT_THAT(reasm.FlushMessages(),
|
|
|
|
|
ElementsAre(SctpMessageIs(kStreamID, kPPID, kMessage2Payload)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(ReassemblyQueueTest, ForwardTSNRemoveALotOrdered) {
|
2024-04-04 12:57:24 +02:00
|
|
|
ReassemblyQueue reasm("log: ", kBufferSize);
|
2021-04-03 20:33:43 +02:00
|
|
|
reasm.Add(TSN(10), gen_.Ordered({1}, "B"));
|
|
|
|
|
reasm.Add(TSN(12), gen_.Ordered({3}));
|
|
|
|
|
reasm.Add(TSN(13), gen_.Ordered({4}, "E"));
|
|
|
|
|
|
|
|
|
|
reasm.Add(TSN(15), gen_.Ordered({5}, "B"));
|
|
|
|
|
reasm.Add(TSN(16), gen_.Ordered({6}));
|
|
|
|
|
reasm.Add(TSN(17), gen_.Ordered({7}));
|
|
|
|
|
reasm.Add(TSN(18), gen_.Ordered({8}, "E"));
|
|
|
|
|
EXPECT_EQ(reasm.queued_bytes(), 7u);
|
|
|
|
|
|
|
|
|
|
EXPECT_FALSE(reasm.HasMessages());
|
|
|
|
|
|
dcsctp: Reset synchronously with incoming request
When a sender has requested a stream to be reset, and the last sender
assigned TSN hasn't been received yet, the receiver will enter deferred
reset mode, where it will store any data chunks received after that
given TSN, and replay those later, when the stream has been reset.
Before this CL, leaving deferred mode was done as soon as the sender's
last assigned TSN was received. That's actually not how the RFC
describes the process[1], but was done that way to properly handle some
sequences of RE-CONFIG and FORWARD-TSN. But after having read the RFCs
again, and realizing that whenever RFC6525 mention "any data arriving",
this also applies to any FORWARD-TSN[2] - it's better to reset streams
synchronously with the incoming requests, and defer not just DATA past
the sender last assigned TSN, but also any FORWARD-TSN after that TSN.
This mostly simplifies the code and is mostly a refactoring, but most
importantly aligns it with how the resetting procedure is explained in
the RFC. It also fixes two bugs:
* It defers FORWARD-TSN *as well as* DATA chunks with a TSN later
than the sender's last assigned TSN - see test case. The old
implementation tried to handle that by exiting the deferred reset
processing as soon as it reached the sender's last assigned TSN, but
it didn't manage to do that in all cases.
* It only defers DATA chunks for streams that are to be reset, not
all DATA chunks with a TSN > sender's last assigned TSN. This was
missed in the old implementation, but as it's now implemented
strictly according to the RFC, this was now done.
[1] https://datatracker.ietf.org/doc/html/rfc6525#section-5.2.2
[2] RFC6525 cover stream resetting, and RFC3758 cover FORWARD-TSN, and
the combination of these is not covered in the RFCs.
Bug: webrtc:14600
Change-Id: Ief878b755291b9c923aa6fb4317b0f5c00231df4
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/322623
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Commit-Queue: Victor Boivie <boivie@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#40889}
2023-09-27 18:01:18 +02:00
|
|
|
reasm.HandleForwardTsn(
|
|
|
|
|
TSN(13), std::vector<SkippedStream>({SkippedStream(kStreamID, kSSN)}));
|
2021-04-03 20:33:43 +02:00
|
|
|
EXPECT_EQ(reasm.queued_bytes(), 0u);
|
|
|
|
|
|
|
|
|
|
// The lost chunk comes, but too late.
|
|
|
|
|
EXPECT_TRUE(reasm.HasMessages());
|
|
|
|
|
EXPECT_THAT(reasm.FlushMessages(),
|
|
|
|
|
ElementsAre(SctpMessageIs(kStreamID, kPPID, kMessage2Payload)));
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-15 11:59:17 +02:00
|
|
|
TEST_F(ReassemblyQueueTest, NotReadyForHandoverWhenResetStreamIsDeferred) {
|
2024-04-04 12:57:24 +02:00
|
|
|
ReassemblyQueue reasm("log: ", kBufferSize);
|
dcsctp: Reset synchronously with incoming request
When a sender has requested a stream to be reset, and the last sender
assigned TSN hasn't been received yet, the receiver will enter deferred
reset mode, where it will store any data chunks received after that
given TSN, and replay those later, when the stream has been reset.
Before this CL, leaving deferred mode was done as soon as the sender's
last assigned TSN was received. That's actually not how the RFC
describes the process[1], but was done that way to properly handle some
sequences of RE-CONFIG and FORWARD-TSN. But after having read the RFCs
again, and realizing that whenever RFC6525 mention "any data arriving",
this also applies to any FORWARD-TSN[2] - it's better to reset streams
synchronously with the incoming requests, and defer not just DATA past
the sender last assigned TSN, but also any FORWARD-TSN after that TSN.
This mostly simplifies the code and is mostly a refactoring, but most
importantly aligns it with how the resetting procedure is explained in
the RFC. It also fixes two bugs:
* It defers FORWARD-TSN *as well as* DATA chunks with a TSN later
than the sender's last assigned TSN - see test case. The old
implementation tried to handle that by exiting the deferred reset
processing as soon as it reached the sender's last assigned TSN, but
it didn't manage to do that in all cases.
* It only defers DATA chunks for streams that are to be reset, not
all DATA chunks with a TSN > sender's last assigned TSN. This was
missed in the old implementation, but as it's now implemented
strictly according to the RFC, this was now done.
[1] https://datatracker.ietf.org/doc/html/rfc6525#section-5.2.2
[2] RFC6525 cover stream resetting, and RFC3758 cover FORWARD-TSN, and
the combination of these is not covered in the RFCs.
Bug: webrtc:14600
Change-Id: Ief878b755291b9c923aa6fb4317b0f5c00231df4
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/322623
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Commit-Queue: Victor Boivie <boivie@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#40889}
2023-09-27 18:01:18 +02:00
|
|
|
reasm.Add(TSN(10), gen_.Ordered({1, 2, 3, 4}, "BE", {.mid = MID(0)}));
|
|
|
|
|
reasm.Add(TSN(11), gen_.Ordered({1, 2, 3, 4}, "BE", {.mid = MID(1)}));
|
2021-09-15 11:59:17 +02:00
|
|
|
EXPECT_THAT(reasm.FlushMessages(), SizeIs(2));
|
|
|
|
|
|
dcsctp: Reset synchronously with incoming request
When a sender has requested a stream to be reset, and the last sender
assigned TSN hasn't been received yet, the receiver will enter deferred
reset mode, where it will store any data chunks received after that
given TSN, and replay those later, when the stream has been reset.
Before this CL, leaving deferred mode was done as soon as the sender's
last assigned TSN was received. That's actually not how the RFC
describes the process[1], but was done that way to properly handle some
sequences of RE-CONFIG and FORWARD-TSN. But after having read the RFCs
again, and realizing that whenever RFC6525 mention "any data arriving",
this also applies to any FORWARD-TSN[2] - it's better to reset streams
synchronously with the incoming requests, and defer not just DATA past
the sender last assigned TSN, but also any FORWARD-TSN after that TSN.
This mostly simplifies the code and is mostly a refactoring, but most
importantly aligns it with how the resetting procedure is explained in
the RFC. It also fixes two bugs:
* It defers FORWARD-TSN *as well as* DATA chunks with a TSN later
than the sender's last assigned TSN - see test case. The old
implementation tried to handle that by exiting the deferred reset
processing as soon as it reached the sender's last assigned TSN, but
it didn't manage to do that in all cases.
* It only defers DATA chunks for streams that are to be reset, not
all DATA chunks with a TSN > sender's last assigned TSN. This was
missed in the old implementation, but as it's now implemented
strictly according to the RFC, this was now done.
[1] https://datatracker.ietf.org/doc/html/rfc6525#section-5.2.2
[2] RFC6525 cover stream resetting, and RFC3758 cover FORWARD-TSN, and
the combination of these is not covered in the RFCs.
Bug: webrtc:14600
Change-Id: Ief878b755291b9c923aa6fb4317b0f5c00231df4
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/322623
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Commit-Queue: Victor Boivie <boivie@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#40889}
2023-09-27 18:01:18 +02:00
|
|
|
reasm.EnterDeferredReset(TSN(12), std::vector<StreamID>({StreamID(1)}));
|
2021-09-15 11:59:17 +02:00
|
|
|
EXPECT_EQ(reasm.GetHandoverReadiness(),
|
|
|
|
|
HandoverReadinessStatus().Add(
|
|
|
|
|
HandoverUnreadinessReason::kStreamResetDeferred));
|
|
|
|
|
|
dcsctp: Reset synchronously with incoming request
When a sender has requested a stream to be reset, and the last sender
assigned TSN hasn't been received yet, the receiver will enter deferred
reset mode, where it will store any data chunks received after that
given TSN, and replay those later, when the stream has been reset.
Before this CL, leaving deferred mode was done as soon as the sender's
last assigned TSN was received. That's actually not how the RFC
describes the process[1], but was done that way to properly handle some
sequences of RE-CONFIG and FORWARD-TSN. But after having read the RFCs
again, and realizing that whenever RFC6525 mention "any data arriving",
this also applies to any FORWARD-TSN[2] - it's better to reset streams
synchronously with the incoming requests, and defer not just DATA past
the sender last assigned TSN, but also any FORWARD-TSN after that TSN.
This mostly simplifies the code and is mostly a refactoring, but most
importantly aligns it with how the resetting procedure is explained in
the RFC. It also fixes two bugs:
* It defers FORWARD-TSN *as well as* DATA chunks with a TSN later
than the sender's last assigned TSN - see test case. The old
implementation tried to handle that by exiting the deferred reset
processing as soon as it reached the sender's last assigned TSN, but
it didn't manage to do that in all cases.
* It only defers DATA chunks for streams that are to be reset, not
all DATA chunks with a TSN > sender's last assigned TSN. This was
missed in the old implementation, but as it's now implemented
strictly according to the RFC, this was now done.
[1] https://datatracker.ietf.org/doc/html/rfc6525#section-5.2.2
[2] RFC6525 cover stream resetting, and RFC3758 cover FORWARD-TSN, and
the combination of these is not covered in the RFCs.
Bug: webrtc:14600
Change-Id: Ief878b755291b9c923aa6fb4317b0f5c00231df4
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/322623
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Commit-Queue: Victor Boivie <boivie@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#40889}
2023-09-27 18:01:18 +02:00
|
|
|
reasm.Add(TSN(12), gen_.Ordered({1, 2, 3, 4}, "BE", {.mid = MID(2)}));
|
2021-09-15 11:59:17 +02:00
|
|
|
|
dcsctp: Reset synchronously with incoming request
When a sender has requested a stream to be reset, and the last sender
assigned TSN hasn't been received yet, the receiver will enter deferred
reset mode, where it will store any data chunks received after that
given TSN, and replay those later, when the stream has been reset.
Before this CL, leaving deferred mode was done as soon as the sender's
last assigned TSN was received. That's actually not how the RFC
describes the process[1], but was done that way to properly handle some
sequences of RE-CONFIG and FORWARD-TSN. But after having read the RFCs
again, and realizing that whenever RFC6525 mention "any data arriving",
this also applies to any FORWARD-TSN[2] - it's better to reset streams
synchronously with the incoming requests, and defer not just DATA past
the sender last assigned TSN, but also any FORWARD-TSN after that TSN.
This mostly simplifies the code and is mostly a refactoring, but most
importantly aligns it with how the resetting procedure is explained in
the RFC. It also fixes two bugs:
* It defers FORWARD-TSN *as well as* DATA chunks with a TSN later
than the sender's last assigned TSN - see test case. The old
implementation tried to handle that by exiting the deferred reset
processing as soon as it reached the sender's last assigned TSN, but
it didn't manage to do that in all cases.
* It only defers DATA chunks for streams that are to be reset, not
all DATA chunks with a TSN > sender's last assigned TSN. This was
missed in the old implementation, but as it's now implemented
strictly according to the RFC, this was now done.
[1] https://datatracker.ietf.org/doc/html/rfc6525#section-5.2.2
[2] RFC6525 cover stream resetting, and RFC3758 cover FORWARD-TSN, and
the combination of these is not covered in the RFCs.
Bug: webrtc:14600
Change-Id: Ief878b755291b9c923aa6fb4317b0f5c00231df4
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/322623
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Commit-Queue: Victor Boivie <boivie@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#40889}
2023-09-27 18:01:18 +02:00
|
|
|
reasm.ResetStreamsAndLeaveDeferredReset(std::vector<StreamID>({StreamID(1)}));
|
2021-09-15 11:59:17 +02:00
|
|
|
EXPECT_EQ(reasm.GetHandoverReadiness(), HandoverReadinessStatus());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(ReassemblyQueueTest, HandoverInInitialState) {
|
2024-04-04 12:57:24 +02:00
|
|
|
ReassemblyQueue reasm1("log: ", kBufferSize);
|
2021-09-15 11:59:17 +02:00
|
|
|
|
|
|
|
|
EXPECT_EQ(reasm1.GetHandoverReadiness(), HandoverReadinessStatus());
|
|
|
|
|
DcSctpSocketHandoverState state;
|
|
|
|
|
reasm1.AddHandoverState(state);
|
2021-09-20 11:35:59 +02:00
|
|
|
g_handover_state_transformer_for_test(&state);
|
2024-04-04 12:57:24 +02:00
|
|
|
ReassemblyQueue reasm2("log: ", kBufferSize,
|
2022-06-27 20:35:37 +00:00
|
|
|
/*use_message_interleaving=*/false);
|
|
|
|
|
reasm2.RestoreFromState(state);
|
2021-09-15 11:59:17 +02:00
|
|
|
|
|
|
|
|
reasm2.Add(TSN(10), gen_.Ordered({1, 2, 3, 4}, "BE"));
|
|
|
|
|
EXPECT_THAT(reasm2.FlushMessages(), SizeIs(1));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(ReassemblyQueueTest, HandoverAfterHavingAssembedOneMessage) {
|
2024-04-04 12:57:24 +02:00
|
|
|
ReassemblyQueue reasm1("log: ", kBufferSize);
|
2021-09-15 11:59:17 +02:00
|
|
|
reasm1.Add(TSN(10), gen_.Ordered({1, 2, 3, 4}, "BE"));
|
|
|
|
|
EXPECT_THAT(reasm1.FlushMessages(), SizeIs(1));
|
|
|
|
|
|
|
|
|
|
EXPECT_EQ(reasm1.GetHandoverReadiness(), HandoverReadinessStatus());
|
|
|
|
|
DcSctpSocketHandoverState state;
|
|
|
|
|
reasm1.AddHandoverState(state);
|
2021-09-20 11:35:59 +02:00
|
|
|
g_handover_state_transformer_for_test(&state);
|
2024-04-04 12:57:24 +02:00
|
|
|
ReassemblyQueue reasm2("log: ", kBufferSize,
|
2022-06-27 20:35:37 +00:00
|
|
|
/*use_message_interleaving=*/false);
|
|
|
|
|
reasm2.RestoreFromState(state);
|
2021-09-15 11:59:17 +02:00
|
|
|
|
|
|
|
|
reasm2.Add(TSN(11), gen_.Ordered({1, 2, 3, 4}, "BE"));
|
|
|
|
|
EXPECT_THAT(reasm2.FlushMessages(), SizeIs(1));
|
|
|
|
|
}
|
dcsctp: Don't deliver skipped messages
If a FORWARD-TSN contains an ordered skipped stream with a large TSN
but with a too small SSN, it can result in messages being assembled
that should've been skipped. Typically:
Receive DATA, ordered, complete, TSN=10, SID=1, SSN=0
- will be delivered.
Receive DATA, ordered, complete, TSN=43, SID=1, SSN=7
- will stay in queue, due to missing SSN=1,2,3,4,5,6.
Receive FORWARD-TSN, TSN=44, SSN=6
- is invalid, as the SSN should've been 7 or higher.
However, as the TSN isn't used for removing messages in ordered streams,
but just the SSN, the SSN=7 isn't removed but instead will be delivered
as it's the next following SSN after 6. This will trigger internal
consistency checks as a chunk with TSN=43 will be delivered when the
current cumulative TSN is set to 44, which is greater.
This was found when fuzzing, and can only be provoked by a client that
is intentionally misbehaving. Before this fix, there was no harm done,
but it failed consistency checks which fuzzers have enabled. When
bug 13799 was fixed (in a previous commit), this allowed the fuzzers to
find it faster.
Bug: webrtc:13799
Change-Id: I830ef189476e227e1dbe08157d34f96ad6453e30
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/254240
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Commit-Queue: Victor Boivie <boivie@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#36157}
2022-03-08 23:05:10 +01:00
|
|
|
|
2021-05-11 22:54:16 +02:00
|
|
|
TEST_F(ReassemblyQueueTest, SingleUnorderedChunkMessageInRfc8260) {
|
2024-04-04 12:57:24 +02:00
|
|
|
ReassemblyQueue reasm("log: ", kBufferSize,
|
2021-05-11 22:54:16 +02:00
|
|
|
/*use_message_interleaving=*/true);
|
|
|
|
|
reasm.Add(TSN(10), Data(StreamID(1), SSN(0), MID(0), FSN(0), kPPID,
|
|
|
|
|
{1, 2, 3, 4}, Data::IsBeginning(true),
|
|
|
|
|
Data::IsEnd(true), IsUnordered(true)));
|
|
|
|
|
EXPECT_EQ(reasm.queued_bytes(), 0u);
|
|
|
|
|
EXPECT_TRUE(reasm.HasMessages());
|
|
|
|
|
EXPECT_THAT(reasm.FlushMessages(),
|
|
|
|
|
ElementsAre(SctpMessageIs(kStreamID, kPPID, kShortPayload)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(ReassemblyQueueTest, TwoInterleavedChunks) {
|
2024-04-04 12:57:24 +02:00
|
|
|
ReassemblyQueue reasm("log: ", kBufferSize,
|
2021-05-11 22:54:16 +02:00
|
|
|
/*use_message_interleaving=*/true);
|
|
|
|
|
reasm.Add(TSN(10), Data(StreamID(1), SSN(0), MID(0), FSN(0), kPPID,
|
|
|
|
|
{1, 2, 3, 4}, Data::IsBeginning(true),
|
|
|
|
|
Data::IsEnd(false), IsUnordered(true)));
|
|
|
|
|
reasm.Add(TSN(11), Data(StreamID(2), SSN(0), MID(0), FSN(0), kPPID,
|
|
|
|
|
{9, 10, 11, 12}, Data::IsBeginning(true),
|
|
|
|
|
Data::IsEnd(false), IsUnordered(true)));
|
|
|
|
|
EXPECT_EQ(reasm.queued_bytes(), 8u);
|
|
|
|
|
reasm.Add(TSN(12), Data(StreamID(1), SSN(0), MID(0), FSN(1), kPPID,
|
|
|
|
|
{5, 6, 7, 8}, Data::IsBeginning(false),
|
|
|
|
|
Data::IsEnd(true), IsUnordered(true)));
|
|
|
|
|
EXPECT_EQ(reasm.queued_bytes(), 4u);
|
|
|
|
|
reasm.Add(TSN(13), Data(StreamID(2), SSN(0), MID(0), FSN(1), kPPID,
|
|
|
|
|
{13, 14, 15, 16}, Data::IsBeginning(false),
|
|
|
|
|
Data::IsEnd(true), IsUnordered(true)));
|
|
|
|
|
EXPECT_EQ(reasm.queued_bytes(), 0u);
|
|
|
|
|
EXPECT_TRUE(reasm.HasMessages());
|
|
|
|
|
EXPECT_THAT(reasm.FlushMessages(),
|
|
|
|
|
ElementsAre(SctpMessageIs(StreamID(1), kPPID, kMediumPayload1),
|
|
|
|
|
SctpMessageIs(StreamID(2), kPPID, kMediumPayload2)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(ReassemblyQueueTest, UnorderedInterleavedMessagesAllPermutations) {
|
|
|
|
|
std::vector<int> indexes = {0, 1, 2, 3, 4, 5};
|
|
|
|
|
TSN tsns[] = {TSN(10), TSN(11), TSN(12), TSN(13), TSN(14), TSN(15)};
|
|
|
|
|
StreamID stream_ids[] = {StreamID(1), StreamID(2), StreamID(1),
|
|
|
|
|
StreamID(1), StreamID(2), StreamID(2)};
|
|
|
|
|
FSN fsns[] = {FSN(0), FSN(0), FSN(1), FSN(2), FSN(1), FSN(2)};
|
|
|
|
|
rtc::ArrayView<const uint8_t> payload(kSixBytePayload);
|
|
|
|
|
do {
|
2024-04-04 12:57:24 +02:00
|
|
|
ReassemblyQueue reasm("log: ", kBufferSize,
|
2021-05-11 22:54:16 +02:00
|
|
|
/*use_message_interleaving=*/true);
|
|
|
|
|
for (int i : indexes) {
|
|
|
|
|
auto span = payload.subview(*fsns[i] * 2, 2);
|
|
|
|
|
Data::IsBeginning is_beginning(fsns[i] == FSN(0));
|
|
|
|
|
Data::IsEnd is_end(fsns[i] == FSN(2));
|
|
|
|
|
reasm.Add(tsns[i], Data(stream_ids[i], SSN(0), MID(0), fsns[i], kPPID,
|
|
|
|
|
std::vector<uint8_t>(span.begin(), span.end()),
|
|
|
|
|
is_beginning, is_end, IsUnordered(true)));
|
|
|
|
|
}
|
|
|
|
|
EXPECT_TRUE(reasm.HasMessages());
|
|
|
|
|
EXPECT_THAT(reasm.FlushMessages(),
|
|
|
|
|
UnorderedElementsAre(
|
|
|
|
|
SctpMessageIs(StreamID(1), kPPID, kSixBytePayload),
|
|
|
|
|
SctpMessageIs(StreamID(2), kPPID, kSixBytePayload)));
|
|
|
|
|
EXPECT_EQ(reasm.queued_bytes(), 0u);
|
|
|
|
|
} while (std::next_permutation(std::begin(indexes), std::end(indexes)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(ReassemblyQueueTest, IForwardTSNRemoveALotOrdered) {
|
2024-04-04 12:57:24 +02:00
|
|
|
ReassemblyQueue reasm("log: ", kBufferSize,
|
2021-05-11 22:54:16 +02:00
|
|
|
/*use_message_interleaving=*/true);
|
|
|
|
|
reasm.Add(TSN(10), gen_.Ordered({1}, "B"));
|
|
|
|
|
gen_.Ordered({2}, "");
|
|
|
|
|
reasm.Add(TSN(12), gen_.Ordered({3}, ""));
|
|
|
|
|
reasm.Add(TSN(13), gen_.Ordered({4}, "E"));
|
|
|
|
|
reasm.Add(TSN(15), gen_.Ordered({5}, "B"));
|
|
|
|
|
reasm.Add(TSN(16), gen_.Ordered({6}, ""));
|
|
|
|
|
reasm.Add(TSN(17), gen_.Ordered({7}, ""));
|
|
|
|
|
reasm.Add(TSN(18), gen_.Ordered({8}, "E"));
|
|
|
|
|
|
|
|
|
|
ASSERT_FALSE(reasm.HasMessages());
|
|
|
|
|
EXPECT_EQ(reasm.queued_bytes(), 7u);
|
|
|
|
|
|
dcsctp: Reset synchronously with incoming request
When a sender has requested a stream to be reset, and the last sender
assigned TSN hasn't been received yet, the receiver will enter deferred
reset mode, where it will store any data chunks received after that
given TSN, and replay those later, when the stream has been reset.
Before this CL, leaving deferred mode was done as soon as the sender's
last assigned TSN was received. That's actually not how the RFC
describes the process[1], but was done that way to properly handle some
sequences of RE-CONFIG and FORWARD-TSN. But after having read the RFCs
again, and realizing that whenever RFC6525 mention "any data arriving",
this also applies to any FORWARD-TSN[2] - it's better to reset streams
synchronously with the incoming requests, and defer not just DATA past
the sender last assigned TSN, but also any FORWARD-TSN after that TSN.
This mostly simplifies the code and is mostly a refactoring, but most
importantly aligns it with how the resetting procedure is explained in
the RFC. It also fixes two bugs:
* It defers FORWARD-TSN *as well as* DATA chunks with a TSN later
than the sender's last assigned TSN - see test case. The old
implementation tried to handle that by exiting the deferred reset
processing as soon as it reached the sender's last assigned TSN, but
it didn't manage to do that in all cases.
* It only defers DATA chunks for streams that are to be reset, not
all DATA chunks with a TSN > sender's last assigned TSN. This was
missed in the old implementation, but as it's now implemented
strictly according to the RFC, this was now done.
[1] https://datatracker.ietf.org/doc/html/rfc6525#section-5.2.2
[2] RFC6525 cover stream resetting, and RFC3758 cover FORWARD-TSN, and
the combination of these is not covered in the RFCs.
Bug: webrtc:14600
Change-Id: Ief878b755291b9c923aa6fb4317b0f5c00231df4
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/322623
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Commit-Queue: Victor Boivie <boivie@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#40889}
2023-09-27 18:01:18 +02:00
|
|
|
reasm.HandleForwardTsn(TSN(13), std::vector<SkippedStream>({SkippedStream(
|
|
|
|
|
IsUnordered(false), kStreamID, MID(0))}));
|
2021-05-11 22:54:16 +02:00
|
|
|
EXPECT_EQ(reasm.queued_bytes(), 0u);
|
|
|
|
|
|
|
|
|
|
// The lost chunk comes, but too late.
|
|
|
|
|
ASSERT_TRUE(reasm.HasMessages());
|
|
|
|
|
EXPECT_THAT(reasm.FlushMessages(),
|
|
|
|
|
ElementsAre(SctpMessageIs(kStreamID, kPPID, kMessage2Payload)));
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-03 20:33:43 +02:00
|
|
|
} // namespace
|
|
|
|
|
} // namespace dcsctp
|