1 /*
2 * Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10 #include "net/dcsctp/rx/traditional_reassembly_streams.h"
11
12 #include <cstdint>
13 #include <memory>
14 #include <utility>
15
16 #include "net/dcsctp/common/handover_testing.h"
17 #include "net/dcsctp/common/sequence_numbers.h"
18 #include "net/dcsctp/packet/chunk/forward_tsn_chunk.h"
19 #include "net/dcsctp/packet/chunk/forward_tsn_common.h"
20 #include "net/dcsctp/packet/data.h"
21 #include "net/dcsctp/rx/reassembly_streams.h"
22 #include "net/dcsctp/testing/data_generator.h"
23 #include "rtc_base/gunit.h"
24 #include "test/gmock.h"
25
26 namespace dcsctp {
27 namespace {
28 using ::testing::ElementsAre;
29 using ::testing::MockFunction;
30 using ::testing::NiceMock;
31 using ::testing::Property;
32
33 class TraditionalReassemblyStreamsTest : public testing::Test {
34 protected:
tsn(uint32_t value)35 UnwrappedTSN tsn(uint32_t value) { return tsn_.Unwrap(TSN(value)); }
36
TraditionalReassemblyStreamsTest()37 TraditionalReassemblyStreamsTest() {}
38 DataGenerator gen_;
39 UnwrappedTSN::Unwrapper tsn_;
40 };
41
TEST_F(TraditionalReassemblyStreamsTest,AddUnorderedMessageReturnsCorrectSize)42 TEST_F(TraditionalReassemblyStreamsTest,
43 AddUnorderedMessageReturnsCorrectSize) {
44 NiceMock<MockFunction<ReassemblyStreams::OnAssembledMessage>> on_assembled;
45
46 TraditionalReassemblyStreams streams("", on_assembled.AsStdFunction());
47
48 EXPECT_EQ(streams.Add(tsn(1), gen_.Unordered({1}, "B")), 1);
49 EXPECT_EQ(streams.Add(tsn(2), gen_.Unordered({2, 3, 4})), 3);
50 EXPECT_EQ(streams.Add(tsn(3), gen_.Unordered({5, 6})), 2);
51 // Adding the end fragment should make it empty again.
52 EXPECT_EQ(streams.Add(tsn(4), gen_.Unordered({7}, "E")), -6);
53 }
54
TEST_F(TraditionalReassemblyStreamsTest,AddSimpleOrderedMessageReturnsCorrectSize)55 TEST_F(TraditionalReassemblyStreamsTest,
56 AddSimpleOrderedMessageReturnsCorrectSize) {
57 NiceMock<MockFunction<ReassemblyStreams::OnAssembledMessage>> on_assembled;
58
59 TraditionalReassemblyStreams streams("", on_assembled.AsStdFunction());
60
61 EXPECT_EQ(streams.Add(tsn(1), gen_.Ordered({1}, "B")), 1);
62 EXPECT_EQ(streams.Add(tsn(2), gen_.Ordered({2, 3, 4})), 3);
63 EXPECT_EQ(streams.Add(tsn(3), gen_.Ordered({5, 6})), 2);
64 EXPECT_EQ(streams.Add(tsn(4), gen_.Ordered({7}, "E")), -6);
65 }
66
TEST_F(TraditionalReassemblyStreamsTest,AddMoreComplexOrderedMessageReturnsCorrectSize)67 TEST_F(TraditionalReassemblyStreamsTest,
68 AddMoreComplexOrderedMessageReturnsCorrectSize) {
69 NiceMock<MockFunction<ReassemblyStreams::OnAssembledMessage>> on_assembled;
70
71 TraditionalReassemblyStreams streams("", on_assembled.AsStdFunction());
72
73 EXPECT_EQ(streams.Add(tsn(1), gen_.Ordered({1}, "B")), 1);
74 Data late = gen_.Ordered({2, 3, 4});
75 EXPECT_EQ(streams.Add(tsn(3), gen_.Ordered({5, 6})), 2);
76 EXPECT_EQ(streams.Add(tsn(4), gen_.Ordered({7}, "E")), 1);
77
78 EXPECT_EQ(streams.Add(tsn(5), gen_.Ordered({1}, "BE")), 1);
79 EXPECT_EQ(streams.Add(tsn(6), gen_.Ordered({5, 6}, "B")), 2);
80 EXPECT_EQ(streams.Add(tsn(7), gen_.Ordered({7}, "E")), 1);
81 EXPECT_EQ(streams.Add(tsn(2), std::move(late)), -8);
82 }
83
TEST_F(TraditionalReassemblyStreamsTest,DeleteUnorderedMessageReturnsCorrectSize)84 TEST_F(TraditionalReassemblyStreamsTest,
85 DeleteUnorderedMessageReturnsCorrectSize) {
86 NiceMock<MockFunction<ReassemblyStreams::OnAssembledMessage>> on_assembled;
87
88 TraditionalReassemblyStreams streams("", on_assembled.AsStdFunction());
89
90 EXPECT_EQ(streams.Add(tsn(1), gen_.Unordered({1}, "B")), 1);
91 EXPECT_EQ(streams.Add(tsn(2), gen_.Unordered({2, 3, 4})), 3);
92 EXPECT_EQ(streams.Add(tsn(3), gen_.Unordered({5, 6})), 2);
93
94 EXPECT_EQ(streams.HandleForwardTsn(tsn(3), {}), 6u);
95 }
96
TEST_F(TraditionalReassemblyStreamsTest,DeleteSimpleOrderedMessageReturnsCorrectSize)97 TEST_F(TraditionalReassemblyStreamsTest,
98 DeleteSimpleOrderedMessageReturnsCorrectSize) {
99 NiceMock<MockFunction<ReassemblyStreams::OnAssembledMessage>> on_assembled;
100
101 TraditionalReassemblyStreams streams("", on_assembled.AsStdFunction());
102
103 EXPECT_EQ(streams.Add(tsn(1), gen_.Ordered({1}, "B")), 1);
104 EXPECT_EQ(streams.Add(tsn(2), gen_.Ordered({2, 3, 4})), 3);
105 EXPECT_EQ(streams.Add(tsn(3), gen_.Ordered({5, 6})), 2);
106
107 ForwardTsnChunk::SkippedStream skipped[] = {
108 ForwardTsnChunk::SkippedStream(StreamID(1), SSN(0))};
109 EXPECT_EQ(streams.HandleForwardTsn(tsn(3), skipped), 6u);
110 }
111
TEST_F(TraditionalReassemblyStreamsTest,DeleteManyOrderedMessagesReturnsCorrectSize)112 TEST_F(TraditionalReassemblyStreamsTest,
113 DeleteManyOrderedMessagesReturnsCorrectSize) {
114 NiceMock<MockFunction<ReassemblyStreams::OnAssembledMessage>> on_assembled;
115
116 TraditionalReassemblyStreams streams("", on_assembled.AsStdFunction());
117
118 EXPECT_EQ(streams.Add(tsn(1), gen_.Ordered({1}, "B")), 1);
119 gen_.Ordered({2, 3, 4});
120 EXPECT_EQ(streams.Add(tsn(3), gen_.Ordered({5, 6})), 2);
121 EXPECT_EQ(streams.Add(tsn(4), gen_.Ordered({7}, "E")), 1);
122
123 EXPECT_EQ(streams.Add(tsn(5), gen_.Ordered({1}, "BE")), 1);
124 EXPECT_EQ(streams.Add(tsn(6), gen_.Ordered({5, 6}, "B")), 2);
125 EXPECT_EQ(streams.Add(tsn(7), gen_.Ordered({7}, "E")), 1);
126
127 // Expire all three messages
128 ForwardTsnChunk::SkippedStream skipped[] = {
129 ForwardTsnChunk::SkippedStream(StreamID(1), SSN(2))};
130 EXPECT_EQ(streams.HandleForwardTsn(tsn(8), skipped), 8u);
131 }
132
TEST_F(TraditionalReassemblyStreamsTest,DeleteOrderedMessageDelivesTwoReturnsCorrectSize)133 TEST_F(TraditionalReassemblyStreamsTest,
134 DeleteOrderedMessageDelivesTwoReturnsCorrectSize) {
135 NiceMock<MockFunction<ReassemblyStreams::OnAssembledMessage>> on_assembled;
136
137 TraditionalReassemblyStreams streams("", on_assembled.AsStdFunction());
138
139 EXPECT_EQ(streams.Add(tsn(1), gen_.Ordered({1}, "B")), 1);
140 gen_.Ordered({2, 3, 4});
141 EXPECT_EQ(streams.Add(tsn(3), gen_.Ordered({5, 6})), 2);
142 EXPECT_EQ(streams.Add(tsn(4), gen_.Ordered({7}, "E")), 1);
143
144 EXPECT_EQ(streams.Add(tsn(5), gen_.Ordered({1}, "BE")), 1);
145 EXPECT_EQ(streams.Add(tsn(6), gen_.Ordered({5, 6}, "B")), 2);
146 EXPECT_EQ(streams.Add(tsn(7), gen_.Ordered({7}, "E")), 1);
147
148 // The first ordered message expire, and the following two are delivered.
149 ForwardTsnChunk::SkippedStream skipped[] = {
150 ForwardTsnChunk::SkippedStream(StreamID(1), SSN(0))};
151 EXPECT_EQ(streams.HandleForwardTsn(tsn(4), skipped), 8u);
152 }
153
TEST_F(TraditionalReassemblyStreamsTest,NoStreamsCanBeHandedOver)154 TEST_F(TraditionalReassemblyStreamsTest, NoStreamsCanBeHandedOver) {
155 NiceMock<MockFunction<ReassemblyStreams::OnAssembledMessage>> on_assembled;
156
157 TraditionalReassemblyStreams streams1("", on_assembled.AsStdFunction());
158 EXPECT_TRUE(streams1.GetHandoverReadiness().IsReady());
159
160 DcSctpSocketHandoverState state;
161 streams1.AddHandoverState(state);
162 g_handover_state_transformer_for_test(&state);
163 TraditionalReassemblyStreams streams2("", on_assembled.AsStdFunction());
164 streams2.RestoreFromState(state);
165
166 EXPECT_EQ(streams2.Add(tsn(1), gen_.Ordered({1}, "B")), 1);
167 EXPECT_EQ(streams2.Add(tsn(2), gen_.Ordered({2, 3, 4})), 3);
168 EXPECT_EQ(streams2.Add(tsn(1), gen_.Unordered({1}, "B")), 1);
169 EXPECT_EQ(streams2.Add(tsn(2), gen_.Unordered({2, 3, 4})), 3);
170 }
171
TEST_F(TraditionalReassemblyStreamsTest,OrderedStreamsCanBeHandedOverWhenNoUnassembledChunksExist)172 TEST_F(TraditionalReassemblyStreamsTest,
173 OrderedStreamsCanBeHandedOverWhenNoUnassembledChunksExist) {
174 NiceMock<MockFunction<ReassemblyStreams::OnAssembledMessage>> on_assembled;
175
176 TraditionalReassemblyStreams streams1("", on_assembled.AsStdFunction());
177
178 EXPECT_EQ(streams1.Add(tsn(1), gen_.Ordered({1}, "B")), 1);
179 EXPECT_EQ(streams1.GetHandoverReadiness(),
180 HandoverReadinessStatus(
181 HandoverUnreadinessReason::kOrderedStreamHasUnassembledChunks));
182 EXPECT_EQ(streams1.Add(tsn(2), gen_.Ordered({2, 3, 4})), 3);
183 EXPECT_EQ(streams1.GetHandoverReadiness(),
184 HandoverReadinessStatus(
185 HandoverUnreadinessReason::kOrderedStreamHasUnassembledChunks));
186 EXPECT_EQ(streams1.Add(tsn(3), gen_.Ordered({5, 6})), 2);
187 EXPECT_EQ(streams1.GetHandoverReadiness(),
188 HandoverReadinessStatus(
189 HandoverUnreadinessReason::kOrderedStreamHasUnassembledChunks));
190
191 ForwardTsnChunk::SkippedStream skipped[] = {
192 ForwardTsnChunk::SkippedStream(StreamID(1), SSN(0))};
193 EXPECT_EQ(streams1.HandleForwardTsn(tsn(3), skipped), 6u);
194 EXPECT_TRUE(streams1.GetHandoverReadiness().IsReady());
195
196 DcSctpSocketHandoverState state;
197 streams1.AddHandoverState(state);
198 g_handover_state_transformer_for_test(&state);
199 TraditionalReassemblyStreams streams2("", on_assembled.AsStdFunction());
200 streams2.RestoreFromState(state);
201 EXPECT_EQ(streams2.Add(tsn(4), gen_.Ordered({7})), 1);
202 }
203
TEST_F(TraditionalReassemblyStreamsTest,UnorderedStreamsCanBeHandedOverWhenNoUnassembledChunksExist)204 TEST_F(TraditionalReassemblyStreamsTest,
205 UnorderedStreamsCanBeHandedOverWhenNoUnassembledChunksExist) {
206 NiceMock<MockFunction<ReassemblyStreams::OnAssembledMessage>> on_assembled;
207
208 TraditionalReassemblyStreams streams1("", on_assembled.AsStdFunction());
209
210 EXPECT_EQ(streams1.Add(tsn(1), gen_.Unordered({1}, "B")), 1);
211 EXPECT_EQ(
212 streams1.GetHandoverReadiness(),
213 HandoverReadinessStatus(
214 HandoverUnreadinessReason::kUnorderedStreamHasUnassembledChunks));
215 EXPECT_EQ(streams1.Add(tsn(2), gen_.Unordered({2, 3, 4})), 3);
216 EXPECT_EQ(
217 streams1.GetHandoverReadiness(),
218 HandoverReadinessStatus(
219 HandoverUnreadinessReason::kUnorderedStreamHasUnassembledChunks));
220 EXPECT_EQ(streams1.Add(tsn(3), gen_.Unordered({5, 6})), 2);
221 EXPECT_EQ(
222 streams1.GetHandoverReadiness(),
223 HandoverReadinessStatus(
224 HandoverUnreadinessReason::kUnorderedStreamHasUnassembledChunks));
225
226 EXPECT_EQ(streams1.HandleForwardTsn(tsn(3), {}), 6u);
227 EXPECT_TRUE(streams1.GetHandoverReadiness().IsReady());
228
229 DcSctpSocketHandoverState state;
230 streams1.AddHandoverState(state);
231 g_handover_state_transformer_for_test(&state);
232 TraditionalReassemblyStreams streams2("", on_assembled.AsStdFunction());
233 streams2.RestoreFromState(state);
234 EXPECT_EQ(streams2.Add(tsn(4), gen_.Unordered({7})), 1);
235 }
236
TEST_F(TraditionalReassemblyStreamsTest,CanDeleteFirstOrderedMessage)237 TEST_F(TraditionalReassemblyStreamsTest, CanDeleteFirstOrderedMessage) {
238 NiceMock<MockFunction<ReassemblyStreams::OnAssembledMessage>> on_assembled;
239 EXPECT_CALL(on_assembled,
240 Call(ElementsAre(tsn(2)),
241 Property(&DcSctpMessage::payload, ElementsAre(2, 3, 4))));
242
243 TraditionalReassemblyStreams streams("", on_assembled.AsStdFunction());
244
245 // Not received, SID=1. TSN=1, SSN=0
246 gen_.Ordered({1}, "BE");
247 // And deleted (SID=1, TSN=1, SSN=0)
248 ForwardTsnChunk::SkippedStream skipped[] = {
249 ForwardTsnChunk::SkippedStream(StreamID(1), SSN(0))};
250 EXPECT_EQ(streams.HandleForwardTsn(tsn(1), skipped), 0u);
251
252 // Receive SID=1, TSN=2, SSN=1
253 EXPECT_EQ(streams.Add(tsn(2), gen_.Ordered({2, 3, 4}, "BE")), 0);
254 }
255
256 } // namespace
257 } // namespace dcsctp
258