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