blob: cc9a71eae8f506ea51ab73c2245e6be5383c5c3f [file] [log] [blame]
Victor Boivieb6580cc2021-04-08 09:56:59 +02001/*
2 * Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10#include "net/dcsctp/socket/dcsctp_socket.h"
11
12#include <algorithm>
13#include <cstdint>
14#include <limits>
15#include <memory>
16#include <string>
17#include <utility>
18#include <vector>
19
Victor Boivie600bb8c2021-08-12 15:43:13 +020020#include "absl/functional/bind_front.h"
Victor Boivieb6580cc2021-04-08 09:56:59 +020021#include "absl/memory/memory.h"
22#include "absl/strings/string_view.h"
23#include "absl/types/optional.h"
24#include "api/array_view.h"
Henrik Boströmb951dc62022-01-26 18:38:13 +010025#include "api/task_queue/task_queue_base.h"
Victor Boivieb6580cc2021-04-08 09:56:59 +020026#include "net/dcsctp/packet/chunk/abort_chunk.h"
27#include "net/dcsctp/packet/chunk/chunk.h"
28#include "net/dcsctp/packet/chunk/cookie_ack_chunk.h"
29#include "net/dcsctp/packet/chunk/cookie_echo_chunk.h"
30#include "net/dcsctp/packet/chunk/data_chunk.h"
31#include "net/dcsctp/packet/chunk/data_common.h"
32#include "net/dcsctp/packet/chunk/error_chunk.h"
33#include "net/dcsctp/packet/chunk/forward_tsn_chunk.h"
34#include "net/dcsctp/packet/chunk/forward_tsn_common.h"
35#include "net/dcsctp/packet/chunk/heartbeat_ack_chunk.h"
36#include "net/dcsctp/packet/chunk/heartbeat_request_chunk.h"
37#include "net/dcsctp/packet/chunk/idata_chunk.h"
38#include "net/dcsctp/packet/chunk/iforward_tsn_chunk.h"
39#include "net/dcsctp/packet/chunk/init_ack_chunk.h"
40#include "net/dcsctp/packet/chunk/init_chunk.h"
41#include "net/dcsctp/packet/chunk/reconfig_chunk.h"
42#include "net/dcsctp/packet/chunk/sack_chunk.h"
43#include "net/dcsctp/packet/chunk/shutdown_ack_chunk.h"
44#include "net/dcsctp/packet/chunk/shutdown_chunk.h"
45#include "net/dcsctp/packet/chunk/shutdown_complete_chunk.h"
46#include "net/dcsctp/packet/chunk_validators.h"
47#include "net/dcsctp/packet/data.h"
48#include "net/dcsctp/packet/error_cause/cookie_received_while_shutting_down_cause.h"
49#include "net/dcsctp/packet/error_cause/error_cause.h"
50#include "net/dcsctp/packet/error_cause/no_user_data_cause.h"
51#include "net/dcsctp/packet/error_cause/out_of_resource_error_cause.h"
52#include "net/dcsctp/packet/error_cause/protocol_violation_cause.h"
53#include "net/dcsctp/packet/error_cause/unrecognized_chunk_type_cause.h"
54#include "net/dcsctp/packet/error_cause/user_initiated_abort_cause.h"
55#include "net/dcsctp/packet/parameter/forward_tsn_supported_parameter.h"
56#include "net/dcsctp/packet/parameter/parameter.h"
57#include "net/dcsctp/packet/parameter/state_cookie_parameter.h"
58#include "net/dcsctp/packet/parameter/supported_extensions_parameter.h"
59#include "net/dcsctp/packet/sctp_packet.h"
60#include "net/dcsctp/packet/tlv_trait.h"
61#include "net/dcsctp/public/dcsctp_message.h"
62#include "net/dcsctp/public/dcsctp_options.h"
63#include "net/dcsctp/public/dcsctp_socket.h"
64#include "net/dcsctp/public/packet_observer.h"
65#include "net/dcsctp/rx/data_tracker.h"
66#include "net/dcsctp/rx/reassembly_queue.h"
67#include "net/dcsctp/socket/callback_deferrer.h"
68#include "net/dcsctp/socket/capabilities.h"
69#include "net/dcsctp/socket/heartbeat_handler.h"
70#include "net/dcsctp/socket/state_cookie.h"
71#include "net/dcsctp/socket/stream_reset_handler.h"
72#include "net/dcsctp/socket/transmission_control_block.h"
73#include "net/dcsctp/timer/timer.h"
74#include "net/dcsctp/tx/retransmission_queue.h"
75#include "net/dcsctp/tx/send_queue.h"
76#include "rtc_base/checks.h"
77#include "rtc_base/logging.h"
78#include "rtc_base/strings/string_builder.h"
79#include "rtc_base/strings/string_format.h"
80
81namespace dcsctp {
82namespace {
83
84// https://tools.ietf.org/html/rfc4960#section-5.1
85constexpr uint32_t kMinVerificationTag = 1;
86constexpr uint32_t kMaxVerificationTag = std::numeric_limits<uint32_t>::max();
87
88// https://tools.ietf.org/html/rfc4960#section-3.3.2
89constexpr uint32_t kMinInitialTsn = 0;
90constexpr uint32_t kMaxInitialTsn = std::numeric_limits<uint32_t>::max();
91
92Capabilities GetCapabilities(const DcSctpOptions& options,
93 const Parameters& parameters) {
94 Capabilities capabilities;
95 absl::optional<SupportedExtensionsParameter> supported_extensions =
96 parameters.get<SupportedExtensionsParameter>();
97
98 if (options.enable_partial_reliability) {
99 capabilities.partial_reliability =
100 parameters.get<ForwardTsnSupportedParameter>().has_value();
101 if (supported_extensions.has_value()) {
102 capabilities.partial_reliability |=
103 supported_extensions->supports(ForwardTsnChunk::kType);
104 }
105 }
106
107 if (options.enable_message_interleaving && supported_extensions.has_value()) {
108 capabilities.message_interleaving =
109 supported_extensions->supports(IDataChunk::kType) &&
110 supported_extensions->supports(IForwardTsnChunk::kType);
111 }
112 if (supported_extensions.has_value() &&
113 supported_extensions->supports(ReConfigChunk::kType)) {
114 capabilities.reconfig = true;
115 }
116 return capabilities;
117}
118
119void AddCapabilityParameters(const DcSctpOptions& options,
120 Parameters::Builder& builder) {
121 std::vector<uint8_t> chunk_types = {ReConfigChunk::kType};
122
123 if (options.enable_partial_reliability) {
124 builder.Add(ForwardTsnSupportedParameter());
125 chunk_types.push_back(ForwardTsnChunk::kType);
126 }
127 if (options.enable_message_interleaving) {
128 chunk_types.push_back(IDataChunk::kType);
129 chunk_types.push_back(IForwardTsnChunk::kType);
130 }
131 builder.Add(SupportedExtensionsParameter(std::move(chunk_types)));
132}
133
134TieTag MakeTieTag(DcSctpSocketCallbacks& cb) {
135 uint32_t tie_tag_upper =
136 cb.GetRandomInt(0, std::numeric_limits<uint32_t>::max());
137 uint32_t tie_tag_lower =
138 cb.GetRandomInt(1, std::numeric_limits<uint32_t>::max());
139 return TieTag(static_cast<uint64_t>(tie_tag_upper) << 32 |
140 static_cast<uint64_t>(tie_tag_lower));
141}
Victor Boivief4fa1662021-09-24 23:01:21 +0200142
143SctpImplementation DeterminePeerImplementation(
144 rtc::ArrayView<const uint8_t> cookie) {
145 if (cookie.size() > 8) {
146 absl::string_view magic(reinterpret_cast<const char*>(cookie.data()), 8);
147 if (magic == "dcSCTP00") {
148 return SctpImplementation::kDcsctp;
149 }
150 if (magic == "KAME-BSD") {
151 return SctpImplementation::kUsrSctp;
152 }
153 }
154 return SctpImplementation::kOther;
155}
Victor Boivieb6580cc2021-04-08 09:56:59 +0200156} // namespace
157
158DcSctpSocket::DcSctpSocket(absl::string_view log_prefix,
159 DcSctpSocketCallbacks& callbacks,
160 std::unique_ptr<PacketObserver> packet_observer,
161 const DcSctpOptions& options)
162 : log_prefix_(std::string(log_prefix) + ": "),
163 packet_observer_(std::move(packet_observer)),
164 options_(options),
165 callbacks_(callbacks),
Henrik Boströmb951dc62022-01-26 18:38:13 +0100166 timer_manager_([this](webrtc::TaskQueueBase::DelayPrecision precision) {
167 return callbacks_.CreateTimeout(precision);
168 }),
Victor Boivieb6580cc2021-04-08 09:56:59 +0200169 t1_init_(timer_manager_.CreateTimer(
170 "t1-init",
Victor Boivie600bb8c2021-08-12 15:43:13 +0200171 absl::bind_front(&DcSctpSocket::OnInitTimerExpiry, this),
Victor Boivieb6580cc2021-04-08 09:56:59 +0200172 TimerOptions(options.t1_init_timeout,
173 TimerBackoffAlgorithm::kExponential,
174 options.max_init_retransmits))),
175 t1_cookie_(timer_manager_.CreateTimer(
176 "t1-cookie",
Victor Boivie600bb8c2021-08-12 15:43:13 +0200177 absl::bind_front(&DcSctpSocket::OnCookieTimerExpiry, this),
Victor Boivieb6580cc2021-04-08 09:56:59 +0200178 TimerOptions(options.t1_cookie_timeout,
179 TimerBackoffAlgorithm::kExponential,
180 options.max_init_retransmits))),
181 t2_shutdown_(timer_manager_.CreateTimer(
182 "t2-shutdown",
Victor Boivie600bb8c2021-08-12 15:43:13 +0200183 absl::bind_front(&DcSctpSocket::OnShutdownTimerExpiry, this),
Victor Boivieb6580cc2021-04-08 09:56:59 +0200184 TimerOptions(options.t2_shutdown_timeout,
185 TimerBackoffAlgorithm::kExponential,
186 options.max_retransmissions))),
Victor Boivieabf61882021-08-12 15:57:49 +0200187 packet_sender_(callbacks_,
188 absl::bind_front(&DcSctpSocket::OnSentPacket, this)),
Victor Boiviebd9031b2021-05-26 19:48:55 +0200189 send_queue_(
190 log_prefix_,
191 options_.max_send_buffer_size,
Victor Boivie236ac502021-05-20 19:34:18 +0200192 [this](StreamID stream_id) {
193 callbacks_.OnBufferedAmountLow(stream_id);
194 },
195 options_.total_buffered_amount_low_threshold,
196 [this]() { callbacks_.OnTotalBufferedAmountLow(); }) {}
Victor Boivieb6580cc2021-04-08 09:56:59 +0200197
198std::string DcSctpSocket::log_prefix() const {
Florent Castelli29ff3ef2022-02-17 16:23:56 +0100199 return log_prefix_ + "[" + std::string(ToString(state_)) + "] ";
Victor Boivieb6580cc2021-04-08 09:56:59 +0200200}
201
202bool DcSctpSocket::IsConsistent() const {
Victor Boivie54e4e352021-09-15 10:42:26 +0200203 if (tcb_ != nullptr && tcb_->reassembly_queue().HasMessages()) {
204 return false;
205 }
Victor Boivieb6580cc2021-04-08 09:56:59 +0200206 switch (state_) {
207 case State::kClosed:
208 return (tcb_ == nullptr && !t1_init_->is_running() &&
209 !t1_cookie_->is_running() && !t2_shutdown_->is_running());
210 case State::kCookieWait:
211 return (tcb_ == nullptr && t1_init_->is_running() &&
212 !t1_cookie_->is_running() && !t2_shutdown_->is_running());
213 case State::kCookieEchoed:
214 return (tcb_ != nullptr && !t1_init_->is_running() &&
215 t1_cookie_->is_running() && !t2_shutdown_->is_running() &&
Victor Boiviec20f1562021-06-16 12:52:42 +0200216 tcb_->has_cookie_echo_chunk());
Victor Boivieb6580cc2021-04-08 09:56:59 +0200217 case State::kEstablished:
218 return (tcb_ != nullptr && !t1_init_->is_running() &&
219 !t1_cookie_->is_running() && !t2_shutdown_->is_running());
220 case State::kShutdownPending:
221 return (tcb_ != nullptr && !t1_init_->is_running() &&
222 !t1_cookie_->is_running() && !t2_shutdown_->is_running());
223 case State::kShutdownSent:
224 return (tcb_ != nullptr && !t1_init_->is_running() &&
225 !t1_cookie_->is_running() && t2_shutdown_->is_running());
226 case State::kShutdownReceived:
227 return (tcb_ != nullptr && !t1_init_->is_running() &&
228 !t1_cookie_->is_running() && !t2_shutdown_->is_running());
229 case State::kShutdownAckSent:
230 return (tcb_ != nullptr && !t1_init_->is_running() &&
231 !t1_cookie_->is_running() && t2_shutdown_->is_running());
232 }
233}
234
235constexpr absl::string_view DcSctpSocket::ToString(DcSctpSocket::State state) {
236 switch (state) {
237 case DcSctpSocket::State::kClosed:
238 return "CLOSED";
239 case DcSctpSocket::State::kCookieWait:
240 return "COOKIE_WAIT";
241 case DcSctpSocket::State::kCookieEchoed:
242 return "COOKIE_ECHOED";
243 case DcSctpSocket::State::kEstablished:
244 return "ESTABLISHED";
245 case DcSctpSocket::State::kShutdownPending:
246 return "SHUTDOWN_PENDING";
247 case DcSctpSocket::State::kShutdownSent:
248 return "SHUTDOWN_SENT";
249 case DcSctpSocket::State::kShutdownReceived:
250 return "SHUTDOWN_RECEIVED";
251 case DcSctpSocket::State::kShutdownAckSent:
252 return "SHUTDOWN_ACK_SENT";
253 }
254}
255
256void DcSctpSocket::SetState(State state, absl::string_view reason) {
257 if (state_ != state) {
258 RTC_DLOG(LS_VERBOSE) << log_prefix_ << "Socket state changed from "
259 << ToString(state_) << " to " << ToString(state)
260 << " due to " << reason;
261 state_ = state;
262 }
263}
264
265void DcSctpSocket::SendInit() {
266 Parameters::Builder params_builder;
267 AddCapabilityParameters(options_, params_builder);
268 InitChunk init(/*initiate_tag=*/connect_params_.verification_tag,
269 /*a_rwnd=*/options_.max_receiver_window_buffer_size,
270 options_.announced_maximum_outgoing_streams,
271 options_.announced_maximum_incoming_streams,
272 connect_params_.initial_tsn, params_builder.Build());
273 SctpPacket::Builder b(VerificationTag(0), options_);
274 b.Add(init);
Victor Boivieabf61882021-08-12 15:57:49 +0200275 packet_sender_.Send(b);
Victor Boivieb6580cc2021-04-08 09:56:59 +0200276}
277
278void DcSctpSocket::MakeConnectionParameters() {
279 VerificationTag new_verification_tag(
280 callbacks_.GetRandomInt(kMinVerificationTag, kMaxVerificationTag));
281 TSN initial_tsn(callbacks_.GetRandomInt(kMinInitialTsn, kMaxInitialTsn));
282 connect_params_.initial_tsn = initial_tsn;
283 connect_params_.verification_tag = new_verification_tag;
284}
285
286void DcSctpSocket::Connect() {
Victor Boivie5755f3e2021-09-29 22:23:15 +0200287 RTC_DCHECK_RUN_ON(&thread_checker_);
Victor Boivie15a0c882021-09-28 21:38:34 +0200288 CallbackDeferrer::ScopedDeferrer deferrer(callbacks_);
289
Victor Boivieb6580cc2021-04-08 09:56:59 +0200290 if (state_ == State::kClosed) {
291 MakeConnectionParameters();
292 RTC_DLOG(LS_INFO)
293 << log_prefix()
294 << rtc::StringFormat(
295 "Connecting. my_verification_tag=%08x, my_initial_tsn=%u",
296 *connect_params_.verification_tag, *connect_params_.initial_tsn);
297 SendInit();
298 t1_init_->Start();
299 SetState(State::kCookieWait, "Connect called");
300 } else {
301 RTC_DLOG(LS_WARNING) << log_prefix()
302 << "Called Connect on a socket that is not closed";
303 }
304 RTC_DCHECK(IsConsistent());
Victor Boivieb6580cc2021-04-08 09:56:59 +0200305}
306
Sergey Sukhanov43972812021-09-17 15:32:48 +0200307void DcSctpSocket::RestoreFromState(const DcSctpSocketHandoverState& state) {
Victor Boivie5755f3e2021-09-29 22:23:15 +0200308 RTC_DCHECK_RUN_ON(&thread_checker_);
Victor Boivie15a0c882021-09-28 21:38:34 +0200309 CallbackDeferrer::ScopedDeferrer deferrer(callbacks_);
310
Sergey Sukhanov43972812021-09-17 15:32:48 +0200311 if (state_ != State::kClosed) {
312 callbacks_.OnError(ErrorKind::kUnsupportedOperation,
313 "Only closed socket can be restored from state");
314 } else {
315 if (state.socket_state ==
316 DcSctpSocketHandoverState::SocketState::kConnected) {
317 VerificationTag my_verification_tag =
318 VerificationTag(state.my_verification_tag);
319 connect_params_.verification_tag = my_verification_tag;
320
321 Capabilities capabilities;
322 capabilities.partial_reliability = state.capabilities.partial_reliability;
323 capabilities.message_interleaving =
324 state.capabilities.message_interleaving;
325 capabilities.reconfig = state.capabilities.reconfig;
326
Sergey Sukhanov72435322021-09-21 13:31:09 +0200327 send_queue_.RestoreFromState(state);
328
Sergey Sukhanov43972812021-09-17 15:32:48 +0200329 tcb_ = std::make_unique<TransmissionControlBlock>(
330 timer_manager_, log_prefix_, options_, capabilities, callbacks_,
331 send_queue_, my_verification_tag, TSN(state.my_initial_tsn),
332 VerificationTag(state.peer_verification_tag),
333 TSN(state.peer_initial_tsn), static_cast<size_t>(0),
334 TieTag(state.tie_tag), packet_sender_,
335 [this]() { return state_ == State::kEstablished; }, &state);
336 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Created peer TCB from state: "
337 << tcb_->ToString();
338
339 SetState(State::kEstablished, "restored from handover state");
340 callbacks_.OnConnected();
341 }
342 }
343
344 RTC_DCHECK(IsConsistent());
Sergey Sukhanov43972812021-09-17 15:32:48 +0200345}
346
Victor Boivieb6580cc2021-04-08 09:56:59 +0200347void DcSctpSocket::Shutdown() {
Victor Boivie5755f3e2021-09-29 22:23:15 +0200348 RTC_DCHECK_RUN_ON(&thread_checker_);
Victor Boivie15a0c882021-09-28 21:38:34 +0200349 CallbackDeferrer::ScopedDeferrer deferrer(callbacks_);
350
Victor Boivieb6580cc2021-04-08 09:56:59 +0200351 if (tcb_ != nullptr) {
352 // https://tools.ietf.org/html/rfc4960#section-9.2
353 // "Upon receipt of the SHUTDOWN primitive from its upper layer, the
354 // endpoint enters the SHUTDOWN-PENDING state and remains there until all
355 // outstanding data has been acknowledged by its peer."
Victor Boivie50a0b122021-05-06 21:07:49 +0200356
357 // TODO(webrtc:12739): Remove this check, as it just hides the problem that
358 // the socket can transition from ShutdownSent to ShutdownPending, or
359 // ShutdownAckSent to ShutdownPending which is illegal.
360 if (state_ != State::kShutdownSent && state_ != State::kShutdownAckSent) {
361 SetState(State::kShutdownPending, "Shutdown called");
362 t1_init_->Stop();
363 t1_cookie_->Stop();
364 MaybeSendShutdownOrAck();
365 }
Victor Boivieb6580cc2021-04-08 09:56:59 +0200366 } else {
367 // Connection closed before even starting to connect, or during the initial
368 // connection phase. There is no outstanding data, so the socket can just
369 // be closed (stopping any connection timers, if any), as this is the
370 // client's intention, by calling Shutdown.
371 InternalClose(ErrorKind::kNoError, "");
372 }
373 RTC_DCHECK(IsConsistent());
Victor Boivieb6580cc2021-04-08 09:56:59 +0200374}
375
376void DcSctpSocket::Close() {
Victor Boivie5755f3e2021-09-29 22:23:15 +0200377 RTC_DCHECK_RUN_ON(&thread_checker_);
Victor Boivie15a0c882021-09-28 21:38:34 +0200378 CallbackDeferrer::ScopedDeferrer deferrer(callbacks_);
379
Victor Boivieb6580cc2021-04-08 09:56:59 +0200380 if (state_ != State::kClosed) {
381 if (tcb_ != nullptr) {
382 SctpPacket::Builder b = tcb_->PacketBuilder();
383 b.Add(AbortChunk(/*filled_in_verification_tag=*/true,
384 Parameters::Builder()
385 .Add(UserInitiatedAbortCause("Close called"))
386 .Build()));
Victor Boivieabf61882021-08-12 15:57:49 +0200387 packet_sender_.Send(b);
Victor Boivieb6580cc2021-04-08 09:56:59 +0200388 }
389 InternalClose(ErrorKind::kNoError, "");
390 } else {
391 RTC_DLOG(LS_INFO) << log_prefix() << "Called Close on a closed socket";
392 }
393 RTC_DCHECK(IsConsistent());
Victor Boivieb6580cc2021-04-08 09:56:59 +0200394}
395
396void DcSctpSocket::CloseConnectionBecauseOfTooManyTransmissionErrors() {
Victor Boivieabf61882021-08-12 15:57:49 +0200397 packet_sender_.Send(tcb_->PacketBuilder().Add(AbortChunk(
Victor Boivieb6580cc2021-04-08 09:56:59 +0200398 true, Parameters::Builder()
399 .Add(UserInitiatedAbortCause("Too many retransmissions"))
400 .Build())));
401 InternalClose(ErrorKind::kTooManyRetries, "Too many retransmissions");
402}
403
404void DcSctpSocket::InternalClose(ErrorKind error, absl::string_view message) {
405 if (state_ != State::kClosed) {
406 t1_init_->Stop();
407 t1_cookie_->Stop();
408 t2_shutdown_->Stop();
409 tcb_ = nullptr;
Victor Boivieb6580cc2021-04-08 09:56:59 +0200410
411 if (error == ErrorKind::kNoError) {
412 callbacks_.OnClosed();
413 } else {
414 callbacks_.OnAborted(error, message);
415 }
416 SetState(State::kClosed, message);
417 }
418 // This method's purpose is to abort/close and make it consistent by ensuring
419 // that e.g. all timers really are stopped.
420 RTC_DCHECK(IsConsistent());
421}
422
423SendStatus DcSctpSocket::Send(DcSctpMessage message,
424 const SendOptions& send_options) {
Victor Boivie5755f3e2021-09-29 22:23:15 +0200425 RTC_DCHECK_RUN_ON(&thread_checker_);
Victor Boivie15a0c882021-09-28 21:38:34 +0200426 CallbackDeferrer::ScopedDeferrer deferrer(callbacks_);
427
Victor Boivieb6580cc2021-04-08 09:56:59 +0200428 if (message.payload().empty()) {
429 callbacks_.OnError(ErrorKind::kProtocolViolation,
430 "Unable to send empty message");
431 return SendStatus::kErrorMessageEmpty;
432 }
433 if (message.payload().size() > options_.max_message_size) {
434 callbacks_.OnError(ErrorKind::kProtocolViolation,
435 "Unable to send too large message");
436 return SendStatus::kErrorMessageTooLarge;
437 }
438 if (state_ == State::kShutdownPending || state_ == State::kShutdownSent ||
439 state_ == State::kShutdownReceived || state_ == State::kShutdownAckSent) {
440 // https://tools.ietf.org/html/rfc4960#section-9.2
441 // "An endpoint should reject any new data request from its upper layer
442 // if it is in the SHUTDOWN-PENDING, SHUTDOWN-SENT, SHUTDOWN-RECEIVED, or
443 // SHUTDOWN-ACK-SENT state."
444 callbacks_.OnError(ErrorKind::kWrongSequence,
445 "Unable to send message as the socket is shutting down");
446 return SendStatus::kErrorShuttingDown;
447 }
448 if (send_queue_.IsFull()) {
449 callbacks_.OnError(ErrorKind::kResourceExhaustion,
450 "Unable to send message as the send queue is full");
451 return SendStatus::kErrorResourceExhaustion;
452 }
453
Victor Boivied3b186e2021-05-05 16:22:29 +0200454 TimeMs now = callbacks_.TimeMillis();
Victor Boivied4716ea2021-08-09 12:26:32 +0200455 ++metrics_.tx_messages_count;
Victor Boivied3b186e2021-05-05 16:22:29 +0200456 send_queue_.Add(now, std::move(message), send_options);
Victor Boivieb6580cc2021-04-08 09:56:59 +0200457 if (tcb_ != nullptr) {
Victor Boivied3b186e2021-05-05 16:22:29 +0200458 tcb_->SendBufferedPackets(now);
Victor Boivieb6580cc2021-04-08 09:56:59 +0200459 }
460
461 RTC_DCHECK(IsConsistent());
Victor Boivieb6580cc2021-04-08 09:56:59 +0200462 return SendStatus::kSuccess;
463}
464
465ResetStreamsStatus DcSctpSocket::ResetStreams(
466 rtc::ArrayView<const StreamID> outgoing_streams) {
Victor Boivie5755f3e2021-09-29 22:23:15 +0200467 RTC_DCHECK_RUN_ON(&thread_checker_);
Victor Boivie15a0c882021-09-28 21:38:34 +0200468 CallbackDeferrer::ScopedDeferrer deferrer(callbacks_);
469
Victor Boivieb6580cc2021-04-08 09:56:59 +0200470 if (tcb_ == nullptr) {
471 callbacks_.OnError(ErrorKind::kWrongSequence,
472 "Can't reset streams as the socket is not connected");
473 return ResetStreamsStatus::kNotConnected;
474 }
475 if (!tcb_->capabilities().reconfig) {
476 callbacks_.OnError(ErrorKind::kUnsupportedOperation,
477 "Can't reset streams as the peer doesn't support it");
478 return ResetStreamsStatus::kNotSupported;
479 }
480
481 tcb_->stream_reset_handler().ResetStreams(outgoing_streams);
Victor Boivief9e116f2022-03-31 17:15:03 +0200482 MaybeSendResetStreamsRequest();
Victor Boivieb6580cc2021-04-08 09:56:59 +0200483
484 RTC_DCHECK(IsConsistent());
Victor Boivieb6580cc2021-04-08 09:56:59 +0200485 return ResetStreamsStatus::kPerformed;
486}
487
488SocketState DcSctpSocket::state() const {
Victor Boivie5755f3e2021-09-29 22:23:15 +0200489 RTC_DCHECK_RUN_ON(&thread_checker_);
Victor Boivieb6580cc2021-04-08 09:56:59 +0200490 switch (state_) {
491 case State::kClosed:
492 return SocketState::kClosed;
493 case State::kCookieWait:
Victor Boivieb6580cc2021-04-08 09:56:59 +0200494 case State::kCookieEchoed:
495 return SocketState::kConnecting;
496 case State::kEstablished:
497 return SocketState::kConnected;
498 case State::kShutdownPending:
Victor Boivieb6580cc2021-04-08 09:56:59 +0200499 case State::kShutdownSent:
Victor Boivieb6580cc2021-04-08 09:56:59 +0200500 case State::kShutdownReceived:
Victor Boivieb6580cc2021-04-08 09:56:59 +0200501 case State::kShutdownAckSent:
502 return SocketState::kShuttingDown;
503 }
504}
505
Florent Castelli0810b052021-05-04 20:12:52 +0200506void DcSctpSocket::SetMaxMessageSize(size_t max_message_size) {
Victor Boivie5755f3e2021-09-29 22:23:15 +0200507 RTC_DCHECK_RUN_ON(&thread_checker_);
Florent Castelli0810b052021-05-04 20:12:52 +0200508 options_.max_message_size = max_message_size;
509}
510
Victor Boivie236ac502021-05-20 19:34:18 +0200511size_t DcSctpSocket::buffered_amount(StreamID stream_id) const {
Victor Boivie5755f3e2021-09-29 22:23:15 +0200512 RTC_DCHECK_RUN_ON(&thread_checker_);
Victor Boivie236ac502021-05-20 19:34:18 +0200513 return send_queue_.buffered_amount(stream_id);
514}
515
516size_t DcSctpSocket::buffered_amount_low_threshold(StreamID stream_id) const {
Victor Boivie5755f3e2021-09-29 22:23:15 +0200517 RTC_DCHECK_RUN_ON(&thread_checker_);
Victor Boivie236ac502021-05-20 19:34:18 +0200518 return send_queue_.buffered_amount_low_threshold(stream_id);
519}
520
521void DcSctpSocket::SetBufferedAmountLowThreshold(StreamID stream_id,
522 size_t bytes) {
Victor Boivie5755f3e2021-09-29 22:23:15 +0200523 RTC_DCHECK_RUN_ON(&thread_checker_);
Victor Boivie236ac502021-05-20 19:34:18 +0200524 send_queue_.SetBufferedAmountLowThreshold(stream_id, bytes);
525}
526
Victor Boivied4716ea2021-08-09 12:26:32 +0200527Metrics DcSctpSocket::GetMetrics() const {
Victor Boivie5755f3e2021-09-29 22:23:15 +0200528 RTC_DCHECK_RUN_ON(&thread_checker_);
Victor Boivied4716ea2021-08-09 12:26:32 +0200529 Metrics metrics = metrics_;
530
531 if (tcb_ != nullptr) {
532 // Update the metrics with some stats that are extracted from
533 // sub-components.
534 metrics.cwnd_bytes = tcb_->cwnd();
535 metrics.srtt_ms = tcb_->current_srtt().value();
536 size_t packet_payload_size =
537 options_.mtu - SctpPacket::kHeaderSize - DataChunk::kHeaderSize;
538 metrics.unack_data_count =
539 tcb_->retransmission_queue().outstanding_items() +
540 (send_queue_.total_buffered_amount() + packet_payload_size - 1) /
541 packet_payload_size;
542 metrics.peer_rwnd_bytes = tcb_->retransmission_queue().rwnd();
543 }
544
545 return metrics;
546}
547
Victor Boivieb6580cc2021-04-08 09:56:59 +0200548void DcSctpSocket::MaybeSendShutdownOnPacketReceived(const SctpPacket& packet) {
549 if (state_ == State::kShutdownSent) {
550 bool has_data_chunk =
551 std::find_if(packet.descriptors().begin(), packet.descriptors().end(),
552 [](const SctpPacket::ChunkDescriptor& descriptor) {
553 return descriptor.type == DataChunk::kType;
554 }) != packet.descriptors().end();
555 if (has_data_chunk) {
556 // https://tools.ietf.org/html/rfc4960#section-9.2
557 // "While in the SHUTDOWN-SENT state, the SHUTDOWN sender MUST immediately
558 // respond to each received packet containing one or more DATA chunks with
559 // a SHUTDOWN chunk and restart the T2-shutdown timer.""
560 SendShutdown();
561 t2_shutdown_->set_duration(tcb_->current_rto());
562 t2_shutdown_->Start();
563 }
564 }
565}
566
Victor Boivief9e116f2022-03-31 17:15:03 +0200567void DcSctpSocket::MaybeSendResetStreamsRequest() {
568 absl::optional<ReConfigChunk> reconfig =
569 tcb_->stream_reset_handler().MakeStreamResetRequest();
570 if (reconfig.has_value()) {
571 SctpPacket::Builder builder = tcb_->PacketBuilder();
572 builder.Add(*reconfig);
573 packet_sender_.Send(builder);
574 }
575}
576
Victor Boivieb6580cc2021-04-08 09:56:59 +0200577bool DcSctpSocket::ValidatePacket(const SctpPacket& packet) {
578 const CommonHeader& header = packet.common_header();
579 VerificationTag my_verification_tag =
580 tcb_ != nullptr ? tcb_->my_verification_tag() : VerificationTag(0);
581
582 if (header.verification_tag == VerificationTag(0)) {
583 if (packet.descriptors().size() == 1 &&
584 packet.descriptors()[0].type == InitChunk::kType) {
585 // https://tools.ietf.org/html/rfc4960#section-8.5.1
586 // "When an endpoint receives an SCTP packet with the Verification Tag
587 // set to 0, it should verify that the packet contains only an INIT chunk.
588 // Otherwise, the receiver MUST silently discard the packet.""
589 return true;
590 }
591 callbacks_.OnError(
592 ErrorKind::kParseFailed,
593 "Only a single INIT chunk can be present in packets sent on "
594 "verification_tag = 0");
595 return false;
596 }
597
598 if (packet.descriptors().size() == 1 &&
599 packet.descriptors()[0].type == AbortChunk::kType) {
600 // https://tools.ietf.org/html/rfc4960#section-8.5.1
601 // "The receiver of an ABORT MUST accept the packet if the Verification
602 // Tag field of the packet matches its own tag and the T bit is not set OR
603 // if it is set to its peer's tag and the T bit is set in the Chunk Flags.
604 // Otherwise, the receiver MUST silently discard the packet and take no
605 // further action."
606 bool t_bit = (packet.descriptors()[0].flags & 0x01) != 0;
607 if (t_bit && tcb_ == nullptr) {
608 // Can't verify the tag - assume it's okey.
609 return true;
610 }
611 if ((!t_bit && header.verification_tag == my_verification_tag) ||
612 (t_bit && header.verification_tag == tcb_->peer_verification_tag())) {
613 return true;
614 }
615 callbacks_.OnError(ErrorKind::kParseFailed,
616 "ABORT chunk verification tag was wrong");
617 return false;
618 }
619
620 if (packet.descriptors()[0].type == InitAckChunk::kType) {
621 if (header.verification_tag == connect_params_.verification_tag) {
622 return true;
623 }
624 callbacks_.OnError(
625 ErrorKind::kParseFailed,
626 rtc::StringFormat(
627 "Packet has invalid verification tag: %08x, expected %08x",
628 *header.verification_tag, *connect_params_.verification_tag));
629 return false;
630 }
631
632 if (packet.descriptors()[0].type == CookieEchoChunk::kType) {
633 // Handled in chunk handler (due to RFC 4960, section 5.2.4).
634 return true;
635 }
636
637 if (packet.descriptors().size() == 1 &&
638 packet.descriptors()[0].type == ShutdownCompleteChunk::kType) {
639 // https://tools.ietf.org/html/rfc4960#section-8.5.1
640 // "The receiver of a SHUTDOWN COMPLETE shall accept the packet if the
641 // Verification Tag field of the packet matches its own tag and the T bit is
642 // not set OR if it is set to its peer's tag and the T bit is set in the
643 // Chunk Flags. Otherwise, the receiver MUST silently discard the packet
644 // and take no further action."
645 bool t_bit = (packet.descriptors()[0].flags & 0x01) != 0;
646 if (t_bit && tcb_ == nullptr) {
647 // Can't verify the tag - assume it's okey.
648 return true;
649 }
650 if ((!t_bit && header.verification_tag == my_verification_tag) ||
651 (t_bit && header.verification_tag == tcb_->peer_verification_tag())) {
652 return true;
653 }
654 callbacks_.OnError(ErrorKind::kParseFailed,
655 "SHUTDOWN_COMPLETE chunk verification tag was wrong");
656 return false;
657 }
658
659 // https://tools.ietf.org/html/rfc4960#section-8.5
660 // "When receiving an SCTP packet, the endpoint MUST ensure that the value
661 // in the Verification Tag field of the received SCTP packet matches its own
662 // tag. If the received Verification Tag value does not match the receiver's
663 // own tag value, the receiver shall silently discard the packet and shall not
664 // process it any further..."
665 if (header.verification_tag == my_verification_tag) {
666 return true;
667 }
668
669 callbacks_.OnError(
670 ErrorKind::kParseFailed,
671 rtc::StringFormat(
672 "Packet has invalid verification tag: %08x, expected %08x",
673 *header.verification_tag, *my_verification_tag));
674 return false;
675}
676
677void DcSctpSocket::HandleTimeout(TimeoutID timeout_id) {
Victor Boivie5755f3e2021-09-29 22:23:15 +0200678 RTC_DCHECK_RUN_ON(&thread_checker_);
Victor Boivie15a0c882021-09-28 21:38:34 +0200679 CallbackDeferrer::ScopedDeferrer deferrer(callbacks_);
680
Victor Boivieb6580cc2021-04-08 09:56:59 +0200681 timer_manager_.HandleTimeout(timeout_id);
682
683 if (tcb_ != nullptr && tcb_->HasTooManyTxErrors()) {
684 // Tearing down the TCB has to be done outside the handlers.
685 CloseConnectionBecauseOfTooManyTransmissionErrors();
686 }
687
688 RTC_DCHECK(IsConsistent());
Victor Boivieb6580cc2021-04-08 09:56:59 +0200689}
690
691void DcSctpSocket::ReceivePacket(rtc::ArrayView<const uint8_t> data) {
Victor Boivie5755f3e2021-09-29 22:23:15 +0200692 RTC_DCHECK_RUN_ON(&thread_checker_);
Victor Boivie15a0c882021-09-28 21:38:34 +0200693 CallbackDeferrer::ScopedDeferrer deferrer(callbacks_);
694
Victor Boivied4716ea2021-08-09 12:26:32 +0200695 ++metrics_.rx_packets_count;
696
Victor Boivieb6580cc2021-04-08 09:56:59 +0200697 if (packet_observer_ != nullptr) {
698 packet_observer_->OnReceivedPacket(callbacks_.TimeMillis(), data);
699 }
700
701 absl::optional<SctpPacket> packet =
702 SctpPacket::Parse(data, options_.disable_checksum_verification);
703 if (!packet.has_value()) {
704 // https://tools.ietf.org/html/rfc4960#section-6.8
705 // "The default procedure for handling invalid SCTP packets is to
706 // silently discard them."
707 callbacks_.OnError(ErrorKind::kParseFailed,
708 "Failed to parse received SCTP packet");
709 RTC_DCHECK(IsConsistent());
Victor Boivieb6580cc2021-04-08 09:56:59 +0200710 return;
711 }
712
713 if (RTC_DLOG_IS_ON) {
714 for (const auto& descriptor : packet->descriptors()) {
715 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Received "
716 << DebugConvertChunkToString(descriptor.data);
717 }
718 }
719
720 if (!ValidatePacket(*packet)) {
721 RTC_DLOG(LS_VERBOSE) << log_prefix()
722 << "Packet failed verification tag check - dropping";
723 RTC_DCHECK(IsConsistent());
Victor Boivieb6580cc2021-04-08 09:56:59 +0200724 return;
725 }
726
727 MaybeSendShutdownOnPacketReceived(*packet);
728
729 for (const auto& descriptor : packet->descriptors()) {
730 if (!Dispatch(packet->common_header(), descriptor)) {
731 break;
732 }
733 }
734
735 if (tcb_ != nullptr) {
736 tcb_->data_tracker().ObservePacketEnd();
737 tcb_->MaybeSendSack();
738 }
739
740 RTC_DCHECK(IsConsistent());
Victor Boivieb6580cc2021-04-08 09:56:59 +0200741}
742
743void DcSctpSocket::DebugPrintOutgoing(rtc::ArrayView<const uint8_t> payload) {
744 auto packet = SctpPacket::Parse(payload);
745 RTC_DCHECK(packet.has_value());
746
747 for (const auto& desc : packet->descriptors()) {
748 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Sent "
749 << DebugConvertChunkToString(desc.data);
750 }
751}
752
753bool DcSctpSocket::Dispatch(const CommonHeader& header,
754 const SctpPacket::ChunkDescriptor& descriptor) {
755 switch (descriptor.type) {
756 case DataChunk::kType:
757 HandleData(header, descriptor);
758 break;
759 case InitChunk::kType:
760 HandleInit(header, descriptor);
761 break;
762 case InitAckChunk::kType:
763 HandleInitAck(header, descriptor);
764 break;
765 case SackChunk::kType:
766 HandleSack(header, descriptor);
767 break;
768 case HeartbeatRequestChunk::kType:
769 HandleHeartbeatRequest(header, descriptor);
770 break;
771 case HeartbeatAckChunk::kType:
772 HandleHeartbeatAck(header, descriptor);
773 break;
774 case AbortChunk::kType:
775 HandleAbort(header, descriptor);
776 break;
777 case ErrorChunk::kType:
778 HandleError(header, descriptor);
779 break;
780 case CookieEchoChunk::kType:
781 HandleCookieEcho(header, descriptor);
782 break;
783 case CookieAckChunk::kType:
784 HandleCookieAck(header, descriptor);
785 break;
786 case ShutdownChunk::kType:
787 HandleShutdown(header, descriptor);
788 break;
789 case ShutdownAckChunk::kType:
790 HandleShutdownAck(header, descriptor);
791 break;
792 case ShutdownCompleteChunk::kType:
793 HandleShutdownComplete(header, descriptor);
794 break;
795 case ReConfigChunk::kType:
796 HandleReconfig(header, descriptor);
797 break;
798 case ForwardTsnChunk::kType:
799 HandleForwardTsn(header, descriptor);
800 break;
801 case IDataChunk::kType:
802 HandleIData(header, descriptor);
803 break;
804 case IForwardTsnChunk::kType:
805 HandleForwardTsn(header, descriptor);
806 break;
807 default:
808 return HandleUnrecognizedChunk(descriptor);
809 }
810 return true;
811}
812
813bool DcSctpSocket::HandleUnrecognizedChunk(
814 const SctpPacket::ChunkDescriptor& descriptor) {
815 bool report_as_error = (descriptor.type & 0x40) != 0;
816 bool continue_processing = (descriptor.type & 0x80) != 0;
817 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Received unknown chunk: "
818 << static_cast<int>(descriptor.type);
819 if (report_as_error) {
820 rtc::StringBuilder sb;
821 sb << "Received unknown chunk of type: "
822 << static_cast<int>(descriptor.type) << " with report-error bit set";
823 callbacks_.OnError(ErrorKind::kParseFailed, sb.str());
824 RTC_DLOG(LS_VERBOSE)
825 << log_prefix()
826 << "Unknown chunk, with type indicating it should be reported.";
827
828 // https://tools.ietf.org/html/rfc4960#section-3.2
829 // "... report in an ERROR chunk using the 'Unrecognized Chunk Type'
830 // cause."
831 if (tcb_ != nullptr) {
832 // Need TCB - this chunk must be sent with a correct verification tag.
Victor Boivieabf61882021-08-12 15:57:49 +0200833 packet_sender_.Send(tcb_->PacketBuilder().Add(
Victor Boivieb6580cc2021-04-08 09:56:59 +0200834 ErrorChunk(Parameters::Builder()
835 .Add(UnrecognizedChunkTypeCause(std::vector<uint8_t>(
836 descriptor.data.begin(), descriptor.data.end())))
837 .Build())));
838 }
839 }
840 if (!continue_processing) {
841 // https://tools.ietf.org/html/rfc4960#section-3.2
842 // "Stop processing this SCTP packet and discard it, do not process any
843 // further chunks within it."
844 RTC_DLOG(LS_VERBOSE) << log_prefix()
845 << "Unknown chunk, with type indicating not to "
846 "process any further chunks";
847 }
848
849 return continue_processing;
850}
851
852absl::optional<DurationMs> DcSctpSocket::OnInitTimerExpiry() {
853 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Timer " << t1_init_->name()
854 << " has expired: " << t1_init_->expiration_count()
Victor Boivie9680d292021-08-30 10:23:49 +0200855 << "/" << t1_init_->options().max_restarts.value_or(-1);
Victor Boivieb6580cc2021-04-08 09:56:59 +0200856 RTC_DCHECK(state_ == State::kCookieWait);
857
858 if (t1_init_->is_running()) {
859 SendInit();
860 } else {
861 InternalClose(ErrorKind::kTooManyRetries, "No INIT_ACK received");
862 }
863 RTC_DCHECK(IsConsistent());
864 return absl::nullopt;
865}
866
867absl::optional<DurationMs> DcSctpSocket::OnCookieTimerExpiry() {
868 // https://tools.ietf.org/html/rfc4960#section-4
869 // "If the T1-cookie timer expires, the endpoint MUST retransmit COOKIE
870 // ECHO and restart the T1-cookie timer without changing state. This MUST
871 // be repeated up to 'Max.Init.Retransmits' times. After that, the endpoint
872 // MUST abort the initialization process and report the error to the SCTP
873 // user."
874 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Timer " << t1_cookie_->name()
875 << " has expired: " << t1_cookie_->expiration_count()
Victor Boivie9680d292021-08-30 10:23:49 +0200876 << "/"
877 << t1_cookie_->options().max_restarts.value_or(-1);
Victor Boivieb6580cc2021-04-08 09:56:59 +0200878
879 RTC_DCHECK(state_ == State::kCookieEchoed);
880
881 if (t1_cookie_->is_running()) {
Victor Boiviec20f1562021-06-16 12:52:42 +0200882 tcb_->SendBufferedPackets(callbacks_.TimeMillis());
Victor Boivieb6580cc2021-04-08 09:56:59 +0200883 } else {
884 InternalClose(ErrorKind::kTooManyRetries, "No COOKIE_ACK received");
885 }
886
887 RTC_DCHECK(IsConsistent());
888 return absl::nullopt;
889}
890
891absl::optional<DurationMs> DcSctpSocket::OnShutdownTimerExpiry() {
892 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Timer " << t2_shutdown_->name()
893 << " has expired: " << t2_shutdown_->expiration_count()
Victor Boivie9680d292021-08-30 10:23:49 +0200894 << "/"
895 << t2_shutdown_->options().max_restarts.value_or(-1);
Victor Boivieb6580cc2021-04-08 09:56:59 +0200896
Victor Boivie914925f2021-05-07 11:22:50 +0200897 if (!t2_shutdown_->is_running()) {
Victor Boivieb6580cc2021-04-08 09:56:59 +0200898 // https://tools.ietf.org/html/rfc4960#section-9.2
899 // "An endpoint should limit the number of retransmissions of the SHUTDOWN
900 // chunk to the protocol parameter 'Association.Max.Retrans'. If this
901 // threshold is exceeded, the endpoint should destroy the TCB..."
902
Victor Boivieabf61882021-08-12 15:57:49 +0200903 packet_sender_.Send(tcb_->PacketBuilder().Add(
Victor Boivieb6580cc2021-04-08 09:56:59 +0200904 AbortChunk(true, Parameters::Builder()
905 .Add(UserInitiatedAbortCause(
906 "Too many retransmissions of SHUTDOWN"))
907 .Build())));
908
909 InternalClose(ErrorKind::kTooManyRetries, "No SHUTDOWN_ACK received");
Victor Boivie914925f2021-05-07 11:22:50 +0200910 RTC_DCHECK(IsConsistent());
911 return absl::nullopt;
Victor Boivieb6580cc2021-04-08 09:56:59 +0200912 }
Victor Boivie914925f2021-05-07 11:22:50 +0200913
914 // https://tools.ietf.org/html/rfc4960#section-9.2
915 // "If the timer expires, the endpoint must resend the SHUTDOWN with the
916 // updated last sequential TSN received from its peer."
917 SendShutdown();
Victor Boivieb6580cc2021-04-08 09:56:59 +0200918 RTC_DCHECK(IsConsistent());
919 return tcb_->current_rto();
920}
921
Victor Boivieabf61882021-08-12 15:57:49 +0200922void DcSctpSocket::OnSentPacket(rtc::ArrayView<const uint8_t> packet,
923 SendPacketStatus status) {
924 // The packet observer is invoked even if the packet was failed to be sent, to
925 // indicate an attempt was made.
Victor Boivieb6580cc2021-04-08 09:56:59 +0200926 if (packet_observer_ != nullptr) {
Victor Boivieabf61882021-08-12 15:57:49 +0200927 packet_observer_->OnSentPacket(callbacks_.TimeMillis(), packet);
Victor Boivieb6580cc2021-04-08 09:56:59 +0200928 }
Victor Boivieabf61882021-08-12 15:57:49 +0200929
930 if (status == SendPacketStatus::kSuccess) {
931 if (RTC_DLOG_IS_ON) {
932 DebugPrintOutgoing(packet);
933 }
934
935 // The heartbeat interval timer is restarted for every sent packet, to
936 // fire when the outgoing channel is inactive.
937 if (tcb_ != nullptr) {
938 tcb_->heartbeat_handler().RestartTimer();
939 }
940
941 ++metrics_.tx_packets_count;
942 }
Victor Boivieb6580cc2021-04-08 09:56:59 +0200943}
944
945bool DcSctpSocket::ValidateHasTCB() {
946 if (tcb_ != nullptr) {
947 return true;
948 }
949
950 callbacks_.OnError(
951 ErrorKind::kNotConnected,
952 "Received unexpected commands on socket that is not connected");
953 return false;
954}
955
956void DcSctpSocket::ReportFailedToParseChunk(int chunk_type) {
957 rtc::StringBuilder sb;
958 sb << "Failed to parse chunk of type: " << chunk_type;
959 callbacks_.OnError(ErrorKind::kParseFailed, sb.str());
960}
961
962void DcSctpSocket::HandleData(const CommonHeader& header,
963 const SctpPacket::ChunkDescriptor& descriptor) {
964 absl::optional<DataChunk> chunk = DataChunk::Parse(descriptor.data);
965 if (ValidateParseSuccess(chunk) && ValidateHasTCB()) {
966 HandleDataCommon(*chunk);
967 }
968}
969
970void DcSctpSocket::HandleIData(const CommonHeader& header,
971 const SctpPacket::ChunkDescriptor& descriptor) {
972 absl::optional<IDataChunk> chunk = IDataChunk::Parse(descriptor.data);
973 if (ValidateParseSuccess(chunk) && ValidateHasTCB()) {
974 HandleDataCommon(*chunk);
975 }
976}
977
978void DcSctpSocket::HandleDataCommon(AnyDataChunk& chunk) {
979 TSN tsn = chunk.tsn();
980 AnyDataChunk::ImmediateAckFlag immediate_ack = chunk.options().immediate_ack;
981 Data data = std::move(chunk).extract();
982
Victor Boivie4b7024b2021-12-01 18:57:22 +0000983 if (data.payload.empty()) {
Victor Boivieb6580cc2021-04-08 09:56:59 +0200984 // Empty DATA chunks are illegal.
Victor Boivieabf61882021-08-12 15:57:49 +0200985 packet_sender_.Send(tcb_->PacketBuilder().Add(
Victor Boivieb6580cc2021-04-08 09:56:59 +0200986 ErrorChunk(Parameters::Builder().Add(NoUserDataCause(tsn)).Build())));
987 callbacks_.OnError(ErrorKind::kProtocolViolation,
988 "Received DATA chunk with no user data");
989 return;
990 }
991
992 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Handle DATA, queue_size="
993 << tcb_->reassembly_queue().queued_bytes()
994 << ", water_mark="
995 << tcb_->reassembly_queue().watermark_bytes()
996 << ", full=" << tcb_->reassembly_queue().is_full()
997 << ", above="
998 << tcb_->reassembly_queue().is_above_watermark();
999
1000 if (tcb_->reassembly_queue().is_full()) {
1001 // If the reassembly queue is full, there is nothing that can be done. The
1002 // specification only allows dropping gap-ack-blocks, and that's not
1003 // likely to help as the socket has been trying to fill gaps since the
1004 // watermark was reached.
Victor Boivieabf61882021-08-12 15:57:49 +02001005 packet_sender_.Send(tcb_->PacketBuilder().Add(AbortChunk(
Victor Boivieb6580cc2021-04-08 09:56:59 +02001006 true, Parameters::Builder().Add(OutOfResourceErrorCause()).Build())));
1007 InternalClose(ErrorKind::kResourceExhaustion,
1008 "Reassembly Queue is exhausted");
1009 return;
1010 }
1011
1012 if (tcb_->reassembly_queue().is_above_watermark()) {
1013 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Is above high watermark";
1014 // If the reassembly queue is above its high watermark, only accept data
1015 // chunks that increase its cumulative ack tsn in an attempt to fill gaps
1016 // to deliver messages.
1017 if (!tcb_->data_tracker().will_increase_cum_ack_tsn(tsn)) {
1018 RTC_DLOG(LS_VERBOSE) << log_prefix()
1019 << "Rejected data because of exceeding watermark";
1020 tcb_->data_tracker().ForceImmediateSack();
1021 return;
1022 }
1023 }
1024
1025 if (!tcb_->data_tracker().IsTSNValid(tsn)) {
1026 RTC_DLOG(LS_VERBOSE) << log_prefix()
1027 << "Rejected data because of failing TSN validity";
1028 return;
1029 }
1030
Victor Boivie568bc232022-03-20 19:59:03 +01001031 if (tcb_->data_tracker().Observe(tsn, immediate_ack)) {
1032 tcb_->reassembly_queue().MaybeResetStreamsDeferred(
1033 tcb_->data_tracker().last_cumulative_acked_tsn());
1034 tcb_->reassembly_queue().Add(tsn, std::move(data));
1035 DeliverReassembledMessages();
1036 }
Victor Boivieb6580cc2021-04-08 09:56:59 +02001037}
1038
1039void DcSctpSocket::HandleInit(const CommonHeader& header,
1040 const SctpPacket::ChunkDescriptor& descriptor) {
1041 absl::optional<InitChunk> chunk = InitChunk::Parse(descriptor.data);
1042 if (!ValidateParseSuccess(chunk)) {
1043 return;
1044 }
1045
1046 if (chunk->initiate_tag() == VerificationTag(0) ||
1047 chunk->nbr_outbound_streams() == 0 || chunk->nbr_inbound_streams() == 0) {
1048 // https://tools.ietf.org/html/rfc4960#section-3.3.2
1049 // "If the value of the Initiate Tag in a received INIT chunk is found
1050 // to be 0, the receiver MUST treat it as an error and close the
1051 // association by transmitting an ABORT."
1052
1053 // "A receiver of an INIT with the OS value set to 0 SHOULD abort the
1054 // association."
1055
1056 // "A receiver of an INIT with the MIS value of 0 SHOULD abort the
1057 // association."
1058
Victor Boivieabf61882021-08-12 15:57:49 +02001059 packet_sender_.Send(
1060 SctpPacket::Builder(VerificationTag(0), options_)
1061 .Add(AbortChunk(
1062 /*filled_in_verification_tag=*/false,
1063 Parameters::Builder()
1064 .Add(ProtocolViolationCause("INIT malformed"))
1065 .Build())));
Victor Boivieb6580cc2021-04-08 09:56:59 +02001066 InternalClose(ErrorKind::kProtocolViolation, "Received invalid INIT");
1067 return;
1068 }
1069
1070 if (state_ == State::kShutdownAckSent) {
1071 // https://tools.ietf.org/html/rfc4960#section-9.2
1072 // "If an endpoint is in the SHUTDOWN-ACK-SENT state and receives an
1073 // INIT chunk (e.g., if the SHUTDOWN COMPLETE was lost) with source and
1074 // destination transport addresses (either in the IP addresses or in the
1075 // INIT chunk) that belong to this association, it should discard the INIT
1076 // chunk and retransmit the SHUTDOWN ACK chunk."
1077 RTC_DLOG(LS_VERBOSE) << log_prefix()
1078 << "Received Init indicating lost ShutdownComplete";
1079 SendShutdownAck();
1080 return;
1081 }
1082
1083 TieTag tie_tag(0);
1084 if (state_ == State::kClosed) {
1085 RTC_DLOG(LS_VERBOSE) << log_prefix()
1086 << "Received Init in closed state (normal)";
1087
1088 MakeConnectionParameters();
1089 } else if (state_ == State::kCookieWait || state_ == State::kCookieEchoed) {
1090 // https://tools.ietf.org/html/rfc4960#section-5.2.1
1091 // "This usually indicates an initialization collision, i.e., each
1092 // endpoint is attempting, at about the same time, to establish an
1093 // association with the other endpoint. Upon receipt of an INIT in the
1094 // COOKIE-WAIT state, an endpoint MUST respond with an INIT ACK using the
1095 // same parameters it sent in its original INIT chunk (including its
1096 // Initiate Tag, unchanged). When responding, the endpoint MUST send the
1097 // INIT ACK back to the same address that the original INIT (sent by this
1098 // endpoint) was sent."
1099 RTC_DLOG(LS_VERBOSE) << log_prefix()
1100 << "Received Init indicating simultaneous connections";
1101 } else {
1102 RTC_DCHECK(tcb_ != nullptr);
1103 // https://tools.ietf.org/html/rfc4960#section-5.2.2
1104 // "The outbound SCTP packet containing this INIT ACK MUST carry a
1105 // Verification Tag value equal to the Initiate Tag found in the
1106 // unexpected INIT. And the INIT ACK MUST contain a new Initiate Tag
1107 // (randomly generated; see Section 5.3.1). Other parameters for the
1108 // endpoint SHOULD be copied from the existing parameters of the
1109 // association (e.g., number of outbound streams) into the INIT ACK and
1110 // cookie."
1111 RTC_DLOG(LS_VERBOSE) << log_prefix()
1112 << "Received Init indicating restarted connection";
1113 // Create a new verification tag - different from the previous one.
1114 for (int tries = 0; tries < 10; ++tries) {
1115 connect_params_.verification_tag = VerificationTag(
1116 callbacks_.GetRandomInt(kMinVerificationTag, kMaxVerificationTag));
1117 if (connect_params_.verification_tag != tcb_->my_verification_tag()) {
1118 break;
1119 }
1120 }
1121
1122 // Make the initial TSN make a large jump, so that there is no overlap
1123 // with the old and new association.
1124 connect_params_.initial_tsn =
1125 TSN(*tcb_->retransmission_queue().next_tsn() + 1000000);
1126 tie_tag = tcb_->tie_tag();
1127 }
1128
1129 RTC_DLOG(LS_VERBOSE)
1130 << log_prefix()
1131 << rtc::StringFormat(
1132 "Proceeding with connection. my_verification_tag=%08x, "
1133 "my_initial_tsn=%u, peer_verification_tag=%08x, "
1134 "peer_initial_tsn=%u",
1135 *connect_params_.verification_tag, *connect_params_.initial_tsn,
1136 *chunk->initiate_tag(), *chunk->initial_tsn());
1137
1138 Capabilities capabilities = GetCapabilities(options_, chunk->parameters());
1139
1140 SctpPacket::Builder b(chunk->initiate_tag(), options_);
1141 Parameters::Builder params_builder =
1142 Parameters::Builder().Add(StateCookieParameter(
1143 StateCookie(chunk->initiate_tag(), chunk->initial_tsn(),
1144 chunk->a_rwnd(), tie_tag, capabilities)
1145 .Serialize()));
1146 AddCapabilityParameters(options_, params_builder);
1147
1148 InitAckChunk init_ack(/*initiate_tag=*/connect_params_.verification_tag,
1149 options_.max_receiver_window_buffer_size,
1150 options_.announced_maximum_outgoing_streams,
1151 options_.announced_maximum_incoming_streams,
1152 connect_params_.initial_tsn, params_builder.Build());
1153 b.Add(init_ack);
Victor Boivieabf61882021-08-12 15:57:49 +02001154 packet_sender_.Send(b);
Victor Boivieb6580cc2021-04-08 09:56:59 +02001155}
1156
Victor Boivieb6580cc2021-04-08 09:56:59 +02001157void DcSctpSocket::HandleInitAck(
1158 const CommonHeader& header,
1159 const SctpPacket::ChunkDescriptor& descriptor) {
1160 absl::optional<InitAckChunk> chunk = InitAckChunk::Parse(descriptor.data);
1161 if (!ValidateParseSuccess(chunk)) {
1162 return;
1163 }
1164
1165 if (state_ != State::kCookieWait) {
1166 // https://tools.ietf.org/html/rfc4960#section-5.2.3
1167 // "If an INIT ACK is received by an endpoint in any state other than
1168 // the COOKIE-WAIT state, the endpoint should discard the INIT ACK chunk."
1169 RTC_DLOG(LS_VERBOSE) << log_prefix()
1170 << "Received INIT_ACK in unexpected state";
1171 return;
1172 }
1173
1174 auto cookie = chunk->parameters().get<StateCookieParameter>();
1175 if (!cookie.has_value()) {
Victor Boivieabf61882021-08-12 15:57:49 +02001176 packet_sender_.Send(
1177 SctpPacket::Builder(connect_params_.verification_tag, options_)
1178 .Add(AbortChunk(
1179 /*filled_in_verification_tag=*/false,
1180 Parameters::Builder()
1181 .Add(ProtocolViolationCause("INIT-ACK malformed"))
1182 .Build())));
Victor Boivieb6580cc2021-04-08 09:56:59 +02001183 InternalClose(ErrorKind::kProtocolViolation,
1184 "InitAck chunk doesn't contain a cookie");
1185 return;
1186 }
1187 Capabilities capabilities = GetCapabilities(options_, chunk->parameters());
1188 t1_init_->Stop();
1189
Victor Boivief4fa1662021-09-24 23:01:21 +02001190 peer_implementation_ = DeterminePeerImplementation(cookie->data());
1191
Victor Boivieb6580cc2021-04-08 09:56:59 +02001192 tcb_ = std::make_unique<TransmissionControlBlock>(
1193 timer_manager_, log_prefix_, options_, capabilities, callbacks_,
1194 send_queue_, connect_params_.verification_tag,
1195 connect_params_.initial_tsn, chunk->initiate_tag(), chunk->initial_tsn(),
Victor Boivieabf61882021-08-12 15:57:49 +02001196 chunk->a_rwnd(), MakeTieTag(callbacks_), packet_sender_,
1197 [this]() { return state_ == State::kEstablished; });
Victor Boivieb6580cc2021-04-08 09:56:59 +02001198 RTC_DLOG(LS_VERBOSE) << log_prefix()
1199 << "Created peer TCB: " << tcb_->ToString();
1200
1201 SetState(State::kCookieEchoed, "INIT_ACK received");
1202
1203 // The connection isn't fully established just yet.
Victor Boiviec20f1562021-06-16 12:52:42 +02001204 tcb_->SetCookieEchoChunk(CookieEchoChunk(cookie->data()));
1205 tcb_->SendBufferedPackets(callbacks_.TimeMillis());
Victor Boivieb6580cc2021-04-08 09:56:59 +02001206 t1_cookie_->Start();
1207}
1208
1209void DcSctpSocket::HandleCookieEcho(
1210 const CommonHeader& header,
1211 const SctpPacket::ChunkDescriptor& descriptor) {
1212 absl::optional<CookieEchoChunk> chunk =
1213 CookieEchoChunk::Parse(descriptor.data);
1214 if (!ValidateParseSuccess(chunk)) {
1215 return;
1216 }
1217
1218 absl::optional<StateCookie> cookie =
1219 StateCookie::Deserialize(chunk->cookie());
1220 if (!cookie.has_value()) {
1221 callbacks_.OnError(ErrorKind::kParseFailed, "Failed to parse state cookie");
1222 return;
1223 }
1224
1225 if (tcb_ != nullptr) {
1226 if (!HandleCookieEchoWithTCB(header, *cookie)) {
1227 return;
1228 }
1229 } else {
1230 if (header.verification_tag != connect_params_.verification_tag) {
1231 callbacks_.OnError(
1232 ErrorKind::kParseFailed,
1233 rtc::StringFormat(
1234 "Received CookieEcho with invalid verification tag: %08x, "
1235 "expected %08x",
1236 *header.verification_tag, *connect_params_.verification_tag));
1237 return;
1238 }
1239 }
1240
1241 // The init timer can be running on simultaneous connections.
1242 t1_init_->Stop();
1243 t1_cookie_->Stop();
1244 if (state_ != State::kEstablished) {
Victor Boiviec20f1562021-06-16 12:52:42 +02001245 if (tcb_ != nullptr) {
1246 tcb_->ClearCookieEchoChunk();
1247 }
Victor Boivieb6580cc2021-04-08 09:56:59 +02001248 SetState(State::kEstablished, "COOKIE_ECHO received");
1249 callbacks_.OnConnected();
1250 }
1251
1252 if (tcb_ == nullptr) {
1253 tcb_ = std::make_unique<TransmissionControlBlock>(
1254 timer_manager_, log_prefix_, options_, cookie->capabilities(),
1255 callbacks_, send_queue_, connect_params_.verification_tag,
1256 connect_params_.initial_tsn, cookie->initiate_tag(),
1257 cookie->initial_tsn(), cookie->a_rwnd(), MakeTieTag(callbacks_),
Victor Boivieabf61882021-08-12 15:57:49 +02001258 packet_sender_, [this]() { return state_ == State::kEstablished; });
Victor Boivieb6580cc2021-04-08 09:56:59 +02001259 RTC_DLOG(LS_VERBOSE) << log_prefix()
1260 << "Created peer TCB: " << tcb_->ToString();
1261 }
1262
1263 SctpPacket::Builder b = tcb_->PacketBuilder();
1264 b.Add(CookieAckChunk());
1265
1266 // https://tools.ietf.org/html/rfc4960#section-5.1
1267 // "A COOKIE ACK chunk may be bundled with any pending DATA chunks (and/or
1268 // SACK chunks), but the COOKIE ACK chunk MUST be the first chunk in the
1269 // packet."
Victor Boivied3b186e2021-05-05 16:22:29 +02001270 tcb_->SendBufferedPackets(b, callbacks_.TimeMillis());
Victor Boivieb6580cc2021-04-08 09:56:59 +02001271}
1272
1273bool DcSctpSocket::HandleCookieEchoWithTCB(const CommonHeader& header,
1274 const StateCookie& cookie) {
1275 RTC_DLOG(LS_VERBOSE) << log_prefix()
1276 << "Handling CookieEchoChunk with TCB. local_tag="
1277 << *tcb_->my_verification_tag()
1278 << ", peer_tag=" << *header.verification_tag
1279 << ", tcb_tag=" << *tcb_->peer_verification_tag()
1280 << ", cookie_tag=" << *cookie.initiate_tag()
1281 << ", local_tie_tag=" << *tcb_->tie_tag()
1282 << ", peer_tie_tag=" << *cookie.tie_tag();
1283 // https://tools.ietf.org/html/rfc4960#section-5.2.4
1284 // "Handle a COOKIE ECHO when a TCB Exists"
1285 if (header.verification_tag != tcb_->my_verification_tag() &&
1286 tcb_->peer_verification_tag() != cookie.initiate_tag() &&
1287 cookie.tie_tag() == tcb_->tie_tag()) {
1288 // "A) In this case, the peer may have restarted."
1289 if (state_ == State::kShutdownAckSent) {
1290 // "If the endpoint is in the SHUTDOWN-ACK-SENT state and recognizes
1291 // that the peer has restarted ... it MUST NOT set up a new association
1292 // but instead resend the SHUTDOWN ACK and send an ERROR chunk with a
1293 // "Cookie Received While Shutting Down" error cause to its peer."
1294 SctpPacket::Builder b(cookie.initiate_tag(), options_);
1295 b.Add(ShutdownAckChunk());
1296 b.Add(ErrorChunk(Parameters::Builder()
1297 .Add(CookieReceivedWhileShuttingDownCause())
1298 .Build()));
Victor Boivieabf61882021-08-12 15:57:49 +02001299 packet_sender_.Send(b);
Victor Boivieb6580cc2021-04-08 09:56:59 +02001300 callbacks_.OnError(ErrorKind::kWrongSequence,
1301 "Received COOKIE-ECHO while shutting down");
1302 return false;
1303 }
1304
1305 RTC_DLOG(LS_VERBOSE) << log_prefix()
1306 << "Received COOKIE-ECHO indicating a restarted peer";
1307
Björn Terelius7bd3bc12022-05-05 14:44:25 +00001308 // If a message was partly sent, and the peer restarted, resend it in
1309 // full by resetting the send queue.
1310 send_queue_.Reset();
Victor Boivieb6580cc2021-04-08 09:56:59 +02001311 tcb_ = nullptr;
1312 callbacks_.OnConnectionRestarted();
1313 } else if (header.verification_tag == tcb_->my_verification_tag() &&
1314 tcb_->peer_verification_tag() != cookie.initiate_tag()) {
1315 // TODO(boivie): Handle the peer_tag == 0?
1316 // "B) In this case, both sides may be attempting to start an
1317 // association at about the same time, but the peer endpoint started its
1318 // INIT after responding to the local endpoint's INIT."
1319 RTC_DLOG(LS_VERBOSE)
1320 << log_prefix()
1321 << "Received COOKIE-ECHO indicating simultaneous connections";
1322 tcb_ = nullptr;
1323 } else if (header.verification_tag != tcb_->my_verification_tag() &&
1324 tcb_->peer_verification_tag() == cookie.initiate_tag() &&
1325 cookie.tie_tag() == TieTag(0)) {
1326 // "C) In this case, the local endpoint's cookie has arrived late.
1327 // Before it arrived, the local endpoint sent an INIT and received an
1328 // INIT ACK and finally sent a COOKIE ECHO with the peer's same tag but
1329 // a new tag of its own. The cookie should be silently discarded. The
1330 // endpoint SHOULD NOT change states and should leave any timers
1331 // running."
1332 RTC_DLOG(LS_VERBOSE)
1333 << log_prefix()
1334 << "Received COOKIE-ECHO indicating a late COOKIE-ECHO. Discarding";
1335 return false;
1336 } else if (header.verification_tag == tcb_->my_verification_tag() &&
1337 tcb_->peer_verification_tag() == cookie.initiate_tag()) {
1338 // "D) When both local and remote tags match, the endpoint should enter
1339 // the ESTABLISHED state, if it is in the COOKIE-ECHOED state. It
1340 // should stop any cookie timer that may be running and send a COOKIE
1341 // ACK."
1342 RTC_DLOG(LS_VERBOSE)
1343 << log_prefix()
1344 << "Received duplicate COOKIE-ECHO, probably because of peer not "
1345 "receiving COOKIE-ACK and retransmitting COOKIE-ECHO. Continuing.";
1346 }
1347 return true;
1348}
1349
1350void DcSctpSocket::HandleCookieAck(
1351 const CommonHeader& header,
1352 const SctpPacket::ChunkDescriptor& descriptor) {
1353 absl::optional<CookieAckChunk> chunk = CookieAckChunk::Parse(descriptor.data);
1354 if (!ValidateParseSuccess(chunk)) {
1355 return;
1356 }
1357
1358 if (state_ != State::kCookieEchoed) {
1359 // https://tools.ietf.org/html/rfc4960#section-5.2.5
1360 // "At any state other than COOKIE-ECHOED, an endpoint should silently
1361 // discard a received COOKIE ACK chunk."
1362 RTC_DLOG(LS_VERBOSE) << log_prefix()
1363 << "Received COOKIE_ACK not in COOKIE_ECHOED state";
1364 return;
1365 }
1366
1367 // RFC 4960, Errata ID: 4400
1368 t1_cookie_->Stop();
Victor Boiviec20f1562021-06-16 12:52:42 +02001369 tcb_->ClearCookieEchoChunk();
Victor Boivieb6580cc2021-04-08 09:56:59 +02001370 SetState(State::kEstablished, "COOKIE_ACK received");
Victor Boivied3b186e2021-05-05 16:22:29 +02001371 tcb_->SendBufferedPackets(callbacks_.TimeMillis());
Victor Boivieb6580cc2021-04-08 09:56:59 +02001372 callbacks_.OnConnected();
1373}
1374
1375void DcSctpSocket::DeliverReassembledMessages() {
1376 if (tcb_->reassembly_queue().HasMessages()) {
1377 for (auto& message : tcb_->reassembly_queue().FlushMessages()) {
Victor Boivied4716ea2021-08-09 12:26:32 +02001378 ++metrics_.rx_messages_count;
Victor Boivieb6580cc2021-04-08 09:56:59 +02001379 callbacks_.OnMessageReceived(std::move(message));
1380 }
1381 }
1382}
1383
1384void DcSctpSocket::HandleSack(const CommonHeader& header,
1385 const SctpPacket::ChunkDescriptor& descriptor) {
1386 absl::optional<SackChunk> chunk = SackChunk::Parse(descriptor.data);
1387
1388 if (ValidateParseSuccess(chunk) && ValidateHasTCB()) {
Victor Boivied3b186e2021-05-05 16:22:29 +02001389 TimeMs now = callbacks_.TimeMillis();
Victor Boivieb6580cc2021-04-08 09:56:59 +02001390 SackChunk sack = ChunkValidators::Clean(*std::move(chunk));
1391
Victor Boivied3b186e2021-05-05 16:22:29 +02001392 if (tcb_->retransmission_queue().HandleSack(now, sack)) {
Victor Boivieb6580cc2021-04-08 09:56:59 +02001393 MaybeSendShutdownOrAck();
Victor Boivie5e354d92022-04-22 16:28:33 +02001394 // Receiving an ACK may make the socket go into fast recovery mode.
1395 // https://datatracker.ietf.org/doc/html/rfc4960#section-7.2.4
1396 // "Determine how many of the earliest (i.e., lowest TSN) DATA chunks
1397 // marked for retransmission will fit into a single packet, subject to
1398 // constraint of the path MTU of the destination transport address to
1399 // which the packet is being sent. Call this value K. Retransmit those K
1400 // DATA chunks in a single packet. When a Fast Retransmit is being
1401 // performed, the sender SHOULD ignore the value of cwnd and SHOULD NOT
1402 // delay retransmission for this single packet."
1403 tcb_->MaybeSendFastRetransmit();
1404
Victor Boivieb6580cc2021-04-08 09:56:59 +02001405 // Receiving an ACK will decrease outstanding bytes (maybe now below
1406 // cwnd?) or indicate packet loss that may result in sending FORWARD-TSN.
Victor Boivied3b186e2021-05-05 16:22:29 +02001407 tcb_->SendBufferedPackets(now);
Victor Boivieb6580cc2021-04-08 09:56:59 +02001408 } else {
1409 RTC_DLOG(LS_VERBOSE) << log_prefix()
1410 << "Dropping out-of-order SACK with TSN "
1411 << *sack.cumulative_tsn_ack();
1412 }
1413 }
1414}
1415
1416void DcSctpSocket::HandleHeartbeatRequest(
1417 const CommonHeader& header,
1418 const SctpPacket::ChunkDescriptor& descriptor) {
1419 absl::optional<HeartbeatRequestChunk> chunk =
1420 HeartbeatRequestChunk::Parse(descriptor.data);
1421
1422 if (ValidateParseSuccess(chunk) && ValidateHasTCB()) {
1423 tcb_->heartbeat_handler().HandleHeartbeatRequest(*std::move(chunk));
1424 }
1425}
1426
1427void DcSctpSocket::HandleHeartbeatAck(
1428 const CommonHeader& header,
1429 const SctpPacket::ChunkDescriptor& descriptor) {
1430 absl::optional<HeartbeatAckChunk> chunk =
1431 HeartbeatAckChunk::Parse(descriptor.data);
1432
1433 if (ValidateParseSuccess(chunk) && ValidateHasTCB()) {
1434 tcb_->heartbeat_handler().HandleHeartbeatAck(*std::move(chunk));
1435 }
1436}
1437
1438void DcSctpSocket::HandleAbort(const CommonHeader& header,
1439 const SctpPacket::ChunkDescriptor& descriptor) {
1440 absl::optional<AbortChunk> chunk = AbortChunk::Parse(descriptor.data);
1441 if (ValidateParseSuccess(chunk)) {
1442 std::string error_string = ErrorCausesToString(chunk->error_causes());
1443 if (tcb_ == nullptr) {
1444 // https://tools.ietf.org/html/rfc4960#section-3.3.7
1445 // "If an endpoint receives an ABORT with a format error or no TCB is
1446 // found, it MUST silently discard it."
1447 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Received ABORT (" << error_string
1448 << ") on a connection with no TCB. Ignoring";
1449 return;
1450 }
1451
1452 RTC_DLOG(LS_WARNING) << log_prefix() << "Received ABORT (" << error_string
1453 << ") - closing connection.";
1454 InternalClose(ErrorKind::kPeerReported, error_string);
1455 }
1456}
1457
1458void DcSctpSocket::HandleError(const CommonHeader& header,
1459 const SctpPacket::ChunkDescriptor& descriptor) {
1460 absl::optional<ErrorChunk> chunk = ErrorChunk::Parse(descriptor.data);
1461 if (ValidateParseSuccess(chunk)) {
1462 std::string error_string = ErrorCausesToString(chunk->error_causes());
1463 if (tcb_ == nullptr) {
1464 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Received ERROR (" << error_string
1465 << ") on a connection with no TCB. Ignoring";
1466 return;
1467 }
1468
1469 RTC_DLOG(LS_WARNING) << log_prefix() << "Received ERROR: " << error_string;
1470 callbacks_.OnError(ErrorKind::kPeerReported,
1471 "Peer reported error: " + error_string);
1472 }
1473}
1474
1475void DcSctpSocket::HandleReconfig(
1476 const CommonHeader& header,
1477 const SctpPacket::ChunkDescriptor& descriptor) {
1478 absl::optional<ReConfigChunk> chunk = ReConfigChunk::Parse(descriptor.data);
1479 if (ValidateParseSuccess(chunk) && ValidateHasTCB()) {
1480 tcb_->stream_reset_handler().HandleReConfig(*std::move(chunk));
Victor Boivief9e116f2022-03-31 17:15:03 +02001481 // Handling this response may result in outgoing stream resets finishing
1482 // (either successfully or with failure). If there still are pending streams
1483 // that were waiting for this request to finish, continue resetting them.
1484 MaybeSendResetStreamsRequest();
Victor Boivieb6580cc2021-04-08 09:56:59 +02001485 }
1486}
1487
1488void DcSctpSocket::HandleShutdown(
1489 const CommonHeader& header,
1490 const SctpPacket::ChunkDescriptor& descriptor) {
1491 if (!ValidateParseSuccess(ShutdownChunk::Parse(descriptor.data))) {
1492 return;
1493 }
1494
1495 if (state_ == State::kClosed) {
1496 return;
1497 } else if (state_ == State::kCookieWait || state_ == State::kCookieEchoed) {
1498 // https://tools.ietf.org/html/rfc4960#section-9.2
1499 // "If a SHUTDOWN is received in the COOKIE-WAIT or COOKIE ECHOED state,
1500 // the SHUTDOWN chunk SHOULD be silently discarded."
1501 } else if (state_ == State::kShutdownSent) {
1502 // https://tools.ietf.org/html/rfc4960#section-9.2
1503 // "If an endpoint is in the SHUTDOWN-SENT state and receives a
1504 // SHUTDOWN chunk from its peer, the endpoint shall respond immediately
1505 // with a SHUTDOWN ACK to its peer, and move into the SHUTDOWN-ACK-SENT
1506 // state restarting its T2-shutdown timer."
1507 SendShutdownAck();
1508 SetState(State::kShutdownAckSent, "SHUTDOWN received");
Victor Boivie50a0b122021-05-06 21:07:49 +02001509 } else if (state_ == State::kShutdownAckSent) {
1510 // TODO(webrtc:12739): This condition should be removed and handled by the
1511 // next (state_ != State::kShutdownReceived).
1512 return;
Victor Boivieb6580cc2021-04-08 09:56:59 +02001513 } else if (state_ != State::kShutdownReceived) {
1514 RTC_DLOG(LS_VERBOSE) << log_prefix()
1515 << "Received SHUTDOWN - shutting down the socket";
1516 // https://tools.ietf.org/html/rfc4960#section-9.2
1517 // "Upon reception of the SHUTDOWN, the peer endpoint shall enter the
1518 // SHUTDOWN-RECEIVED state, stop accepting new data from its SCTP user,
1519 // and verify, by checking the Cumulative TSN Ack field of the chunk, that
1520 // all its outstanding DATA chunks have been received by the SHUTDOWN
1521 // sender."
1522 SetState(State::kShutdownReceived, "SHUTDOWN received");
1523 MaybeSendShutdownOrAck();
1524 }
1525}
1526
1527void DcSctpSocket::HandleShutdownAck(
1528 const CommonHeader& header,
1529 const SctpPacket::ChunkDescriptor& descriptor) {
1530 if (!ValidateParseSuccess(ShutdownAckChunk::Parse(descriptor.data))) {
1531 return;
1532 }
1533
1534 if (state_ == State::kShutdownSent || state_ == State::kShutdownAckSent) {
1535 // https://tools.ietf.org/html/rfc4960#section-9.2
1536 // "Upon the receipt of the SHUTDOWN ACK, the SHUTDOWN sender shall stop
1537 // the T2-shutdown timer, send a SHUTDOWN COMPLETE chunk to its peer, and
1538 // remove all record of the association."
1539
1540 // "If an endpoint is in the SHUTDOWN-ACK-SENT state and receives a
1541 // SHUTDOWN ACK, it shall stop the T2-shutdown timer, send a SHUTDOWN
1542 // COMPLETE chunk to its peer, and remove all record of the association."
1543
1544 SctpPacket::Builder b = tcb_->PacketBuilder();
1545 b.Add(ShutdownCompleteChunk(/*tag_reflected=*/false));
Victor Boivieabf61882021-08-12 15:57:49 +02001546 packet_sender_.Send(b);
Victor Boivieb6580cc2021-04-08 09:56:59 +02001547 InternalClose(ErrorKind::kNoError, "");
1548 } else {
1549 // https://tools.ietf.org/html/rfc4960#section-8.5.1
1550 // "If the receiver is in COOKIE-ECHOED or COOKIE-WAIT state
1551 // the procedures in Section 8.4 SHOULD be followed; in other words, it
1552 // should be treated as an Out Of The Blue packet."
1553
1554 // https://tools.ietf.org/html/rfc4960#section-8.4
1555 // "If the packet contains a SHUTDOWN ACK chunk, the receiver
1556 // should respond to the sender of the OOTB packet with a SHUTDOWN
1557 // COMPLETE. When sending the SHUTDOWN COMPLETE, the receiver of the OOTB
1558 // packet must fill in the Verification Tag field of the outbound packet
1559 // with the Verification Tag received in the SHUTDOWN ACK and set the T
1560 // bit in the Chunk Flags to indicate that the Verification Tag is
1561 // reflected."
1562
1563 SctpPacket::Builder b(header.verification_tag, options_);
1564 b.Add(ShutdownCompleteChunk(/*tag_reflected=*/true));
Victor Boivieabf61882021-08-12 15:57:49 +02001565 packet_sender_.Send(b);
Victor Boivieb6580cc2021-04-08 09:56:59 +02001566 }
1567}
1568
1569void DcSctpSocket::HandleShutdownComplete(
1570 const CommonHeader& header,
1571 const SctpPacket::ChunkDescriptor& descriptor) {
1572 if (!ValidateParseSuccess(ShutdownCompleteChunk::Parse(descriptor.data))) {
1573 return;
1574 }
1575
1576 if (state_ == State::kShutdownAckSent) {
1577 // https://tools.ietf.org/html/rfc4960#section-9.2
1578 // "Upon reception of the SHUTDOWN COMPLETE chunk, the endpoint will
1579 // verify that it is in the SHUTDOWN-ACK-SENT state; if it is not, the
1580 // chunk should be discarded. If the endpoint is in the SHUTDOWN-ACK-SENT
1581 // state, the endpoint should stop the T2-shutdown timer and remove all
1582 // knowledge of the association (and thus the association enters the
1583 // CLOSED state)."
1584 InternalClose(ErrorKind::kNoError, "");
1585 }
1586}
1587
1588void DcSctpSocket::HandleForwardTsn(
1589 const CommonHeader& header,
1590 const SctpPacket::ChunkDescriptor& descriptor) {
1591 absl::optional<ForwardTsnChunk> chunk =
1592 ForwardTsnChunk::Parse(descriptor.data);
1593 if (ValidateParseSuccess(chunk) && ValidateHasTCB()) {
1594 HandleForwardTsnCommon(*chunk);
1595 }
1596}
1597
1598void DcSctpSocket::HandleIForwardTsn(
1599 const CommonHeader& header,
1600 const SctpPacket::ChunkDescriptor& descriptor) {
1601 absl::optional<IForwardTsnChunk> chunk =
1602 IForwardTsnChunk::Parse(descriptor.data);
1603 if (ValidateParseSuccess(chunk) && ValidateHasTCB()) {
1604 HandleForwardTsnCommon(*chunk);
1605 }
1606}
1607
1608void DcSctpSocket::HandleForwardTsnCommon(const AnyForwardTsnChunk& chunk) {
1609 if (!tcb_->capabilities().partial_reliability) {
1610 SctpPacket::Builder b = tcb_->PacketBuilder();
1611 b.Add(AbortChunk(/*filled_in_verification_tag=*/true,
1612 Parameters::Builder()
1613 .Add(ProtocolViolationCause(
1614 "I-FORWARD-TSN received, but not indicated "
1615 "during connection establishment"))
1616 .Build()));
Victor Boivieabf61882021-08-12 15:57:49 +02001617 packet_sender_.Send(b);
Victor Boivieb6580cc2021-04-08 09:56:59 +02001618
1619 callbacks_.OnError(ErrorKind::kProtocolViolation,
1620 "Received a FORWARD_TSN without announced peer support");
1621 return;
1622 }
1623 tcb_->data_tracker().HandleForwardTsn(chunk.new_cumulative_tsn());
1624 tcb_->reassembly_queue().Handle(chunk);
1625 // A forward TSN - for ordered streams - may allow messages to be
1626 // delivered.
1627 DeliverReassembledMessages();
1628
1629 // Processing a FORWARD_TSN might result in sending a SACK.
1630 tcb_->MaybeSendSack();
1631}
1632
1633void DcSctpSocket::MaybeSendShutdownOrAck() {
1634 if (tcb_->retransmission_queue().outstanding_bytes() != 0) {
1635 return;
1636 }
1637
1638 if (state_ == State::kShutdownPending) {
1639 // https://tools.ietf.org/html/rfc4960#section-9.2
1640 // "Once all its outstanding data has been acknowledged, the endpoint
1641 // shall send a SHUTDOWN chunk to its peer including in the Cumulative TSN
1642 // Ack field the last sequential TSN it has received from the peer. It
1643 // shall then start the T2-shutdown timer and enter the SHUTDOWN-SENT
1644 // state.""
1645
1646 SendShutdown();
1647 t2_shutdown_->set_duration(tcb_->current_rto());
1648 t2_shutdown_->Start();
1649 SetState(State::kShutdownSent, "No more outstanding data");
1650 } else if (state_ == State::kShutdownReceived) {
1651 // https://tools.ietf.org/html/rfc4960#section-9.2
1652 // "If the receiver of the SHUTDOWN has no more outstanding DATA
1653 // chunks, the SHUTDOWN receiver MUST send a SHUTDOWN ACK and start a
1654 // T2-shutdown timer of its own, entering the SHUTDOWN-ACK-SENT state. If
1655 // the timer expires, the endpoint must resend the SHUTDOWN ACK."
1656
1657 SendShutdownAck();
1658 SetState(State::kShutdownAckSent, "No more outstanding data");
1659 }
1660}
1661
1662void DcSctpSocket::SendShutdown() {
1663 SctpPacket::Builder b = tcb_->PacketBuilder();
1664 b.Add(ShutdownChunk(tcb_->data_tracker().last_cumulative_acked_tsn()));
Victor Boivieabf61882021-08-12 15:57:49 +02001665 packet_sender_.Send(b);
Victor Boivieb6580cc2021-04-08 09:56:59 +02001666}
1667
1668void DcSctpSocket::SendShutdownAck() {
Victor Boivieabf61882021-08-12 15:57:49 +02001669 packet_sender_.Send(tcb_->PacketBuilder().Add(ShutdownAckChunk()));
Victor Boivieb6580cc2021-04-08 09:56:59 +02001670 t2_shutdown_->set_duration(tcb_->current_rto());
1671 t2_shutdown_->Start();
1672}
1673
Sergey Sukhanov43972812021-09-17 15:32:48 +02001674HandoverReadinessStatus DcSctpSocket::GetHandoverReadiness() const {
Victor Boivie5755f3e2021-09-29 22:23:15 +02001675 RTC_DCHECK_RUN_ON(&thread_checker_);
Sergey Sukhanov43972812021-09-17 15:32:48 +02001676 HandoverReadinessStatus status;
1677 if (state_ != State::kClosed && state_ != State::kEstablished) {
1678 status.Add(HandoverUnreadinessReason::kWrongConnectionState);
1679 }
Sergey Sukhanov72435322021-09-21 13:31:09 +02001680 status.Add(send_queue_.GetHandoverReadiness());
Sergey Sukhanov43972812021-09-17 15:32:48 +02001681 if (tcb_) {
1682 status.Add(tcb_->GetHandoverReadiness());
1683 }
1684 return status;
1685}
1686
1687absl::optional<DcSctpSocketHandoverState>
1688DcSctpSocket::GetHandoverStateAndClose() {
Victor Boivie5755f3e2021-09-29 22:23:15 +02001689 RTC_DCHECK_RUN_ON(&thread_checker_);
Victor Boivie15a0c882021-09-28 21:38:34 +02001690 CallbackDeferrer::ScopedDeferrer deferrer(callbacks_);
1691
Sergey Sukhanov43972812021-09-17 15:32:48 +02001692 if (!GetHandoverReadiness().IsReady()) {
1693 return absl::nullopt;
1694 }
1695
1696 DcSctpSocketHandoverState state;
1697
1698 if (state_ == State::kClosed) {
1699 state.socket_state = DcSctpSocketHandoverState::SocketState::kClosed;
1700 } else if (state_ == State::kEstablished) {
1701 state.socket_state = DcSctpSocketHandoverState::SocketState::kConnected;
1702 tcb_->AddHandoverState(state);
Sergey Sukhanov72435322021-09-21 13:31:09 +02001703 send_queue_.AddHandoverState(state);
Sergey Sukhanov43972812021-09-17 15:32:48 +02001704 InternalClose(ErrorKind::kNoError, "handover");
Sergey Sukhanov43972812021-09-17 15:32:48 +02001705 }
1706
1707 return std::move(state);
1708}
1709
Victor Boivieb6580cc2021-04-08 09:56:59 +02001710} // namespace dcsctp