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,604 @@
1
+ #ifndef MS_RTC_SCTP_OUTSTANDING_DATA_HPP
2
+ #define MS_RTC_SCTP_OUTSTANDING_DATA_HPP
3
+
4
+ #include "common.hpp"
5
+ #include "RTC/SCTP/common/UnwrappedSequenceNumber.hpp"
6
+ #include "RTC/SCTP/packet/Packet.hpp"
7
+ #include "RTC/SCTP/packet/UserData.hpp"
8
+ #include "RTC/SCTP/packet/chunks/SackChunk.hpp"
9
+ #include "RTC/SCTP/public/SctpTypes.hpp"
10
+ #include <deque>
11
+ #include <limits>
12
+ #include <optional>
13
+ #include <ostream>
14
+ #include <set>
15
+ #include <span>
16
+ #include <vector>
17
+
18
+ namespace RTC
19
+ {
20
+ namespace SCTP
21
+ {
22
+ /**
23
+ * This class keeps track of outstanding data Chunks (sent, not yet acked)
24
+ * and handles acking, nacking, rescheduling and abandoning.
25
+ *
26
+ * Items are added to this queue as they are sent and will be removed when
27
+ * the peer acks them using the cumulative TSN ack.
28
+ */
29
+ class OutstandingData
30
+ {
31
+ public:
32
+ static constexpr uint16_t MaxRetransmitsNoLimit{ std::numeric_limits<uint16_t>::max() };
33
+ static constexpr uint16_t ExpiresAtMsInfinite{ 0 };
34
+
35
+ #ifdef MS_TEST
36
+ public:
37
+ /**
38
+ * State for DATA Chunks (message fragments) in the queue.
39
+ *
40
+ * @remarks
41
+ * - Used in tests.
42
+ */
43
+ enum class State : uint8_t
44
+ {
45
+ /**
46
+ * The Chunk has been sent but not received yet (from the sender's point
47
+ * of view, as no SACK has been received yet that reference this Chunk).
48
+ */
49
+ IN_FLIGHT,
50
+ /**
51
+ * A SACK has been received which explicitly marked this Chunk as missing.
52
+ * It's now NACKED and may be retransmitted if NACKED enough times.
53
+ */
54
+ NACKED,
55
+ /**
56
+ * A Chunk that will be retransmitted when possible.
57
+ */
58
+ TO_BE_RETRANSMITTED,
59
+ /**
60
+ * A SACK has been received which explicitly marked this Chunk as
61
+ * received.
62
+ */
63
+ ACKED,
64
+ /**
65
+ * A Chunk whose message has expired or has been retransmitted too many
66
+ * times (RFC3758). It will not be retransmitted anymore.
67
+ */
68
+ ABANDONED,
69
+ };
70
+ #endif
71
+
72
+ public:
73
+ using UnwrappedTsn = UnwrappedSequenceNumber<uint32_t>;
74
+
75
+ public:
76
+ /**
77
+ * Contains variables scoped to a processing of an incoming SACK.
78
+ */
79
+ struct AckInfo
80
+ {
81
+ explicit AckInfo(UnwrappedTsn cumulativeTsnAck) : highestTsnAcked(cumulativeTsnAck)
82
+ {
83
+ }
84
+
85
+ /**
86
+ * Bytes acked by increasing `cumulativeTsnAck` and `gapAckBlocks`.
87
+ */
88
+ size_t bytesAcked{ 0 };
89
+
90
+ /**
91
+ * Indicates if this SACK indicates that packet loss has occurred. Just
92
+ * because a packet is missing in the SACK doesn't necessarily mean that
93
+ * there is packet loss as that packet might be in-flight and received
94
+ * out-of-order. But when it has been reported missing consecutive
95
+ * times, it will eventually be considered "lost" and this will be set.
96
+ */
97
+ bool hasPacketLoss{ false };
98
+
99
+ /**
100
+ * Highest TSN Newly Acknowledged, an SCTP variable.
101
+ */
102
+ UnwrappedTsn highestTsnAcked;
103
+
104
+ /**
105
+ * The set of lifecycle IDs that were acked using `cumulativeTsnAck`.
106
+ */
107
+ std::vector<uint64_t> ackedLifecycleIds;
108
+
109
+ /**
110
+ * The set of lifecycle IDs that were acked, but had been abandoned.
111
+ */
112
+ std::vector<uint64_t> abandonedLifecycleIds;
113
+ };
114
+
115
+ private:
116
+ /**
117
+ * A fragmented message's DATA Chunk while in the retransmission queue,
118
+ * and its associated metadata.
119
+ *
120
+ * @remarks
121
+ * - This data structure has been optimized for size, by ordering fields
122
+ * to avoid unnecessary padding.
123
+ */
124
+ class Item
125
+ {
126
+ public:
127
+ enum class NackAction : uint8_t
128
+ {
129
+ NOTHING,
130
+ RETRANSMIT,
131
+ ABANDON,
132
+ };
133
+
134
+ private:
135
+ private:
136
+ enum class Lifecycle : uint8_t
137
+ {
138
+ /**
139
+ * The Chunk is alive (sent, received, etc).
140
+ */
141
+ ACTIVE,
142
+ /**
143
+ * The Chunk is scheduled to be retransmitted, and will then
144
+ * transition to become active.
145
+ */
146
+ TO_BE_RETRANSMITTED,
147
+ /**
148
+ * The Chunk has been abandoned. This is a terminal state.
149
+ */
150
+ ABANDONED
151
+ };
152
+
153
+ enum class AckState : uint8_t
154
+ {
155
+ /**
156
+ * The Chunk is in-flight.
157
+ */
158
+ UNACKED,
159
+ /**
160
+ * The Chunk has been received and acknowledged.
161
+ */
162
+ ACKED,
163
+ /**
164
+ * The Chunk has been nacked and is possibly lost.
165
+ */
166
+ NACKED
167
+ };
168
+
169
+ public:
170
+ Item(
171
+ uint32_t messageId,
172
+ UserData data,
173
+ uint64_t timeSentMs,
174
+ uint16_t maxRetransmissions,
175
+ uint64_t expiresAtMs,
176
+ uint64_t lifecycleId);
177
+
178
+ Item(const Item&) = delete;
179
+
180
+ Item& operator=(const Item&) = delete;
181
+
182
+ public:
183
+ uint32_t GetMessageId() const
184
+ {
185
+ return this->messageId;
186
+ }
187
+
188
+ uint64_t GetTimeSentMs() const
189
+ {
190
+ return this->timeSentMs;
191
+ }
192
+
193
+ const UserData& GetData() const
194
+ {
195
+ return this->data;
196
+ }
197
+
198
+ /**
199
+ * Acks an item.
200
+ */
201
+ void Ack();
202
+
203
+ /**
204
+ * Nacks an item. If it has been nacked enough times, or if
205
+ * `retransmitNow` is set, it might be marked for retransmission. If
206
+ * the item has reached its max retransmission value, it will instead
207
+ * be abandoned. The action performed is indicated as return value.
208
+ */
209
+ NackAction Nack(bool retransmitNow);
210
+
211
+ /**
212
+ * Prepares the item to be retransmitted. Sets it as outstanding and
213
+ * clears all nack counters.
214
+ */
215
+ void MarkAsRetransmitted();
216
+
217
+ /**
218
+ * Marks this item as abandoned.
219
+ */
220
+ void Abandon();
221
+
222
+ bool IsOutstanding() const
223
+ {
224
+ return this->ackState != AckState::ACKED && this->lifecycle == Lifecycle::ACTIVE;
225
+ }
226
+
227
+ bool IsAcked() const
228
+ {
229
+ return this->ackState == AckState::ACKED;
230
+ }
231
+
232
+ bool IsNacked() const
233
+ {
234
+ return this->ackState == AckState::NACKED;
235
+ }
236
+
237
+ bool IsAbandoned() const
238
+ {
239
+ return this->lifecycle == Lifecycle::ABANDONED;
240
+ }
241
+
242
+ /**
243
+ * Indicates if this Chunk should be retransmitted.
244
+ */
245
+ bool ShouldBeRetransmitted() const
246
+ {
247
+ return this->lifecycle == Lifecycle::TO_BE_RETRANSMITTED;
248
+ }
249
+
250
+ /**
251
+ * Indicates if this Chunk has ever been retransmitted.
252
+ */
253
+ bool HasBeenRetransmitted() const
254
+ {
255
+ return this->numRetransmissions > 0;
256
+ }
257
+
258
+ /**
259
+ * Given the current time, and the current state of this DATA Chunk, it
260
+ * will indicate if it has expired (SCTP Partial Reliability Extension).
261
+ */
262
+ bool HasExpired(uint64_t nowMs) const
263
+ {
264
+ return (
265
+ this->expiresAtMs != OutstandingData::ExpiresAtMsInfinite && this->expiresAtMs <= nowMs);
266
+ }
267
+
268
+ uint64_t GetLifecycleId() const
269
+ {
270
+ return this->lifecycleId;
271
+ }
272
+
273
+ const uint32_t messageId;
274
+ // When the packet was sent, and placed in this queue.
275
+ const uint64_t timeSentMs;
276
+ // If the message was sent with a maximum number of retransmissions,
277
+ // this is set to that number. The value zero (0) means that it will
278
+ // never be retransmitted.
279
+ const uint16_t maxRetransmissions;
280
+ // Indicates the life cycle status of this Chunk.
281
+ Lifecycle lifecycle{ Lifecycle::ACTIVE };
282
+ // Indicates the presence of this Chunk, if it's in flight (UNACKED),
283
+ // has been received (ACKED) or is possibly lost (NACKED).
284
+ AckState ackState{ AckState::UNACKED };
285
+ // The number of times the DATA Chunk has been nacked (by having
286
+ // received a SACK which doesn't include it). Will be cleared on
287
+ // retransmissions.
288
+ uint8_t nackCount{ 0 };
289
+ // The number of times the DATA Chunk has been retransmitted.
290
+ uint16_t numRetransmissions{ 0 };
291
+ // At this exact millisecond, the item is considered expired. If the
292
+ // message is not to be expired, this is set to the infinite future.
293
+ // NOTE: If 0 it means infinite time.
294
+ const uint64_t expiresAtMs;
295
+ // An optional lifecycle id, which may only be set for the last
296
+ // fragment.
297
+ const uint64_t lifecycleId;
298
+ // The actual data to send/retransmit.
299
+ const UserData data;
300
+ };
301
+
302
+ public:
303
+ OutstandingData(
304
+ size_t dataChunkHeaderLength,
305
+ UnwrappedTsn lastCumulativeTsnAck,
306
+ std::function<bool(uint16_t /*streamId*/, uint32_t /*outgoingMessageId*/)> discardFromSendQueue);
307
+
308
+ public:
309
+ AckInfo HandleSack(
310
+ UnwrappedTsn cumulativeTsnAck,
311
+ std::span<const SackChunk::GapAckBlock> gapAckBlocks,
312
+ bool isInFastRecovery);
313
+
314
+ /**
315
+ * Returns as many of the Chunks that are eligible for fast retransmissions
316
+ * and that would fit in a single packet of `maxLength`. The eligible
317
+ * Chunks that didn't fit will be marked for (normal) retransmission and
318
+ * will not be returned if this method is called again.
319
+ */
320
+ std::vector<std::pair<uint32_t /*tsn*/, UserData>> GetChunksToBeFastRetransmitted(size_t maxLength);
321
+
322
+ /**
323
+ * Given `maxLength` of space left in a packet, which Chunks can be added
324
+ * to it?
325
+ */
326
+ std::vector<std::pair<uint32_t /*tsn*/, UserData>> GetChunksToBeRetransmitted(size_t maxLength);
327
+
328
+ /**
329
+ * How many inflight bytes there are, as sent on the wire as packets.
330
+ */
331
+ size_t GetUnackedPacketBytes() const
332
+ {
333
+ return this->unackedPacketBytes;
334
+ }
335
+
336
+ /**
337
+ * How many inflight bytes there are, counting only the payload.
338
+ */
339
+ size_t GetUnackedPayloadBytes() const
340
+ {
341
+ return this->unackedPayloadBytes;
342
+ }
343
+
344
+ /**
345
+ * Returns the number of DATA Chunks that are in-flight (not acked or
346
+ * nacked).
347
+ */
348
+ size_t GetUnackedItems() const
349
+ {
350
+ return this->unackedItems;
351
+ }
352
+
353
+ /**
354
+ * Given the current time `nowMs`, expire and abandon outstanding (sent
355
+ * at least once) Chunks that have a limited lifetime.
356
+ */
357
+ void ExpireOutstandingChunks(uint64_t nowMs);
358
+
359
+ bool IsEmpty() const
360
+ {
361
+ return this->outstandingData.empty();
362
+ }
363
+
364
+ bool HasDataToBeFastRetransmitted() const
365
+ {
366
+ return !this->toBeFastRetransmitted.empty();
367
+ }
368
+
369
+ bool HasDataToBeRetransmitted() const
370
+ {
371
+ return !this->toBeRetransmitted.empty() || !this->toBeFastRetransmitted.empty();
372
+ }
373
+
374
+ UnwrappedTsn GetLastCumulativeTsnAck() const
375
+ {
376
+ return this->lastCumulativeTsnAck;
377
+ }
378
+
379
+ UnwrappedTsn GetNextTsn() const
380
+ {
381
+ return this->GetHighestOutstandingTsn().GetNextValue();
382
+ }
383
+
384
+ UnwrappedTsn GetHighestOutstandingTsn() const;
385
+
386
+ /**
387
+ * Schedules `data` to be sent, with the provided partial reliability
388
+ * parameters. Returns the TSN if the item was actually added and
389
+ * scheduled to be sent, and std::nullopt if it shouldn't be sent.
390
+ */
391
+ std::optional<UnwrappedTsn> Insert(
392
+ uint32_t messageId,
393
+ const UserData& data,
394
+ uint64_t timeSentMs,
395
+ uint16_t maxRetransmissions = OutstandingData::MaxRetransmitsNoLimit,
396
+ uint64_t expiresAtMs = OutstandingData::ExpiresAtMsInfinite,
397
+ uint64_t lifecycleId = 0);
398
+
399
+ /**
400
+ * Nacks all outstanding data.
401
+ */
402
+ void NackAll();
403
+
404
+ /**
405
+ * Creates a FORWARD-TSN Chunk and adds it to the given Packet.
406
+ */
407
+ void CreateForwardTsn(Packet* packet) const;
408
+
409
+ /**
410
+ * Creates an I-FORWARD-TSN Chunk and adds it to the given Packet.
411
+ */
412
+ void CreateIForwardTsn(Packet* packet) const;
413
+
414
+ /**
415
+ * Given the current time and a TSN, it returns the measured RTT between
416
+ * when the Chunk was sent and now. It takes into acccount Karn's
417
+ * algorithm, so if the Chunk has ever been retransmitted, it will return
418
+ * `std::nullopt`.
419
+ */
420
+ std::optional<uint64_t> MeasureRtt(uint64_t nowMs, UnwrappedTsn tsn) const;
421
+
422
+ /**
423
+ * Returns true if the next Chunk that is not acked by the peer has been
424
+ * abandoned, which means that a FORWARD-TSN should be sent.
425
+ */
426
+ bool ShouldSendForwardTsn() const;
427
+
428
+ /**
429
+ * Called when an outgoing stream reset is sent, marking the last assigned
430
+ * TSN as a breakpoint that a FORWARD-TSN shouldn't cross.
431
+ */
432
+ void BeginResetStreams();
433
+
434
+ #ifdef MS_TEST
435
+ /**
436
+ * Returns the internal state of all queued Chunks.
437
+ *
438
+ * @remarks
439
+ * - Used in tests.
440
+ */
441
+ std::vector<std::pair<uint32_t /*tsn*/, State>> GetChunkStatesForTesting() const;
442
+ #endif
443
+
444
+ private:
445
+ /**
446
+ * Returns how large a Chunk will be, serialized, carrying the data.
447
+ */
448
+ size_t GetSerializedChunkLength(const UserData& data) const;
449
+
450
+ Item& GetItem(UnwrappedTsn tsn);
451
+
452
+ const Item& GetItem(UnwrappedTsn tsn) const;
453
+
454
+ /**
455
+ * Given a `cumulativeTsnAck` from an incoming SACK, will remove those
456
+ * items in the retransmission queue up until this value and will update
457
+ * `ackInfo` by setting `this->lastCumulativeTsnAck`.
458
+ */
459
+ void RemoveAcked(UnwrappedTsn cumulativeTsnAck, AckInfo& ackInfo);
460
+
461
+ /**
462
+ * Will mark the Chunks covered by the `gapAckBlocks` from an incoming
463
+ * SACK as "acked" and update `ackInfo` by adding new TSNs to
464
+ * `this->cumulativeTsnAck`.
465
+ */
466
+ void AckGapBlocks(
467
+ UnwrappedTsn cumulativeTsnAck,
468
+ std::span<const SackChunk::GapAckBlock> gapAckBlocks,
469
+ AckInfo& ackInfo);
470
+
471
+ /**
472
+ * Mark Chunks reported as "missing", as "nacked" or "to be retransmitted"
473
+ * depending how many times this has happened. Only packets up until
474
+ * `ackInfo.highestTsnAcked` (highest TSN newly acknowledged) are
475
+ * nacked/retransmitted. The method will set `ackInfo.hasPacketLoss`.
476
+ */
477
+ void NackBetweenAckBlocks(
478
+ UnwrappedTsn cumulativeTsnAck,
479
+ std::span<const SackChunk::GapAckBlock> gapAckBlocks,
480
+ bool isInFastRecovery,
481
+ bool cumulativeTsnAckedAdvanced,
482
+ AckInfo& ackInfo);
483
+
484
+ /**
485
+ * Process the acknowledgement of the Chunk referenced by `item` and
486
+ * updates state in `ackInfo` and the object's state.
487
+ */
488
+ void AckChunk(AckInfo& ackInfo, UnwrappedTsn tsn, Item& item);
489
+
490
+ /**
491
+ * Helper method to process an incoming nack of an item and perform the
492
+ * correct operations given the action indicated when nacking an item
493
+ * (e.g. retransmitting or abandoning). The return value indicate if an
494
+ * action was performed, meaning that packet loss was detected and acted
495
+ * upon. If `doFastRetransmit` is set and if the item has been nacked
496
+ * sufficiently many times so that it should be retransmitted, this will
497
+ * schedule it to be "fast retransmitted". This is only done just before
498
+ * going into fast recovery.
499
+ *
500
+ * @remarks
501
+ * - Note that since nacking an item may result in it becoming abandoned,
502
+ * which in turn could alter `this->outstandingData`, any iterators are
503
+ * invalidated after having called this method.
504
+ */
505
+ bool NackItem(UnwrappedTsn tsn, bool retransmitNow, bool doFastRetransmit);
506
+
507
+ /**
508
+ * Given that a message fragment, `item` has been abandoned, abandon all
509
+ * other fragments that share the same message - both never-before-sent
510
+ * fragments that are still in the SendQueue and outstanding Chunks.
511
+ */
512
+ void AbandonAllFor(const OutstandingData::Item& item);
513
+
514
+ std::vector<std::pair<uint32_t /*tsn*/, UserData>> ExtractChunksThatCanFit(
515
+ std::set<UnwrappedTsn>& chunks, size_t maxLength);
516
+
517
+ void AssertIsConsistent() const;
518
+
519
+ private:
520
+ // The size of the data Chunk (DATA/I-DATA) header that is used.
521
+ const size_t dataChunkHeaderLength;
522
+ // The last cumulative TSN ack number.
523
+ UnwrappedTsn lastCumulativeTsnAck;
524
+ // Callback when to discard items from the send queue.
525
+ std::function<bool(uint16_t /*streamId*/, uint32_t /*outgoingMessageId*/)> discardFromSendQueue;
526
+ // Outstanding items. If non-empty, the first element has
527
+ // `TSN=this->lastCumulativeTsnAck_ + 1` and the following items are in
528
+ // strict increasing TSN order. The last item has
529
+ // `TSN=GetHighestOutstandingTsn()`.
530
+ std::deque<Item> outstandingData;
531
+ // The number of bytes that are in-flight, counting only the payload.
532
+ size_t unackedPayloadBytes{ 0 };
533
+ // The number of bytes that are in-flight, as sent on the wire (as
534
+ // packets).
535
+ size_t unackedPacketBytes{ 0 };
536
+ // The number of DATA Chunks that are in-flight (sent but not yet acked
537
+ // or nacked).
538
+ size_t unackedItems{ 0 };
539
+ // Data Chunks that are eligible for fast retransmission.
540
+ std::set<UnwrappedTsn> toBeFastRetransmitted;
541
+ // Data Chunks that are to be retransmitted.
542
+ std::set<UnwrappedTsn> toBeRetransmitted;
543
+ // Wben a stream reset has begun, the "next TSN to assign" is added to
544
+ // this set, and removed when the cum-ack TSN reaches it. This is used
545
+ // to limit a FORWARD-TSN to reset streams past a "stream reset last
546
+ // assigned TSN".
547
+ // NOTE: dcsctp uses `webrtc::flat_set<UnwrappedTsn>` type which is more
548
+ // efficient in read operations.
549
+ std::set<UnwrappedTsn> streamResetBreakpointTsns;
550
+ };
551
+
552
+ #ifdef MS_TEST
553
+ /**
554
+ * For logging purposes in Catch2 tests.
555
+ */
556
+ inline std::ostream& operator<<(std::ostream& os, OutstandingData::State state)
557
+ {
558
+ switch (state)
559
+ {
560
+ case OutstandingData::State::IN_FLIGHT:
561
+ {
562
+ return os << "IN_FLIGHT";
563
+ }
564
+
565
+ case OutstandingData::State::NACKED:
566
+ {
567
+ return os << "NACKED";
568
+ }
569
+
570
+ case OutstandingData::State::TO_BE_RETRANSMITTED:
571
+ {
572
+ return os << "TO_BE_RETRANSMITTED";
573
+ }
574
+
575
+ case OutstandingData::State::ACKED:
576
+ {
577
+ return os << "ACKED";
578
+ }
579
+
580
+ case OutstandingData::State::ABANDONED:
581
+ {
582
+ return os << "ABANDONED";
583
+ }
584
+
585
+ default:
586
+ {
587
+ return os << "UNKNOWN(" << static_cast<int>(state) << ")";
588
+ }
589
+ }
590
+ }
591
+
592
+ /**
593
+ * For Catch2 to print it nicely.
594
+ */
595
+ inline std::ostream& operator<<(
596
+ std::ostream& os, const std::pair<uint32_t, OutstandingData::State>& s)
597
+ {
598
+ return os << "{tsn:" << s.first << ", state:" << s.second << "}";
599
+ }
600
+ #endif
601
+ } // namespace SCTP
602
+ } // namespace RTC
603
+
604
+ #endif