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
|
@@ -1,30 +1,31 @@
|
|
|
1
|
-
#define MS_CLASS "RTC::SCTP::
|
|
1
|
+
#define MS_CLASS "RTC::SCTP::AssociationListenerDeferrer"
|
|
2
2
|
// #define MS_LOG_DEV_LEVEL 3
|
|
3
3
|
|
|
4
|
-
#include "RTC/SCTP/association/
|
|
4
|
+
#include "RTC/SCTP/association/AssociationListenerDeferrer.hpp"
|
|
5
5
|
#include "Logger.hpp"
|
|
6
6
|
|
|
7
7
|
namespace RTC
|
|
8
8
|
{
|
|
9
9
|
namespace SCTP
|
|
10
10
|
{
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
:
|
|
11
|
+
AssociationListenerDeferrer::ScopedDeferrer::ScopedDeferrer(
|
|
12
|
+
AssociationListenerDeferrer& listenerDeferrer)
|
|
13
|
+
: listenerDeferrer(listenerDeferrer)
|
|
14
14
|
{
|
|
15
15
|
MS_TRACE();
|
|
16
16
|
|
|
17
|
-
this->
|
|
17
|
+
this->listenerDeferrer.SetReady();
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
// NOLINTNEXTLINE(bugprone-exception-escape)
|
|
21
|
+
AssociationListenerDeferrer::ScopedDeferrer::~ScopedDeferrer()
|
|
21
22
|
{
|
|
22
23
|
MS_TRACE();
|
|
23
24
|
|
|
24
|
-
this->
|
|
25
|
+
this->listenerDeferrer.TriggerDeferredCallbacks();
|
|
25
26
|
}
|
|
26
27
|
|
|
27
|
-
|
|
28
|
+
AssociationListenerDeferrer::AssociationListenerDeferrer(AssociationListener* innerListener)
|
|
28
29
|
: innerListener(innerListener)
|
|
29
30
|
{
|
|
30
31
|
MS_TRACE();
|
|
@@ -32,21 +33,20 @@ namespace RTC
|
|
|
32
33
|
this->deferredCallbacks.reserve(8);
|
|
33
34
|
}
|
|
34
35
|
|
|
35
|
-
void
|
|
36
|
+
void AssociationListenerDeferrer::SetReady()
|
|
36
37
|
{
|
|
37
38
|
MS_TRACE();
|
|
38
39
|
|
|
40
|
+
MS_ASSERT(!this->ready, "already ready");
|
|
41
|
+
|
|
39
42
|
this->ready = true;
|
|
40
43
|
}
|
|
41
44
|
|
|
42
|
-
void
|
|
45
|
+
void AssociationListenerDeferrer::TriggerDeferredCallbacks()
|
|
43
46
|
{
|
|
44
47
|
MS_TRACE();
|
|
45
48
|
|
|
46
|
-
|
|
47
|
-
{
|
|
48
|
-
return;
|
|
49
|
-
}
|
|
49
|
+
MS_ASSERT(this->ready, "not ready");
|
|
50
50
|
|
|
51
51
|
this->ready = false;
|
|
52
52
|
|
|
@@ -72,17 +72,15 @@ namespace RTC
|
|
|
72
72
|
}
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
-
bool
|
|
75
|
+
bool AssociationListenerDeferrer::OnAssociationSendData(const uint8_t* data, size_t len)
|
|
76
76
|
{
|
|
77
77
|
MS_TRACE();
|
|
78
78
|
|
|
79
|
-
MS_ASSERT(this->ready, "not ready");
|
|
80
|
-
|
|
81
79
|
// Will not be deferred but called directly.
|
|
82
80
|
return this->innerListener->OnAssociationSendData(data, len);
|
|
83
81
|
}
|
|
84
82
|
|
|
85
|
-
void
|
|
83
|
+
void AssociationListenerDeferrer::OnAssociationConnecting()
|
|
86
84
|
{
|
|
87
85
|
MS_TRACE();
|
|
88
86
|
|
|
@@ -96,7 +94,7 @@ namespace RTC
|
|
|
96
94
|
std::monostate{});
|
|
97
95
|
}
|
|
98
96
|
|
|
99
|
-
void
|
|
97
|
+
void AssociationListenerDeferrer::OnAssociationConnected()
|
|
100
98
|
{
|
|
101
99
|
MS_TRACE();
|
|
102
100
|
|
|
@@ -110,7 +108,7 @@ namespace RTC
|
|
|
110
108
|
std::monostate{});
|
|
111
109
|
}
|
|
112
110
|
|
|
113
|
-
void
|
|
111
|
+
void AssociationListenerDeferrer::OnAssociationFailed(
|
|
114
112
|
Types::ErrorKind errorKind, std::string_view errorMessage)
|
|
115
113
|
{
|
|
116
114
|
MS_TRACE();
|
|
@@ -126,7 +124,7 @@ namespace RTC
|
|
|
126
124
|
Error{ .errorKind = errorKind, .message = std::string(errorMessage) });
|
|
127
125
|
}
|
|
128
126
|
|
|
129
|
-
void
|
|
127
|
+
void AssociationListenerDeferrer::OnAssociationClosed(
|
|
130
128
|
Types::ErrorKind errorKind, std::string_view errorMessage)
|
|
131
129
|
{
|
|
132
130
|
MS_TRACE();
|
|
@@ -142,7 +140,7 @@ namespace RTC
|
|
|
142
140
|
Error{ .errorKind = errorKind, .message = std::string(errorMessage) });
|
|
143
141
|
}
|
|
144
142
|
|
|
145
|
-
void
|
|
143
|
+
void AssociationListenerDeferrer::OnAssociationRestarted()
|
|
146
144
|
{
|
|
147
145
|
MS_TRACE();
|
|
148
146
|
|
|
@@ -156,7 +154,7 @@ namespace RTC
|
|
|
156
154
|
std::monostate{});
|
|
157
155
|
}
|
|
158
156
|
|
|
159
|
-
void
|
|
157
|
+
void AssociationListenerDeferrer::OnAssociationError(
|
|
160
158
|
Types::ErrorKind errorKind, std::string_view errorMessage)
|
|
161
159
|
{
|
|
162
160
|
MS_TRACE();
|
|
@@ -172,7 +170,7 @@ namespace RTC
|
|
|
172
170
|
Error{ .errorKind = errorKind, .message = std::string(errorMessage) });
|
|
173
171
|
}
|
|
174
172
|
|
|
175
|
-
void
|
|
173
|
+
void AssociationListenerDeferrer::OnAssociationMessageReceived(Message message)
|
|
176
174
|
{
|
|
177
175
|
MS_TRACE();
|
|
178
176
|
|
|
@@ -186,7 +184,7 @@ namespace RTC
|
|
|
186
184
|
std::move(message));
|
|
187
185
|
}
|
|
188
186
|
|
|
189
|
-
void
|
|
187
|
+
void AssociationListenerDeferrer::OnAssociationStreamsResetPerformed(
|
|
190
188
|
std::span<const uint16_t> outboundStreamIds)
|
|
191
189
|
{
|
|
192
190
|
MS_TRACE();
|
|
@@ -202,7 +200,7 @@ namespace RTC
|
|
|
202
200
|
StreamReset{ .streamIds = { outboundStreamIds.begin(), outboundStreamIds.end() } });
|
|
203
201
|
}
|
|
204
202
|
|
|
205
|
-
void
|
|
203
|
+
void AssociationListenerDeferrer::OnAssociationStreamsResetFailed(
|
|
206
204
|
std::span<const uint16_t> outboundStreamIds, std::string_view errorMessage)
|
|
207
205
|
{
|
|
208
206
|
MS_TRACE();
|
|
@@ -219,7 +217,7 @@ namespace RTC
|
|
|
219
217
|
.errorMessage = std::string(errorMessage) });
|
|
220
218
|
}
|
|
221
219
|
|
|
222
|
-
void
|
|
220
|
+
void AssociationListenerDeferrer::OnAssociationInboundStreamsReset(
|
|
223
221
|
std::span<const uint16_t> inboundStreamIds)
|
|
224
222
|
{
|
|
225
223
|
MS_TRACE();
|
|
@@ -235,9 +233,10 @@ namespace RTC
|
|
|
235
233
|
StreamReset{ .streamIds = { inboundStreamIds.begin(), inboundStreamIds.end() } });
|
|
236
234
|
}
|
|
237
235
|
|
|
238
|
-
void
|
|
236
|
+
void AssociationListenerDeferrer::OnAssociationStreamBufferedAmountLow(uint16_t streamId)
|
|
239
237
|
{
|
|
240
238
|
MS_TRACE();
|
|
239
|
+
;
|
|
241
240
|
|
|
242
241
|
MS_ASSERT(this->ready, "not ready");
|
|
243
242
|
|
|
@@ -249,7 +248,7 @@ namespace RTC
|
|
|
249
248
|
streamId);
|
|
250
249
|
}
|
|
251
250
|
|
|
252
|
-
void
|
|
251
|
+
void AssociationListenerDeferrer::OnAssociationTotalBufferedAmountLow()
|
|
253
252
|
{
|
|
254
253
|
MS_TRACE();
|
|
255
254
|
|
|
@@ -262,5 +261,14 @@ namespace RTC
|
|
|
262
261
|
},
|
|
263
262
|
std::monostate{});
|
|
264
263
|
}
|
|
264
|
+
|
|
265
|
+
bool AssociationListenerDeferrer::OnAssociationIsTransportReadyForSctp()
|
|
266
|
+
{
|
|
267
|
+
MS_TRACE();
|
|
268
|
+
;
|
|
269
|
+
|
|
270
|
+
// Will not be deferred but called directly.
|
|
271
|
+
return this->innerListener->OnAssociationIsTransportReadyForSctp();
|
|
272
|
+
}
|
|
265
273
|
} // namespace SCTP
|
|
266
274
|
} // namespace RTC
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
#define MS_CLASS "RTC::SCTP::HeartbeatHandler"
|
|
2
|
+
// TODO: SCTP: COMMENT
|
|
3
|
+
#define MS_LOG_DEV_LEVEL 3
|
|
4
|
+
|
|
5
|
+
#include "RTC/SCTP/association/HeartbeatHandler.hpp"
|
|
6
|
+
#include "DepLibUV.hpp"
|
|
7
|
+
#include "Logger.hpp"
|
|
8
|
+
#include "Utils.hpp"
|
|
9
|
+
#include "RTC/SCTP/packet/parameters/HeartbeatInfoParameter.hpp"
|
|
10
|
+
#include "RTC/SCTP/public/SctpTypes.hpp"
|
|
11
|
+
#include <string>
|
|
12
|
+
|
|
13
|
+
namespace RTC
|
|
14
|
+
{
|
|
15
|
+
namespace SCTP
|
|
16
|
+
{
|
|
17
|
+
/* Static. */
|
|
18
|
+
|
|
19
|
+
static constexpr int HeartbeatInfoLength{ 8 };
|
|
20
|
+
|
|
21
|
+
/* Instance methods. */
|
|
22
|
+
|
|
23
|
+
HeartbeatHandler::HeartbeatHandler(
|
|
24
|
+
AssociationListener& associationListener, const SctpOptions& sctpOptions, TCBContext* tcbContext)
|
|
25
|
+
: associationListener(associationListener),
|
|
26
|
+
sctpOptions(sctpOptions),
|
|
27
|
+
tcbContext(tcbContext),
|
|
28
|
+
intervalDurationMs(sctpOptions.heartbeatIntervalMs),
|
|
29
|
+
intervalDurationShouldIncludeRtt(sctpOptions.heartbeatIntervalIncludeRtt),
|
|
30
|
+
intervalTimer(
|
|
31
|
+
std::make_unique<BackoffTimerHandle>(
|
|
32
|
+
/*listener*/ this,
|
|
33
|
+
/*baseTimeoutMs*/ sctpOptions.initialRtoMs,
|
|
34
|
+
/*backoffAlgorithm*/ BackoffTimerHandle::BackoffAlgorithm::EXPONENTIAL,
|
|
35
|
+
/*maxBackoffTimeoutMs*/ sctpOptions.timerMaxBackoffTimeoutMs,
|
|
36
|
+
/*maxRestarts*/ std::nullopt)),
|
|
37
|
+
timeoutTimer(
|
|
38
|
+
std::make_unique<BackoffTimerHandle>(
|
|
39
|
+
/*listener*/ this,
|
|
40
|
+
/*baseTimeoutMs*/ sctpOptions.initialRtoMs,
|
|
41
|
+
/*backoffAlgorithm*/ BackoffTimerHandle::BackoffAlgorithm::FIXED,
|
|
42
|
+
/*maxBackoffTimeoutMs*/ std::nullopt,
|
|
43
|
+
/*maxRestarts*/ 0))
|
|
44
|
+
{
|
|
45
|
+
MS_TRACE();
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
HeartbeatHandler::~HeartbeatHandler()
|
|
49
|
+
{
|
|
50
|
+
MS_TRACE();
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
void HeartbeatHandler::RestartTimer()
|
|
54
|
+
{
|
|
55
|
+
MS_TRACE();
|
|
56
|
+
|
|
57
|
+
// Heartbeating has been disabled.
|
|
58
|
+
if (this->intervalDurationMs == 0)
|
|
59
|
+
{
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (intervalDurationShouldIncludeRtt)
|
|
64
|
+
{
|
|
65
|
+
this->intervalTimer->SetBaseTimeoutMs(
|
|
66
|
+
this->intervalDurationMs + this->tcbContext->GetCurrentRtoMs());
|
|
67
|
+
}
|
|
68
|
+
else
|
|
69
|
+
{
|
|
70
|
+
this->intervalTimer->SetBaseTimeoutMs(this->intervalDurationMs);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
this->intervalTimer->Start();
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
void HeartbeatHandler::HandleReceivedHeartbeatRequestChunk(
|
|
77
|
+
const HeartbeatRequestChunk* receivedHeartbeatRequestChunk)
|
|
78
|
+
{
|
|
79
|
+
MS_TRACE();
|
|
80
|
+
|
|
81
|
+
// https://datatracker.ietf.org/doc/html/rfc9260#section-8.3
|
|
82
|
+
//
|
|
83
|
+
// "The receiver of the HEARTBEAT chunk SHOULD immediately respond with a
|
|
84
|
+
// HEARTBEAT ACK chunk that contains the Heartbeat Information TLV,
|
|
85
|
+
// together with any other received TLVs, copied unchanged from the
|
|
86
|
+
// received HEARTBEAT chunk."
|
|
87
|
+
auto packet = this->tcbContext->CreatePacket();
|
|
88
|
+
auto* heartbeatAckChunk = packet->BuildChunkInPlace<HeartbeatAckChunk>();
|
|
89
|
+
|
|
90
|
+
// Here we have to extract all Parameters from receivedHeartbeatRequestChunk
|
|
91
|
+
// and add them into heartbeatAckChunk.
|
|
92
|
+
for (auto it = receivedHeartbeatRequestChunk->ParametersBegin();
|
|
93
|
+
it != receivedHeartbeatRequestChunk->ParametersEnd();
|
|
94
|
+
++it)
|
|
95
|
+
{
|
|
96
|
+
const auto* parameter = *it;
|
|
97
|
+
|
|
98
|
+
heartbeatAckChunk->AddParameter(parameter);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
heartbeatAckChunk->Consolidate();
|
|
102
|
+
|
|
103
|
+
this->tcbContext->Send(packet.get());
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
void HeartbeatHandler::HandleReceivedHeartbeatAckChunk(
|
|
107
|
+
const HeartbeatAckChunk* receivedHeartbeatAckChunk)
|
|
108
|
+
{
|
|
109
|
+
MS_TRACE();
|
|
110
|
+
|
|
111
|
+
this->timeoutTimer->Stop();
|
|
112
|
+
|
|
113
|
+
const auto* heartbeatInfoParameter =
|
|
114
|
+
receivedHeartbeatAckChunk->GetFirstParameterOfType<HeartbeatInfoParameter>();
|
|
115
|
+
|
|
116
|
+
if (!heartbeatInfoParameter)
|
|
117
|
+
{
|
|
118
|
+
this->associationListener.OnAssociationError(
|
|
119
|
+
Types::ErrorKind::PARSE_FAILED,
|
|
120
|
+
"ignoring HEARTBEAT_ACK chunk without Heartbeat Info parameter");
|
|
121
|
+
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const auto* info = heartbeatInfoParameter->GetInfo();
|
|
126
|
+
const uint16_t infoLen = heartbeatInfoParameter->GetInfoLength();
|
|
127
|
+
|
|
128
|
+
if (!info)
|
|
129
|
+
{
|
|
130
|
+
this->associationListener.OnAssociationError(
|
|
131
|
+
Types::ErrorKind::PARSE_FAILED, "ignoring Heartbeat Info parameter without info field");
|
|
132
|
+
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
else if (infoLen != HeartbeatInfoLength)
|
|
136
|
+
{
|
|
137
|
+
this->associationListener.OnAssociationError(
|
|
138
|
+
Types::ErrorKind::PARSE_FAILED, "ignoring Heartbeat Info parameter with wrong length");
|
|
139
|
+
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const uint64_t createdAtMs = Utils::Byte::Get8Bytes(info, 0);
|
|
144
|
+
const uint64_t nowMs = DepLibUV::GetTimeMs();
|
|
145
|
+
|
|
146
|
+
if (createdAtMs > 0 && createdAtMs <= nowMs)
|
|
147
|
+
{
|
|
148
|
+
const uint64_t rtt = nowMs - createdAtMs;
|
|
149
|
+
|
|
150
|
+
MS_DEBUG_DEV("valid HEARTBEAT_ACK Chunk received, calling ObserveRtt(%" PRIu64 ")", rtt);
|
|
151
|
+
|
|
152
|
+
this->tcbContext->ObserveRtt(rtt);
|
|
153
|
+
}
|
|
154
|
+
else
|
|
155
|
+
{
|
|
156
|
+
MS_WARN_DEV(
|
|
157
|
+
"ignoring received HEARTBEAT_ACK Chunk with invalid info content [createdAtMs:%" PRIu64
|
|
158
|
+
", nowMs:%" PRIu64 "]",
|
|
159
|
+
createdAtMs,
|
|
160
|
+
nowMs);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// https://datatracker.ietf.org/doc/html/rfc9260#section-8.1
|
|
164
|
+
//
|
|
165
|
+
// "When a HEARTBEAT ACK chunk is received from the peer endpoint, the
|
|
166
|
+
// counter SHOULD also be reset."
|
|
167
|
+
this->tcbContext->ClearTxErrorCounter();
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
void HeartbeatHandler::OnIntervalTimer(uint64_t& /*baseTimeoutMs*/, bool& /*stop*/)
|
|
171
|
+
{
|
|
172
|
+
MS_TRACE();
|
|
173
|
+
|
|
174
|
+
if (!this->tcbContext->IsAssociationEstablished())
|
|
175
|
+
{
|
|
176
|
+
MS_DEBUG_DEV("won't send HEARTBEAT_REQUEST when SCTP Association is not established");
|
|
177
|
+
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const auto maxRestarts = this->intervalTimer->GetMaxRestarts();
|
|
182
|
+
|
|
183
|
+
MS_DEBUG_TAG(
|
|
184
|
+
sctp,
|
|
185
|
+
"interval timer has expired %zu/%s]",
|
|
186
|
+
this->intervalTimer->GetExpirationCount(),
|
|
187
|
+
maxRestarts ? std::to_string(maxRestarts.value()).c_str() : "Infinite");
|
|
188
|
+
|
|
189
|
+
this->timeoutTimer->SetBaseTimeoutMs(this->tcbContext->GetCurrentRtoMs());
|
|
190
|
+
this->timeoutTimer->Start();
|
|
191
|
+
|
|
192
|
+
alignas(8) uint8_t info[HeartbeatInfoLength];
|
|
193
|
+
const uint64_t nowMs = DepLibUV::GetTimeMs();
|
|
194
|
+
|
|
195
|
+
Utils::Byte::Set8Bytes(info, 0, nowMs);
|
|
196
|
+
|
|
197
|
+
auto packet = this->tcbContext->CreatePacket();
|
|
198
|
+
auto* heartbeatRequestChunk = packet->BuildChunkInPlace<HeartbeatRequestChunk>();
|
|
199
|
+
auto* heartbeatInfoParameter =
|
|
200
|
+
heartbeatRequestChunk->BuildParameterInPlace<HeartbeatInfoParameter>();
|
|
201
|
+
|
|
202
|
+
heartbeatInfoParameter->SetInfo(info, HeartbeatInfoLength);
|
|
203
|
+
heartbeatInfoParameter->Consolidate();
|
|
204
|
+
heartbeatRequestChunk->Consolidate();
|
|
205
|
+
|
|
206
|
+
MS_DEBUG_DEV("sending HEARTBEAT_REQUEST Chunk with info content [nowMs:%" PRIu64 "]", nowMs);
|
|
207
|
+
|
|
208
|
+
this->tcbContext->Send(packet.get());
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
void HeartbeatHandler::OnTimeoutTimer(uint64_t& /*baseTimeoutMs*/, bool& /*stop*/)
|
|
212
|
+
{
|
|
213
|
+
MS_TRACE();
|
|
214
|
+
|
|
215
|
+
const auto maxRestarts = this->timeoutTimer->GetMaxRestarts();
|
|
216
|
+
|
|
217
|
+
MS_DEBUG_TAG(
|
|
218
|
+
sctp,
|
|
219
|
+
"timeout timer has expired %zu/%s]",
|
|
220
|
+
this->timeoutTimer->GetExpirationCount(),
|
|
221
|
+
maxRestarts ? std::to_string(maxRestarts.value()).c_str() : "Infinite");
|
|
222
|
+
|
|
223
|
+
// Note that the timeout timer is not restarted. It will be started again when
|
|
224
|
+
// the interval timer expires.
|
|
225
|
+
MS_ASSERT(!this->timeoutTimer->IsRunning(), "timeout timer shouldn't be running");
|
|
226
|
+
|
|
227
|
+
this->tcbContext->IncrementTxErrorCounter("hearbeat timeout");
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
void HeartbeatHandler::OnTimer(BackoffTimerHandle* backoffTimer, uint64_t& baseTimeoutMs, bool& stop)
|
|
231
|
+
{
|
|
232
|
+
MS_TRACE();
|
|
233
|
+
|
|
234
|
+
if (backoffTimer == this->intervalTimer.get())
|
|
235
|
+
{
|
|
236
|
+
OnIntervalTimer(baseTimeoutMs, stop);
|
|
237
|
+
}
|
|
238
|
+
else if (backoffTimer == this->timeoutTimer.get())
|
|
239
|
+
{
|
|
240
|
+
OnTimeoutTimer(baseTimeoutMs, stop);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
} // namespace SCTP
|
|
244
|
+
} // namespace RTC
|
|
@@ -27,11 +27,11 @@ namespace RTC
|
|
|
27
27
|
const auto* remoteZeroChecksumAcceptableParameter =
|
|
28
28
|
remoteChunk->template GetFirstParameterOfType<ZeroChecksumAcceptableParameter>();
|
|
29
29
|
|
|
30
|
-
negotiatedCapabilities.
|
|
31
|
-
std::min(sctpOptions.
|
|
30
|
+
negotiatedCapabilities.negotiatedMaxOutboundStreams =
|
|
31
|
+
std::min(sctpOptions.announcedMaxOutboundStreams, remoteChunk->GetNumberOfInboundStreams());
|
|
32
32
|
|
|
33
|
-
negotiatedCapabilities.
|
|
34
|
-
std::min(sctpOptions.
|
|
33
|
+
negotiatedCapabilities.negotiatedMaxInboundStreams =
|
|
34
|
+
std::min(sctpOptions.announcedMaxInboundStreams, remoteChunk->GetNumberOfOutboundStreams());
|
|
35
35
|
|
|
36
36
|
// Partial Reliability Extension is negotiated if we desire it and
|
|
37
37
|
// peer announces support via Forward-TSN-Supported Parameter or via
|
|
@@ -75,8 +75,10 @@ namespace RTC
|
|
|
75
75
|
MS_TRACE();
|
|
76
76
|
|
|
77
77
|
MS_DUMP_CLEAN(indentation, "<SCTP::NegotiatedCapabilities>");
|
|
78
|
-
MS_DUMP_CLEAN(
|
|
79
|
-
|
|
78
|
+
MS_DUMP_CLEAN(
|
|
79
|
+
indentation, " negotiated max outbound streams: %" PRIu16, this->negotiatedMaxOutboundStreams);
|
|
80
|
+
MS_DUMP_CLEAN(
|
|
81
|
+
indentation, " negotiated max inbound streams: %" PRIu16, this->negotiatedMaxInboundStreams);
|
|
80
82
|
MS_DUMP_CLEAN(indentation, " partial reliability: %s", this->partialReliability ? "yes" : "no");
|
|
81
83
|
MS_DUMP_CLEAN(
|
|
82
84
|
indentation, " message interleaving: %s", this->messageInterleaving ? "yes" : "no");
|
|
@@ -8,7 +8,7 @@ namespace RTC
|
|
|
8
8
|
{
|
|
9
9
|
namespace SCTP
|
|
10
10
|
{
|
|
11
|
-
PacketSender::PacketSender(Listener
|
|
11
|
+
PacketSender::PacketSender(Listener* listener, AssociationListener& associationListener)
|
|
12
12
|
: listener(listener), associationListener(associationListener)
|
|
13
13
|
{
|
|
14
14
|
MS_TRACE();
|
|
@@ -38,7 +38,12 @@ namespace RTC
|
|
|
38
38
|
const bool sent =
|
|
39
39
|
this->associationListener.OnAssociationSendData(packet->GetBuffer(), packet->GetLength());
|
|
40
40
|
|
|
41
|
-
this->listener
|
|
41
|
+
this->listener->OnPacketSenderPacketSent(this, packet, sent);
|
|
42
|
+
|
|
43
|
+
if (!sent)
|
|
44
|
+
{
|
|
45
|
+
MS_WARN_TAG(sctp, "coudln't send SCTP Packet");
|
|
46
|
+
}
|
|
42
47
|
|
|
43
48
|
return sent;
|
|
44
49
|
}
|
|
@@ -115,10 +115,10 @@ namespace RTC
|
|
|
115
115
|
negotiatedCapabilitiesField->bitC = negotiatedCapabilities.reConfig;
|
|
116
116
|
negotiatedCapabilitiesField->bitD = negotiatedCapabilities.zeroChecksum;
|
|
117
117
|
negotiatedCapabilitiesField->magic2 = htons(StateCookie::Magic2);
|
|
118
|
-
negotiatedCapabilitiesField->
|
|
119
|
-
htons(negotiatedCapabilities.
|
|
120
|
-
negotiatedCapabilitiesField->
|
|
121
|
-
htons(negotiatedCapabilities.
|
|
118
|
+
negotiatedCapabilitiesField->negotiatedMaxOutboundStreams =
|
|
119
|
+
htons(negotiatedCapabilities.negotiatedMaxOutboundStreams);
|
|
120
|
+
negotiatedCapabilitiesField->negotiatedMaxInboundStreams =
|
|
121
|
+
htons(negotiatedCapabilities.negotiatedMaxInboundStreams);
|
|
122
122
|
}
|
|
123
123
|
|
|
124
124
|
Types::SctpImplementation StateCookie::DetermineSctpImplementation(
|
|
@@ -206,10 +206,10 @@ namespace RTC
|
|
|
206
206
|
|
|
207
207
|
NegotiatedCapabilities negotiatedCapabilities;
|
|
208
208
|
|
|
209
|
-
negotiatedCapabilities.
|
|
210
|
-
ntohs(negotiatedCapabilitiesField->
|
|
211
|
-
negotiatedCapabilities.
|
|
212
|
-
ntohs(negotiatedCapabilitiesField->
|
|
209
|
+
negotiatedCapabilities.negotiatedMaxOutboundStreams =
|
|
210
|
+
ntohs(negotiatedCapabilitiesField->negotiatedMaxOutboundStreams);
|
|
211
|
+
negotiatedCapabilities.negotiatedMaxInboundStreams =
|
|
212
|
+
ntohs(negotiatedCapabilitiesField->negotiatedMaxInboundStreams);
|
|
213
213
|
negotiatedCapabilities.partialReliability = negotiatedCapabilitiesField->bitA;
|
|
214
214
|
negotiatedCapabilities.messageInterleaving = negotiatedCapabilitiesField->bitB;
|
|
215
215
|
negotiatedCapabilities.reConfig = negotiatedCapabilitiesField->bitC;
|