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
@@ -41,11 +41,10 @@ namespace RTC
41
41
 
42
42
  Association::Association(const SctpOptions& sctpOptions, AssociationListener* listener)
43
43
  : sctpOptions(sctpOptions),
44
- // Our `listener` member is a `AssociationDeferredListener` which takes
44
+ // Our `listener` member is a `AssociationListenerDeferrer` which takes
45
45
  // `AssociationListener` as constructor argument.
46
46
  listener(listener),
47
- // Create the `packetSender` member.
48
- packetSender(*this, this->listener),
47
+ packetSender(this, this->listener),
49
48
  t1InitTimer(
50
49
  std::make_unique<BackoffTimerHandle>(
51
50
  /*listener*/ this,
@@ -67,7 +66,6 @@ namespace RTC
67
66
  /*backoffAlgorithm*/ BackoffTimerHandle::BackoffAlgorithm::EXPONENTIAL,
68
67
  /*maxBackoffTimeoutMs*/ sctpOptions.timerMaxBackoffTimeoutMs,
69
68
  /*maxRestarts*/ sctpOptions.maxRetransmissions))
70
- // TODO: Set RRSendQueue this->sendQueue.
71
69
  {
72
70
  MS_TRACE();
73
71
  }
@@ -121,11 +119,11 @@ namespace RTC
121
119
  // Add OS.
122
120
  // TODO: SCTP: We should put here current value which may be different after
123
121
  // negotiation with peer and reconfig.
124
- this->sctpOptions.maxOutboundStreams,
122
+ this->sctpOptions.announcedMaxOutboundStreams,
125
123
  // Add MIS.
126
124
  // TODO: SCTP: We should put here current value which may be different after
127
125
  // negotiation with peer and reconfig.
128
- this->sctpOptions.maxInboundStreams,
126
+ this->sctpOptions.announcedMaxInboundStreams,
129
127
  // Add maxMessageSize.
130
128
  this->sctpOptions.maxSendMessageSize,
131
129
  // Add sendBufferSize.
@@ -134,6 +132,7 @@ namespace RTC
134
132
  this->sctpOptions.totalBufferedAmountLowThreshold,
135
133
  // Add isDataChannel.
136
134
  // TODO: SCTP: Have a member for this.
135
+ // TODO: SCTP: So remove this hardcoded `true`.
137
136
  /*isDataChannel*/ true);
138
137
  }
139
138
 
@@ -176,26 +175,55 @@ namespace RTC
176
175
  }
177
176
  }
178
177
 
178
+ void Association::MayConnect()
179
+ {
180
+ MS_TRACE();
181
+
182
+ // Just run the SCTP stack if our state is 'new'.
183
+ // Notice that once MayConnect() is called (and the code below is executed),
184
+ // SCTP state will no longer be "NEW".
185
+ if (this->state != State::NEW)
186
+ {
187
+ MS_DEBUG_DEV("internal Association state is not NEW, ignoring");
188
+
189
+ return;
190
+ }
191
+
192
+ // If we haven't received any SCTP packet yet and the transport is not
193
+ // ready for SCTP traffic, don't do anything.
194
+ if (this->privateMetrics.rxPacketsCount == 0 && !this->listener.OnAssociationIsTransportReadyForSctp())
195
+ {
196
+ MS_DEBUG_DEV(
197
+ "no SCTP data has been received yet and transport is not ready for SCTP traffic, ignoring");
198
+
199
+ return;
200
+ }
201
+
202
+ MS_DEBUG_DEV("invoking Connect()");
203
+
204
+ Connect();
205
+ }
206
+
179
207
  void Association::Connect()
180
208
  {
181
209
  MS_TRACE();
182
210
 
183
- // NOTE: We could only accept NEW state here so once closed the Association
184
- // cannot be reused. However there is no real technical reason for it.
185
- if (this->state != State::NEW && this->state != State::CLOSED)
211
+ // NOTE: We only accept NEW state here so once the Association is closed
212
+ // it cannot be reused. However there is no real technical reason for it.
213
+ if (this->state != State::NEW)
186
214
  {
187
215
  const auto stateStringView = Association::StateToString(this->state);
188
216
 
189
217
  MS_WARN_TAG(
190
218
  sctp,
191
- "cannot initiate the Association since internal state is not NEW or CLOSED but %.*s",
219
+ "cannot initiate the Association since internal state is not NEW but %.*s",
192
220
  static_cast<int>(stateStringView.size()),
193
221
  stateStringView.data());
194
222
 
195
223
  return;
196
224
  }
197
225
 
198
- const AssociationDeferredListener::ScopedDeferred deferrer(this->listener);
226
+ const AssociationListenerDeferrer::ScopedDeferrer deferrer(this->listener);
199
227
 
200
228
  this->preTcb.localVerificationTag =
201
229
  Utils::Crypto::GetRandomUInt<uint32_t>(MinVerificationTag, MaxVerificationTag);
@@ -224,7 +252,7 @@ namespace RTC
224
252
  return;
225
253
  }
226
254
 
227
- const AssociationDeferredListener::ScopedDeferred deferrer(this->listener);
255
+ const AssociationListenerDeferrer::ScopedDeferrer deferrer(this->listener);
228
256
 
229
257
  // https://datatracker.ietf.org/doc/html/rfc9260#section-9.2
230
258
  //
@@ -233,12 +261,14 @@ namespace RTC
233
261
  // outstanding data has been acknowledged by its peer."
234
262
  if (this->tcb)
235
263
  {
236
- // TODO: Remove this check, as it just hides the problem that the
264
+ // TODO: dcsctp: Remove this check, as it just hides the problem that the
237
265
  // Association can transition from ShutdownSent to ShutdownPending, or
238
266
  // from ShutdownAckSent to ShutdownPending, which is illegal.
239
267
  //
240
268
  // @see https://issues.webrtc.org/issues/42222897
241
- if (this->state != State::SHUTDOWN_SENT && this->state != State::SHUTDOWN_ACK_SENT)
269
+ if (
270
+ this->state != State::SHUTDOWN_SENT && this->state != State::SHUTDOWN_ACK_SENT &&
271
+ this->state != State::SHUTDOWN_RECEIVED && this->state != State::SHUTDOWN_PENDING)
242
272
  {
243
273
  this->t1InitTimer->Stop();
244
274
  this->t1CookieTimer->Stop();
@@ -271,7 +301,7 @@ namespace RTC
271
301
  return;
272
302
  }
273
303
 
274
- const AssociationDeferredListener::ScopedDeferred deferrer(this->listener);
304
+ const AssociationListenerDeferrer::ScopedDeferrer deferrer(this->listener);
275
305
 
276
306
  if (this->tcb)
277
307
  {
@@ -306,7 +336,7 @@ namespace RTC
306
336
  // const size_t packetPayloadLength =
307
337
  // this->sctpOptions.mtu - Packet::CommonHeaderLength - DataChunk::DataChunkHeaderLength;
308
338
 
309
- // TODO: Implement missing fields.
339
+ // TODO: SCTP: Implement missing fields.
310
340
  AssociationMetrics metrics{
311
341
  .txPacketsCount = this->privateMetrics.txPacketsCount,
312
342
  .txMessagesCount = this->privateMetrics.txMessagesCount,
@@ -337,10 +367,10 @@ namespace RTC
337
367
  {
338
368
  MS_TRACE();
339
369
 
340
- // TODO: Implement it.
370
+ // TODO: SCTP: Implement it.
341
371
  // return this->sendQueue.GetStreamPriority(streamId);
342
372
 
343
- // TODO: Remove.
373
+ // TODO: SCTP: Remove.
344
374
  return 0;
345
375
  }
346
376
 
@@ -348,7 +378,7 @@ namespace RTC
348
378
  {
349
379
  MS_TRACE();
350
380
 
351
- // TODO: Implement it.
381
+ // TODO: SCTP: Implement it.
352
382
  // this->sendQueue.SetStreamPriority(streamId, priority);
353
383
  }
354
384
 
@@ -363,10 +393,10 @@ namespace RTC
363
393
  {
364
394
  MS_TRACE();
365
395
 
366
- // TODO: Implement it.
396
+ // TODO: SCTP: Implement it.
367
397
  // return this->sendQueue.GetStreamBufferedAmount(streamId);
368
398
 
369
- // TODO: Remove.
399
+ // TODO: SCTP: Remove.
370
400
  return 0;
371
401
  }
372
402
 
@@ -374,10 +404,10 @@ namespace RTC
374
404
  {
375
405
  MS_TRACE();
376
406
 
377
- // TODO: Implement it.
407
+ // TODO: SCTP: Implement it.
378
408
  // return this->sendQueue.GetStreamBufferedAmountLowThreshold(streamId);
379
409
 
380
- // TODO: Remove.
410
+ // TODO: SCTP: Remove.
381
411
  return 0;
382
412
  }
383
413
 
@@ -385,7 +415,7 @@ namespace RTC
385
415
  {
386
416
  MS_TRACE();
387
417
 
388
- // TODO: Implement it.
418
+ // TODO: SCTP: Implement it.
389
419
  // this->sendQueue.SetBufferedAmountLowThreshold(streamId, bytes);
390
420
  }
391
421
 
@@ -393,13 +423,13 @@ namespace RTC
393
423
  {
394
424
  MS_TRACE();
395
425
 
396
- const AssociationDeferredListener::ScopedDeferred deferrer(this->listener);
426
+ const AssociationListenerDeferrer::ScopedDeferrer deferrer(this->listener);
397
427
 
398
428
  if (!this->tcb)
399
429
  {
400
430
  this->listener.OnAssociationError(
401
431
  Types::ErrorKind::WRONG_SEQUENCE,
402
- "cannot reset outbound streams as the Association is not connected");
432
+ "cannot reset outbound streams as the association is not connected");
403
433
 
404
434
  return Types::ResetStreamsStatus::NOT_CONNECTED;
405
435
  }
@@ -413,7 +443,7 @@ namespace RTC
413
443
  return Types::ResetStreamsStatus::NOT_SUPPORTED;
414
444
  }
415
445
 
416
- // TODO: Implement it.
446
+ // TODO: SCTP: Implement it.
417
447
  // this->tcb->GetStreamResetHandler().ResetStreams(outboundStreamIds);
418
448
 
419
449
  MaySendResetStreamsRequest();
@@ -427,7 +457,7 @@ namespace RTC
427
457
  {
428
458
  MS_TRACE();
429
459
 
430
- const AssociationDeferredListener::ScopedDeferred deferrer(this->listener);
460
+ const AssociationListenerDeferrer::ScopedDeferrer deferrer(this->listener);
431
461
 
432
462
  const auto status = InternalSendMessage(message, sendMessageOptions);
433
463
 
@@ -436,17 +466,17 @@ namespace RTC
436
466
  return status;
437
467
  }
438
468
 
439
- // TODO: Uncomment.
469
+ // TODO: SCTP: Uncomment.
440
470
  // const uint64_t now = DepLibUV::GetTimeMs();
441
471
 
442
472
  this->privateMetrics.txMessagesCount++;
443
473
 
444
- // TODO: Implement it.
474
+ // TODO: SCTP: Implement it.
445
475
  // this->sendQueue.AddMessage(now, std::move(message), sendMessageOptions);
446
476
 
447
477
  if (this->tcb)
448
478
  {
449
- // TODO: Implement it.
479
+ // TODO: SCTP: Implement it.
450
480
  // this->tcb->SendBufferedPackets(now);
451
481
  }
452
482
 
@@ -460,9 +490,9 @@ namespace RTC
460
490
  {
461
491
  MS_TRACE();
462
492
 
463
- const AssociationDeferredListener::ScopedDeferred deferrer(this->listener);
493
+ const AssociationListenerDeferrer::ScopedDeferrer deferrer(this->listener);
464
494
 
465
- // TODO: Uncomment.
495
+ // TODO: SCTP: Uncomment.
466
496
  // const uint64_t now = DepLibUV::GetTimeMs();
467
497
  std::vector<Types::SendMessageStatus> statuses;
468
498
 
@@ -481,13 +511,13 @@ namespace RTC
481
511
 
482
512
  this->privateMetrics.txMessagesCount++;
483
513
 
484
- // TODO: Implement it.
514
+ // TODO: SCTP: Implement it.
485
515
  // this->sendQueue.AddMessage(now, std::move(message), sendMessageOptions);
486
516
  }
487
517
 
488
518
  if (this->tcb)
489
519
  {
490
- // TODO: Implement it.
520
+ // TODO: SCTP: Implement it.
491
521
  // this->tcb->SendBufferedPackets(now);
492
522
  }
493
523
 
@@ -518,10 +548,17 @@ namespace RTC
518
548
  }
519
549
  }
520
550
 
521
- const AssociationDeferredListener::ScopedDeferred deferrer(this->listener);
522
-
523
551
  this->privateMetrics.rxPacketsCount++;
524
552
 
553
+ // If we are received SCTP data from the remote peer it means that we may
554
+ // initiate the SCTP association (if not already connected).
555
+ MayConnect();
556
+
557
+ // NOTE: It's important to create the deferrer here, otherwise it may
558
+ // happen that MayConnect() ends calling to Connect() so we end with two
559
+ // nested deferreds (and hence an assertion).
560
+ const AssociationListenerDeferrer::ScopedDeferrer deferrer(this->listener);
561
+
525
562
  std::unique_ptr<Packet> receivedPacket{ Packet::Parse(data, len) };
526
563
 
527
564
  if (!receivedPacket)
@@ -549,7 +586,7 @@ namespace RTC
549
586
  {
550
587
  const auto* receivedChunk = *it;
551
588
 
552
- if (!ProcessReceivedChunk(receivedPacket.get(), receivedChunk))
589
+ if (!HandleReceivedChunk(receivedPacket.get(), receivedChunk))
553
590
  {
554
591
  break;
555
592
  }
@@ -557,7 +594,7 @@ namespace RTC
557
594
 
558
595
  if (this->tcb)
559
596
  {
560
- // TODO: Implement it.
597
+ // TODO: SCTP: Implement it.
561
598
  // this->tcb->GetDadaTracker().ObservePacketEnd();
562
599
  this->tcb->MaySendSackChunk();
563
600
  }
@@ -608,7 +645,7 @@ namespace RTC
608
645
  if (state == this->state)
609
646
  {
610
647
  MS_WARN_DEV(
611
- "SCTP Association internal state is already %.*s (message: %.*s)",
648
+ "SCTP Association internal state is already %.*s (message:\"%.*s\")",
612
649
  static_cast<int>(stateStringView.size()),
613
650
  stateStringView.data(),
614
651
  static_cast<int>(message.size()),
@@ -621,7 +658,7 @@ namespace RTC
621
658
 
622
659
  MS_DEBUG_TAG(
623
660
  sctp,
624
- "SCTP Association internal state changed from %.*s to %.*s (message: %.*s)",
661
+ "SCTP Association internal state changed from %.*s to %.*s (message:\"%.*s\")",
625
662
  static_cast<int>(previousStateStringView.size()),
626
663
  previousStateStringView.data(),
627
664
  static_cast<int>(stateStringView.size()),
@@ -696,11 +733,17 @@ namespace RTC
696
733
  remoteInitialTsn,
697
734
  remoteAdvertisedReceiverWindowCredit,
698
735
  tieTag,
699
- negotiatedCapabilities);
700
-
701
- this->privateMetrics.negotiatedMaxOutboundStreams = negotiatedCapabilities.maxOutboundStreams;
702
- this->privateMetrics.negotiatedMaxInboundStreams = negotiatedCapabilities.maxInboundStreams;
703
- this->privateMetrics.usesPartialReliability = negotiatedCapabilities.partialReliability;
736
+ negotiatedCapabilities,
737
+ [this]()
738
+ {
739
+ return this->state == State::ESTABLISHED;
740
+ });
741
+
742
+ this->privateMetrics.negotiatedMaxOutboundStreams =
743
+ negotiatedCapabilities.negotiatedMaxOutboundStreams;
744
+ this->privateMetrics.negotiatedMaxInboundStreams =
745
+ negotiatedCapabilities.negotiatedMaxInboundStreams;
746
+ this->privateMetrics.usesPartialReliability = negotiatedCapabilities.partialReliability;
704
747
  this->privateMetrics.usesMessageInterleaving = negotiatedCapabilities.messageInterleaving;
705
748
  this->privateMetrics.usesReConfig = negotiatedCapabilities.reConfig;
706
749
  this->privateMetrics.usesZeroChecksum = negotiatedCapabilities.zeroChecksum;
@@ -738,8 +781,8 @@ namespace RTC
738
781
 
739
782
  initChunk->SetInitiateTag(this->preTcb.localVerificationTag);
740
783
  initChunk->SetAdvertisedReceiverWindowCredit(this->sctpOptions.maxReceiverWindowBufferSize);
741
- initChunk->SetNumberOfOutboundStreams(this->sctpOptions.maxOutboundStreams);
742
- initChunk->SetNumberOfInboundStreams(this->sctpOptions.maxInboundStreams);
784
+ initChunk->SetNumberOfOutboundStreams(this->sctpOptions.announcedMaxOutboundStreams);
785
+ initChunk->SetNumberOfInboundStreams(this->sctpOptions.announcedMaxInboundStreams);
743
786
  initChunk->SetInitialTsn(this->preTcb.localInitialTsn);
744
787
 
745
788
  // Insert capabilities related Parameters in the INIT Chunk.
@@ -763,7 +806,7 @@ namespace RTC
763
806
  auto packet = this->tcb->CreatePacket();
764
807
  const auto* shutdownChunk = packet->BuildChunkInPlace<ShutdownChunk>();
765
808
 
766
- // TODO: Implement it.
809
+ // TODO: SCTP: Implement it.
767
810
  // shutdownChunk->SetCumulativeTsnAck(this->tcb->GetDataTracker().GetLastCumulativeAckedTsn());
768
811
  shutdownChunk->Consolidate();
769
812
 
@@ -793,7 +836,7 @@ namespace RTC
793
836
 
794
837
  AssertHasTcb();
795
838
 
796
- // TODO: Implement it.
839
+ // TODO: SCTP: Implement it.
797
840
  // if (this->tcb->GetRetransmissionQueue().GetUnackedItems() != 0) {
798
841
  // return;
799
842
  // }
@@ -870,7 +913,7 @@ namespace RTC
870
913
 
871
914
  AssertHasTcb();
872
915
 
873
- // TODO: I don't like this. I don't want to use Packet::AddChunk() (which
916
+ // TODO: SCTP: I don't like this. I don't want to use Packet::AddChunk() (which
874
917
  // clones the given Chunk). I want to use Packet::BuildChunkInPlace() so
875
918
  // we need that `tcb->GetStreamResetHandler().MakeStreamResetRequest()`
876
919
  // doesn't return a `ReConfigChunk` but something different such as the
@@ -909,7 +952,7 @@ namespace RTC
909
952
 
910
953
  AssertHasTcb();
911
954
 
912
- // TODO: Implement it.
955
+ // TODO: SCTP: Implement it.
913
956
  // while (std::optional<Message> message = this->tcb->GetReassemblyQueue().GetNextMessage())
914
957
  // {
915
958
  // this->privateMetrics.rxMessagesCount++;
@@ -964,11 +1007,11 @@ namespace RTC
964
1007
 
965
1008
  this->listener.OnAssociationError(
966
1009
  Types::ErrorKind::WRONG_SEQUENCE,
967
- "cannot send message as the Association is shutting down");
1010
+ "cannot send message as the association is shutting down");
968
1011
 
969
1012
  return Types::SendMessageStatus::ERROR_SHUTTING_DOWN;
970
1013
  }
971
- // TODO: Implement it.
1014
+ // TODO: SCTP: Implement it.
972
1015
  // else if (
973
1016
  // this->sendQueue.GetTotalBufferedAmount() >= this->sctpOptions.maxSendBufferSize ||
974
1017
  // this->sendQueue.GetStreamBufferedAmount(message.GetStreamId()) >=
@@ -1082,7 +1125,7 @@ namespace RTC
1082
1125
 
1083
1126
  // https://datatracker.ietf.org/doc/html/rfc9260#section-5.2.4
1084
1127
  //
1085
- // This is handled in ProcessReceivedCookieEchoChunk().
1128
+ // This is handled in HandleReceivedCookieEchoChunk().
1086
1129
  if (receivedPacket->GetChunksCount() >= 1 && receivedPacket->GetChunkAt(0)->GetType() == Chunk::ChunkType::COOKIE_ECHO)
1087
1130
  {
1088
1131
  return true;
@@ -1155,7 +1198,7 @@ namespace RTC
1155
1198
  }
1156
1199
  }
1157
1200
 
1158
- bool Association::ProcessReceivedChunk(const Packet* receivedPacket, const Chunk* receivedChunk)
1201
+ bool Association::HandleReceivedChunk(const Packet* receivedPacket, const Chunk* receivedChunk)
1159
1202
  {
1160
1203
  MS_TRACE();
1161
1204
 
@@ -1163,21 +1206,21 @@ namespace RTC
1163
1206
  {
1164
1207
  case Chunk::ChunkType::INIT:
1165
1208
  {
1166
- ProcessReceivedInitChunk(receivedPacket, static_cast<const InitChunk*>(receivedChunk));
1209
+ HandleReceivedInitChunk(receivedPacket, static_cast<const InitChunk*>(receivedChunk));
1167
1210
 
1168
1211
  break;
1169
1212
  }
1170
1213
 
1171
1214
  case Chunk::ChunkType::INIT_ACK:
1172
1215
  {
1173
- ProcessReceivedInitAckChunk(receivedPacket, static_cast<const InitAckChunk*>(receivedChunk));
1216
+ HandleReceivedInitAckChunk(receivedPacket, static_cast<const InitAckChunk*>(receivedChunk));
1174
1217
 
1175
1218
  break;
1176
1219
  }
1177
1220
 
1178
1221
  case Chunk::ChunkType::COOKIE_ECHO:
1179
1222
  {
1180
- ProcessReceivedCookieEchoChunk(
1223
+ HandleReceivedCookieEchoChunk(
1181
1224
  receivedPacket, static_cast<const CookieEchoChunk*>(receivedChunk));
1182
1225
 
1183
1226
  break;
@@ -1185,7 +1228,7 @@ namespace RTC
1185
1228
 
1186
1229
  case Chunk::ChunkType::COOKIE_ACK:
1187
1230
  {
1188
- ProcessReceivedCookieAckChunk(
1231
+ HandleReceivedCookieAckChunk(
1189
1232
  receivedPacket, static_cast<const CookieAckChunk*>(receivedChunk));
1190
1233
 
1191
1234
  break;
@@ -1193,7 +1236,7 @@ namespace RTC
1193
1236
 
1194
1237
  case Chunk::ChunkType::SHUTDOWN:
1195
1238
  {
1196
- ProcessReceivedShutdownChunk(
1239
+ HandleReceivedShutdownChunk(
1197
1240
  receivedPacket, static_cast<const ShutdownChunk*>(receivedChunk));
1198
1241
 
1199
1242
  break;
@@ -1201,7 +1244,7 @@ namespace RTC
1201
1244
 
1202
1245
  case Chunk::ChunkType::SHUTDOWN_ACK:
1203
1246
  {
1204
- ProcessReceivedShutdownAckChunk(
1247
+ HandleReceivedShutdownAckChunk(
1205
1248
  receivedPacket, static_cast<const ShutdownAckChunk*>(receivedChunk));
1206
1249
 
1207
1250
  break;
@@ -1209,7 +1252,7 @@ namespace RTC
1209
1252
 
1210
1253
  case Chunk::ChunkType::SHUTDOWN_COMPLETE:
1211
1254
  {
1212
- ProcessReceivedShutdownCompleteChunk(
1255
+ HandleReceivedShutdownCompleteChunk(
1213
1256
  receivedPacket, static_cast<const ShutdownCompleteChunk*>(receivedChunk));
1214
1257
 
1215
1258
  break;
@@ -1217,7 +1260,7 @@ namespace RTC
1217
1260
 
1218
1261
  case Chunk::ChunkType::OPERATION_ERROR:
1219
1262
  {
1220
- ProcessReceivedOperationErrorChunk(
1263
+ HandleReceivedOperationErrorChunk(
1221
1264
  receivedPacket, static_cast<const OperationErrorChunk*>(receivedChunk));
1222
1265
 
1223
1266
  break;
@@ -1225,7 +1268,7 @@ namespace RTC
1225
1268
 
1226
1269
  case Chunk::ChunkType::ABORT:
1227
1270
  {
1228
- ProcessReceivedAbortAssociationChunk(
1271
+ HandleReceivedAbortAssociationChunk(
1229
1272
  receivedPacket, static_cast<const AbortAssociationChunk*>(receivedChunk));
1230
1273
 
1231
1274
  break;
@@ -1233,7 +1276,7 @@ namespace RTC
1233
1276
 
1234
1277
  case Chunk::ChunkType::HEARTBEAT_REQUEST:
1235
1278
  {
1236
- ProcessReceivedHeartbeatRequestChunk(
1279
+ HandleReceivedHeartbeatRequestChunk(
1237
1280
  receivedPacket, static_cast<const HeartbeatRequestChunk*>(receivedChunk));
1238
1281
 
1239
1282
  break;
@@ -1241,7 +1284,7 @@ namespace RTC
1241
1284
 
1242
1285
  case Chunk::ChunkType::HEARTBEAT_ACK:
1243
1286
  {
1244
- ProcessReceivedHeartbeatAckChunk(
1287
+ HandleReceivedHeartbeatAckChunk(
1245
1288
  receivedPacket, static_cast<const HeartbeatAckChunk*>(receivedChunk));
1246
1289
 
1247
1290
  break;
@@ -1249,7 +1292,7 @@ namespace RTC
1249
1292
 
1250
1293
  case Chunk::ChunkType::RE_CONFIG:
1251
1294
  {
1252
- ProcessReceivedReConfigChunk(
1295
+ HandleReceivedReConfigChunk(
1253
1296
  receivedPacket, static_cast<const ReConfigChunk*>(receivedChunk));
1254
1297
 
1255
1298
  break;
@@ -1257,7 +1300,7 @@ namespace RTC
1257
1300
 
1258
1301
  case Chunk::ChunkType::FORWARD_TSN:
1259
1302
  {
1260
- ProcessReceivedForwardTsnChunk(
1303
+ HandleReceivedForwardTsnChunk(
1261
1304
  receivedPacket, static_cast<const ForwardTsnChunk*>(receivedChunk));
1262
1305
 
1263
1306
  break;
@@ -1265,7 +1308,7 @@ namespace RTC
1265
1308
 
1266
1309
  case Chunk::ChunkType::I_FORWARD_TSN:
1267
1310
  {
1268
- ProcessReceivedIForwardTsnChunk(
1311
+ HandleReceivedIForwardTsnChunk(
1269
1312
  receivedPacket, static_cast<const IForwardTsnChunk*>(receivedChunk));
1270
1313
 
1271
1314
  break;
@@ -1273,28 +1316,28 @@ namespace RTC
1273
1316
 
1274
1317
  case Chunk::ChunkType::DATA:
1275
1318
  {
1276
- ProcessReceivedDataChunk(receivedPacket, static_cast<const DataChunk*>(receivedChunk));
1319
+ HandleReceivedDataChunk(receivedPacket, static_cast<const DataChunk*>(receivedChunk));
1277
1320
 
1278
1321
  break;
1279
1322
  }
1280
1323
 
1281
1324
  case Chunk::ChunkType::I_DATA:
1282
1325
  {
1283
- ProcessReceivedIDataChunk(receivedPacket, static_cast<const IDataChunk*>(receivedChunk));
1326
+ HandleReceivedIDataChunk(receivedPacket, static_cast<const IDataChunk*>(receivedChunk));
1284
1327
 
1285
1328
  break;
1286
1329
  }
1287
1330
 
1288
1331
  case Chunk::ChunkType::SACK:
1289
1332
  {
1290
- ProcessReceivedSackChunk(receivedPacket, static_cast<const SackChunk*>(receivedChunk));
1333
+ HandleReceivedSackChunk(receivedPacket, static_cast<const SackChunk*>(receivedChunk));
1291
1334
 
1292
1335
  break;
1293
1336
  }
1294
1337
 
1295
1338
  default:
1296
1339
  {
1297
- return ProcessReceivedUnknownChunk(
1340
+ return HandleReceivedUnknownChunk(
1298
1341
  receivedPacket, static_cast<const UnknownChunk*>(receivedChunk));
1299
1342
  }
1300
1343
  }
@@ -1302,7 +1345,7 @@ namespace RTC
1302
1345
  return true;
1303
1346
  }
1304
1347
 
1305
- void Association::ProcessReceivedInitChunk(
1348
+ void Association::HandleReceivedInitChunk(
1306
1349
  const Packet* /*receivedPacket*/, const InitChunk* receivedInitChunk)
1307
1350
  {
1308
1351
  MS_TRACE();
@@ -1381,9 +1424,8 @@ namespace RTC
1381
1424
  switch (this->state)
1382
1425
  {
1383
1426
  case State::NEW:
1384
- case State::CLOSED:
1385
1427
  {
1386
- MS_DEBUG_TAG(sctp, "INIT Chunk received in NEW or CLOSED state (normal scenario)");
1428
+ MS_DEBUG_TAG(sctp, "INIT Chunk received in NEW state (normal scenario)");
1387
1429
 
1388
1430
  localVerificationTag =
1389
1431
  Utils::Crypto::GetRandomUInt<uint32_t>(MinVerificationTag, MaxVerificationTag);
@@ -1392,6 +1434,11 @@ namespace RTC
1392
1434
  break;
1393
1435
  }
1394
1436
 
1437
+ case State::CLOSED:
1438
+ {
1439
+ MS_WARN_TAG(sctp, "ignoring INIT Chunk received in CLOSED state)");
1440
+ }
1441
+
1395
1442
  // https://datatracker.ietf.org/doc/html/rfc9260#section-5.2.1
1396
1443
  //
1397
1444
  // "This usually indicates an initialization collision, i.e., each
@@ -1452,8 +1499,8 @@ namespace RTC
1452
1499
 
1453
1500
  initAckChunk->SetInitiateTag(localVerificationTag);
1454
1501
  initAckChunk->SetAdvertisedReceiverWindowCredit(this->sctpOptions.maxReceiverWindowBufferSize);
1455
- initAckChunk->SetNumberOfOutboundStreams(this->sctpOptions.maxOutboundStreams);
1456
- initAckChunk->SetNumberOfInboundStreams(this->sctpOptions.maxInboundStreams);
1502
+ initAckChunk->SetNumberOfOutboundStreams(this->sctpOptions.announcedMaxOutboundStreams);
1503
+ initAckChunk->SetNumberOfInboundStreams(this->sctpOptions.announcedMaxInboundStreams);
1457
1504
  initAckChunk->SetInitialTsn(localInitialTsn);
1458
1505
 
1459
1506
  // Insert a StateCookieParameter in the INIT_ACK Chunk.
@@ -1485,7 +1532,7 @@ namespace RTC
1485
1532
  packet.get(), /*writeChecksum*/ !negotiatedCapabilities.zeroChecksum);
1486
1533
  }
1487
1534
 
1488
- void Association::ProcessReceivedInitAckChunk(
1535
+ void Association::HandleReceivedInitAckChunk(
1489
1536
  const Packet* /*receivedPacket*/, const InitAckChunk* receivedInitAckChunk)
1490
1537
  {
1491
1538
  MS_TRACE();
@@ -1547,7 +1594,7 @@ namespace RTC
1547
1594
  // partly sent message is re-sent in full. The same is true when the
1548
1595
  // Association is closed and later re-opened, which never happens in
1549
1596
  // WebRTC, but is a valid operation on the SCTP level.
1550
- // TODO: Implement it.
1597
+ // TODO: SCTP: Implement it.
1551
1598
  // this->sendQueue.Reset();
1552
1599
 
1553
1600
  CreateTransmissionControlBlock(
@@ -1569,14 +1616,17 @@ namespace RTC
1569
1616
 
1570
1617
  this->tcb->SetRemoteStateCookie(std::move(remoteStateCookie));
1571
1618
 
1572
- // TODO: Implement it.
1619
+ // TODO: SCTP: Implement it.
1620
+ // TODO: SCTP: tcb->SendBufferedPackets() must check that the remote state cookie
1621
+ // is set in TCB and must send a COOKIE_ECHO Chunk before potentially
1622
+ // buffered messages.
1573
1623
  // this->tcb->SendBufferedPackets(callbacks_.Now());
1574
1624
 
1575
1625
  this->t1CookieTimer->Start();
1576
1626
  this->listener.OnAssociationConnecting();
1577
1627
  }
1578
1628
 
1579
- void Association::ProcessReceivedCookieEchoChunk(
1629
+ void Association::HandleReceivedCookieEchoChunk(
1580
1630
  const Packet* receivedPacket, const CookieEchoChunk* receivedCookieEchoChunk)
1581
1631
  {
1582
1632
  MS_TRACE();
@@ -1606,7 +1656,7 @@ namespace RTC
1606
1656
 
1607
1657
  if (this->tcb)
1608
1658
  {
1609
- if (!ProcessReceivedCookieEchoChunkWithTcb(receivedPacket, cookie.get()))
1659
+ if (!HandleReceivedCookieEchoChunkWithTcb(receivedPacket, cookie.get()))
1610
1660
  {
1611
1661
  return;
1612
1662
  }
@@ -1647,7 +1697,7 @@ namespace RTC
1647
1697
  // partly sent message is re-sent in full. The same is true when the
1648
1698
  // Association is closed and later re-opened, which never happens in
1649
1699
  // WebRTC, but is a valid operation on the SCTP level.
1650
- // TODO: Implement it.
1700
+ // TODO: SCTP: Implement it.
1651
1701
  // this->sendQueue.Reset();
1652
1702
 
1653
1703
  CreateTransmissionControlBlock(
@@ -1670,7 +1720,7 @@ namespace RTC
1670
1720
  // "A COOKIE ACK chunk MAY be bundled with any pending DATA chunks (and/or
1671
1721
  // SACK chunks), but the COOKIE ACK chunk MUST be the first chunk in the
1672
1722
  // packet."
1673
- // TODO: Implement it. Note that we pass Packet as argument!
1723
+ // TODO: SCTP: Implement it. Note that we pass Packet as argument!
1674
1724
  // this->tcb->SendBufferedPackets(packet.get(), callbacks_.Now());
1675
1725
 
1676
1726
  // TODO: SCTP: Remove this since COOKIE_ACK must be sent by
@@ -1679,7 +1729,7 @@ namespace RTC
1679
1729
  this->packetSender.SendPacket(packet.get());
1680
1730
  }
1681
1731
 
1682
- bool Association::ProcessReceivedCookieEchoChunkWithTcb(
1732
+ bool Association::HandleReceivedCookieEchoChunkWithTcb(
1683
1733
  const Packet* receivedPacket, const StateCookie* cookie)
1684
1734
  {
1685
1735
  MS_TRACE();
@@ -1737,7 +1787,7 @@ namespace RTC
1737
1787
  receivedPacket->GetVerificationTag() == this->tcb->GetLocalVerificationTag() &&
1738
1788
  cookie->GetRemoteVerificationTag() != this->tcb->GetRemoteVerificationTag())
1739
1789
  {
1740
- // TODO: Handle the case in which remote Verification Tag is 0?
1790
+ // TODO: dcsctp: Handle the case in which remote Verification Tag is 0?
1741
1791
 
1742
1792
  MS_DEBUG_DEV("received COOKIE_ECHO indicating simultaneous associations");
1743
1793
 
@@ -1771,7 +1821,7 @@ namespace RTC
1771
1821
  return true;
1772
1822
  }
1773
1823
 
1774
- void Association::ProcessReceivedCookieAckChunk(
1824
+ void Association::HandleReceivedCookieAckChunk(
1775
1825
  const Packet* /*receivedPacket*/, const CookieAckChunk* /*receivedCookieAckChunk*/)
1776
1826
  {
1777
1827
  MS_TRACE();
@@ -1794,13 +1844,13 @@ namespace RTC
1794
1844
 
1795
1845
  SetState(State::ESTABLISHED, "COOKIE_ACK received");
1796
1846
 
1797
- // TODO: Implement this.
1847
+ // TODO: SCTP: Implement this.
1798
1848
  // this->tcb->SendBufferedPackets(callbacks_.Now());
1799
1849
 
1800
1850
  this->listener.OnAssociationConnected();
1801
1851
  }
1802
1852
 
1803
- void Association::ProcessReceivedShutdownChunk(
1853
+ void Association::HandleReceivedShutdownChunk(
1804
1854
  const Packet* /*receivedPacket*/, const ShutdownChunk* /*receivedShutdownChunk*/)
1805
1855
  {
1806
1856
  MS_TRACE();
@@ -1831,18 +1881,16 @@ namespace RTC
1831
1881
  // state, restarting its T2-shutdown timer.
1832
1882
  case State::SHUTDOWN_SENT:
1833
1883
  {
1834
- SetState(State::SHUTDOWN_ACK_SENT, "SHUTDOWN received");
1835
1884
  SendShutdownAckChunk();
1885
+ SetState(State::SHUTDOWN_ACK_SENT, "SHUTDOWN received");
1836
1886
 
1837
1887
  break;
1838
1888
  }
1839
1889
 
1840
- // TODO: This case block should be removed and handled by the `default`
1841
- // case block.
1842
- //
1843
- // @see https://issues.webrtc.org/issues/42222897
1844
1890
  case State::SHUTDOWN_ACK_SENT:
1845
1891
  {
1892
+ SendShutdownAckChunk();
1893
+
1846
1894
  break;
1847
1895
  }
1848
1896
 
@@ -1870,7 +1918,7 @@ namespace RTC
1870
1918
  }
1871
1919
  }
1872
1920
 
1873
- void Association::ProcessReceivedShutdownAckChunk(
1921
+ void Association::HandleReceivedShutdownAckChunk(
1874
1922
  const Packet* receivedPacket, const ShutdownAckChunk* /*receivedShutdownAckChunk*/)
1875
1923
  {
1876
1924
  MS_TRACE();
@@ -1929,7 +1977,7 @@ namespace RTC
1929
1977
  }
1930
1978
  }
1931
1979
 
1932
- void Association::ProcessReceivedShutdownCompleteChunk(
1980
+ void Association::HandleReceivedShutdownCompleteChunk(
1933
1981
  const Packet* /*receivedPacket*/, const ShutdownCompleteChunk* /*receivedShutdownCompleteChunk*/)
1934
1982
  {
1935
1983
  MS_TRACE();
@@ -1949,7 +1997,7 @@ namespace RTC
1949
1997
  InternalClose(Types::ErrorKind::SUCCESS, "");
1950
1998
  }
1951
1999
 
1952
- void Association::ProcessReceivedOperationErrorChunk(
2000
+ void Association::HandleReceivedOperationErrorChunk(
1953
2001
  const Packet* /*receivedPacket*/, const OperationErrorChunk* receivedOperationErrorChunk)
1954
2002
  {
1955
2003
  MS_TRACE();
@@ -1987,7 +2035,7 @@ namespace RTC
1987
2035
  this->listener.OnAssociationError(Types::ErrorKind::PEER_REPORTED, errorCausesStr);
1988
2036
  }
1989
2037
 
1990
- void Association::ProcessReceivedAbortAssociationChunk(
2038
+ void Association::HandleReceivedAbortAssociationChunk(
1991
2039
  const Packet* /*receivedPacket*/, const AbortAssociationChunk* receivedAbortAssociationChunk)
1992
2040
  {
1993
2041
  MS_TRACE();
@@ -2025,8 +2073,8 @@ namespace RTC
2025
2073
  InternalClose(Types::ErrorKind::PEER_REPORTED, errorCausesStr);
2026
2074
  }
2027
2075
 
2028
- void Association::ProcessReceivedHeartbeatRequestChunk(
2029
- const Packet* /*receivedPacket*/, const HeartbeatRequestChunk* /*receivedHeartbeatRequestChunk*/)
2076
+ void Association::HandleReceivedHeartbeatRequestChunk(
2077
+ const Packet* /*receivedPacket*/, const HeartbeatRequestChunk* receivedHeartbeatRequestChunk)
2030
2078
  {
2031
2079
  MS_TRACE();
2032
2080
 
@@ -2035,12 +2083,12 @@ namespace RTC
2035
2083
  return;
2036
2084
  }
2037
2085
 
2038
- // TODO: Implement it.
2039
- // this->tcb->GetHearbeatHandler().HandleHeartbeatRequest(*std::move(receivedHeartbeatRequestChunk));
2086
+ this->tcb->GetHeartbeatHandler().HandleReceivedHeartbeatRequestChunk(
2087
+ receivedHeartbeatRequestChunk);
2040
2088
  }
2041
2089
 
2042
- void Association::ProcessReceivedHeartbeatAckChunk(
2043
- const Packet* /*receivedPacket*/, const HeartbeatAckChunk* /*receivedHeartbeatAckChunk*/)
2090
+ void Association::HandleReceivedHeartbeatAckChunk(
2091
+ const Packet* /*receivedPacket*/, const HeartbeatAckChunk* receivedHeartbeatAckChunk)
2044
2092
  {
2045
2093
  MS_TRACE();
2046
2094
 
@@ -2049,11 +2097,10 @@ namespace RTC
2049
2097
  return;
2050
2098
  }
2051
2099
 
2052
- // TODO: Implement it.
2053
- // this->tcb->GetHearbeatHandler().HandleHeartbeatAck(*std::move(receivedHeartbeatAckChunk));
2100
+ this->tcb->GetHeartbeatHandler().HandleReceivedHeartbeatAckChunk(receivedHeartbeatAckChunk);
2054
2101
  }
2055
2102
 
2056
- void Association::ProcessReceivedReConfigChunk(
2103
+ void Association::HandleReceivedReConfigChunk(
2057
2104
  const Packet* /*receivedPacket*/, const ReConfigChunk* /*receivedReConfigChunk*/)
2058
2105
  {
2059
2106
  MS_TRACE();
@@ -2063,7 +2110,7 @@ namespace RTC
2063
2110
  return;
2064
2111
  }
2065
2112
 
2066
- // TODO: Implement it.
2113
+ // TODO: SCTP: Implement it.
2067
2114
  // this->tcb->GetStreamResetHandler().HandleReConfig(*std::move(receivedReConfigChunk));
2068
2115
 
2069
2116
  // Handling this response may result in outgoing stream resets finishing
@@ -2074,7 +2121,7 @@ namespace RTC
2074
2121
 
2075
2122
  // If a response was processed, pending to-be-reset streams may now have
2076
2123
  // become unpaused. Try to send more DATA/I_DATA chunks.
2077
- // TODO: Implement it.
2124
+ // TODO: SCTP: Implement it.
2078
2125
  // this->tcb->SendBufferedPackets(callbacks_.Now());
2079
2126
 
2080
2127
  // If it leaves "deferred reset processing", there may be chunks to
@@ -2082,23 +2129,23 @@ namespace RTC
2082
2129
  MayDeliverMessages();
2083
2130
  }
2084
2131
 
2085
- void Association::ProcessReceivedForwardTsnChunk(
2132
+ void Association::HandleReceivedForwardTsnChunk(
2086
2133
  const Packet* receivedPacket, const ForwardTsnChunk* receivedForwardTsnChunk)
2087
2134
  {
2088
2135
  MS_TRACE();
2089
2136
 
2090
- ProcessReceivedAnyForwardTsnChunk(receivedPacket, receivedForwardTsnChunk);
2137
+ HandleReceivedAnyForwardTsnChunk(receivedPacket, receivedForwardTsnChunk);
2091
2138
  }
2092
2139
 
2093
- void Association::ProcessReceivedIForwardTsnChunk(
2140
+ void Association::HandleReceivedIForwardTsnChunk(
2094
2141
  const Packet* receivedPacket, const IForwardTsnChunk* receivedIForwardTsnChunk)
2095
2142
  {
2096
2143
  MS_TRACE();
2097
2144
 
2098
- ProcessReceivedAnyForwardTsnChunk(receivedPacket, receivedIForwardTsnChunk);
2145
+ HandleReceivedAnyForwardTsnChunk(receivedPacket, receivedIForwardTsnChunk);
2099
2146
  }
2100
2147
 
2101
- void Association::ProcessReceivedAnyForwardTsnChunk(
2148
+ void Association::HandleReceivedAnyForwardTsnChunk(
2102
2149
  const Packet* /*receivedPacket*/, const AnyForwardTsnChunk* /*receivedAnyForwardTsnChunk*/)
2103
2150
  {
2104
2151
  MS_TRACE();
@@ -2134,7 +2181,7 @@ namespace RTC
2134
2181
  return;
2135
2182
  }
2136
2183
 
2137
- // TODO: Implement it.
2184
+ // TODO: SCTP: Implement it.
2138
2185
  // if
2139
2186
  // (this->tcb->GetDataTracker().HandleForwardTsn(receivedAnyForwardTsnChunk->GetNewCumulativeTsn()))
2140
2187
  // {
@@ -2147,23 +2194,23 @@ namespace RTC
2147
2194
  MayDeliverMessages();
2148
2195
  }
2149
2196
 
2150
- void Association::ProcessReceivedDataChunk(
2197
+ void Association::HandleReceivedDataChunk(
2151
2198
  const Packet* receivedPacket, const DataChunk* receivedDataChunk)
2152
2199
  {
2153
2200
  MS_TRACE();
2154
2201
 
2155
- ProcessReceivedAnyDataChunk(receivedPacket, receivedDataChunk);
2202
+ HandleReceivedAnyDataChunk(receivedPacket, receivedDataChunk);
2156
2203
  }
2157
2204
 
2158
- void Association::ProcessReceivedIDataChunk(
2205
+ void Association::HandleReceivedIDataChunk(
2159
2206
  const Packet* receivedPacket, const IDataChunk* receivedIDataChunk)
2160
2207
  {
2161
2208
  MS_TRACE();
2162
2209
 
2163
- ProcessReceivedAnyDataChunk(receivedPacket, receivedIDataChunk);
2210
+ HandleReceivedAnyDataChunk(receivedPacket, receivedIDataChunk);
2164
2211
  }
2165
2212
 
2166
- void Association::ProcessReceivedAnyDataChunk(
2213
+ void Association::HandleReceivedAnyDataChunk(
2167
2214
  const Packet* /*receivedPacket*/, const AnyDataChunk* receivedAnyDataChunk)
2168
2215
  {
2169
2216
  MS_TRACE();
@@ -2174,7 +2221,7 @@ namespace RTC
2174
2221
  }
2175
2222
 
2176
2223
  const uint32_t tsn = receivedAnyDataChunk->GetTsn();
2177
- // TODO: Uncomment.
2224
+ // TODO: SCTP: Uncomment.
2178
2225
  // const bool immediateAck = receivedAnyDataChunk->GetI();
2179
2226
 
2180
2227
  if (receivedAnyDataChunk->GetUserDataPayloadLength() == 0)
@@ -2196,7 +2243,7 @@ namespace RTC
2196
2243
  return;
2197
2244
  }
2198
2245
 
2199
- // TODO: Implement it.
2246
+ // TODO: SCTP: Implement it.
2200
2247
  // MS_DEBUG_DEV("data received [data length:%" PRIu16 ", queue size:%zu, watermark:%zu,
2201
2248
  // full:%s, above:%s]", receivedAnyDataChunk->GetUserDataLength(),
2202
2249
  // this->tcb->GetReassemblyQueue()->GetQueuedBytes(),
@@ -2205,7 +2252,7 @@ namespace RTC
2205
2252
  // this->tcb->GetReassemblyQueue()->IsAboveWatermark(),
2206
2253
  // );
2207
2254
 
2208
- // TODO: Implement it.
2255
+ // TODO: SCTP: Implement it.
2209
2256
  // if (this->tcb->GetReassemblyQueue()->IsFull())
2210
2257
  // {
2211
2258
  // // If the reassembly queue is full but there are assembled messages
@@ -2247,7 +2294,7 @@ namespace RTC
2247
2294
  // If the reassembly queue is above its high watermark, only accept data
2248
2295
  // chunks that increase its cumulative ack tsn in an attempt to fill gaps
2249
2296
  // to deliver messages.
2250
- // TODO: Implement it.
2297
+ // TODO: SCTP: Implement it.
2251
2298
  // if (this->tcb->GetReassemblyQueue()->IsAboveWatermark())
2252
2299
  // {
2253
2300
  // MS_WARN_TAG(sctp, "reassembly queue is above watermark");
@@ -2262,7 +2309,7 @@ namespace RTC
2262
2309
  // }
2263
2310
  // }
2264
2311
 
2265
- // TODO: Implement it.
2312
+ // TODO: SCTP: Implement it.
2266
2313
  // if (this->tcb->GetDataTracker()->IsTsnValid(tsn))
2267
2314
  // {
2268
2315
  // MS_WARN_TAG(sctp, "data rejected because of failing TSN validity");
@@ -2270,10 +2317,10 @@ namespace RTC
2270
2317
  // return;
2271
2318
  // }
2272
2319
 
2273
- // TODO: Implement it.
2320
+ // TODO: SCTP: Implement it.
2274
2321
  // if (this->tcb->GetDataTracker()->Observe(tsn, immediateAck))
2275
2322
  // {
2276
- // // TODO: Here we should have a std::vector<uint8_t> holding the data so
2323
+ // // TODO: SCTP: Here we should have a std::vector<uint8_t> holding the data so
2277
2324
  // // we can move it.
2278
2325
  // this->tcb->GetReassemblyQueue()->Add(tsn, std::move(data));
2279
2326
 
@@ -2281,7 +2328,7 @@ namespace RTC
2281
2328
  // }
2282
2329
  }
2283
2330
 
2284
- void Association::ProcessReceivedSackChunk(
2331
+ void Association::HandleReceivedSackChunk(
2285
2332
  const Packet* /*receivedPacket*/, const SackChunk* /*receivedSackChunk*/)
2286
2333
  {
2287
2334
  MS_TRACE();
@@ -2291,8 +2338,8 @@ namespace RTC
2291
2338
  return;
2292
2339
  }
2293
2340
 
2294
- // TODO: Implement it.
2295
- // if (this->tcb->GetRetransmissionQueue()->ProcessSack(receivedSackChunk))
2341
+ // TODO: SCTP: Implement it.
2342
+ // if (this->tcb->GetRetransmissionQueue()->HandleReceivedSack(receivedSackChunk))
2296
2343
  // {
2297
2344
  // MaySendShutdownOrShutdownAckChunk();
2298
2345
 
@@ -2324,7 +2371,7 @@ namespace RTC
2324
2371
  // }
2325
2372
  }
2326
2373
 
2327
- bool Association::ProcessReceivedUnknownChunk(
2374
+ bool Association::HandleReceivedUnknownChunk(
2328
2375
  const Packet* /*receivedPacket*/, const UnknownChunk* receivedUnknownChunk)
2329
2376
  {
2330
2377
  MS_TRACE();
@@ -2337,7 +2384,7 @@ namespace RTC
2337
2384
 
2338
2385
  if (skipProcessing)
2339
2386
  {
2340
- MS_DEBUG_TAG(
2387
+ MS_WARN_TAG(
2341
2388
  sctp,
2342
2389
  "Chunk with unknown type %" PRIu8
2343
2390
  " received, skipping further processing of Chunks in the Packet",
@@ -2382,6 +2429,8 @@ namespace RTC
2382
2429
  {
2383
2430
  MS_TRACE();
2384
2431
 
2432
+ const AssociationListenerDeferrer::ScopedDeferrer deferrer(this->listener);
2433
+
2385
2434
  const auto maxRestarts = this->t1InitTimer->GetMaxRestarts();
2386
2435
 
2387
2436
  MS_DEBUG_TAG(
@@ -2408,6 +2457,8 @@ namespace RTC
2408
2457
  {
2409
2458
  MS_TRACE();
2410
2459
 
2460
+ const AssociationListenerDeferrer::ScopedDeferrer deferrer(this->listener);
2461
+
2411
2462
  const auto maxRestarts = this->t1CookieTimer->GetMaxRestarts();
2412
2463
 
2413
2464
  MS_DEBUG_TAG(
@@ -2420,7 +2471,7 @@ namespace RTC
2420
2471
 
2421
2472
  if (this->t1CookieTimer->IsRunning())
2422
2473
  {
2423
- // TODO: Implement it.
2474
+ // TODO: SCTP: Implement it.
2424
2475
  // this->tcb->SendBufferedPackets(now);
2425
2476
  }
2426
2477
  else
@@ -2431,10 +2482,15 @@ namespace RTC
2431
2482
  AssertStateIsConsistent();
2432
2483
  }
2433
2484
 
2434
- void Association::OnT2ShutdownTimer(uint64_t& /*baseTimeoutMs*/, bool& /*stop*/)
2485
+ void Association::OnT2ShutdownTimer(uint64_t& baseTimeoutMs, bool& /*stop*/)
2435
2486
  {
2436
2487
  MS_TRACE();
2437
2488
 
2489
+ AssertState(State::SHUTDOWN_SENT, State::SHUTDOWN_ACK_SENT);
2490
+ AssertHasTcb();
2491
+
2492
+ const AssociationListenerDeferrer::ScopedDeferrer deferrer(this->listener);
2493
+
2438
2494
  const auto maxRestarts = this->t2ShutdownTimer->GetMaxRestarts();
2439
2495
 
2440
2496
  MS_DEBUG_TAG(
@@ -2443,14 +2499,6 @@ namespace RTC
2443
2499
  this->t2ShutdownTimer->GetExpirationCount(),
2444
2500
  maxRestarts ? std::to_string(maxRestarts.value()).c_str() : "Infinite");
2445
2501
 
2446
- // https://datatracker.ietf.org/doc/html/rfc9260#section-9.2
2447
- //
2448
- // "If the timer expires, the endpoint MUST resend the SHUTDOWN chunk
2449
- // with the updated last sequential TSN received from its peer."
2450
- if (this->t2ShutdownTimer->IsRunning())
2451
- {
2452
- SendShutdownChunk();
2453
- }
2454
2502
  // https://datatracker.ietf.org/doc/html/rfc9260#section-9.2
2455
2503
  //
2456
2504
  // "An endpoint SHOULD limit the number of retransmissions of the
@@ -2458,10 +2506,8 @@ namespace RTC
2458
2506
  // this threshold is exceeded, the endpoint SHOULD destroy the TCB and
2459
2507
  // SHOULD report the peer endpoint unreachable to the upper layer (and
2460
2508
  // thus the association enters the CLOSED state)."
2461
- else
2509
+ if (!this->t2ShutdownTimer->IsRunning())
2462
2510
  {
2463
- AssertHasTcb();
2464
-
2465
2511
  auto packet = this->tcb->CreatePacket();
2466
2512
  auto* abortAssociationChunk = packet->BuildChunkInPlace<AbortAssociationChunk>();
2467
2513
 
@@ -2480,9 +2526,33 @@ namespace RTC
2480
2526
  this->packetSender.SendPacket(packet.get());
2481
2527
 
2482
2528
  InternalClose(Types::ErrorKind::TOO_MANY_RETRIES, "no SHUTDOWN_ACK chunk received");
2529
+ AssertStateIsConsistent();
2530
+
2531
+ return;
2532
+ }
2533
+
2534
+ // https://datatracker.ietf.org/doc/html/rfc9260#section-9.2
2535
+ //
2536
+ // "the SHUTDOWN chunk receiver MUST send a SHUTDOWN ACK chunk and start
2537
+ // a T2-shutdown timer of its own, entering the SHUTDOWN-ACK-SENT state.
2538
+ // If the timer expires, the endpoint MUST resend the SHUTDOWN ACK chunk."
2539
+ if (this->state == State::SHUTDOWN_ACK_SENT)
2540
+ {
2541
+ SendShutdownAckChunk();
2542
+ }
2543
+ // https://datatracker.ietf.org/doc/html/rfc9260#section-9.2
2544
+ //
2545
+ // "It SHOULD then start the T2-shutdown timer and enter the SHUTDOWN-SENT
2546
+ // state. If the timer expires, the endpoint MUST resend the SHUTDOWN
2547
+ // chunk with the updated last sequential TSN received from its peer."
2548
+ else
2549
+ {
2550
+ SendShutdownChunk();
2483
2551
  }
2484
2552
 
2485
2553
  AssertStateIsConsistent();
2554
+
2555
+ baseTimeoutMs = this->tcb->GetCurrentRtoMs();
2486
2556
  }
2487
2557
 
2488
2558
  template<typename... States>
@@ -2558,7 +2628,7 @@ namespace RTC
2558
2628
 
2559
2629
  this->listener.OnAssociationError(
2560
2630
  Types::ErrorKind::NOT_CONNECTED,
2561
- "received unexpected commands on Association that is not connected");
2631
+ "received unexpected commands on association that is not connected");
2562
2632
 
2563
2633
  return false;
2564
2634
  }