mediasoup 3.19.19 → 3.19.21

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 (91) hide show
  1. package/README.md +4 -4
  2. package/node/lib/Worker.d.ts +1 -1
  3. package/node/lib/Worker.d.ts.map +1 -1
  4. package/node/lib/Worker.js +8 -2
  5. package/node/lib/WorkerTypes.d.ts +8 -4
  6. package/node/lib/WorkerTypes.d.ts.map +1 -1
  7. package/node/lib/index.d.ts +1 -1
  8. package/node/lib/index.d.ts.map +1 -1
  9. package/node/lib/index.js +2 -1
  10. package/node/lib/sctpParametersTypes.d.ts +3 -13
  11. package/node/lib/sctpParametersTypes.d.ts.map +1 -1
  12. package/node/lib/test/test-PlainTransport.js +8 -3
  13. package/node/lib/test/test-WebRtcTransport.js +9 -4
  14. package/package.json +10 -10
  15. package/worker/Makefile +0 -4
  16. package/worker/fuzzer/src/fuzzer.cpp +6 -5
  17. package/worker/include/RTC/DataConsumer.hpp +4 -14
  18. package/worker/include/RTC/SCTP/TODO_SCTP.md +18 -10
  19. package/worker/include/RTC/SCTP/association/Association.hpp +39 -31
  20. package/worker/include/RTC/SCTP/association/{AssociationDeferredListener.hpp → AssociationListenerDeferrer.hpp} +10 -8
  21. package/worker/include/RTC/SCTP/association/HeartbeatHandler.hpp +77 -0
  22. package/worker/include/RTC/SCTP/association/NegotiatedCapabilities.hpp +2 -2
  23. package/worker/include/RTC/SCTP/association/PacketSender.hpp +2 -2
  24. package/worker/include/RTC/SCTP/association/StateCookie.hpp +2 -2
  25. package/worker/include/RTC/SCTP/association/StreamResetHandler.hpp +272 -0
  26. package/worker/include/RTC/SCTP/association/TCBContext.hpp +67 -0
  27. package/worker/include/RTC/SCTP/association/TransmissionControlBlock.hpp +81 -11
  28. package/worker/include/RTC/SCTP/common/UnwrappedSequenceNumber.hpp +274 -0
  29. package/worker/include/RTC/SCTP/packet/Chunk.hpp +0 -1
  30. package/worker/include/RTC/SCTP/packet/UserData.hpp +1 -0
  31. package/worker/include/RTC/SCTP/packet/parameters/IncomingSsnResetRequestParameter.hpp +14 -10
  32. package/worker/include/RTC/SCTP/packet/parameters/OutgoingSsnResetRequestParameter.hpp +14 -10
  33. package/worker/include/RTC/SCTP/packet/parameters/ZeroChecksumAcceptableParameter.hpp +13 -2
  34. package/worker/include/RTC/SCTP/public/AssociationInterface.hpp +7 -1
  35. package/worker/include/RTC/SCTP/public/AssociationListener.hpp +11 -0
  36. package/worker/include/RTC/SCTP/public/Message.hpp +1 -0
  37. package/worker/include/RTC/SCTP/public/SctpOptions.hpp +4 -4
  38. package/worker/include/RTC/SctpAssociation.hpp +2 -2
  39. package/worker/include/RTC/Transport.hpp +9 -13
  40. package/worker/include/Settings.hpp +2 -1
  41. package/worker/include/Utils.hpp +130 -6
  42. package/worker/meson.build +10 -39
  43. package/worker/meson_options.txt +0 -1
  44. package/worker/scripts/package-lock.json +6 -6
  45. package/worker/src/DepLibUring.cpp +1 -1
  46. package/worker/src/RTC/DataConsumer.cpp +5 -29
  47. package/worker/src/RTC/PipeTransport.cpp +15 -12
  48. package/worker/src/RTC/PlainTransport.cpp +15 -12
  49. package/worker/src/RTC/RTP/RetransmissionBuffer.cpp +5 -5
  50. package/worker/src/RTC/RTP/RtpStream.cpp +2 -2
  51. package/worker/src/RTC/RTP/RtxStream.cpp +1 -1
  52. package/worker/src/RTC/RateCalculator.cpp +5 -5
  53. package/worker/src/RTC/SCTP/association/Association.cpp +218 -148
  54. package/worker/src/RTC/SCTP/association/{AssociationDeferredListener.cpp → AssociationListenerDeferrer.cpp} +38 -30
  55. package/worker/src/RTC/SCTP/association/HeartbeatHandler.cpp +244 -0
  56. package/worker/src/RTC/SCTP/association/NegotiatedCapabilities.cpp +8 -6
  57. package/worker/src/RTC/SCTP/association/PacketSender.cpp +7 -2
  58. package/worker/src/RTC/SCTP/association/StateCookie.cpp +8 -8
  59. package/worker/src/RTC/SCTP/association/StreamResetHandler.cpp +512 -0
  60. package/worker/src/RTC/SCTP/association/TransmissionControlBlock.cpp +45 -39
  61. package/worker/src/RTC/SCTP/packet/chunks/SackChunk.cpp +1 -1
  62. package/worker/src/RTC/SCTP/packet/errorCauses/UserInitiatedAbortErrorCause.cpp +1 -1
  63. package/worker/src/RTC/SCTP/packet/parameters/IncomingSsnResetRequestParameter.cpp +22 -5
  64. package/worker/src/RTC/SCTP/packet/parameters/OutgoingSsnResetRequestParameter.cpp +22 -5
  65. package/worker/src/RTC/SCTP/tx/RetransmissionErrorCounter.cpp +1 -1
  66. package/worker/src/RTC/SctpAssociation.cpp +1 -2
  67. package/worker/src/RTC/SeqManager.cpp +4 -4
  68. package/worker/src/RTC/Transport.cpp +247 -134
  69. package/worker/src/RTC/WebRtcTransport.cpp +9 -5
  70. package/worker/src/Settings.cpp +21 -1
  71. package/worker/src/Worker.cpp +13 -10
  72. package/worker/src/lib.cpp +11 -8
  73. package/worker/tasks.py +2 -35
  74. package/worker/test/src/RTC/SCTP/association/TestNegotiatedCapabilities.cpp +13 -12
  75. package/worker/test/src/RTC/SCTP/association/TestStateCookie.cpp +20 -20
  76. package/worker/test/src/RTC/SCTP/common/TestUnwrappedSequenceNumber.cpp +210 -0
  77. package/worker/test/src/RTC/SCTP/packet/chunks/TestAbortAssociationChunk.cpp +2 -2
  78. package/worker/test/src/RTC/SCTP/packet/chunks/TestHeartbeatAckChunk.cpp +9 -4
  79. package/worker/test/src/RTC/SCTP/packet/chunks/TestHeartbeatRequestChunk.cpp +5 -0
  80. package/worker/test/src/RTC/SCTP/packet/chunks/TestInitAckChunk.cpp +1 -1
  81. package/worker/test/src/RTC/SCTP/packet/chunks/TestInitChunk.cpp +5 -5
  82. package/worker/test/src/RTC/SCTP/packet/chunks/TestReConfigChunk.cpp +19 -20
  83. package/worker/test/src/RTC/SCTP/packet/chunks/TestUnknownChunk.cpp +3 -0
  84. package/worker/test/src/RTC/SCTP/packet/errorCauses/TestUnknownErrorCause.cpp +3 -0
  85. package/worker/test/src/RTC/SCTP/packet/parameters/TestIncomingSsnResetRequestParameter.cpp +24 -27
  86. package/worker/test/src/RTC/SCTP/packet/parameters/TestOutgoingSsnResetRequestParameter.cpp +25 -30
  87. package/worker/test/src/RTC/SCTP/packet/parameters/TestStateCookieParameter.cpp +8 -6
  88. package/worker/test/src/RTC/SCTP/packet/parameters/TestSupportedExtensionsParameter.cpp +12 -0
  89. package/worker/test/src/RTC/SCTP/packet/parameters/TestZeroChecksumAcceptableParameter.cpp +5 -8
  90. package/worker/test/src/Utils/TestNumber.cpp +119 -49
  91. package/worker/test/src/tests.cpp +11 -8
@@ -0,0 +1,512 @@
1
+ #define MS_CLASS "RTC::SCTP::StreamResetHandler"
2
+ // TODO: SCTP: COMMENT
3
+ #define MS_LOG_DEV_LEVEL 3
4
+
5
+ #include "RTC/SCTP/association/StreamResetHandler.hpp"
6
+ #include "Logger.hpp"
7
+ #include "RTC/Consts.hpp"
8
+ #include "RTC/SCTP/packet/Parameter.hpp"
9
+ #include "RTC/SCTP/packet/parameters/ReconfigurationResponseParameter.hpp"
10
+
11
+ namespace RTC
12
+ {
13
+ namespace SCTP
14
+ {
15
+ /* Static. */
16
+
17
+ alignas(4) thread_local static uint8_t ChunkFactoryBuffer[RTC::Consts::MaxSafeMtuSizeForSctp];
18
+
19
+ /* Instance methods. */
20
+
21
+ StreamResetHandler::StreamResetHandler(
22
+ AssociationListener& associationListener, TCBContext* tcbContext
23
+ // TODO: SCTP: Implement
24
+ // DataTracker* dataTracker,
25
+ // ReassemblyQueue* reassemblyQueue,
26
+ // RetransmissionQueue* retransmissionQueue
27
+ )
28
+ : associationListener(associationListener),
29
+ tcbContext(tcbContext),
30
+ reConfigTimer(
31
+ std::make_unique<BackoffTimerHandle>(
32
+ /*listener*/ this,
33
+ /*baseTimeoutMs*/ 0,
34
+ /*backoffAlgorithm*/ BackoffTimerHandle::BackoffAlgorithm::EXPONENTIAL,
35
+ /*maxBackoffTimeoutMs*/ std::nullopt,
36
+ /*maxRestarts*/ std::nullopt)),
37
+ nextOutgoingReqSeqNbr(tcbContext->GetLocalInitialTsn()),
38
+ lastProcessedReqSeqNbr(
39
+ this->incomingReConfigRequestSnUnwrapper.Unwrap(tcbContext->GetRemoteInitialTsn() - 1)),
40
+ lastProcessedReqResult(ReconfigurationResponseParameter::Result::SUCCESS_NOTHING_TO_DO)
41
+ {
42
+ MS_TRACE();
43
+ }
44
+
45
+ StreamResetHandler::~StreamResetHandler()
46
+ {
47
+ MS_TRACE();
48
+ }
49
+
50
+ void StreamResetHandler::ResetStreams(std::span<const uint16_t> /*outgoingStreamIds*/)
51
+ {
52
+ MS_TRACE();
53
+
54
+ // TODO: SCTP: Uncomment.
55
+ // for (const auto streamId : outgoingStreamIds)
56
+ {
57
+ // TODO: SCTP: Implement it.
58
+ // this->retransmissionQueue->PrepareResetStream(streamId);
59
+ }
60
+ }
61
+
62
+ void StreamResetHandler::HandleReceivedReConfigChunk(const ReConfigChunk* receivedReConfigChunk)
63
+ {
64
+ MS_TRACE();
65
+
66
+ if (!ValidateReceivedReConfigChunk(receivedReConfigChunk))
67
+ {
68
+ this->associationListener.OnAssociationError(
69
+ Types::ErrorKind::PARSE_FAILED, "invalid RE-CONFIG command received");
70
+
71
+ return;
72
+ }
73
+
74
+ auto packet = this->tcbContext->CreatePacket();
75
+ auto* reConfigChunk = packet->BuildChunkInPlace<ReConfigChunk>();
76
+
77
+ for (auto it = receivedReConfigChunk->ParametersBegin();
78
+ it != receivedReConfigChunk->ParametersEnd();
79
+ ++it)
80
+ {
81
+ const auto* parameter = *it;
82
+
83
+ switch (parameter->GetType())
84
+ {
85
+ case Parameter::ParameterType::OUTGOING_SSN_RESET_REQUEST:
86
+ {
87
+ HandleReceivedOutgoingSsnResetRequestParameter(
88
+ reinterpret_cast<const OutgoingSsnResetRequestParameter*>(parameter), reConfigChunk);
89
+
90
+ break;
91
+ }
92
+
93
+ case Parameter::ParameterType::INCOMING_SSN_RESET_REQUEST:
94
+ {
95
+ HandleReceivedIncomingSsnResetRequestParameter(
96
+ reinterpret_cast<const IncomingSsnResetRequestParameter*>(parameter), reConfigChunk);
97
+
98
+ break;
99
+ }
100
+
101
+ case Parameter::ParameterType::RECONFIGURATION_RESPONSE:
102
+ {
103
+ HandleReceivedReconfigurationResponseParameter(
104
+ reinterpret_cast<const ReconfigurationResponseParameter*>(parameter));
105
+
106
+ break;
107
+ }
108
+
109
+ default:;
110
+ }
111
+ }
112
+
113
+ reConfigChunk->Consolidate();
114
+
115
+ if (reConfigChunk->GetParametersCount() > 0)
116
+ {
117
+ this->tcbContext->Send(packet.get());
118
+ }
119
+ }
120
+
121
+ bool StreamResetHandler::ValidateReceivedReConfigChunk(const ReConfigChunk* receivedReConfigChunk)
122
+ {
123
+ MS_TRACE();
124
+
125
+ if (receivedReConfigChunk->GetParametersCount() == 1)
126
+ {
127
+ const auto* firstParameter = receivedReConfigChunk->GetParameterAt(0);
128
+
129
+ if (
130
+ firstParameter->GetType() == Parameter::ParameterType::OUTGOING_SSN_RESET_REQUEST ||
131
+ firstParameter->GetType() == Parameter::ParameterType::INCOMING_SSN_RESET_REQUEST ||
132
+ firstParameter->GetType() == Parameter::ParameterType::SSN_TSN_RESET_REQUEST ||
133
+ firstParameter->GetType() == Parameter::ParameterType::ADD_OUTGOING_STREAMS_REQUEST ||
134
+ firstParameter->GetType() == Parameter::ParameterType::ADD_INCOMING_STREAMS_REQUEST ||
135
+ firstParameter->GetType() == Parameter::ParameterType::RECONFIGURATION_RESPONSE)
136
+ {
137
+ return true;
138
+ }
139
+ }
140
+ else if (receivedReConfigChunk->GetParametersCount() == 2)
141
+ {
142
+ const auto* firstParameter = receivedReConfigChunk->GetParameterAt(0);
143
+ const auto* secondParameter = receivedReConfigChunk->GetParameterAt(1);
144
+
145
+ if (
146
+ (firstParameter->GetType() == Parameter::ParameterType::OUTGOING_SSN_RESET_REQUEST &&
147
+ secondParameter->GetType() == Parameter::ParameterType::INCOMING_SSN_RESET_REQUEST) ||
148
+ (firstParameter->GetType() == Parameter::ParameterType::INCOMING_SSN_RESET_REQUEST &&
149
+ secondParameter->GetType() == Parameter::ParameterType::OUTGOING_SSN_RESET_REQUEST) ||
150
+ (firstParameter->GetType() == Parameter::ParameterType::ADD_OUTGOING_STREAMS_REQUEST &&
151
+ secondParameter->GetType() == Parameter::ParameterType::ADD_INCOMING_STREAMS_REQUEST) ||
152
+ (firstParameter->GetType() == Parameter::ParameterType::ADD_INCOMING_STREAMS_REQUEST &&
153
+ secondParameter->GetType() == Parameter::ParameterType::ADD_OUTGOING_STREAMS_REQUEST) ||
154
+ (firstParameter->GetType() == Parameter::ParameterType::RECONFIGURATION_RESPONSE &&
155
+ secondParameter->GetType() == Parameter::ParameterType::OUTGOING_SSN_RESET_REQUEST) ||
156
+ (firstParameter->GetType() == Parameter::ParameterType::OUTGOING_SSN_RESET_REQUEST &&
157
+ secondParameter->GetType() == Parameter::ParameterType::RECONFIGURATION_RESPONSE) ||
158
+ (firstParameter->GetType() == Parameter::ParameterType::RECONFIGURATION_RESPONSE &&
159
+ secondParameter->GetType() == Parameter::ParameterType::RECONFIGURATION_RESPONSE) ||
160
+ (firstParameter->GetType() == Parameter::ParameterType::RECONFIGURATION_RESPONSE &&
161
+ secondParameter->GetType() == Parameter::ParameterType::RECONFIGURATION_RESPONSE))
162
+ {
163
+ return true;
164
+ }
165
+ }
166
+
167
+ MS_WARN_TAG(sctp, "invalid set of RE-CONFIG Parameters");
168
+
169
+ return false;
170
+ }
171
+
172
+ ReConfigChunk* StreamResetHandler::CreateStreamResetRequest()
173
+ {
174
+ MS_TRACE();
175
+
176
+ // Only send stream resets if there are streams to reset, and no current
177
+ // ongoing request (there can only be one at a time), and if the stream
178
+ // can be reset.
179
+ // TODO: SCTP: Implement it.
180
+ // if (this->currentRequest.has_value() ||
181
+ // !this->retransmissionQueue->HasStreamsReadyToBeReset())
182
+ // {
183
+ // return nullptr;
184
+ // }
185
+
186
+ // TODO: SCTP: Implement it.
187
+ // this->currentRequest.emplace(
188
+ // this->retransmissionQueue->GetLastAssignedTsn(),
189
+ // this->retransmissionQueue->BeginResetStreams());
190
+
191
+ this->reConfigTimer->SetBaseTimeoutMs(this->tcbContext->GetCurrentRtoMs());
192
+ this->reConfigTimer->Start();
193
+
194
+ return CreateReconfigChunk();
195
+ }
196
+
197
+ ReConfigChunk* StreamResetHandler::CreateReconfigChunk()
198
+ {
199
+ MS_TRACE();
200
+
201
+ // The `reqSeqNbr` will be empty if the request has never been sent before,
202
+ // or if it was sent, but the sender responded "in progress", and then the
203
+ // `reqSeqNbr` will be cleared to re-send with a new number. But if the
204
+ // request is re-sent due to timeout (re-config timer expiring), the same
205
+ // `reqSeqNbr` will be used.
206
+ MS_ASSERT(this->currentRequest.has_value(), "currentRequest optional must have value");
207
+
208
+ if (this->currentRequest->HasBeenSent())
209
+ {
210
+ this->currentRequest->PrepareToSend(this->nextOutgoingReqSeqNbr);
211
+ this->nextOutgoingReqSeqNbr = uint32_t{ this->nextOutgoingReqSeqNbr + 1 };
212
+ }
213
+
214
+ auto* reConfigChunk = ReConfigChunk::Factory(ChunkFactoryBuffer, sizeof(ChunkFactoryBuffer));
215
+ auto* outgoingSsnResetRequestParameter =
216
+ reConfigChunk->BuildParameterInPlace<OutgoingSsnResetRequestParameter>();
217
+
218
+ outgoingSsnResetRequestParameter->SetReconfigurationRequestSequenceNumber(
219
+ this->currentRequest->GetReqSeqNbr());
220
+ outgoingSsnResetRequestParameter->SetReconfigurationResponseSequenceNumber(
221
+ this->currentRequest->GetReqSeqNbr());
222
+ outgoingSsnResetRequestParameter->SetSenderLastAssignedTsn(
223
+ this->currentRequest->GetSenderLastAssignedTsn());
224
+
225
+ for (const auto& streamId : this->currentRequest->GetStreamIds())
226
+ {
227
+ outgoingSsnResetRequestParameter->AddStreamId(streamId);
228
+ }
229
+
230
+ outgoingSsnResetRequestParameter->Consolidate();
231
+
232
+ return reConfigChunk;
233
+ }
234
+
235
+ StreamResetHandler::ReqSeqNbrValidationResult StreamResetHandler::ValidateReqSeqNbr(
236
+ StreamResetHandler::UnwrappedReConfigRequestSn reqSeqNbr)
237
+ {
238
+ MS_TRACE();
239
+
240
+ if (reqSeqNbr == this->lastProcessedReqSeqNbr)
241
+ {
242
+ return ReqSeqNbrValidationResult::RETRANSMISSION;
243
+ }
244
+ else if (reqSeqNbr != this->lastProcessedReqSeqNbr.GetNextValue())
245
+ {
246
+ // Too old, too new, from wrong Association, etc.
247
+ MS_WARN_TAG(sctp, "bad reqSeqNbr: %" PRIu32, reqSeqNbr.Wrap());
248
+
249
+ return ReqSeqNbrValidationResult::BAD_SEQUENCE_NUMBER;
250
+ }
251
+ else
252
+ {
253
+ return ReqSeqNbrValidationResult::VALID;
254
+ }
255
+ }
256
+
257
+ void StreamResetHandler::HandleReceivedOutgoingSsnResetRequestParameter(
258
+ const OutgoingSsnResetRequestParameter* receivedOutgoingSsnResetRequestParameter,
259
+ ReConfigChunk* reConfigChunk)
260
+ {
261
+ MS_TRACE();
262
+
263
+ const UnwrappedReConfigRequestSn requestSn = this->incomingReConfigRequestSnUnwrapper.Unwrap(
264
+ receivedOutgoingSsnResetRequestParameter->GetReconfigurationRequestSequenceNumber());
265
+ const ReqSeqNbrValidationResult validationResult = ValidateReqSeqNbr(requestSn);
266
+
267
+ if (validationResult == ReqSeqNbrValidationResult::BAD_SEQUENCE_NUMBER)
268
+ {
269
+ auto* reconfigurationResponseParameter =
270
+ reConfigChunk->BuildParameterInPlace<ReconfigurationResponseParameter>();
271
+
272
+ reconfigurationResponseParameter->SetReconfigurationResponseSequenceNumber(
273
+ receivedOutgoingSsnResetRequestParameter->GetReconfigurationRequestSequenceNumber());
274
+ reconfigurationResponseParameter->SetResult(
275
+ ReconfigurationResponseParameter::Result::ERROR_BAD_SEQUENCE_NUMBER);
276
+
277
+ reconfigurationResponseParameter->Consolidate();
278
+
279
+ return;
280
+ }
281
+
282
+ // If this is a retransmission of a request that has already been finalized
283
+ // (i.e., not "In Progress"), just send the previous final response.
284
+ if (
285
+ validationResult == ReqSeqNbrValidationResult::RETRANSMISSION &&
286
+ this->lastProcessedReqResult != ReconfigurationResponseParameter::Result::IN_PROGRESS)
287
+ {
288
+ auto* reconfigurationResponseParameter =
289
+ reConfigChunk->BuildParameterInPlace<ReconfigurationResponseParameter>();
290
+
291
+ reconfigurationResponseParameter->SetReconfigurationResponseSequenceNumber(
292
+ receivedOutgoingSsnResetRequestParameter->GetReconfigurationRequestSequenceNumber());
293
+ reconfigurationResponseParameter->SetResult(this->lastProcessedReqResult);
294
+
295
+ reconfigurationResponseParameter->Consolidate();
296
+
297
+ return;
298
+ }
299
+
300
+ // At this point, the request is either brand new, a buggy client sending
301
+ // a new SN after "In Progress", or a compliant client retransmitting an
302
+ // "In Progress" request. In all cases, re-evaluate the state.
303
+ this->lastProcessedReqSeqNbr = requestSn;
304
+
305
+ // // TODO: SCTP implement.
306
+ // if (this->dataTracker->IsLaterThanCumulativeAckedTsn(
307
+ // receivedOutgoingSsnResetRequestParameter->GetSenderLastAssignedTsn()))
308
+ // {
309
+ // // https://datatracker.ietf.org/doc/html/rfc6525#section-5.2.2
310
+ // //
311
+ // // E2) "If the Sender's Last Assigned TSN is greater than the cumulative
312
+ // // acknowledgment point, then the endpoint MUST enter 'deferred reset
313
+ // // processing'."
314
+ // this->reassemblyQueue->EnterDeferredReset(
315
+ // receivedOutgoingSsnResetRequestParameter->GetSenderLastAssignedTsn(),
316
+ // receivedOutgoingSsnResetRequestParameter->GetStreamIds());
317
+
318
+ // // "If the endpoint enters 'deferred reset processing', it MUST put a
319
+ // // Re-configuration Response Parameter into a RE-CONFIG chunk indicating
320
+ // // 'In progress' and MUST send the RE-CONFIG chunk.
321
+ // this->lastProcessedReqResult = ReconfigurationResponseParameter::Result::IN_PROGRESS;
322
+
323
+ // MS_DEBUG_DEV("reset outgoing in progress, sender last assigned tsn %" PRIu32 " not yet
324
+ // reached", receivedOutgoingSsnResetRequestParameter->GetSenderLastAssignedTsn());
325
+ // } else {
326
+ // // https://datatracker.ietf.org/doc/html/rfc6525#section-5.2.2
327
+ // //
328
+ // // E3) If no stream numbers are listed in the parameter, then all incoming
329
+ // // streams MUST be reset to 0 as the next expected SSN. If specific stream
330
+ // // numbers are listed, then only these specific streams MUST be reset to
331
+ // // 0, and all other non-listed SSNs remain unchanged. E4: Any queued TSNs
332
+ // // (queued at step E2) MUST now be released and processed normally.
333
+ // this->reassemblyQueue->ResetStreamsAndLeaveDeferredReset(receivedOutgoingSsnResetRequestParameter->GetStreamIds());
334
+
335
+ // this->associationListener.OnAssociationInboundStreamsReset(receivedOutgoingSsnResetRequestParameter->GetStreamIds());
336
+
337
+ // this->lastProcessedReqResult = ReconfigurationResponseParameter::Result::SUCCESS_PERFORMED;
338
+
339
+ // MS_DEBUG_DEV("reset outgoing performed");
340
+ // MS_DEBUG_DEV("reset outgoing performed, sender last assigned tsn %" PRIu32 " reached",
341
+ // receivedOutgoingSsnResetRequestParameter->GetSenderLastAssignedTsn());
342
+ // }
343
+
344
+ auto* reconfigurationResponseParameter =
345
+ reConfigChunk->BuildParameterInPlace<ReconfigurationResponseParameter>();
346
+
347
+ reconfigurationResponseParameter->SetReconfigurationResponseSequenceNumber(
348
+ receivedOutgoingSsnResetRequestParameter->GetReconfigurationRequestSequenceNumber());
349
+ reconfigurationResponseParameter->SetResult(this->lastProcessedReqResult);
350
+
351
+ reconfigurationResponseParameter->Consolidate();
352
+ }
353
+
354
+ void StreamResetHandler::HandleReceivedIncomingSsnResetRequestParameter(
355
+ const IncomingSsnResetRequestParameter* receivedIncomingSsnResetRequestParameter,
356
+ ReConfigChunk* reConfigChunk)
357
+ {
358
+ MS_TRACE();
359
+
360
+ const UnwrappedReConfigRequestSn requestSn = this->incomingReConfigRequestSnUnwrapper.Unwrap(
361
+ receivedIncomingSsnResetRequestParameter->GetReconfigurationRequestSequenceNumber());
362
+ const ReqSeqNbrValidationResult validationResult = ValidateReqSeqNbr(requestSn);
363
+
364
+ if (validationResult == ReqSeqNbrValidationResult::VALID || validationResult == ReqSeqNbrValidationResult::RETRANSMISSION)
365
+ {
366
+ auto* reconfigurationResponseParameter =
367
+ reConfigChunk->BuildParameterInPlace<ReconfigurationResponseParameter>();
368
+
369
+ reconfigurationResponseParameter->SetReconfigurationResponseSequenceNumber(
370
+ receivedIncomingSsnResetRequestParameter->GetReconfigurationRequestSequenceNumber());
371
+ reconfigurationResponseParameter->SetResult(
372
+ ReconfigurationResponseParameter::Result::SUCCESS_NOTHING_TO_DO);
373
+
374
+ reconfigurationResponseParameter->Consolidate();
375
+ }
376
+ else
377
+ {
378
+ auto* reconfigurationResponseParameter =
379
+ reConfigChunk->BuildParameterInPlace<ReconfigurationResponseParameter>();
380
+
381
+ reconfigurationResponseParameter->SetReconfigurationResponseSequenceNumber(
382
+ receivedIncomingSsnResetRequestParameter->GetReconfigurationRequestSequenceNumber());
383
+ reconfigurationResponseParameter->SetResult(
384
+ ReconfigurationResponseParameter::Result::ERROR_BAD_SEQUENCE_NUMBER);
385
+
386
+ reconfigurationResponseParameter->Consolidate();
387
+ }
388
+ }
389
+
390
+ void StreamResetHandler::HandleReceivedReconfigurationResponseParameter(
391
+ const ReconfigurationResponseParameter* receivedReconfigurationResponseParameter)
392
+
393
+ {
394
+ MS_TRACE();
395
+
396
+ if (
397
+ this->currentRequest.has_value() && this->currentRequest->HasBeenSent() &&
398
+ receivedReconfigurationResponseParameter->GetReconfigurationResponseSequenceNumber() ==
399
+ this->currentRequest->GetReqSeqNbr())
400
+ {
401
+ this->reConfigTimer->Stop();
402
+
403
+ switch (receivedReconfigurationResponseParameter->GetResult())
404
+ {
405
+ case RTC::SCTP::ReconfigurationResponseParameter::Result::SUCCESS_NOTHING_TO_DO:
406
+ case RTC::SCTP::ReconfigurationResponseParameter::Result::SUCCESS_PERFORMED:
407
+ {
408
+ MS_DEBUG_DEV(
409
+ "reset stream success [reqSeqNbr:%" PRIu32 "]", this->currentRequest->GetReqSeqNbr());
410
+
411
+ this->associationListener.OnAssociationStreamsResetPerformed(
412
+ this->currentRequest->GetStreamIds());
413
+
414
+ this->currentRequest = std::nullopt;
415
+
416
+ // TODO: SCTP: Implement it.
417
+ // this->retransmissionQueue->CommitResetSteam();
418
+
419
+ break;
420
+ }
421
+
422
+ case RTC::SCTP::ReconfigurationResponseParameter::Result::IN_PROGRESS:
423
+ {
424
+ MS_DEBUG_DEV(
425
+ "reset stream still pending [reqSeqNbr:%" PRIu32 "]",
426
+ this->currentRequest->GetReqSeqNbr());
427
+
428
+ // Force this request to be sent again, but with the same `reqSeqNbr`.
429
+ this->currentRequest->SetDeferred(true);
430
+
431
+ this->reConfigTimer->SetBaseTimeoutMs(this->tcbContext->GetCurrentRtoMs());
432
+ this->reConfigTimer->Start();
433
+
434
+ break;
435
+ }
436
+
437
+ case RTC::SCTP::ReconfigurationResponseParameter::Result::ERROR_REQUEST_ALREADY_IN_PROGRESS:
438
+ case RTC::SCTP::ReconfigurationResponseParameter::Result::DENIED:
439
+ case RTC::SCTP::ReconfigurationResponseParameter::Result::ERROR_WRONG_SSN:
440
+ case RTC::SCTP::ReconfigurationResponseParameter::Result::ERROR_BAD_SEQUENCE_NUMBER:
441
+ {
442
+ MS_WARN_TAG(
443
+ sctp,
444
+ "reset stream error [reqSeqNbr:%" PRIu32 ", result:%s]",
445
+ this->currentRequest->GetReqSeqNbr(),
446
+ ReconfigurationResponseParameter::ResultToString(
447
+ receivedReconfigurationResponseParameter->GetResult())
448
+ .c_str());
449
+
450
+ this->associationListener.OnAssociationStreamsResetFailed(
451
+ this->currentRequest->GetStreamIds(),
452
+ ReconfigurationResponseParameter::ResultToString(
453
+ receivedReconfigurationResponseParameter->GetResult()));
454
+
455
+ this->currentRequest = std::nullopt;
456
+
457
+ // TODO: SCTP: Implement it.
458
+ // this->retransmissionQueue->RollbackResetStreams();
459
+
460
+ break;
461
+ }
462
+ }
463
+ }
464
+ }
465
+
466
+ void StreamResetHandler::OnReConfigTimer(uint64_t& baseTimeoutMs, bool& /*stop*/)
467
+ {
468
+ MS_TRACE();
469
+
470
+ if (this->currentRequest && this->currentRequest->HasBeenSent())
471
+ {
472
+ // The request was deferred (received "In Progress"). This is not a
473
+ // timeout, but just time to retry.
474
+ if (this->currentRequest->IsDeferred())
475
+ {
476
+ this->currentRequest->SetDeferred(false);
477
+ }
478
+ // There is an outstanding request, which timed out while waiting for a
479
+ // response.
480
+ else if (!this->tcbContext->IncrementTxErrorCounter("RECONFIG timeout"))
481
+ {
482
+ // Timed out. The connection will close after processing the timers.
483
+ return;
484
+ }
485
+ }
486
+ else
487
+ {
488
+ // There is no outstanding request, but there is a prepared one. This means
489
+ // that the receiver has previously responded "in progress", which resulted
490
+ // in retrying the request (but with a new `reqSeqNbr`) after a while.
491
+ }
492
+
493
+ auto packet = this->tcbContext->CreatePacket();
494
+
495
+ packet->AddChunk(CreateReconfigChunk());
496
+
497
+ this->tcbContext->Send(packet.get());
498
+
499
+ baseTimeoutMs = this->tcbContext->GetCurrentRtoMs();
500
+ }
501
+
502
+ void StreamResetHandler::OnTimer(BackoffTimerHandle* backoffTimer, uint64_t& baseTimeoutMs, bool& stop)
503
+ {
504
+ MS_TRACE();
505
+
506
+ if (backoffTimer == this->reConfigTimer.get())
507
+ {
508
+ OnReConfigTimer(baseTimeoutMs, stop);
509
+ }
510
+ }
511
+ } // namespace SCTP
512
+ } // namespace RTC
@@ -1,10 +1,13 @@
1
1
  #define MS_CLASS "RTC::SCTP::TransmissionControlBlock"
2
- // #define MS_LOG_DEV_LEVEL 3
2
+ // TODO: SCTP: COMMENT
3
+ #define MS_LOG_DEV_LEVEL 3
3
4
 
4
5
  #include "RTC/SCTP/association/TransmissionControlBlock.hpp"
5
6
  #include "DepLibUV.hpp"
6
7
  #include "Logger.hpp"
8
+ #include "RTC/Consts.hpp"
7
9
  #include <cmath> // std::min()
10
+ #include <string>
8
11
 
9
12
  namespace RTC
10
13
  {
@@ -26,7 +29,8 @@ namespace RTC
26
29
  uint32_t remoteInitialTsn,
27
30
  uint32_t remoteAdvertisedReceiverWindowCredit,
28
31
  uint64_t tieTag,
29
- const NegotiatedCapabilities& negotiatedCapabilities)
32
+ const NegotiatedCapabilities& negotiatedCapabilities,
33
+ std::function<bool()> isAssociationEstablished)
30
34
  : associationListener(associationListener),
31
35
  sctpOptions(sctpOptions),
32
36
  packetSender(packetSender),
@@ -37,6 +41,7 @@ namespace RTC
37
41
  remoteAdvertisedReceiverWindowCredit(remoteAdvertisedReceiverWindowCredit),
38
42
  tieTag(tieTag),
39
43
  negotiatedCapabilities(negotiatedCapabilities),
44
+ isAssociationEstablished(std::move(isAssociationEstablished)),
40
45
  t3RtxTimer(
41
46
  std::make_unique<BackoffTimerHandle>(
42
47
  /*listener*/ this,
@@ -52,7 +57,8 @@ namespace RTC
52
57
  /*maxBackoffTimeoutMs*/ std::nullopt,
53
58
  /*maxRestarts*/ 0)),
54
59
  rto(sctpOptions),
55
- txErrorCounter(sctpOptions)
60
+ txErrorCounter(sctpOptions),
61
+ heartbeatHandler(this->associationListener, sctpOptions, this)
56
62
  {
57
63
  MS_TRACE();
58
64
  }
@@ -102,16 +108,14 @@ namespace RTC
102
108
  rtt,
103
109
  prevRtoMs,
104
110
  this->rto.GetRtoMs(),
105
- this - rto.GetSrttMs());
111
+ this->rto.GetSrttMs());
106
112
 
107
113
  this->t3RtxTimer->SetBaseTimeoutMs(this->rto.GetRtoMs());
108
- this->t3RtxTimer->Start();
109
114
 
110
115
  const uint64_t delayedAckTimeoutMs = std::min(
111
116
  static_cast<uint64_t>(this->rto.GetRtoMs() * 0.5), this->sctpOptions.delayedAckMaxTimeoutMs);
112
117
 
113
118
  this->delayedAckTimer->SetBaseTimeoutMs(delayedAckTimeoutMs);
114
- this->delayedAckTimer->Start();
115
119
  }
116
120
 
117
121
  std::unique_ptr<Packet> TransmissionControlBlock::CreatePacket() const
@@ -136,6 +140,15 @@ namespace RTC
136
140
  return packet;
137
141
  }
138
142
 
143
+ void TransmissionControlBlock::Send(Packet* packet)
144
+ {
145
+ MS_TRACE();
146
+
147
+ this->packetSender.SendPacket(
148
+ packet,
149
+ /*writeChecksum*/ !this->negotiatedCapabilities.zeroChecksum);
150
+ }
151
+
139
152
  void TransmissionControlBlock::SetRemoteStateCookie(std::vector<uint8_t> remoteStateCookie)
140
153
  {
141
154
  MS_TRACE();
@@ -154,26 +167,19 @@ namespace RTC
154
167
  {
155
168
  MS_TRACE();
156
169
 
157
- // TODO: Implement it.
158
- // if (this->dataTracker.ShouldSendAckChunk(/*alsoIfDelayed*/ false))
170
+ // TODO: SCTP: Implement it.
171
+ // if (!this->dataTracker.ShouldSendAckChunk(/*alsoIfDelayed*/ false))
159
172
  // {
160
- // auto packet = CreatePacket();
161
-
162
- // // TODO: Here we must create a SackChunk in the Packet, however the
163
- // // SackChunk is in theory generated by this->dataTracker... Let's see.
164
- // builder.Add(this->dataTracker.CreateSelectiveAck(this->reassemblyQueue.GetRemainingBytes()));
165
-
166
- // Send(packet.get());
173
+ // return;
167
174
  // }
168
- }
169
175
 
170
- void TransmissionControlBlock::Send(Packet* packet)
171
- {
172
- MS_TRACE();
176
+ // auto packet = CreatePacket();
173
177
 
174
- this->packetSender.SendPacket(
175
- packet,
176
- /*writeChecksum*/ !this->negotiatedCapabilities.zeroChecksum);
178
+ // TODO: SCTP: Here we must create a SackChunk in the Packet, however the
179
+ // SackChunk is in theory generated by this->dataTracker... Let's see.
180
+ // builder.Add(this->dataTracker.CreateSelectiveAck(this->reassemblyQueue.GetRemainingBytes()));
181
+
182
+ // Send(packet.get());
177
183
  }
178
184
 
179
185
  void TransmissionControlBlock::OnT3RtxTimer(uint64_t& /*baseTimeoutMs*/, bool& /*stop*/)
@@ -190,22 +196,23 @@ namespace RTC
190
196
 
191
197
  // In the COOKIE_ECHO state, let the T1-COOKIE timer trigger
192
198
  // retransmissions, to avoid having two timers doing that.
193
- // TODO: Implement it.
194
- // if (this->cookieEchoChunk.has_value())
195
- // {
196
- // MS_DEBUG_DEV("not retransmitting as T1-cookie is active");
197
- // }
198
- // else
199
- // {
200
- // if (IncrementTxErrorCounter("t3-rtx expired"))
201
- // {
202
- // this->retransmissionQueue.HandleT3RtxTimerExpiry();
199
+ if (this->remoteStateCookie.has_value())
200
+ {
201
+ MS_DEBUG_DEV("not retransmitting as T1-cookie is active");
202
+ }
203
+ else
204
+ {
205
+ if (IncrementTxErrorCounter("t3-rtx expired"))
206
+ {
207
+ // TODO: SCTP: Implement
208
+ // this->retransmissionQueue.HandleT3RtxTimerExpiry();
203
209
 
204
- // const uint64_t now = DepLibUV::GetTimeMs();
210
+ // const uint64_t now = DepLibUV::GetTimeMs();
205
211
 
206
- // SendBufferedPackets(now);
207
- // }
208
- // }
212
+ // TODO: SCTP: Implement
213
+ // SendBufferedPackets(now);
214
+ }
215
+ }
209
216
  }
210
217
 
211
218
  void TransmissionControlBlock::OnDelayedAckTimer(uint64_t& /*baseTimeoutMs*/, bool& /*stop*/)
@@ -220,11 +227,10 @@ namespace RTC
220
227
  this->delayedAckTimer->GetExpirationCount(),
221
228
  maxRestarts ? std::to_string(maxRestarts.value()).c_str() : "Infinite");
222
229
 
223
- // TODO: Implement it.
230
+ // TODO: SCTP: Implement it.
224
231
  // this->dataTracker.HandleDelayedAckTimerExpiry();
225
232
 
226
- // TODO: Implement it.
227
- // MaySendSackChunk();
233
+ MaySendSackChunk();
228
234
  }
229
235
 
230
236
  void TransmissionControlBlock::OnTimer(
@@ -233,7 +233,7 @@ namespace RTC
233
233
 
234
234
  duplicateTsns.reserve(numberOfDuplicateTsns);
235
235
 
236
- for (uint32_t idx{ 0 }; idx < GetNumberOfDuplicateTsns(); ++idx)
236
+ for (uint32_t idx{ 0 }; idx < numberOfDuplicateTsns; ++idx)
237
237
  {
238
238
  duplicateTsns.emplace_back(GetDuplicateTsnAt(idx));
239
239
  }
@@ -97,7 +97,7 @@ namespace RTC
97
97
  MS_DUMP_CLEAN(indentation, " has upper layer abort reason: yes");
98
98
  MS_DUMP_CLEAN(
99
99
  indentation,
100
- " upper layer abort reason: %.*s",
100
+ " upper layer abort reason: \"%.*s\"",
101
101
  static_cast<int>(reason.size()),
102
102
  reason.data());
103
103
  }