mediasoup 3.19.21 → 3.19.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (130) hide show
  1. package/node/lib/Worker.d.ts +1 -0
  2. package/node/lib/Worker.d.ts.map +1 -1
  3. package/node/lib/Worker.js +14 -0
  4. package/package.json +4 -2
  5. package/worker/fuzzer/src/RTC/FuzzerDtlsTransport.cpp +9 -3
  6. package/worker/fuzzer/src/RTC/RTP/FuzzerRtpStreamSend.cpp +9 -1
  7. package/worker/include/Channel/ChannelMessageRegistrator.hpp +39 -0
  8. package/worker/include/Channel/ChannelMessageRegistratorInterface.hpp +32 -0
  9. package/worker/include/Channel/ChannelSocket.hpp +1 -1
  10. package/worker/include/DepUsrSCTP.hpp +8 -7
  11. package/worker/include/RTC/ActiveSpeakerObserver.hpp +7 -7
  12. package/worker/include/RTC/AudioLevelObserver.hpp +7 -7
  13. package/worker/include/RTC/Consumer.hpp +3 -3
  14. package/worker/include/RTC/DataConsumer.hpp +3 -3
  15. package/worker/include/RTC/DataProducer.hpp +3 -3
  16. package/worker/include/RTC/DirectTransport.hpp +2 -2
  17. package/worker/include/RTC/DtlsTransport.hpp +8 -6
  18. package/worker/include/RTC/ICE/IceServer.hpp +8 -5
  19. package/worker/include/RTC/KeyFrameRequestManager.hpp +15 -12
  20. package/worker/include/RTC/NackGenerator.hpp +7 -6
  21. package/worker/include/RTC/PipeConsumer.hpp +1 -2
  22. package/worker/include/RTC/PipeTransport.hpp +2 -2
  23. package/worker/include/RTC/PlainTransport.hpp +2 -2
  24. package/worker/include/RTC/Producer.hpp +3 -3
  25. package/worker/include/RTC/RTP/RtpStream.hpp +7 -1
  26. package/worker/include/RTC/RTP/RtpStreamRecv.hpp +6 -5
  27. package/worker/include/RTC/RTP/RtpStreamSend.hpp +4 -1
  28. package/worker/include/RTC/Router.hpp +3 -3
  29. package/worker/include/RTC/RtpObserver.hpp +3 -3
  30. package/worker/include/RTC/SCTP/TODO_SCTP.md +18 -6
  31. package/worker/include/RTC/SCTP/association/Association.hpp +11 -8
  32. package/worker/include/RTC/SCTP/association/HeartbeatHandler.hpp +9 -6
  33. package/worker/include/RTC/SCTP/association/StreamResetHandler.hpp +37 -23
  34. package/worker/include/RTC/SCTP/association/TCBContext.hpp +3 -2
  35. package/worker/include/RTC/SCTP/association/TransmissionControlBlock.hpp +81 -8
  36. package/worker/include/RTC/SCTP/packet/UserData.hpp +36 -0
  37. package/worker/include/RTC/SCTP/packet/chunks/ForwardTsnChunk.hpp +1 -1
  38. package/worker/include/RTC/SCTP/packet/chunks/IForwardTsnChunk.hpp +1 -1
  39. package/worker/include/RTC/SCTP/public/SctpOptions.hpp +2 -1
  40. package/worker/include/RTC/SCTP/tx/OutstandingData.hpp +604 -0
  41. package/worker/include/RTC/SCTP/tx/RetransmissionQueue.hpp +336 -0
  42. package/worker/include/RTC/SCTP/tx/RetransmissionTimeout.hpp +5 -4
  43. package/worker/include/RTC/Serializable.hpp +8 -0
  44. package/worker/include/RTC/SimpleConsumer.hpp +1 -2
  45. package/worker/include/RTC/SimulcastConsumer.hpp +1 -2
  46. package/worker/include/RTC/SvcConsumer.hpp +1 -2
  47. package/worker/include/RTC/Transport.hpp +8 -8
  48. package/worker/include/RTC/TransportCongestionControlClient.hpp +8 -5
  49. package/worker/include/RTC/TransportCongestionControlServer.hpp +8 -5
  50. package/worker/include/RTC/WebRtcServer.hpp +3 -3
  51. package/worker/include/RTC/WebRtcTransport.hpp +3 -3
  52. package/worker/include/Shared.hpp +40 -0
  53. package/worker/include/SharedInterface.hpp +44 -0
  54. package/worker/include/Utils.hpp +6 -0
  55. package/worker/include/Worker.hpp +3 -3
  56. package/worker/include/common.hpp +1 -1
  57. package/worker/include/handles/BackoffTimerHandle.hpp +27 -65
  58. package/worker/include/handles/BackoffTimerHandleInterface.hpp +116 -0
  59. package/worker/include/handles/TimerHandle.hpp +36 -20
  60. package/worker/include/handles/TimerHandleInterface.hpp +43 -0
  61. package/worker/meson.build +21 -4
  62. package/worker/meson_options.txt +2 -1
  63. package/worker/mocks/include/Channel/MockChannelMessageRegistrator.hpp +45 -0
  64. package/worker/mocks/include/MockShared.hpp +43 -0
  65. package/worker/mocks/src/Channel/MockChannelMessageRegistrator.cpp +128 -0
  66. package/worker/mocks/src/MockShared.cpp +26 -0
  67. package/worker/scripts/clang-scripts.mjs +4 -1
  68. package/worker/src/Channel/ChannelMessageRegistrator.cpp +125 -0
  69. package/worker/src/Channel/ChannelSocket.cpp +1 -1
  70. package/worker/src/DepUsrSCTP.cpp +10 -4
  71. package/worker/src/RTC/ActiveSpeakerObserver.cpp +7 -7
  72. package/worker/src/RTC/AudioLevelObserver.cpp +12 -10
  73. package/worker/src/RTC/Consumer.cpp +23 -20
  74. package/worker/src/RTC/DataConsumer.cpp +11 -11
  75. package/worker/src/RTC/DataProducer.cpp +3 -3
  76. package/worker/src/RTC/DirectTransport.cpp +16 -16
  77. package/worker/src/RTC/DtlsTransport.cpp +4 -4
  78. package/worker/src/RTC/ICE/IceServer.cpp +4 -3
  79. package/worker/src/RTC/KeyFrameRequestManager.cpp +15 -15
  80. package/worker/src/RTC/NackGenerator.cpp +3 -3
  81. package/worker/src/RTC/PipeConsumer.cpp +5 -4
  82. package/worker/src/RTC/PipeTransport.cpp +3 -3
  83. package/worker/src/RTC/PlainTransport.cpp +10 -9
  84. package/worker/src/RTC/Producer.cpp +30 -28
  85. package/worker/src/RTC/RTCP/FeedbackPsRpsi.cpp +1 -2
  86. package/worker/src/RTC/RTP/RtpStream.cpp +9 -2
  87. package/worker/src/RTC/RTP/RtpStreamRecv.cpp +5 -4
  88. package/worker/src/RTC/RTP/RtpStreamSend.cpp +5 -2
  89. package/worker/src/RTC/Router.cpp +3 -3
  90. package/worker/src/RTC/RtpObserver.cpp +2 -1
  91. package/worker/src/RTC/SCTP/association/Association.cpp +94 -114
  92. package/worker/src/RTC/SCTP/association/HeartbeatHandler.cpp +27 -21
  93. package/worker/src/RTC/SCTP/association/StreamResetHandler.cpp +52 -55
  94. package/worker/src/RTC/SCTP/association/TransmissionControlBlock.cpp +144 -25
  95. package/worker/src/RTC/SCTP/packet/chunks/ForwardTsnChunk.cpp +2 -2
  96. package/worker/src/RTC/SCTP/packet/chunks/IForwardTsnChunk.cpp +2 -2
  97. package/worker/src/RTC/SCTP/tx/OutstandingData.cpp +905 -0
  98. package/worker/src/RTC/SCTP/tx/RetransmissionQueue.cpp +799 -0
  99. package/worker/src/RTC/SCTP/tx/RetransmissionTimeout.cpp +1 -1
  100. package/worker/src/RTC/SctpAssociation.cpp +1 -1
  101. package/worker/src/RTC/SimpleConsumer.cpp +8 -7
  102. package/worker/src/RTC/SimulcastConsumer.cpp +11 -10
  103. package/worker/src/RTC/SvcConsumer.cpp +11 -10
  104. package/worker/src/RTC/Transport.cpp +36 -26
  105. package/worker/src/RTC/TransportCongestionControlClient.cpp +4 -2
  106. package/worker/src/RTC/TransportCongestionControlServer.cpp +4 -3
  107. package/worker/src/RTC/WebRtcServer.cpp +5 -4
  108. package/worker/src/RTC/WebRtcTransport.cpp +39 -26
  109. package/worker/src/Shared.cpp +35 -0
  110. package/worker/src/Worker.cpp +10 -23
  111. package/worker/src/handles/BackoffTimerHandle.cpp +11 -16
  112. package/worker/src/handles/TimerHandle.cpp +5 -4
  113. package/worker/src/lib.cpp +14 -1
  114. package/worker/tasks.py +1 -1
  115. package/worker/test/include/RTC/ICE/iceCommon.hpp +1 -0
  116. package/worker/test/include/RTC/RTP/rtpCommon.hpp +1 -0
  117. package/worker/test/include/RTC/SCTP/sctpCommon.hpp +6 -0
  118. package/worker/test/src/RTC/RTP/TestRtpStreamRecv.cpp +12 -5
  119. package/worker/test/src/RTC/RTP/TestRtpStreamSend.cpp +34 -23
  120. package/worker/test/src/RTC/SCTP/tx/TestOutstandingData.cpp +1196 -0
  121. package/worker/test/src/RTC/SCTP/tx/TestRetransmissionTimeout.cpp +33 -33
  122. package/worker/test/src/RTC/TestKeyFrameRequestManager.cpp +14 -6
  123. package/worker/test/src/RTC/TestNackGenerator.cpp +6 -2
  124. package/worker/test/src/RTC/TestSimpleConsumer.cpp +6 -10
  125. package/worker/test/src/RTC/TestTransportCongestionControlServer.cpp +9 -2
  126. package/worker/test/src/Utils/TestByte.cpp +98 -0
  127. package/worker/include/ChannelMessageRegistrator.hpp +0 -30
  128. package/worker/include/RTC/Shared.hpp +0 -23
  129. package/worker/src/ChannelMessageRegistrator.cpp +0 -119
  130. package/worker/src/RTC/Shared.cpp +0 -23
@@ -0,0 +1,1196 @@
1
+ #include "common.hpp"
2
+ #include "Utils.hpp"
3
+ #include "RTC/SCTP/packet/UserData.hpp"
4
+ #include "RTC/SCTP/packet/chunks/DataChunk.hpp"
5
+ #include "RTC/SCTP/packet/chunks/ForwardTsnChunk.hpp"
6
+ #include "RTC/SCTP/packet/chunks/SackChunk.hpp"
7
+ #include "RTC/SCTP/public/SctpTypes.hpp"
8
+ #include "RTC/SCTP/sctpCommon.hpp"
9
+ #include "RTC/SCTP/tx/OutstandingData.hpp"
10
+ #include <catch2/catch_test_macros.hpp>
11
+ #include <vector>
12
+
13
+ SCENARIO("SCTP OutstandingData", "[sctp][outstandingdata]")
14
+ {
15
+ sctpCommon::ResetBuffers();
16
+
17
+ class DiscardFromSendQueueTester
18
+ {
19
+ public:
20
+ void Prepare(bool returnValue)
21
+ {
22
+ if (this->prepared)
23
+ {
24
+ throw std::runtime_error("already prepared");
25
+ }
26
+
27
+ this->prepared = true;
28
+ this->returnValue = returnValue;
29
+ }
30
+
31
+ bool Called(uint16_t streamId, uint32_t outgoingMessageId)
32
+ {
33
+ if (!this->prepared)
34
+ {
35
+ return false;
36
+ }
37
+
38
+ this->callCount++;
39
+ this->lastStreamId = streamId;
40
+ this->lastOutgoingMessageId = outgoingMessageId;
41
+
42
+ return this->returnValue;
43
+ }
44
+
45
+ void Test(
46
+ size_t expectedCallCount, uint16_t expectedLastStreamId, uint32_t expectedLastOutgoingMessageId)
47
+ {
48
+ if (!this->prepared)
49
+ {
50
+ throw std::runtime_error("not prepared");
51
+ }
52
+
53
+ REQUIRE(this->callCount == expectedCallCount);
54
+ REQUIRE(this->lastStreamId == expectedLastStreamId);
55
+ REQUIRE(this->lastOutgoingMessageId == expectedLastOutgoingMessageId);
56
+
57
+ // Reset.
58
+ this->prepared = false;
59
+ this->callCount = 0;
60
+ this->lastStreamId = 0;
61
+ this->lastOutgoingMessageId = 0;
62
+ this->returnValue = false;
63
+ }
64
+
65
+ private:
66
+ bool prepared{ false };
67
+ size_t callCount{ 0 };
68
+ uint16_t lastStreamId{ 0 };
69
+ uint32_t lastOutgoingMessageId{ 0 };
70
+ bool returnValue{ false };
71
+ };
72
+
73
+ constexpr uint64_t NowMs{ 42 };
74
+ constexpr uint32_t MessageId{ 17 };
75
+
76
+ RTC::SCTP::OutstandingData::UnwrappedTsn::Unwrapper unwrapper;
77
+ DiscardFromSendQueueTester discardFromSendQueueTester;
78
+
79
+ auto discardFromSendQueue =
80
+ [&discardFromSendQueueTester](uint16_t streamId, uint32_t outgoingMessageId)
81
+ {
82
+ return discardFromSendQueueTester.Called(streamId, outgoingMessageId);
83
+ };
84
+
85
+ RTC::SCTP::OutstandingData buffer(
86
+ /*dataChunkHeaderLength*/ RTC::SCTP::DataChunk::DataChunkHeaderLength,
87
+ /*lastCumulativeTsnAck*/ unwrapper.Unwrap(9),
88
+ discardFromSendQueue);
89
+
90
+ SECTION("has initial state")
91
+ {
92
+ REQUIRE(buffer.IsEmpty() == true);
93
+ REQUIRE(buffer.GetUnackedPayloadBytes() == 0);
94
+ REQUIRE(buffer.GetUnackedPacketBytes() == 0);
95
+ REQUIRE(buffer.GetUnackedItems() == 0);
96
+ REQUIRE(buffer.HasDataToBeRetransmitted() == false);
97
+ REQUIRE(buffer.GetLastCumulativeTsnAck().Wrap() == 9);
98
+ REQUIRE(buffer.GetNextTsn().Wrap() == 10);
99
+ REQUIRE(buffer.GetHighestOutstandingTsn().Wrap() == 9);
100
+
101
+ const std::vector<std::pair<uint32_t /*tsn*/, RTC::SCTP::OutstandingData::State>> expectedState = {
102
+ { 9, RTC::SCTP::OutstandingData::State::ACKED },
103
+ };
104
+
105
+ REQUIRE(buffer.GetChunkStatesForTesting() == expectedState);
106
+ REQUIRE(buffer.ShouldSendForwardTsn() == false);
107
+ }
108
+
109
+ SECTION("insert chunk")
110
+ {
111
+ const auto tsn = buffer.Insert(
112
+ MessageId, RTC::SCTP::UserData(1, 0, 0, 0, 53, { 0x00 }, true, true, false), NowMs);
113
+
114
+ REQUIRE(tsn.has_value());
115
+ // NOLINTNEXTLINE(bugprone-unchecked-optional-access)
116
+ REQUIRE(tsn->Wrap() == 10);
117
+
118
+ REQUIRE(buffer.IsEmpty() == false);
119
+ REQUIRE(buffer.GetUnackedPayloadBytes() == 1);
120
+ REQUIRE(buffer.GetUnackedItems() == 1);
121
+ REQUIRE(buffer.HasDataToBeRetransmitted() == false);
122
+ REQUIRE(buffer.GetLastCumulativeTsnAck().Wrap() == 9);
123
+ REQUIRE(buffer.GetNextTsn().Wrap() == 11);
124
+ REQUIRE(buffer.GetHighestOutstandingTsn().Wrap() == 10);
125
+
126
+ const std::vector<std::pair<uint32_t /*tsn*/, RTC::SCTP::OutstandingData::State>> expectedState = {
127
+ { 9, RTC::SCTP::OutstandingData::State::ACKED },
128
+ { 10, RTC::SCTP::OutstandingData::State::IN_FLIGHT },
129
+ };
130
+
131
+ REQUIRE(buffer.GetChunkStatesForTesting() == expectedState);
132
+ }
133
+
134
+ SECTION("acks single chunk")
135
+ {
136
+ buffer.Insert(MessageId, RTC::SCTP::UserData(1, 0, 0, 0, 53, { 0x00 }, true, true, false), NowMs);
137
+
138
+ const auto ackInfo = buffer.HandleSack(unwrapper.Unwrap(10), {}, false);
139
+
140
+ REQUIRE(
141
+ ackInfo.bytesAcked ==
142
+ RTC::SCTP::DataChunk::DataChunkHeaderLength + Utils::Byte::PadTo4Bytes<size_t>(1));
143
+ REQUIRE(ackInfo.highestTsnAcked.Wrap() == 10);
144
+ REQUIRE(ackInfo.hasPacketLoss == false);
145
+
146
+ REQUIRE(buffer.IsEmpty() == true);
147
+ REQUIRE(buffer.GetUnackedPayloadBytes() == 0);
148
+ REQUIRE(buffer.GetUnackedPacketBytes() == 0);
149
+ REQUIRE(buffer.GetUnackedItems() == 0);
150
+ REQUIRE(buffer.HasDataToBeRetransmitted() == false);
151
+ REQUIRE(buffer.GetLastCumulativeTsnAck().Wrap() == 10);
152
+ REQUIRE(buffer.GetNextTsn().Wrap() == 11);
153
+ REQUIRE(buffer.GetHighestOutstandingTsn().Wrap() == 10);
154
+
155
+ const std::vector<std::pair<uint32_t /*tsn*/, RTC::SCTP::OutstandingData::State>> expectedState = {
156
+ { 10, RTC::SCTP::OutstandingData::State::ACKED },
157
+ };
158
+
159
+ REQUIRE(buffer.GetChunkStatesForTesting() == expectedState);
160
+ }
161
+
162
+ SECTION("acks previous chunk doesn't update")
163
+ {
164
+ buffer.Insert(MessageId, RTC::SCTP::UserData(1, 0, 0, 0, 53, { 0x00 }, true, true, false), NowMs);
165
+
166
+ REQUIRE(buffer.IsEmpty() == false);
167
+ REQUIRE(buffer.GetUnackedPayloadBytes() == 1);
168
+ REQUIRE(buffer.GetUnackedItems() == 1);
169
+ REQUIRE(buffer.HasDataToBeRetransmitted() == false);
170
+ REQUIRE(buffer.GetLastCumulativeTsnAck().Wrap() == 9);
171
+ REQUIRE(buffer.GetNextTsn().Wrap() == 11);
172
+ REQUIRE(buffer.GetHighestOutstandingTsn().Wrap() == 10);
173
+
174
+ const std::vector<std::pair<uint32_t /*tsn*/, RTC::SCTP::OutstandingData::State>> expectedState = {
175
+ { 9, RTC::SCTP::OutstandingData::State::ACKED },
176
+ { 10, RTC::SCTP::OutstandingData::State::IN_FLIGHT },
177
+ };
178
+
179
+ REQUIRE(buffer.GetChunkStatesForTesting() == expectedState);
180
+ }
181
+
182
+ SECTION("acks and nacks with gap-ack-blocks")
183
+ {
184
+ buffer.Insert(MessageId, RTC::SCTP::UserData(1, 0, 0, 0, 53, { 0x00 }, true, false, false), NowMs);
185
+ buffer.Insert(MessageId, RTC::SCTP::UserData(1, 0, 0, 0, 53, { 0x00 }, false, true, false), NowMs);
186
+
187
+ const std::vector<RTC::SCTP::SackChunk::GapAckBlock> gab = {
188
+ { 2, 2 }
189
+ };
190
+ const auto ackInfo = buffer.HandleSack(unwrapper.Unwrap(9), gab, false);
191
+
192
+ REQUIRE(
193
+ ackInfo.bytesAcked ==
194
+ RTC::SCTP::DataChunk::DataChunkHeaderLength + Utils::Byte::PadTo4Bytes<size_t>(1));
195
+ REQUIRE(ackInfo.highestTsnAcked.Wrap() == 11);
196
+ REQUIRE(ackInfo.hasPacketLoss == false);
197
+
198
+ // TSN 10 is still outstanding.
199
+ REQUIRE(buffer.GetUnackedPayloadBytes() == 1);
200
+ REQUIRE(buffer.GetUnackedItems() == 1);
201
+ REQUIRE(buffer.HasDataToBeRetransmitted() == false);
202
+ REQUIRE(buffer.GetLastCumulativeTsnAck().Wrap() == 9);
203
+ REQUIRE(buffer.GetNextTsn().Wrap() == 12);
204
+ REQUIRE(buffer.GetHighestOutstandingTsn().Wrap() == 11);
205
+
206
+ const std::vector<std::pair<uint32_t, RTC::SCTP::OutstandingData::State>> expectedState = {
207
+ { 9, RTC::SCTP::OutstandingData::State::ACKED },
208
+ { 10, RTC::SCTP::OutstandingData::State::NACKED },
209
+ { 11, RTC::SCTP::OutstandingData::State::ACKED },
210
+ };
211
+ REQUIRE(buffer.GetChunkStatesForTesting() == expectedState);
212
+ }
213
+
214
+ SECTION("nacks three times with same TSN doesn't retransmit")
215
+ {
216
+ buffer.Insert(MessageId, RTC::SCTP::UserData(1, 0, 0, 0, 53, { 0x00 }, true, false, false), NowMs);
217
+
218
+ buffer.Insert(MessageId, RTC::SCTP::UserData(1, 0, 0, 0, 53, { 0x00 }, false, true, false), NowMs);
219
+
220
+ const std::vector<RTC::SCTP::SackChunk::GapAckBlock> gab1 = {
221
+ { 2, 2 }
222
+ };
223
+
224
+ REQUIRE(buffer.HandleSack(unwrapper.Unwrap(9), gab1, false).hasPacketLoss == false);
225
+ REQUIRE(buffer.HasDataToBeRetransmitted() == false);
226
+
227
+ REQUIRE(buffer.HandleSack(unwrapper.Unwrap(9), gab1, false).hasPacketLoss == false);
228
+ REQUIRE(buffer.HasDataToBeRetransmitted() == false);
229
+
230
+ REQUIRE(buffer.HandleSack(unwrapper.Unwrap(9), gab1, false).hasPacketLoss == false);
231
+ REQUIRE(buffer.HasDataToBeRetransmitted() == false);
232
+
233
+ const std::vector<std::pair<uint32_t, RTC::SCTP::OutstandingData::State>> expectedState = {
234
+ { 9, RTC::SCTP::OutstandingData::State::ACKED },
235
+ { 10, RTC::SCTP::OutstandingData::State::NACKED },
236
+ { 11, RTC::SCTP::OutstandingData::State::ACKED },
237
+ };
238
+
239
+ REQUIRE(buffer.GetChunkStatesForTesting() == expectedState);
240
+ }
241
+
242
+ SECTION("nacks three times results in retransmission")
243
+ {
244
+ buffer.Insert(MessageId, RTC::SCTP::UserData(1, 0, 0, 0, 53, { 0x00 }, true, false, false), NowMs);
245
+
246
+ buffer.Insert(
247
+ MessageId, RTC::SCTP::UserData(1, 0, 0, 0, 53, { 0x00 }, false, false, false), NowMs);
248
+
249
+ buffer.Insert(
250
+ MessageId, RTC::SCTP::UserData(1, 0, 0, 0, 53, { 0x00 }, false, false, false), NowMs);
251
+
252
+ buffer.Insert(MessageId, RTC::SCTP::UserData(1, 0, 0, 0, 53, { 0x00 }, false, true, false), NowMs);
253
+
254
+ const std::vector<RTC::SCTP::SackChunk::GapAckBlock> gab1 = {
255
+ { 2, 2 }
256
+ };
257
+
258
+ REQUIRE(buffer.HandleSack(unwrapper.Unwrap(9), gab1, false).hasPacketLoss == false);
259
+ REQUIRE(buffer.HasDataToBeRetransmitted() == false);
260
+
261
+ const std::vector<RTC::SCTP::SackChunk::GapAckBlock> gab2 = {
262
+ { 2, 3 }
263
+ };
264
+
265
+ REQUIRE(buffer.HandleSack(unwrapper.Unwrap(9), gab2, false).hasPacketLoss == false);
266
+ REQUIRE(buffer.HasDataToBeRetransmitted() == false);
267
+
268
+ const std::vector<RTC::SCTP::SackChunk::GapAckBlock> gab3 = {
269
+ { 2, 4 }
270
+ };
271
+ const auto ackInfo = buffer.HandleSack(unwrapper.Unwrap(9), gab3, false);
272
+
273
+ REQUIRE(
274
+ ackInfo.bytesAcked ==
275
+ RTC::SCTP::DataChunk::DataChunkHeaderLength + Utils::Byte::PadTo4Bytes<size_t>(1));
276
+ REQUIRE(ackInfo.highestTsnAcked.Wrap() == 13);
277
+ REQUIRE(ackInfo.hasPacketLoss == true);
278
+
279
+ REQUIRE(buffer.HasDataToBeRetransmitted() == true);
280
+
281
+ const std::vector<std::pair<uint32_t, RTC::SCTP::OutstandingData::State>> expectedState = {
282
+ { 9, RTC::SCTP::OutstandingData::State::ACKED },
283
+ { 10, RTC::SCTP::OutstandingData::State::TO_BE_RETRANSMITTED },
284
+ { 11, RTC::SCTP::OutstandingData::State::ACKED },
285
+ { 12, RTC::SCTP::OutstandingData::State::ACKED },
286
+ { 13, RTC::SCTP::OutstandingData::State::ACKED },
287
+ };
288
+
289
+ REQUIRE(buffer.GetChunkStatesForTesting() == expectedState);
290
+
291
+ std::vector<std::pair<uint32_t, RTC::SCTP::UserData>> expectedChunksToBeFastRetransmitted;
292
+
293
+ expectedChunksToBeFastRetransmitted.emplace_back(
294
+ 10, RTC::SCTP::UserData(1, 0, 0, 0, 53, { 0x00 }, true, false, false));
295
+
296
+ REQUIRE(buffer.GetChunksToBeFastRetransmitted(1000) == expectedChunksToBeFastRetransmitted);
297
+
298
+ const std::vector<std::pair<uint32_t, RTC::SCTP::UserData>> expectedChunksToBeRetransmitted = {};
299
+
300
+ REQUIRE(buffer.GetChunksToBeRetransmitted(1000) == expectedChunksToBeRetransmitted);
301
+ }
302
+
303
+ SECTION("nacks three times results in abandoning")
304
+ {
305
+ buffer.Insert(
306
+ MessageId,
307
+ RTC::SCTP::UserData(1, 0, 0, 0, 53, { 0x00 }, true, false, false),
308
+ NowMs,
309
+ /*maxRetransmits*/ 0);
310
+
311
+ buffer.Insert(
312
+ MessageId,
313
+ RTC::SCTP::UserData(1, 0, 0, 0, 53, { 0x00 }, false, false, false),
314
+ NowMs,
315
+ /*maxRetransmits*/ 0);
316
+
317
+ buffer.Insert(
318
+ MessageId,
319
+ RTC::SCTP::UserData(1, 0, 0, 0, 53, { 0x00 }, false, false, false),
320
+ NowMs,
321
+ /*maxRetransmits*/ 0);
322
+
323
+ buffer.Insert(
324
+ MessageId,
325
+ RTC::SCTP::UserData(1, 0, 0, 0, 53, { 0x00 }, false, true, false),
326
+ NowMs,
327
+ /*maxRetransmits*/ 0);
328
+
329
+ const std::vector<RTC::SCTP::SackChunk::GapAckBlock> gab1 = {
330
+ { 2, 2 }
331
+ };
332
+
333
+ REQUIRE(buffer.HandleSack(unwrapper.Unwrap(9), gab1, false).hasPacketLoss == false);
334
+ REQUIRE(buffer.HasDataToBeRetransmitted() == false);
335
+
336
+ const std::vector<RTC::SCTP::SackChunk::GapAckBlock> gab2 = {
337
+ { 2, 3 }
338
+ };
339
+
340
+ REQUIRE(buffer.HandleSack(unwrapper.Unwrap(9), gab2, false).hasPacketLoss == false);
341
+ REQUIRE(buffer.HasDataToBeRetransmitted() == false);
342
+
343
+ discardFromSendQueueTester.Prepare(/*returnValue*/ false);
344
+
345
+ const std::vector<RTC::SCTP::SackChunk::GapAckBlock> gab3 = {
346
+ { 2, 4 }
347
+ };
348
+ const auto ackInfo = buffer.HandleSack(unwrapper.Unwrap(9), gab3, false);
349
+
350
+ discardFromSendQueueTester.Test(
351
+ /*expectedCallCount*/ 1,
352
+ /*expectedLastStreamId*/ 1,
353
+ /*expectedLastOutgoingMessageId*/ MessageId);
354
+
355
+ REQUIRE(
356
+ ackInfo.bytesAcked ==
357
+ RTC::SCTP::DataChunk::DataChunkHeaderLength + Utils::Byte::PadTo4Bytes<size_t>(1));
358
+ REQUIRE(ackInfo.highestTsnAcked.Wrap() == 13);
359
+ REQUIRE(ackInfo.hasPacketLoss == true);
360
+ REQUIRE(buffer.HasDataToBeRetransmitted() == false);
361
+ REQUIRE(buffer.GetNextTsn().Wrap() == 14);
362
+
363
+ const std::vector<std::pair<uint32_t, RTC::SCTP::OutstandingData::State>> expectedState = {
364
+ { 9, RTC::SCTP::OutstandingData::State::ACKED },
365
+ { 10, RTC::SCTP::OutstandingData::State::ABANDONED },
366
+ { 11, RTC::SCTP::OutstandingData::State::ABANDONED },
367
+ { 12, RTC::SCTP::OutstandingData::State::ABANDONED },
368
+ { 13, RTC::SCTP::OutstandingData::State::ABANDONED },
369
+ };
370
+
371
+ REQUIRE(buffer.GetChunkStatesForTesting() == expectedState);
372
+ }
373
+
374
+ SECTION("nacks three times results in abandoning with placeholder")
375
+ {
376
+ buffer.Insert(
377
+ MessageId,
378
+ RTC::SCTP::UserData(1, 0, 0, 0, 53, { 0x00 }, true, false, false),
379
+ NowMs,
380
+ /*maxRetransmits*/ 0);
381
+
382
+ buffer.Insert(
383
+ MessageId,
384
+ RTC::SCTP::UserData(1, 0, 0, 0, 53, { 0x00 }, false, false, false),
385
+ NowMs,
386
+ /*maxRetransmits*/ 0);
387
+
388
+ buffer.Insert(
389
+ MessageId,
390
+ RTC::SCTP::UserData(1, 0, 0, 0, 53, { 0x00 }, false, false, false),
391
+ NowMs,
392
+ /*maxRetransmits*/ 0);
393
+
394
+ buffer.Insert(
395
+ MessageId,
396
+ RTC::SCTP::UserData(1, 0, 0, 0, 53, { 0x00 }, false, false, false),
397
+ NowMs,
398
+ /*maxRetransmits*/ 0);
399
+
400
+ const std::vector<RTC::SCTP::SackChunk::GapAckBlock> gab1 = {
401
+ { 2, 2 }
402
+ };
403
+
404
+ REQUIRE(buffer.HandleSack(unwrapper.Unwrap(9), gab1, false).hasPacketLoss == false);
405
+ REQUIRE(buffer.HasDataToBeRetransmitted() == false);
406
+
407
+ const std::vector<RTC::SCTP::SackChunk::GapAckBlock> gab2 = {
408
+ { 2, 3 }
409
+ };
410
+
411
+ REQUIRE(buffer.HandleSack(unwrapper.Unwrap(9), gab2, false).hasPacketLoss == false);
412
+ REQUIRE(buffer.HasDataToBeRetransmitted() == false);
413
+
414
+ discardFromSendQueueTester.Prepare(/*returnValue*/ true);
415
+
416
+ const std::vector<RTC::SCTP::SackChunk::GapAckBlock> gab3 = {
417
+ { 2, 4 }
418
+ };
419
+ const auto ackInfo = buffer.HandleSack(unwrapper.Unwrap(9), gab3, false);
420
+
421
+ discardFromSendQueueTester.Test(
422
+ /*expectedCallCount*/ 1,
423
+ /*expectedLastStreamId*/ 1,
424
+ /*expectedLastOutgoingMessageId*/ MessageId);
425
+
426
+ REQUIRE(
427
+ ackInfo.bytesAcked ==
428
+ RTC::SCTP::DataChunk::DataChunkHeaderLength + Utils::Byte::PadTo4Bytes<size_t>(1));
429
+ REQUIRE(ackInfo.highestTsnAcked.Wrap() == 13);
430
+ REQUIRE(ackInfo.hasPacketLoss == true);
431
+ REQUIRE(buffer.HasDataToBeRetransmitted() == false);
432
+ REQUIRE(buffer.GetNextTsn().Wrap() == 15);
433
+
434
+ const std::vector<std::pair<uint32_t, RTC::SCTP::OutstandingData::State>> expectedState = {
435
+ { 9, RTC::SCTP::OutstandingData::State::ACKED },
436
+ { 10, RTC::SCTP::OutstandingData::State::ABANDONED },
437
+ { 11, RTC::SCTP::OutstandingData::State::ABANDONED },
438
+ { 12, RTC::SCTP::OutstandingData::State::ABANDONED },
439
+ { 13, RTC::SCTP::OutstandingData::State::ABANDONED },
440
+ { 14, RTC::SCTP::OutstandingData::State::ABANDONED },
441
+ };
442
+
443
+ REQUIRE(buffer.GetChunkStatesForTesting() == expectedState);
444
+ }
445
+
446
+ SECTION("expires chunk before it is inserted")
447
+ {
448
+ constexpr uint64_t ExpiresAtMs = NowMs + 1;
449
+
450
+ auto tsn = buffer.Insert(
451
+ MessageId,
452
+ RTC::SCTP::UserData(1, 0, 0, 0, 53, { 0x00 }, true, false, false),
453
+ NowMs,
454
+ /*maxRetransmits*/ RTC::SCTP::OutstandingData::MaxRetransmitsNoLimit,
455
+ ExpiresAtMs);
456
+
457
+ REQUIRE(tsn.has_value());
458
+
459
+ tsn = buffer.Insert(
460
+ MessageId,
461
+ RTC::SCTP::UserData(1, 0, 0, 0, 53, { 0x00 }, false, false, false),
462
+ NowMs,
463
+ /*maxRetransmits*/ RTC::SCTP::OutstandingData::MaxRetransmitsNoLimit,
464
+ ExpiresAtMs);
465
+
466
+ REQUIRE(tsn.has_value());
467
+
468
+ discardFromSendQueueTester.Prepare(/*returnValue*/ false);
469
+
470
+ tsn = buffer.Insert(
471
+ MessageId,
472
+ RTC::SCTP::UserData(1, 0, 0, 0, 53, { 0x00 }, false, true, false),
473
+ NowMs + 1,
474
+ /*maxRetransmits*/ RTC::SCTP::OutstandingData::MaxRetransmitsNoLimit,
475
+ ExpiresAtMs);
476
+
477
+ REQUIRE(!tsn.has_value());
478
+
479
+ discardFromSendQueueTester.Test(
480
+ /*expectedCallCount*/ 1,
481
+ /*expectedLastStreamId*/ 1,
482
+ /*expectedLastOutgoingMessageId*/ MessageId);
483
+
484
+ REQUIRE(buffer.HasDataToBeRetransmitted() == false);
485
+ REQUIRE(buffer.GetLastCumulativeTsnAck().Wrap() == 9);
486
+ REQUIRE(buffer.GetNextTsn().Wrap() == 13);
487
+ REQUIRE(buffer.GetHighestOutstandingTsn().Wrap() == 12);
488
+
489
+ const std::vector<std::pair<uint32_t, RTC::SCTP::OutstandingData::State>> expectedState = {
490
+ { 9, RTC::SCTP::OutstandingData::State::ACKED },
491
+ { 10, RTC::SCTP::OutstandingData::State::ABANDONED },
492
+ { 11, RTC::SCTP::OutstandingData::State::ABANDONED },
493
+ { 12, RTC::SCTP::OutstandingData::State::ABANDONED },
494
+ };
495
+
496
+ REQUIRE(buffer.GetChunkStatesForTesting() == expectedState);
497
+ }
498
+
499
+ SECTION("can generate Forward TSN")
500
+ {
501
+ buffer.Insert(
502
+ MessageId,
503
+ RTC::SCTP::UserData(1, 0, 0, 0, 53, { 0x00 }, true, false, false),
504
+ NowMs,
505
+ /*maxRetransmits*/ 0);
506
+
507
+ buffer.Insert(
508
+ MessageId,
509
+ RTC::SCTP::UserData(1, 0, 0, 0, 53, { 0x00 }, false, false, false),
510
+ NowMs,
511
+ /*maxRetransmits*/ 0);
512
+
513
+ buffer.Insert(
514
+ MessageId,
515
+ RTC::SCTP::UserData(1, 0, 0, 0, 53, { 0x00 }, false, true, false),
516
+ NowMs,
517
+ /*maxRetransmits*/ 0);
518
+
519
+ discardFromSendQueueTester.Prepare(/*returnValue*/ false);
520
+
521
+ buffer.NackAll();
522
+
523
+ discardFromSendQueueTester.Test(
524
+ /*expectedCallCount*/ 1,
525
+ /*expectedLastStreamId*/ 1,
526
+ /*expectedLastOutgoingMessageId*/ MessageId);
527
+
528
+ REQUIRE(buffer.HasDataToBeRetransmitted() == false);
529
+
530
+ const std::vector<std::pair<uint32_t, RTC::SCTP::OutstandingData::State>> expectedState = {
531
+ { 9, RTC::SCTP::OutstandingData::State::ACKED },
532
+ { 10, RTC::SCTP::OutstandingData::State::ABANDONED },
533
+ { 11, RTC::SCTP::OutstandingData::State::ABANDONED },
534
+ { 12, RTC::SCTP::OutstandingData::State::ABANDONED },
535
+ };
536
+
537
+ REQUIRE(buffer.GetChunkStatesForTesting() == expectedState);
538
+ REQUIRE(buffer.ShouldSendForwardTsn() == true);
539
+
540
+ std::unique_ptr<RTC::SCTP::Packet> packet{ RTC::SCTP::Packet::Factory(
541
+ sctpCommon::FactoryBuffer, sizeof(sctpCommon::FactoryBuffer)) };
542
+
543
+ buffer.CreateForwardTsn(packet.get());
544
+
545
+ const auto* forwardTsnChunk = packet->GetFirstChunkOfType<RTC::SCTP::ForwardTsnChunk>();
546
+
547
+ REQUIRE(forwardTsnChunk);
548
+ // NOLINTNEXTLINE(bugprone-unchecked-optional-access)
549
+ REQUIRE(forwardTsnChunk->GetNewCumulativeTsn() == 12);
550
+ }
551
+
552
+ SECTION("ack with gap blocks from RFC 9260 section 3.3.4")
553
+ {
554
+ for (int i{ 0 }; i < 8; ++i)
555
+ {
556
+ const bool isBeginning = (i == 0);
557
+ const bool isEnd = (i == 7);
558
+
559
+ buffer.Insert(
560
+ MessageId, RTC::SCTP::UserData(1, 0, 0, 0, 53, { 0x00 }, isBeginning, isEnd, false), NowMs);
561
+ }
562
+
563
+ const std::vector<std::pair<uint32_t, RTC::SCTP::OutstandingData::State>> expectedStateAfterInsert = {
564
+ { 9, RTC::SCTP::OutstandingData::State::ACKED },
565
+ { 10, RTC::SCTP::OutstandingData::State::IN_FLIGHT },
566
+ { 11, RTC::SCTP::OutstandingData::State::IN_FLIGHT },
567
+ { 12, RTC::SCTP::OutstandingData::State::IN_FLIGHT },
568
+ { 13, RTC::SCTP::OutstandingData::State::IN_FLIGHT },
569
+ { 14, RTC::SCTP::OutstandingData::State::IN_FLIGHT },
570
+ { 15, RTC::SCTP::OutstandingData::State::IN_FLIGHT },
571
+ { 16, RTC::SCTP::OutstandingData::State::IN_FLIGHT },
572
+ { 17, RTC::SCTP::OutstandingData::State::IN_FLIGHT },
573
+ };
574
+
575
+ REQUIRE(buffer.GetChunkStatesForTesting() == expectedStateAfterInsert);
576
+
577
+ const std::vector<RTC::SCTP::SackChunk::GapAckBlock> gab = {
578
+ { 2, 3 },
579
+ { 5, 5 }
580
+ };
581
+
582
+ buffer.HandleSack(unwrapper.Unwrap(12), gab, false);
583
+
584
+ const std::vector<std::pair<uint32_t, RTC::SCTP::OutstandingData::State>> expectedState = {
585
+ { 12, RTC::SCTP::OutstandingData::State::ACKED },
586
+ { 13, RTC::SCTP::OutstandingData::State::NACKED },
587
+ { 14, RTC::SCTP::OutstandingData::State::ACKED },
588
+ { 15, RTC::SCTP::OutstandingData::State::ACKED },
589
+ { 16, RTC::SCTP::OutstandingData::State::NACKED },
590
+ { 17, RTC::SCTP::OutstandingData::State::ACKED },
591
+ };
592
+
593
+ REQUIRE(buffer.GetChunkStatesForTesting() == expectedState);
594
+ }
595
+
596
+ SECTION("MeasureRtt()")
597
+ {
598
+ buffer.Insert(MessageId, RTC::SCTP::UserData(1, 0, 0, 0, 53, { 0x00 }, true, true, false), NowMs);
599
+
600
+ buffer.Insert(
601
+ MessageId, RTC::SCTP::UserData(1, 0, 0, 0, 53, { 0x00 }, true, true, false), NowMs + 1);
602
+
603
+ buffer.Insert(
604
+ MessageId, RTC::SCTP::UserData(1, 0, 0, 0, 53, { 0x00 }, true, true, false), NowMs + 2);
605
+
606
+ constexpr uint64_t Duration{ 123 };
607
+
608
+ const auto duration = buffer.MeasureRtt(NowMs + Duration, unwrapper.Unwrap(11));
609
+
610
+ REQUIRE(duration.has_value());
611
+ // NOLINTNEXTLINE(bugprone-unchecked-optional-access)
612
+ REQUIRE(duration.value() == Duration - 1);
613
+ }
614
+
615
+ SECTION("must retransmit before getting nacked again")
616
+ {
617
+ // A chunk that has been nacked and scheduled for retransmission should not
618
+ // get nacked again until it has actually been sent on the wire.
619
+ for (int i{ 0 }; i <= 10; ++i)
620
+ {
621
+ const bool isBeginning = (i == 0);
622
+ const bool isEnd = (i == 10);
623
+
624
+ buffer.Insert(
625
+ MessageId,
626
+ RTC::SCTP::UserData(1, 0, 0, 0, 53, { 0x00 }, isBeginning, isEnd, false),
627
+ NowMs,
628
+ /*maxRetransmits*/ 1);
629
+ }
630
+
631
+ const std::vector<RTC::SCTP::SackChunk::GapAckBlock> gab1 = {
632
+ { 2, 2 }
633
+ };
634
+
635
+ REQUIRE(buffer.HandleSack(unwrapper.Unwrap(9), gab1, false).hasPacketLoss == false);
636
+ REQUIRE(buffer.HasDataToBeRetransmitted() == false);
637
+
638
+ const std::vector<RTC::SCTP::SackChunk::GapAckBlock> gab2 = {
639
+ { 2, 3 }
640
+ };
641
+
642
+ REQUIRE(buffer.HandleSack(unwrapper.Unwrap(9), gab2, false).hasPacketLoss == false);
643
+ REQUIRE(buffer.HasDataToBeRetransmitted() == false);
644
+
645
+ const std::vector<RTC::SCTP::SackChunk::GapAckBlock> gab3 = {
646
+ { 2, 4 }
647
+ };
648
+ const auto ackInfo = buffer.HandleSack(unwrapper.Unwrap(9), gab3, false);
649
+
650
+ REQUIRE(ackInfo.hasPacketLoss == true);
651
+
652
+ REQUIRE(buffer.HasDataToBeRetransmitted() == true);
653
+
654
+ // Don't retransmit yet. S simulate congestion window blocking it.
655
+ // It still gets more SACKs indicating packet loss.
656
+ const std::vector<RTC::SCTP::SackChunk::GapAckBlock> gab4 = {
657
+ { 2, 5 }
658
+ };
659
+
660
+ REQUIRE(buffer.HandleSack(unwrapper.Unwrap(9), gab4, false).hasPacketLoss == false);
661
+ REQUIRE(buffer.HasDataToBeRetransmitted() == true);
662
+
663
+ const std::vector<RTC::SCTP::SackChunk::GapAckBlock> gab5 = {
664
+ { 2, 6 }
665
+ };
666
+
667
+ REQUIRE(buffer.HandleSack(unwrapper.Unwrap(9), gab5, false).hasPacketLoss == false);
668
+ REQUIRE(buffer.HasDataToBeRetransmitted() == true);
669
+
670
+ const std::vector<RTC::SCTP::SackChunk::GapAckBlock> gab6 = {
671
+ { 2, 7 }
672
+ };
673
+ const auto ackInfo2 = buffer.HandleSack(unwrapper.Unwrap(9), gab6, false);
674
+
675
+ REQUIRE(ackInfo2.hasPacketLoss == false);
676
+ REQUIRE(buffer.HasDataToBeRetransmitted() == true);
677
+
678
+ // Now retransmit.
679
+ const auto fastRetransmit = buffer.GetChunksToBeFastRetransmitted(1000);
680
+
681
+ REQUIRE(fastRetransmit.size() == 1);
682
+ REQUIRE(fastRetransmit[0].first == 10);
683
+ REQUIRE(buffer.GetChunksToBeRetransmitted(1000).empty() == true);
684
+
685
+ // TSN 10 is now lost again. It gets nacked and eventually abandoned.
686
+ const std::vector<RTC::SCTP::SackChunk::GapAckBlock> gab7 = {
687
+ { 2, 8 }
688
+ };
689
+
690
+ REQUIRE(buffer.HandleSack(unwrapper.Unwrap(9), gab7, false).hasPacketLoss == false);
691
+ REQUIRE(buffer.HasDataToBeRetransmitted() == false);
692
+
693
+ const std::vector<RTC::SCTP::SackChunk::GapAckBlock> gab8 = {
694
+ { 2, 9 }
695
+ };
696
+
697
+ REQUIRE(buffer.HandleSack(unwrapper.Unwrap(9), gab8, false).hasPacketLoss == false);
698
+ REQUIRE(buffer.HasDataToBeRetransmitted() == false);
699
+
700
+ const std::vector<RTC::SCTP::SackChunk::GapAckBlock> gab9 = {
701
+ { 2, 10 }
702
+ };
703
+ const auto ackInfo3 = buffer.HandleSack(unwrapper.Unwrap(9), gab9, false);
704
+
705
+ REQUIRE(ackInfo3.hasPacketLoss == true);
706
+ REQUIRE(buffer.HasDataToBeRetransmitted() == false);
707
+ }
708
+
709
+ SECTION("lifecyle returns acked items in ack-info")
710
+ {
711
+ buffer.Insert(
712
+ 1,
713
+ RTC::SCTP::UserData(1, 0, 0, 0, 53, { 0x00 }, true, true, false),
714
+ NowMs,
715
+ RTC::SCTP::OutstandingData::MaxRetransmitsNoLimit,
716
+ RTC::SCTP::OutstandingData::ExpiresAtMsInfinite,
717
+ /*lifecycleId*/ 42);
718
+
719
+ buffer.Insert(
720
+ 2,
721
+ RTC::SCTP::UserData(1, 0, 0, 0, 53, { 0x00 }, true, true, false),
722
+ NowMs,
723
+ RTC::SCTP::OutstandingData::MaxRetransmitsNoLimit,
724
+ RTC::SCTP::OutstandingData::ExpiresAtMsInfinite,
725
+ /*lifecycleId*/ 43);
726
+
727
+ buffer.Insert(
728
+ 3,
729
+ RTC::SCTP::UserData(1, 0, 0, 0, 53, { 0x00 }, true, true, false),
730
+ NowMs,
731
+ RTC::SCTP::OutstandingData::MaxRetransmitsNoLimit,
732
+ RTC::SCTP::OutstandingData::ExpiresAtMsInfinite,
733
+ /*lifecycleId*/ 44);
734
+
735
+ const auto ackInfo1 = buffer.HandleSack(unwrapper.Unwrap(11), {}, false);
736
+
737
+ std::vector<uint64_t> expectedAckedLifecycleIds = { 42, 43 };
738
+
739
+ REQUIRE(ackInfo1.ackedLifecycleIds == expectedAckedLifecycleIds);
740
+
741
+ const auto ackInfo2 = buffer.HandleSack(unwrapper.Unwrap(12), {}, false);
742
+
743
+ expectedAckedLifecycleIds = { 44 };
744
+
745
+ REQUIRE(ackInfo2.ackedLifecycleIds == expectedAckedLifecycleIds);
746
+ }
747
+
748
+ SECTION("lifecyle returns abandoned nacked three times")
749
+ {
750
+ buffer.Insert(
751
+ MessageId,
752
+ RTC::SCTP::UserData(1, 0, 0, 0, 53, { 0x00 }, true, false, false),
753
+ NowMs,
754
+ /*maxRetransmits*/ 0);
755
+
756
+ buffer.Insert(
757
+ MessageId,
758
+ RTC::SCTP::UserData(1, 0, 0, 0, 53, { 0x00 }, false, false, false),
759
+ NowMs,
760
+ /*maxRetransmits*/ 0);
761
+
762
+ buffer.Insert(
763
+ MessageId,
764
+ RTC::SCTP::UserData(1, 0, 0, 0, 53, { 0x00 }, false, false, false),
765
+ NowMs,
766
+ /*maxRetransmits*/ 0);
767
+
768
+ buffer.Insert(
769
+ MessageId,
770
+ RTC::SCTP::UserData(1, 0, 0, 0, 53, { 0x00 }, false, true, false),
771
+ NowMs,
772
+ /*maxRetransmits*/ 0);
773
+
774
+ const std::vector<RTC::SCTP::SackChunk::GapAckBlock> gab1 = {
775
+ { 2, 2 }
776
+ };
777
+ const auto ackInfo1 = buffer.HandleSack(unwrapper.Unwrap(9), gab1, false);
778
+
779
+ REQUIRE(ackInfo1.hasPacketLoss == false);
780
+ REQUIRE(buffer.HasDataToBeRetransmitted() == false);
781
+
782
+ const std::vector<RTC::SCTP::SackChunk::GapAckBlock> gab2 = {
783
+ { 2, 3 }
784
+ };
785
+ const auto ackInfo2 = buffer.HandleSack(unwrapper.Unwrap(9), gab2, false);
786
+
787
+ REQUIRE(ackInfo2.hasPacketLoss == false);
788
+ REQUIRE(buffer.HasDataToBeRetransmitted() == false);
789
+
790
+ discardFromSendQueueTester.Prepare(/*returnValue*/ false);
791
+
792
+ const std::vector<RTC::SCTP::SackChunk::GapAckBlock> gab3 = {
793
+ { 2, 4 }
794
+ };
795
+ const auto ackInfo3 = buffer.HandleSack(unwrapper.Unwrap(9), gab3, false);
796
+
797
+ discardFromSendQueueTester.Test(
798
+ /*expectedCallCount*/ 1,
799
+ /*expectedLastStreamId*/ 1,
800
+ /*expectedLastOutgoingMessageId*/ MessageId);
801
+
802
+ REQUIRE(ackInfo3.hasPacketLoss == true);
803
+
804
+ const std::vector<uint64_t> expectedAbandonedLifecycleIds = {};
805
+
806
+ REQUIRE(ackInfo3.abandonedLifecycleIds == expectedAbandonedLifecycleIds);
807
+ }
808
+
809
+ SECTION("lifecyle returns abandoned after T3 RTX timer expired")
810
+ {
811
+ buffer.Insert(
812
+ MessageId,
813
+ RTC::SCTP::UserData(1, 0, 0, 0, 53, { 0x00 }, true, false, false),
814
+ NowMs,
815
+ /*maxRetransmits*/ 0);
816
+
817
+ buffer.Insert(
818
+ MessageId,
819
+ RTC::SCTP::UserData(1, 0, 0, 0, 53, { 0x00 }, false, false, false),
820
+ NowMs,
821
+ /*maxRetransmits*/ 0);
822
+
823
+ buffer.Insert(
824
+ MessageId,
825
+ RTC::SCTP::UserData(1, 0, 0, 0, 53, { 0x00 }, false, false, false),
826
+ NowMs,
827
+ /*maxRetransmits*/ 0);
828
+
829
+ buffer.Insert(
830
+ MessageId,
831
+ RTC::SCTP::UserData(1, 0, 0, 0, 53, { 0x00 }, false, true, false),
832
+ NowMs,
833
+ /*maxRetransmits*/ 0,
834
+ /*expiresAtMs*/ RTC::SCTP::OutstandingData::ExpiresAtMsInfinite,
835
+ /*lifecycleId*/ 42);
836
+
837
+ std::vector<std::pair<uint32_t /*tsn*/, RTC::SCTP::OutstandingData::State>> expectedState = {
838
+ { 9, RTC::SCTP::OutstandingData::State::ACKED },
839
+ { 10, RTC::SCTP::OutstandingData::State::IN_FLIGHT },
840
+ { 11, RTC::SCTP::OutstandingData::State::IN_FLIGHT },
841
+ { 12, RTC::SCTP::OutstandingData::State::IN_FLIGHT },
842
+ { 13, RTC::SCTP::OutstandingData::State::IN_FLIGHT },
843
+ };
844
+
845
+ REQUIRE(buffer.GetChunkStatesForTesting() == expectedState);
846
+
847
+ const std::vector<RTC::SCTP::SackChunk::GapAckBlock> gab1 = {
848
+ { 2, 4 }
849
+ };
850
+ const auto ackInfo1 = buffer.HandleSack(unwrapper.Unwrap(9), gab1, false);
851
+
852
+ REQUIRE(ackInfo1.hasPacketLoss == false);
853
+ REQUIRE(buffer.HasDataToBeRetransmitted() == false);
854
+
855
+ expectedState = {
856
+ { 9, RTC::SCTP::OutstandingData::State::ACKED },
857
+ { 10, RTC::SCTP::OutstandingData::State::NACKED },
858
+ { 11, RTC::SCTP::OutstandingData::State::ACKED },
859
+ { 12, RTC::SCTP::OutstandingData::State::ACKED },
860
+ { 13, RTC::SCTP::OutstandingData::State::ACKED },
861
+ };
862
+
863
+ REQUIRE(buffer.GetChunkStatesForTesting() == expectedState);
864
+
865
+ discardFromSendQueueTester.Prepare(/*returnValue*/ false);
866
+
867
+ buffer.NackAll();
868
+
869
+ discardFromSendQueueTester.Test(
870
+ /*expectedCallCount*/ 1,
871
+ /*expectedLastStreamId*/ 1,
872
+ /*expectedLastOutgoingMessageId*/ MessageId);
873
+
874
+ expectedState = {
875
+ { 9, RTC::SCTP::OutstandingData::State::ACKED },
876
+ { 10, RTC::SCTP::OutstandingData::State::ABANDONED },
877
+ { 11, RTC::SCTP::OutstandingData::State::ABANDONED },
878
+ { 12, RTC::SCTP::OutstandingData::State::ABANDONED },
879
+ { 13, RTC::SCTP::OutstandingData::State::ABANDONED },
880
+ };
881
+
882
+ REQUIRE(buffer.GetChunkStatesForTesting() == expectedState);
883
+ REQUIRE(buffer.ShouldSendForwardTsn() == true);
884
+
885
+ std::unique_ptr<RTC::SCTP::Packet> packet{ RTC::SCTP::Packet::Factory(
886
+ sctpCommon::FactoryBuffer, sizeof(sctpCommon::FactoryBuffer)) };
887
+
888
+ buffer.CreateForwardTsn(packet.get());
889
+
890
+ const auto* forwardTsnChunk = packet->GetFirstChunkOfType<RTC::SCTP::ForwardTsnChunk>();
891
+
892
+ REQUIRE(forwardTsnChunk);
893
+ // NOLINTNEXTLINE(bugprone-unchecked-optional-access)
894
+ REQUIRE(forwardTsnChunk->GetNewCumulativeTsn() == 13);
895
+
896
+ const auto ackInfo2 = buffer.HandleSack(unwrapper.Unwrap(13), {}, false);
897
+
898
+ REQUIRE(ackInfo2.hasPacketLoss == false);
899
+
900
+ const std::vector<uint64_t> expectedAbandonedLifecycleIds = { 42 };
901
+
902
+ REQUIRE(ackInfo2.abandonedLifecycleIds == expectedAbandonedLifecycleIds);
903
+ }
904
+
905
+ SECTION("generates Forward TSN until next stream reset TSN")
906
+ {
907
+ // This test generates:
908
+ // * Stream 1: TSN 10, 11, 12 <RESET>
909
+ // * Stream 2: TSN 13, 14 <RESET>
910
+ // * Stream 3: TSN 15, 16
911
+ //
912
+ // Then it expires chunk 12-15, and ensures that the generated FORWARD-TSN
913
+ // only includes up till TSN 12 until the cum ack TSN has reached 12, and
914
+ // then 13 and 14 are included, and then after the cum ack TSN has reached
915
+ // 14, then 15 is included.
916
+ //
917
+ // What it shouldn't do, is to generate a FORWARD-TSN directly at the start
918
+ // with new TSN=15, and setting [(sid=1, ssn=44), (sid=2, ssn=46),
919
+ // (sid=3, ssn=47)], because that will confuse the receiver at TSN=17,
920
+ // receiving SID=1, SSN=0 (it's reset!), expecting SSN to be 45.
921
+
922
+ // TSN 10-12.
923
+ buffer.Insert(
924
+ 0,
925
+ RTC::SCTP::UserData(1, /*ssn*/ 42, 0, 0, 53, { 0x00 }, true, true, false),
926
+ NowMs,
927
+ /*maxRetransmits*/ 0);
928
+ buffer.Insert(
929
+ 1,
930
+ RTC::SCTP::UserData(1, /*ssn*/ 43, 0, 0, 53, { 0x00 }, true, true, false),
931
+ NowMs,
932
+ /*maxRetransmits*/ 0);
933
+ buffer.Insert(
934
+ 2,
935
+ RTC::SCTP::UserData(1, /*ssn*/ 44, 0, 0, 53, { 0x00 }, true, true, false),
936
+ NowMs,
937
+ /*maxRetransmits*/ 0);
938
+ buffer.BeginResetStreams();
939
+
940
+ // TSN 13, 14.
941
+ buffer.Insert(
942
+ 3,
943
+ RTC::SCTP::UserData(2, /*ssn*/ 45, 0, 0, 53, { 0x00 }, true, true, false),
944
+ NowMs,
945
+ /*maxRetransmits*/ 0);
946
+ buffer.Insert(
947
+ 4,
948
+ RTC::SCTP::UserData(2, /*ssn*/ 46, 0, 0, 53, { 0x00 }, true, true, false),
949
+ NowMs,
950
+ /*maxRetransmits*/ 0);
951
+ buffer.BeginResetStreams();
952
+
953
+ // TSN 15, 16.
954
+ buffer.Insert(
955
+ 5,
956
+ RTC::SCTP::UserData(3, /*ssn*/ 47, 0, 0, 53, { 0x00 }, true, true, false),
957
+ NowMs,
958
+ /*maxRetransmits*/ 0);
959
+ buffer.Insert(6, RTC::SCTP::UserData(3, /*ssn*/ 48, 0, 0, 53, { 0x00 }, true, true, false), NowMs);
960
+
961
+ REQUIRE(buffer.ShouldSendForwardTsn() == false);
962
+
963
+ buffer.HandleSack(unwrapper.Unwrap(11), {}, false);
964
+ buffer.NackAll();
965
+
966
+ const std::vector<std::pair<uint32_t /*tsn*/, RTC::SCTP::OutstandingData::State>> expectedState = {
967
+ { 11, RTC::SCTP::OutstandingData::State::ACKED },
968
+ { 12, RTC::SCTP::OutstandingData::State::ABANDONED },
969
+ { 13, RTC::SCTP::OutstandingData::State::ABANDONED },
970
+ { 14, RTC::SCTP::OutstandingData::State::ABANDONED },
971
+ { 15, RTC::SCTP::OutstandingData::State::ABANDONED },
972
+ { 16, RTC::SCTP::OutstandingData::State::TO_BE_RETRANSMITTED },
973
+ };
974
+
975
+ REQUIRE(buffer.GetChunkStatesForTesting() == expectedState);
976
+ REQUIRE(buffer.ShouldSendForwardTsn() == true);
977
+
978
+ std::unique_ptr<RTC::SCTP::Packet> packet{ RTC::SCTP::Packet::Factory(
979
+ sctpCommon::FactoryBuffer, sizeof(sctpCommon::FactoryBuffer)) };
980
+
981
+ buffer.CreateForwardTsn(packet.get());
982
+
983
+ const auto* forwardTsnChunk = packet->GetFirstChunkOfType<RTC::SCTP::ForwardTsnChunk>();
984
+
985
+ REQUIRE(forwardTsnChunk);
986
+ // NOLINTNEXTLINE(bugprone-unchecked-optional-access)
987
+ REQUIRE(forwardTsnChunk->GetNewCumulativeTsn() == 12);
988
+
989
+ std::vector<RTC::SCTP::ForwardTsnChunk::SkippedStream> expectedSkippedStreams{
990
+ { 1, 44 },
991
+ };
992
+
993
+ REQUIRE(forwardTsnChunk->GetSkippedStreams() == expectedSkippedStreams);
994
+
995
+ // Ack 12, allowing a FORWARD-TSN that spans to TSN=14 to be created.
996
+ buffer.HandleSack(unwrapper.Unwrap(12), {}, false);
997
+
998
+ REQUIRE(buffer.ShouldSendForwardTsn() == true);
999
+
1000
+ packet.reset(
1001
+ RTC::SCTP::Packet::Factory(sctpCommon::FactoryBuffer, sizeof(sctpCommon::FactoryBuffer)));
1002
+
1003
+ buffer.CreateForwardTsn(packet.get());
1004
+
1005
+ forwardTsnChunk = packet->GetFirstChunkOfType<RTC::SCTP::ForwardTsnChunk>();
1006
+
1007
+ REQUIRE(forwardTsnChunk);
1008
+ // NOLINTNEXTLINE(bugprone-unchecked-optional-access)
1009
+ REQUIRE(forwardTsnChunk->GetNewCumulativeTsn() == 14);
1010
+
1011
+ expectedSkippedStreams = {
1012
+ { 2, 46 },
1013
+ };
1014
+
1015
+ REQUIRE(forwardTsnChunk->GetSkippedStreams() == expectedSkippedStreams);
1016
+
1017
+ // Ack 13, allowing a FORWARD-TSN that spans to TSN=14 to be created.
1018
+ buffer.HandleSack(unwrapper.Unwrap(13), {}, false);
1019
+
1020
+ REQUIRE(buffer.ShouldSendForwardTsn() == true);
1021
+
1022
+ packet.reset(
1023
+ RTC::SCTP::Packet::Factory(sctpCommon::FactoryBuffer, sizeof(sctpCommon::FactoryBuffer)));
1024
+
1025
+ buffer.CreateForwardTsn(packet.get());
1026
+
1027
+ forwardTsnChunk = packet->GetFirstChunkOfType<RTC::SCTP::ForwardTsnChunk>();
1028
+
1029
+ REQUIRE(forwardTsnChunk);
1030
+ // NOLINTNEXTLINE(bugprone-unchecked-optional-access)
1031
+ REQUIRE(forwardTsnChunk->GetNewCumulativeTsn() == 14);
1032
+
1033
+ expectedSkippedStreams = {
1034
+ { 2, 46 },
1035
+ };
1036
+
1037
+ REQUIRE(forwardTsnChunk->GetSkippedStreams() == expectedSkippedStreams);
1038
+
1039
+ // Ack 14, allowing a FORWARD-TSN that spans to TSN=15 to be created.
1040
+ buffer.HandleSack(unwrapper.Unwrap(14), {}, false);
1041
+
1042
+ REQUIRE(buffer.ShouldSendForwardTsn() == true);
1043
+
1044
+ packet.reset(
1045
+ RTC::SCTP::Packet::Factory(sctpCommon::FactoryBuffer, sizeof(sctpCommon::FactoryBuffer)));
1046
+
1047
+ buffer.CreateForwardTsn(packet.get());
1048
+
1049
+ forwardTsnChunk = packet->GetFirstChunkOfType<RTC::SCTP::ForwardTsnChunk>();
1050
+
1051
+ REQUIRE(forwardTsnChunk);
1052
+ // NOLINTNEXTLINE(bugprone-unchecked-optional-access)
1053
+ REQUIRE(forwardTsnChunk->GetNewCumulativeTsn() == 15);
1054
+
1055
+ expectedSkippedStreams = {
1056
+ { 3, 47 },
1057
+ };
1058
+
1059
+ REQUIRE(forwardTsnChunk->GetSkippedStreams() == expectedSkippedStreams);
1060
+
1061
+ buffer.HandleSack(unwrapper.Unwrap(15), {}, false);
1062
+
1063
+ REQUIRE(buffer.ShouldSendForwardTsn() == false);
1064
+ }
1065
+
1066
+ SECTION("treats unacked payload bytes different from packet bytes")
1067
+ {
1068
+ buffer.Insert(MessageId, RTC::SCTP::UserData(1, 0, 0, 0, 53, { 0x00 }, true, true, false), NowMs);
1069
+
1070
+ REQUIRE(buffer.GetUnackedPayloadBytes() == 1);
1071
+ REQUIRE(
1072
+ buffer.GetUnackedPacketBytes() ==
1073
+ RTC::SCTP::DataChunk::DataChunkHeaderLength + Utils::Byte::PadTo4Bytes<size_t>(1));
1074
+ REQUIRE(buffer.GetUnackedItems() == 1);
1075
+
1076
+ buffer.Insert(MessageId, RTC::SCTP::UserData(1, 0, 0, 0, 53, { 0x00 }, true, true, false), NowMs);
1077
+
1078
+ REQUIRE(buffer.GetUnackedPayloadBytes() == 2);
1079
+ REQUIRE(
1080
+ buffer.GetUnackedPacketBytes() ==
1081
+ 2 * (RTC::SCTP::DataChunk::DataChunkHeaderLength + Utils::Byte::PadTo4Bytes<size_t>(1)));
1082
+ REQUIRE(buffer.GetUnackedItems() == 2);
1083
+ }
1084
+
1085
+ SECTION("fast recovery increments nack count when cumulative TSN advances")
1086
+ {
1087
+ // This test verifies that the Fast Recovery retransmission rules are
1088
+ // correctly applied when the Cumulative TSN Ack point advances. RFC 9260
1089
+ // Section 7.2.4: "If an endpoint is in Fast Recovery and a SACK arrives that
1090
+ // advances the Cumulative TSN Ack Point, the miss indications are incremented
1091
+ // for all TSNs reported missing in the SACK."
1092
+
1093
+ for (int i{ 10 }; i <= 16; ++i)
1094
+ {
1095
+ buffer.Insert(
1096
+ MessageId, RTC::SCTP::UserData(1, 0, 0, 0, 53, { 0x00 }, false, false, false), NowMs);
1097
+ }
1098
+
1099
+ // SACK 1: Cumulative Ack = 10. Gap blocks for 12, 14, 16.
1100
+ // Missing: 11, 13, 15.
1101
+ // This marks 12, 14, 16 as Acked.
1102
+ // TSNs 11, 13, 15 get their 1st miss indication each.
1103
+ std::vector<RTC::SCTP::SackChunk::GapAckBlock> gab1 = {
1104
+ { 2, 2 }, // TSN 12
1105
+ { 4, 4 }, // TSN 14
1106
+ { 6, 6 } // TSN 16
1107
+ };
1108
+
1109
+ buffer.HandleSack(unwrapper.Unwrap(10), gab1, /*isInFastRecovery*/ false);
1110
+
1111
+ // SACK 2: Cumulative Ack advances to 11. Same gap blocks (12, 14, 16).
1112
+ // Endpoint is now in Fast Recovery (is_in_fast_recovery = true). Because the
1113
+ // Cumulative TSN Ack Point advanced from 10 to 11, 13 and 15 should get their
1114
+ // 2nd miss indication.
1115
+ std::vector<RTC::SCTP::SackChunk::GapAckBlock> gab2 = {
1116
+ { 1, 1 }, // TSN 12
1117
+ { 3, 3 }, // TSN 14
1118
+ { 5, 5 } // TSN 16
1119
+ };
1120
+
1121
+ buffer.HandleSack(unwrapper.Unwrap(11), gab2, /*isInFastRecovery*/ true);
1122
+
1123
+ // SACK 3: Cumulative Ack advances to 12.
1124
+ // Note: TSN 12 was already acked via gap block, so this just advances the
1125
+ // Cumulative Ack. 13 and 15 should get their 3rd miss indication and trigger
1126
+ // retransmission.
1127
+ std::vector<RTC::SCTP::SackChunk::GapAckBlock> gab3 = {
1128
+ { 2, 2 }, // TSN 14
1129
+ { 4, 4 } // TSN 16
1130
+ };
1131
+
1132
+ buffer.HandleSack(unwrapper.Unwrap(12), gab3, /*isInFastRecovery*/ true);
1133
+
1134
+ const std::vector<std::pair<uint32_t /*tsn*/, RTC::SCTP::OutstandingData::State>> expectedState = {
1135
+ { 12, RTC::SCTP::OutstandingData::State::ACKED },
1136
+ { 13, RTC::SCTP::OutstandingData::State::TO_BE_RETRANSMITTED },
1137
+ { 14, RTC::SCTP::OutstandingData::State::ACKED },
1138
+ { 15, RTC::SCTP::OutstandingData::State::TO_BE_RETRANSMITTED },
1139
+ { 16, RTC::SCTP::OutstandingData::State::ACKED },
1140
+ };
1141
+
1142
+ REQUIRE(buffer.GetChunkStatesForTesting() == expectedState);
1143
+ }
1144
+
1145
+ SECTION("nack between ack blocks does not access out of bounds")
1146
+ {
1147
+ for (int i{ 0 }; i < 5; ++i)
1148
+ {
1149
+ buffer.Insert(
1150
+ MessageId, RTC::SCTP::UserData(1, 0, 0, 0, 53, { 0x00 }, false, false, false), NowMs);
1151
+ }
1152
+
1153
+ // Inject a malformed SACK where the GapAckBlock exceeds the number of
1154
+ // outstanding items, potentially triggering an OOB read/write.
1155
+ std::vector<RTC::SCTP::SackChunk::GapAckBlock> malformedBlocks = {
1156
+ { 1, 40000 },
1157
+ };
1158
+
1159
+ buffer.HandleSack(unwrapper.Unwrap(10), malformedBlocks, /*isInFastRecovery*/ false);
1160
+
1161
+ REQUIRE(buffer.HasDataToBeRetransmitted() == false);
1162
+ }
1163
+
1164
+ SECTION("handles SACKs with out of bounds TSNs")
1165
+ {
1166
+ // Send chunks with TSNs 10, 11, 12, 13, 14, 15, 16
1167
+ for (int i{ 0 }; i < 7; ++i)
1168
+ {
1169
+ buffer.Insert(
1170
+ MessageId, RTC::SCTP::UserData(1, 0, 0, 0, 53, { 0x00 }, false, false, false), NowMs);
1171
+ }
1172
+
1173
+ // This NACKs TSN 11, 13, 15 (1st miss indication).
1174
+ std::vector<RTC::SCTP::SackChunk::GapAckBlock> gab1 = {
1175
+ { 2, 2 }, // TSN 12
1176
+ { 4, 4 }, // TSN 14
1177
+ { 6, 6 } // TSN 16
1178
+ };
1179
+
1180
+ buffer.HandleSack(unwrapper.Unwrap(10), gab1, /*isInFastRecovery*/ false);
1181
+
1182
+ REQUIRE(buffer.GetUnackedItems() == 3);
1183
+
1184
+ // The gap between block1-end (12) and block2-start (1011) causes
1185
+ // NackBetweenAckBlocks to loop TSN 13..1010, but only TSN 13..16 are valid.
1186
+ std::vector<RTC::SCTP::SackChunk::GapAckBlock> gab2 = {
1187
+ { 1, 1 }, // TSN 12
1188
+ { 1000, 60000 } // TSN 1011..60011
1189
+ };
1190
+
1191
+ buffer.HandleSack(unwrapper.Unwrap(11), gab2, /*isInFastRecovery*/ true);
1192
+
1193
+ // Packet 11 has been acknowledged.
1194
+ REQUIRE(buffer.GetUnackedItems() == 2);
1195
+ }
1196
+ }