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.
- package/README.md +4 -4
- package/node/lib/Worker.d.ts +1 -1
- package/node/lib/Worker.d.ts.map +1 -1
- package/node/lib/Worker.js +8 -2
- package/node/lib/WorkerTypes.d.ts +8 -4
- package/node/lib/WorkerTypes.d.ts.map +1 -1
- package/node/lib/index.d.ts +1 -1
- package/node/lib/index.d.ts.map +1 -1
- package/node/lib/index.js +2 -1
- package/node/lib/sctpParametersTypes.d.ts +3 -13
- package/node/lib/sctpParametersTypes.d.ts.map +1 -1
- package/node/lib/test/test-PlainTransport.js +8 -3
- package/node/lib/test/test-WebRtcTransport.js +9 -4
- package/package.json +10 -10
- package/worker/Makefile +0 -4
- package/worker/fuzzer/src/fuzzer.cpp +6 -5
- package/worker/include/RTC/DataConsumer.hpp +4 -14
- package/worker/include/RTC/SCTP/TODO_SCTP.md +18 -10
- package/worker/include/RTC/SCTP/association/Association.hpp +39 -31
- package/worker/include/RTC/SCTP/association/{AssociationDeferredListener.hpp → AssociationListenerDeferrer.hpp} +10 -8
- package/worker/include/RTC/SCTP/association/HeartbeatHandler.hpp +77 -0
- package/worker/include/RTC/SCTP/association/NegotiatedCapabilities.hpp +2 -2
- package/worker/include/RTC/SCTP/association/PacketSender.hpp +2 -2
- package/worker/include/RTC/SCTP/association/StateCookie.hpp +2 -2
- package/worker/include/RTC/SCTP/association/StreamResetHandler.hpp +272 -0
- package/worker/include/RTC/SCTP/association/TCBContext.hpp +67 -0
- package/worker/include/RTC/SCTP/association/TransmissionControlBlock.hpp +81 -11
- package/worker/include/RTC/SCTP/common/UnwrappedSequenceNumber.hpp +274 -0
- package/worker/include/RTC/SCTP/packet/Chunk.hpp +0 -1
- package/worker/include/RTC/SCTP/packet/UserData.hpp +1 -0
- package/worker/include/RTC/SCTP/packet/parameters/IncomingSsnResetRequestParameter.hpp +14 -10
- package/worker/include/RTC/SCTP/packet/parameters/OutgoingSsnResetRequestParameter.hpp +14 -10
- package/worker/include/RTC/SCTP/packet/parameters/ZeroChecksumAcceptableParameter.hpp +13 -2
- package/worker/include/RTC/SCTP/public/AssociationInterface.hpp +7 -1
- package/worker/include/RTC/SCTP/public/AssociationListener.hpp +11 -0
- package/worker/include/RTC/SCTP/public/Message.hpp +1 -0
- package/worker/include/RTC/SCTP/public/SctpOptions.hpp +4 -4
- package/worker/include/RTC/SctpAssociation.hpp +2 -2
- package/worker/include/RTC/Transport.hpp +9 -13
- package/worker/include/Settings.hpp +2 -1
- package/worker/include/Utils.hpp +130 -6
- package/worker/meson.build +10 -39
- package/worker/meson_options.txt +0 -1
- package/worker/scripts/package-lock.json +6 -6
- package/worker/src/DepLibUring.cpp +1 -1
- package/worker/src/RTC/DataConsumer.cpp +5 -29
- package/worker/src/RTC/PipeTransport.cpp +15 -12
- package/worker/src/RTC/PlainTransport.cpp +15 -12
- package/worker/src/RTC/RTP/RetransmissionBuffer.cpp +5 -5
- package/worker/src/RTC/RTP/RtpStream.cpp +2 -2
- package/worker/src/RTC/RTP/RtxStream.cpp +1 -1
- package/worker/src/RTC/RateCalculator.cpp +5 -5
- package/worker/src/RTC/SCTP/association/Association.cpp +218 -148
- package/worker/src/RTC/SCTP/association/{AssociationDeferredListener.cpp → AssociationListenerDeferrer.cpp} +38 -30
- package/worker/src/RTC/SCTP/association/HeartbeatHandler.cpp +244 -0
- package/worker/src/RTC/SCTP/association/NegotiatedCapabilities.cpp +8 -6
- package/worker/src/RTC/SCTP/association/PacketSender.cpp +7 -2
- package/worker/src/RTC/SCTP/association/StateCookie.cpp +8 -8
- package/worker/src/RTC/SCTP/association/StreamResetHandler.cpp +512 -0
- package/worker/src/RTC/SCTP/association/TransmissionControlBlock.cpp +45 -39
- package/worker/src/RTC/SCTP/packet/chunks/SackChunk.cpp +1 -1
- package/worker/src/RTC/SCTP/packet/errorCauses/UserInitiatedAbortErrorCause.cpp +1 -1
- package/worker/src/RTC/SCTP/packet/parameters/IncomingSsnResetRequestParameter.cpp +22 -5
- package/worker/src/RTC/SCTP/packet/parameters/OutgoingSsnResetRequestParameter.cpp +22 -5
- package/worker/src/RTC/SCTP/tx/RetransmissionErrorCounter.cpp +1 -1
- package/worker/src/RTC/SctpAssociation.cpp +1 -2
- package/worker/src/RTC/SeqManager.cpp +4 -4
- package/worker/src/RTC/Transport.cpp +247 -134
- package/worker/src/RTC/WebRtcTransport.cpp +9 -5
- package/worker/src/Settings.cpp +21 -1
- package/worker/src/Worker.cpp +13 -10
- package/worker/src/lib.cpp +11 -8
- package/worker/tasks.py +2 -35
- package/worker/test/src/RTC/SCTP/association/TestNegotiatedCapabilities.cpp +13 -12
- package/worker/test/src/RTC/SCTP/association/TestStateCookie.cpp +20 -20
- package/worker/test/src/RTC/SCTP/common/TestUnwrappedSequenceNumber.cpp +210 -0
- package/worker/test/src/RTC/SCTP/packet/chunks/TestAbortAssociationChunk.cpp +2 -2
- package/worker/test/src/RTC/SCTP/packet/chunks/TestHeartbeatAckChunk.cpp +9 -4
- package/worker/test/src/RTC/SCTP/packet/chunks/TestHeartbeatRequestChunk.cpp +5 -0
- package/worker/test/src/RTC/SCTP/packet/chunks/TestInitAckChunk.cpp +1 -1
- package/worker/test/src/RTC/SCTP/packet/chunks/TestInitChunk.cpp +5 -5
- package/worker/test/src/RTC/SCTP/packet/chunks/TestReConfigChunk.cpp +19 -20
- package/worker/test/src/RTC/SCTP/packet/chunks/TestUnknownChunk.cpp +3 -0
- package/worker/test/src/RTC/SCTP/packet/errorCauses/TestUnknownErrorCause.cpp +3 -0
- package/worker/test/src/RTC/SCTP/packet/parameters/TestIncomingSsnResetRequestParameter.cpp +24 -27
- package/worker/test/src/RTC/SCTP/packet/parameters/TestOutgoingSsnResetRequestParameter.cpp +25 -30
- package/worker/test/src/RTC/SCTP/packet/parameters/TestStateCookieParameter.cpp +8 -6
- package/worker/test/src/RTC/SCTP/packet/parameters/TestSupportedExtensionsParameter.cpp +12 -0
- package/worker/test/src/RTC/SCTP/packet/parameters/TestZeroChecksumAcceptableParameter.cpp +5 -8
- package/worker/test/src/Utils/TestNumber.cpp +119 -49
- 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 `
|
|
44
|
+
// Our `listener` member is a `AssociationListenerDeferrer` which takes
|
|
45
45
|
// `AssociationListener` as constructor argument.
|
|
46
46
|
listener(listener),
|
|
47
|
-
|
|
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.
|
|
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.
|
|
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
|
|
184
|
-
// cannot be reused. However there is no real technical reason for it.
|
|
185
|
-
if (this->state != State::NEW
|
|
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
|
|
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
|
|
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
|
|
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 (
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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 (!
|
|
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
|
|
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
|
|
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
|
-
|
|
702
|
-
|
|
703
|
-
|
|
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.
|
|
742
|
-
initChunk->SetNumberOfInboundStreams(this->sctpOptions.
|
|
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
|
|
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
|
|
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::
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1333
|
+
HandleReceivedSackChunk(receivedPacket, static_cast<const SackChunk*>(receivedChunk));
|
|
1291
1334
|
|
|
1292
1335
|
break;
|
|
1293
1336
|
}
|
|
1294
1337
|
|
|
1295
1338
|
default:
|
|
1296
1339
|
{
|
|
1297
|
-
return
|
|
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::
|
|
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
|
|
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.
|
|
1456
|
-
initAckChunk->SetNumberOfInboundStreams(this->sctpOptions.
|
|
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::
|
|
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::
|
|
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 (!
|
|
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::
|
|
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::
|
|
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::
|
|
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::
|
|
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::
|
|
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::
|
|
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::
|
|
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::
|
|
2029
|
-
const Packet* /*receivedPacket*/, const HeartbeatRequestChunk*
|
|
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
|
-
|
|
2039
|
-
|
|
2086
|
+
this->tcb->GetHeartbeatHandler().HandleReceivedHeartbeatRequestChunk(
|
|
2087
|
+
receivedHeartbeatRequestChunk);
|
|
2040
2088
|
}
|
|
2041
2089
|
|
|
2042
|
-
void Association::
|
|
2043
|
-
const Packet* /*receivedPacket*/, const HeartbeatAckChunk*
|
|
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
|
-
|
|
2053
|
-
// this->tcb->GetHearbeatHandler().HandleHeartbeatAck(*std::move(receivedHeartbeatAckChunk));
|
|
2100
|
+
this->tcb->GetHeartbeatHandler().HandleReceivedHeartbeatAckChunk(receivedHeartbeatAckChunk);
|
|
2054
2101
|
}
|
|
2055
2102
|
|
|
2056
|
-
void Association::
|
|
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::
|
|
2132
|
+
void Association::HandleReceivedForwardTsnChunk(
|
|
2086
2133
|
const Packet* receivedPacket, const ForwardTsnChunk* receivedForwardTsnChunk)
|
|
2087
2134
|
{
|
|
2088
2135
|
MS_TRACE();
|
|
2089
2136
|
|
|
2090
|
-
|
|
2137
|
+
HandleReceivedAnyForwardTsnChunk(receivedPacket, receivedForwardTsnChunk);
|
|
2091
2138
|
}
|
|
2092
2139
|
|
|
2093
|
-
void Association::
|
|
2140
|
+
void Association::HandleReceivedIForwardTsnChunk(
|
|
2094
2141
|
const Packet* receivedPacket, const IForwardTsnChunk* receivedIForwardTsnChunk)
|
|
2095
2142
|
{
|
|
2096
2143
|
MS_TRACE();
|
|
2097
2144
|
|
|
2098
|
-
|
|
2145
|
+
HandleReceivedAnyForwardTsnChunk(receivedPacket, receivedIForwardTsnChunk);
|
|
2099
2146
|
}
|
|
2100
2147
|
|
|
2101
|
-
void Association::
|
|
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::
|
|
2197
|
+
void Association::HandleReceivedDataChunk(
|
|
2151
2198
|
const Packet* receivedPacket, const DataChunk* receivedDataChunk)
|
|
2152
2199
|
{
|
|
2153
2200
|
MS_TRACE();
|
|
2154
2201
|
|
|
2155
|
-
|
|
2202
|
+
HandleReceivedAnyDataChunk(receivedPacket, receivedDataChunk);
|
|
2156
2203
|
}
|
|
2157
2204
|
|
|
2158
|
-
void Association::
|
|
2205
|
+
void Association::HandleReceivedIDataChunk(
|
|
2159
2206
|
const Packet* receivedPacket, const IDataChunk* receivedIDataChunk)
|
|
2160
2207
|
{
|
|
2161
2208
|
MS_TRACE();
|
|
2162
2209
|
|
|
2163
|
-
|
|
2210
|
+
HandleReceivedAnyDataChunk(receivedPacket, receivedIDataChunk);
|
|
2164
2211
|
}
|
|
2165
2212
|
|
|
2166
|
-
void Association::
|
|
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::
|
|
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()->
|
|
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::
|
|
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
|
-
|
|
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&
|
|
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
|
-
|
|
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
|
|
2631
|
+
"received unexpected commands on association that is not connected");
|
|
2562
2632
|
|
|
2563
2633
|
return false;
|
|
2564
2634
|
}
|