blob: 56abb492c07e52cac27765fea645dc55810db31d [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 Boiviea2476e32022-05-12 22:40:04 +0200192 options_.mtu,
Victor Boivie7e897ae2022-05-02 13:04:37 +0200193 options_.default_stream_priority,
Victor Boivie236ac502021-05-20 19:34:18 +0200194 [this](StreamID stream_id) {
195 callbacks_.OnBufferedAmountLow(stream_id);
196 },
197 options_.total_buffered_amount_low_threshold,
198 [this]() { callbacks_.OnTotalBufferedAmountLow(); }) {}
Victor Boivieb6580cc2021-04-08 09:56:59 +0200199
200std::string DcSctpSocket::log_prefix() const {
Florent Castelli29ff3ef2022-02-17 16:23:56 +0100201 return log_prefix_ + "[" + std::string(ToString(state_)) + "] ";
Victor Boivieb6580cc2021-04-08 09:56:59 +0200202}
203
204bool DcSctpSocket::IsConsistent() const {
Victor Boivie54e4e352021-09-15 10:42:26 +0200205 if (tcb_ != nullptr && tcb_->reassembly_queue().HasMessages()) {
206 return false;
207 }
Victor Boivieb6580cc2021-04-08 09:56:59 +0200208 switch (state_) {
209 case State::kClosed:
210 return (tcb_ == nullptr && !t1_init_->is_running() &&
211 !t1_cookie_->is_running() && !t2_shutdown_->is_running());
212 case State::kCookieWait:
213 return (tcb_ == nullptr && t1_init_->is_running() &&
214 !t1_cookie_->is_running() && !t2_shutdown_->is_running());
215 case State::kCookieEchoed:
216 return (tcb_ != nullptr && !t1_init_->is_running() &&
217 t1_cookie_->is_running() && !t2_shutdown_->is_running() &&
Victor Boiviec20f1562021-06-16 12:52:42 +0200218 tcb_->has_cookie_echo_chunk());
Victor Boivieb6580cc2021-04-08 09:56:59 +0200219 case State::kEstablished:
220 return (tcb_ != nullptr && !t1_init_->is_running() &&
221 !t1_cookie_->is_running() && !t2_shutdown_->is_running());
222 case State::kShutdownPending:
223 return (tcb_ != nullptr && !t1_init_->is_running() &&
224 !t1_cookie_->is_running() && !t2_shutdown_->is_running());
225 case State::kShutdownSent:
226 return (tcb_ != nullptr && !t1_init_->is_running() &&
227 !t1_cookie_->is_running() && t2_shutdown_->is_running());
228 case State::kShutdownReceived:
229 return (tcb_ != nullptr && !t1_init_->is_running() &&
230 !t1_cookie_->is_running() && !t2_shutdown_->is_running());
231 case State::kShutdownAckSent:
232 return (tcb_ != nullptr && !t1_init_->is_running() &&
233 !t1_cookie_->is_running() && t2_shutdown_->is_running());
234 }
235}
236
237constexpr absl::string_view DcSctpSocket::ToString(DcSctpSocket::State state) {
238 switch (state) {
239 case DcSctpSocket::State::kClosed:
240 return "CLOSED";
241 case DcSctpSocket::State::kCookieWait:
242 return "COOKIE_WAIT";
243 case DcSctpSocket::State::kCookieEchoed:
244 return "COOKIE_ECHOED";
245 case DcSctpSocket::State::kEstablished:
246 return "ESTABLISHED";
247 case DcSctpSocket::State::kShutdownPending:
248 return "SHUTDOWN_PENDING";
249 case DcSctpSocket::State::kShutdownSent:
250 return "SHUTDOWN_SENT";
251 case DcSctpSocket::State::kShutdownReceived:
252 return "SHUTDOWN_RECEIVED";
253 case DcSctpSocket::State::kShutdownAckSent:
254 return "SHUTDOWN_ACK_SENT";
255 }
256}
257
258void DcSctpSocket::SetState(State state, absl::string_view reason) {
259 if (state_ != state) {
260 RTC_DLOG(LS_VERBOSE) << log_prefix_ << "Socket state changed from "
261 << ToString(state_) << " to " << ToString(state)
262 << " due to " << reason;
263 state_ = state;
264 }
265}
266
267void DcSctpSocket::SendInit() {
268 Parameters::Builder params_builder;
269 AddCapabilityParameters(options_, params_builder);
270 InitChunk init(/*initiate_tag=*/connect_params_.verification_tag,
271 /*a_rwnd=*/options_.max_receiver_window_buffer_size,
272 options_.announced_maximum_outgoing_streams,
273 options_.announced_maximum_incoming_streams,
274 connect_params_.initial_tsn, params_builder.Build());
275 SctpPacket::Builder b(VerificationTag(0), options_);
276 b.Add(init);
Victor Boivieabf61882021-08-12 15:57:49 +0200277 packet_sender_.Send(b);
Victor Boivieb6580cc2021-04-08 09:56:59 +0200278}
279
280void DcSctpSocket::MakeConnectionParameters() {
281 VerificationTag new_verification_tag(
282 callbacks_.GetRandomInt(kMinVerificationTag, kMaxVerificationTag));
283 TSN initial_tsn(callbacks_.GetRandomInt(kMinInitialTsn, kMaxInitialTsn));
284 connect_params_.initial_tsn = initial_tsn;
285 connect_params_.verification_tag = new_verification_tag;
286}
287
288void DcSctpSocket::Connect() {
Victor Boivie5755f3e2021-09-29 22:23:15 +0200289 RTC_DCHECK_RUN_ON(&thread_checker_);
Victor Boivie15a0c882021-09-28 21:38:34 +0200290 CallbackDeferrer::ScopedDeferrer deferrer(callbacks_);
291
Victor Boivieb6580cc2021-04-08 09:56:59 +0200292 if (state_ == State::kClosed) {
293 MakeConnectionParameters();
294 RTC_DLOG(LS_INFO)
295 << log_prefix()
296 << rtc::StringFormat(
297 "Connecting. my_verification_tag=%08x, my_initial_tsn=%u",
298 *connect_params_.verification_tag, *connect_params_.initial_tsn);
299 SendInit();
300 t1_init_->Start();
301 SetState(State::kCookieWait, "Connect called");
302 } else {
303 RTC_DLOG(LS_WARNING) << log_prefix()
304 << "Called Connect on a socket that is not closed";
305 }
306 RTC_DCHECK(IsConsistent());
Victor Boivieb6580cc2021-04-08 09:56:59 +0200307}
308
Sergey Sukhanov43972812021-09-17 15:32:48 +0200309void DcSctpSocket::RestoreFromState(const DcSctpSocketHandoverState& state) {
Victor Boivie5755f3e2021-09-29 22:23:15 +0200310 RTC_DCHECK_RUN_ON(&thread_checker_);
Victor Boivie15a0c882021-09-28 21:38:34 +0200311 CallbackDeferrer::ScopedDeferrer deferrer(callbacks_);
312
Sergey Sukhanov43972812021-09-17 15:32:48 +0200313 if (state_ != State::kClosed) {
314 callbacks_.OnError(ErrorKind::kUnsupportedOperation,
315 "Only closed socket can be restored from state");
316 } else {
317 if (state.socket_state ==
318 DcSctpSocketHandoverState::SocketState::kConnected) {
319 VerificationTag my_verification_tag =
320 VerificationTag(state.my_verification_tag);
321 connect_params_.verification_tag = my_verification_tag;
322
323 Capabilities capabilities;
324 capabilities.partial_reliability = state.capabilities.partial_reliability;
325 capabilities.message_interleaving =
326 state.capabilities.message_interleaving;
327 capabilities.reconfig = state.capabilities.reconfig;
328
Sergey Sukhanov72435322021-09-21 13:31:09 +0200329 send_queue_.RestoreFromState(state);
330
Sergey Sukhanov43972812021-09-17 15:32:48 +0200331 tcb_ = std::make_unique<TransmissionControlBlock>(
332 timer_manager_, log_prefix_, options_, capabilities, callbacks_,
333 send_queue_, my_verification_tag, TSN(state.my_initial_tsn),
334 VerificationTag(state.peer_verification_tag),
335 TSN(state.peer_initial_tsn), static_cast<size_t>(0),
336 TieTag(state.tie_tag), packet_sender_,
337 [this]() { return state_ == State::kEstablished; }, &state);
338 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Created peer TCB from state: "
339 << tcb_->ToString();
340
341 SetState(State::kEstablished, "restored from handover state");
342 callbacks_.OnConnected();
343 }
344 }
345
346 RTC_DCHECK(IsConsistent());
Sergey Sukhanov43972812021-09-17 15:32:48 +0200347}
348
Victor Boivieb6580cc2021-04-08 09:56:59 +0200349void DcSctpSocket::Shutdown() {
Victor Boivie5755f3e2021-09-29 22:23:15 +0200350 RTC_DCHECK_RUN_ON(&thread_checker_);
Victor Boivie15a0c882021-09-28 21:38:34 +0200351 CallbackDeferrer::ScopedDeferrer deferrer(callbacks_);
352
Victor Boivieb6580cc2021-04-08 09:56:59 +0200353 if (tcb_ != nullptr) {
354 // https://tools.ietf.org/html/rfc4960#section-9.2
355 // "Upon receipt of the SHUTDOWN primitive from its upper layer, the
356 // endpoint enters the SHUTDOWN-PENDING state and remains there until all
357 // outstanding data has been acknowledged by its peer."
Victor Boivie50a0b122021-05-06 21:07:49 +0200358
359 // TODO(webrtc:12739): Remove this check, as it just hides the problem that
360 // the socket can transition from ShutdownSent to ShutdownPending, or
361 // ShutdownAckSent to ShutdownPending which is illegal.
362 if (state_ != State::kShutdownSent && state_ != State::kShutdownAckSent) {
363 SetState(State::kShutdownPending, "Shutdown called");
364 t1_init_->Stop();
365 t1_cookie_->Stop();
366 MaybeSendShutdownOrAck();
367 }
Victor Boivieb6580cc2021-04-08 09:56:59 +0200368 } else {
369 // Connection closed before even starting to connect, or during the initial
370 // connection phase. There is no outstanding data, so the socket can just
371 // be closed (stopping any connection timers, if any), as this is the
372 // client's intention, by calling Shutdown.
373 InternalClose(ErrorKind::kNoError, "");
374 }
375 RTC_DCHECK(IsConsistent());
Victor Boivieb6580cc2021-04-08 09:56:59 +0200376}
377
378void DcSctpSocket::Close() {
Victor Boivie5755f3e2021-09-29 22:23:15 +0200379 RTC_DCHECK_RUN_ON(&thread_checker_);
Victor Boivie15a0c882021-09-28 21:38:34 +0200380 CallbackDeferrer::ScopedDeferrer deferrer(callbacks_);
381
Victor Boivieb6580cc2021-04-08 09:56:59 +0200382 if (state_ != State::kClosed) {
383 if (tcb_ != nullptr) {
384 SctpPacket::Builder b = tcb_->PacketBuilder();
385 b.Add(AbortChunk(/*filled_in_verification_tag=*/true,
386 Parameters::Builder()
387 .Add(UserInitiatedAbortCause("Close called"))
388 .Build()));
Victor Boivieabf61882021-08-12 15:57:49 +0200389 packet_sender_.Send(b);
Victor Boivieb6580cc2021-04-08 09:56:59 +0200390 }
391 InternalClose(ErrorKind::kNoError, "");
392 } else {
393 RTC_DLOG(LS_INFO) << log_prefix() << "Called Close on a closed socket";
394 }
395 RTC_DCHECK(IsConsistent());
Victor Boivieb6580cc2021-04-08 09:56:59 +0200396}
397
398void DcSctpSocket::CloseConnectionBecauseOfTooManyTransmissionErrors() {
Victor Boivieabf61882021-08-12 15:57:49 +0200399 packet_sender_.Send(tcb_->PacketBuilder().Add(AbortChunk(
Victor Boivieb6580cc2021-04-08 09:56:59 +0200400 true, Parameters::Builder()
401 .Add(UserInitiatedAbortCause("Too many retransmissions"))
402 .Build())));
403 InternalClose(ErrorKind::kTooManyRetries, "Too many retransmissions");
404}
405
406void DcSctpSocket::InternalClose(ErrorKind error, absl::string_view message) {
407 if (state_ != State::kClosed) {
408 t1_init_->Stop();
409 t1_cookie_->Stop();
410 t2_shutdown_->Stop();
411 tcb_ = nullptr;
Victor Boivieb6580cc2021-04-08 09:56:59 +0200412
413 if (error == ErrorKind::kNoError) {
414 callbacks_.OnClosed();
415 } else {
416 callbacks_.OnAborted(error, message);
417 }
418 SetState(State::kClosed, message);
419 }
420 // This method's purpose is to abort/close and make it consistent by ensuring
421 // that e.g. all timers really are stopped.
422 RTC_DCHECK(IsConsistent());
423}
424
Victor Boivie7e897ae2022-05-02 13:04:37 +0200425void DcSctpSocket::SetStreamPriority(StreamID stream_id,
426 StreamPriority priority) {
427 RTC_DCHECK_RUN_ON(&thread_checker_);
428 send_queue_.SetStreamPriority(stream_id, priority);
429}
430StreamPriority DcSctpSocket::GetStreamPriority(StreamID stream_id) const {
431 RTC_DCHECK_RUN_ON(&thread_checker_);
432 return send_queue_.GetStreamPriority(stream_id);
433}
434
Victor Boivieb6580cc2021-04-08 09:56:59 +0200435SendStatus DcSctpSocket::Send(DcSctpMessage message,
436 const SendOptions& send_options) {
Victor Boivie5755f3e2021-09-29 22:23:15 +0200437 RTC_DCHECK_RUN_ON(&thread_checker_);
Victor Boivie15a0c882021-09-28 21:38:34 +0200438 CallbackDeferrer::ScopedDeferrer deferrer(callbacks_);
439
Victor Boivieb6580cc2021-04-08 09:56:59 +0200440 if (message.payload().empty()) {
441 callbacks_.OnError(ErrorKind::kProtocolViolation,
442 "Unable to send empty message");
443 return SendStatus::kErrorMessageEmpty;
444 }
445 if (message.payload().size() > options_.max_message_size) {
446 callbacks_.OnError(ErrorKind::kProtocolViolation,
447 "Unable to send too large message");
448 return SendStatus::kErrorMessageTooLarge;
449 }
450 if (state_ == State::kShutdownPending || state_ == State::kShutdownSent ||
451 state_ == State::kShutdownReceived || state_ == State::kShutdownAckSent) {
452 // https://tools.ietf.org/html/rfc4960#section-9.2
453 // "An endpoint should reject any new data request from its upper layer
454 // if it is in the SHUTDOWN-PENDING, SHUTDOWN-SENT, SHUTDOWN-RECEIVED, or
455 // SHUTDOWN-ACK-SENT state."
456 callbacks_.OnError(ErrorKind::kWrongSequence,
457 "Unable to send message as the socket is shutting down");
458 return SendStatus::kErrorShuttingDown;
459 }
460 if (send_queue_.IsFull()) {
461 callbacks_.OnError(ErrorKind::kResourceExhaustion,
462 "Unable to send message as the send queue is full");
463 return SendStatus::kErrorResourceExhaustion;
464 }
465
Victor Boivied3b186e2021-05-05 16:22:29 +0200466 TimeMs now = callbacks_.TimeMillis();
Victor Boivied4716ea2021-08-09 12:26:32 +0200467 ++metrics_.tx_messages_count;
Victor Boivied3b186e2021-05-05 16:22:29 +0200468 send_queue_.Add(now, std::move(message), send_options);
Victor Boivieb6580cc2021-04-08 09:56:59 +0200469 if (tcb_ != nullptr) {
Victor Boivied3b186e2021-05-05 16:22:29 +0200470 tcb_->SendBufferedPackets(now);
Victor Boivieb6580cc2021-04-08 09:56:59 +0200471 }
472
473 RTC_DCHECK(IsConsistent());
Victor Boivieb6580cc2021-04-08 09:56:59 +0200474 return SendStatus::kSuccess;
475}
476
477ResetStreamsStatus DcSctpSocket::ResetStreams(
478 rtc::ArrayView<const StreamID> outgoing_streams) {
Victor Boivie5755f3e2021-09-29 22:23:15 +0200479 RTC_DCHECK_RUN_ON(&thread_checker_);
Victor Boivie15a0c882021-09-28 21:38:34 +0200480 CallbackDeferrer::ScopedDeferrer deferrer(callbacks_);
481
Victor Boivieb6580cc2021-04-08 09:56:59 +0200482 if (tcb_ == nullptr) {
483 callbacks_.OnError(ErrorKind::kWrongSequence,
484 "Can't reset streams as the socket is not connected");
485 return ResetStreamsStatus::kNotConnected;
486 }
487 if (!tcb_->capabilities().reconfig) {
488 callbacks_.OnError(ErrorKind::kUnsupportedOperation,
489 "Can't reset streams as the peer doesn't support it");
490 return ResetStreamsStatus::kNotSupported;
491 }
492
493 tcb_->stream_reset_handler().ResetStreams(outgoing_streams);
Victor Boivief9e116f2022-03-31 17:15:03 +0200494 MaybeSendResetStreamsRequest();
Victor Boivieb6580cc2021-04-08 09:56:59 +0200495
496 RTC_DCHECK(IsConsistent());
Victor Boivieb6580cc2021-04-08 09:56:59 +0200497 return ResetStreamsStatus::kPerformed;
498}
499
500SocketState DcSctpSocket::state() const {
Victor Boivie5755f3e2021-09-29 22:23:15 +0200501 RTC_DCHECK_RUN_ON(&thread_checker_);
Victor Boivieb6580cc2021-04-08 09:56:59 +0200502 switch (state_) {
503 case State::kClosed:
504 return SocketState::kClosed;
505 case State::kCookieWait:
Victor Boivieb6580cc2021-04-08 09:56:59 +0200506 case State::kCookieEchoed:
507 return SocketState::kConnecting;
508 case State::kEstablished:
509 return SocketState::kConnected;
510 case State::kShutdownPending:
Victor Boivieb6580cc2021-04-08 09:56:59 +0200511 case State::kShutdownSent:
Victor Boivieb6580cc2021-04-08 09:56:59 +0200512 case State::kShutdownReceived:
Victor Boivieb6580cc2021-04-08 09:56:59 +0200513 case State::kShutdownAckSent:
514 return SocketState::kShuttingDown;
515 }
516}
517
Florent Castelli0810b052021-05-04 20:12:52 +0200518void DcSctpSocket::SetMaxMessageSize(size_t max_message_size) {
Victor Boivie5755f3e2021-09-29 22:23:15 +0200519 RTC_DCHECK_RUN_ON(&thread_checker_);
Florent Castelli0810b052021-05-04 20:12:52 +0200520 options_.max_message_size = max_message_size;
521}
522
Victor Boivie236ac502021-05-20 19:34:18 +0200523size_t DcSctpSocket::buffered_amount(StreamID stream_id) const {
Victor Boivie5755f3e2021-09-29 22:23:15 +0200524 RTC_DCHECK_RUN_ON(&thread_checker_);
Victor Boivie236ac502021-05-20 19:34:18 +0200525 return send_queue_.buffered_amount(stream_id);
526}
527
528size_t DcSctpSocket::buffered_amount_low_threshold(StreamID stream_id) const {
Victor Boivie5755f3e2021-09-29 22:23:15 +0200529 RTC_DCHECK_RUN_ON(&thread_checker_);
Victor Boivie236ac502021-05-20 19:34:18 +0200530 return send_queue_.buffered_amount_low_threshold(stream_id);
531}
532
533void DcSctpSocket::SetBufferedAmountLowThreshold(StreamID stream_id,
534 size_t bytes) {
Victor Boivie5755f3e2021-09-29 22:23:15 +0200535 RTC_DCHECK_RUN_ON(&thread_checker_);
Victor Boivie236ac502021-05-20 19:34:18 +0200536 send_queue_.SetBufferedAmountLowThreshold(stream_id, bytes);
537}
538
Victor Boivief7fc71d2022-05-13 14:27:55 +0200539absl::optional<Metrics> DcSctpSocket::GetMetrics() const {
Victor Boivie5755f3e2021-09-29 22:23:15 +0200540 RTC_DCHECK_RUN_ON(&thread_checker_);
Victor Boivied4716ea2021-08-09 12:26:32 +0200541
Victor Boivief7fc71d2022-05-13 14:27:55 +0200542 if (tcb_ == nullptr) {
543 return absl::nullopt;
Victor Boivied4716ea2021-08-09 12:26:32 +0200544 }
545
Victor Boivief7fc71d2022-05-13 14:27:55 +0200546 Metrics metrics = metrics_;
547 metrics.cwnd_bytes = tcb_->cwnd();
548 metrics.srtt_ms = tcb_->current_srtt().value();
549 size_t packet_payload_size =
550 options_.mtu - SctpPacket::kHeaderSize - DataChunk::kHeaderSize;
551 metrics.unack_data_count =
552 tcb_->retransmission_queue().outstanding_items() +
553 (send_queue_.total_buffered_amount() + packet_payload_size - 1) /
554 packet_payload_size;
555 metrics.peer_rwnd_bytes = tcb_->retransmission_queue().rwnd();
556
Victor Boivied4716ea2021-08-09 12:26:32 +0200557 return metrics;
558}
559
Victor Boivieb6580cc2021-04-08 09:56:59 +0200560void DcSctpSocket::MaybeSendShutdownOnPacketReceived(const SctpPacket& packet) {
561 if (state_ == State::kShutdownSent) {
562 bool has_data_chunk =
563 std::find_if(packet.descriptors().begin(), packet.descriptors().end(),
564 [](const SctpPacket::ChunkDescriptor& descriptor) {
565 return descriptor.type == DataChunk::kType;
566 }) != packet.descriptors().end();
567 if (has_data_chunk) {
568 // https://tools.ietf.org/html/rfc4960#section-9.2
569 // "While in the SHUTDOWN-SENT state, the SHUTDOWN sender MUST immediately
570 // respond to each received packet containing one or more DATA chunks with
571 // a SHUTDOWN chunk and restart the T2-shutdown timer.""
572 SendShutdown();
573 t2_shutdown_->set_duration(tcb_->current_rto());
574 t2_shutdown_->Start();
575 }
576 }
577}
578
Victor Boivief9e116f2022-03-31 17:15:03 +0200579void DcSctpSocket::MaybeSendResetStreamsRequest() {
580 absl::optional<ReConfigChunk> reconfig =
581 tcb_->stream_reset_handler().MakeStreamResetRequest();
582 if (reconfig.has_value()) {
583 SctpPacket::Builder builder = tcb_->PacketBuilder();
584 builder.Add(*reconfig);
585 packet_sender_.Send(builder);
586 }
587}
588
Victor Boivieb6580cc2021-04-08 09:56:59 +0200589bool DcSctpSocket::ValidatePacket(const SctpPacket& packet) {
590 const CommonHeader& header = packet.common_header();
591 VerificationTag my_verification_tag =
592 tcb_ != nullptr ? tcb_->my_verification_tag() : VerificationTag(0);
593
594 if (header.verification_tag == VerificationTag(0)) {
595 if (packet.descriptors().size() == 1 &&
596 packet.descriptors()[0].type == InitChunk::kType) {
597 // https://tools.ietf.org/html/rfc4960#section-8.5.1
598 // "When an endpoint receives an SCTP packet with the Verification Tag
599 // set to 0, it should verify that the packet contains only an INIT chunk.
600 // Otherwise, the receiver MUST silently discard the packet.""
601 return true;
602 }
603 callbacks_.OnError(
604 ErrorKind::kParseFailed,
605 "Only a single INIT chunk can be present in packets sent on "
606 "verification_tag = 0");
607 return false;
608 }
609
610 if (packet.descriptors().size() == 1 &&
611 packet.descriptors()[0].type == AbortChunk::kType) {
612 // https://tools.ietf.org/html/rfc4960#section-8.5.1
613 // "The receiver of an ABORT MUST accept the packet if the Verification
614 // Tag field of the packet matches its own tag and the T bit is not set OR
615 // if it is set to its peer's tag and the T bit is set in the Chunk Flags.
616 // Otherwise, the receiver MUST silently discard the packet and take no
617 // further action."
618 bool t_bit = (packet.descriptors()[0].flags & 0x01) != 0;
619 if (t_bit && tcb_ == nullptr) {
620 // Can't verify the tag - assume it's okey.
621 return true;
622 }
623 if ((!t_bit && header.verification_tag == my_verification_tag) ||
624 (t_bit && header.verification_tag == tcb_->peer_verification_tag())) {
625 return true;
626 }
627 callbacks_.OnError(ErrorKind::kParseFailed,
628 "ABORT chunk verification tag was wrong");
629 return false;
630 }
631
632 if (packet.descriptors()[0].type == InitAckChunk::kType) {
633 if (header.verification_tag == connect_params_.verification_tag) {
634 return true;
635 }
636 callbacks_.OnError(
637 ErrorKind::kParseFailed,
638 rtc::StringFormat(
639 "Packet has invalid verification tag: %08x, expected %08x",
640 *header.verification_tag, *connect_params_.verification_tag));
641 return false;
642 }
643
644 if (packet.descriptors()[0].type == CookieEchoChunk::kType) {
645 // Handled in chunk handler (due to RFC 4960, section 5.2.4).
646 return true;
647 }
648
649 if (packet.descriptors().size() == 1 &&
650 packet.descriptors()[0].type == ShutdownCompleteChunk::kType) {
651 // https://tools.ietf.org/html/rfc4960#section-8.5.1
652 // "The receiver of a SHUTDOWN COMPLETE shall accept the packet if the
653 // Verification Tag field of the packet matches its own tag and the T bit is
654 // not set OR if it is set to its peer's tag and the T bit is set in the
655 // Chunk Flags. Otherwise, the receiver MUST silently discard the packet
656 // and take no further action."
657 bool t_bit = (packet.descriptors()[0].flags & 0x01) != 0;
658 if (t_bit && tcb_ == nullptr) {
659 // Can't verify the tag - assume it's okey.
660 return true;
661 }
662 if ((!t_bit && header.verification_tag == my_verification_tag) ||
663 (t_bit && header.verification_tag == tcb_->peer_verification_tag())) {
664 return true;
665 }
666 callbacks_.OnError(ErrorKind::kParseFailed,
667 "SHUTDOWN_COMPLETE chunk verification tag was wrong");
668 return false;
669 }
670
671 // https://tools.ietf.org/html/rfc4960#section-8.5
672 // "When receiving an SCTP packet, the endpoint MUST ensure that the value
673 // in the Verification Tag field of the received SCTP packet matches its own
674 // tag. If the received Verification Tag value does not match the receiver's
675 // own tag value, the receiver shall silently discard the packet and shall not
676 // process it any further..."
677 if (header.verification_tag == my_verification_tag) {
678 return true;
679 }
680
681 callbacks_.OnError(
682 ErrorKind::kParseFailed,
683 rtc::StringFormat(
684 "Packet has invalid verification tag: %08x, expected %08x",
685 *header.verification_tag, *my_verification_tag));
686 return false;
687}
688
689void DcSctpSocket::HandleTimeout(TimeoutID timeout_id) {
Victor Boivie5755f3e2021-09-29 22:23:15 +0200690 RTC_DCHECK_RUN_ON(&thread_checker_);
Victor Boivie15a0c882021-09-28 21:38:34 +0200691 CallbackDeferrer::ScopedDeferrer deferrer(callbacks_);
692
Victor Boivieb6580cc2021-04-08 09:56:59 +0200693 timer_manager_.HandleTimeout(timeout_id);
694
695 if (tcb_ != nullptr && tcb_->HasTooManyTxErrors()) {
696 // Tearing down the TCB has to be done outside the handlers.
697 CloseConnectionBecauseOfTooManyTransmissionErrors();
698 }
699
700 RTC_DCHECK(IsConsistent());
Victor Boivieb6580cc2021-04-08 09:56:59 +0200701}
702
703void DcSctpSocket::ReceivePacket(rtc::ArrayView<const uint8_t> data) {
Victor Boivie5755f3e2021-09-29 22:23:15 +0200704 RTC_DCHECK_RUN_ON(&thread_checker_);
Victor Boivie15a0c882021-09-28 21:38:34 +0200705 CallbackDeferrer::ScopedDeferrer deferrer(callbacks_);
706
Victor Boivied4716ea2021-08-09 12:26:32 +0200707 ++metrics_.rx_packets_count;
708
Victor Boivieb6580cc2021-04-08 09:56:59 +0200709 if (packet_observer_ != nullptr) {
710 packet_observer_->OnReceivedPacket(callbacks_.TimeMillis(), data);
711 }
712
713 absl::optional<SctpPacket> packet =
714 SctpPacket::Parse(data, options_.disable_checksum_verification);
715 if (!packet.has_value()) {
716 // https://tools.ietf.org/html/rfc4960#section-6.8
717 // "The default procedure for handling invalid SCTP packets is to
718 // silently discard them."
719 callbacks_.OnError(ErrorKind::kParseFailed,
720 "Failed to parse received SCTP packet");
721 RTC_DCHECK(IsConsistent());
Victor Boivieb6580cc2021-04-08 09:56:59 +0200722 return;
723 }
724
725 if (RTC_DLOG_IS_ON) {
726 for (const auto& descriptor : packet->descriptors()) {
727 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Received "
728 << DebugConvertChunkToString(descriptor.data);
729 }
730 }
731
732 if (!ValidatePacket(*packet)) {
733 RTC_DLOG(LS_VERBOSE) << log_prefix()
734 << "Packet failed verification tag check - dropping";
735 RTC_DCHECK(IsConsistent());
Victor Boivieb6580cc2021-04-08 09:56:59 +0200736 return;
737 }
738
739 MaybeSendShutdownOnPacketReceived(*packet);
740
741 for (const auto& descriptor : packet->descriptors()) {
742 if (!Dispatch(packet->common_header(), descriptor)) {
743 break;
744 }
745 }
746
747 if (tcb_ != nullptr) {
748 tcb_->data_tracker().ObservePacketEnd();
749 tcb_->MaybeSendSack();
750 }
751
752 RTC_DCHECK(IsConsistent());
Victor Boivieb6580cc2021-04-08 09:56:59 +0200753}
754
755void DcSctpSocket::DebugPrintOutgoing(rtc::ArrayView<const uint8_t> payload) {
756 auto packet = SctpPacket::Parse(payload);
757 RTC_DCHECK(packet.has_value());
758
759 for (const auto& desc : packet->descriptors()) {
760 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Sent "
761 << DebugConvertChunkToString(desc.data);
762 }
763}
764
765bool DcSctpSocket::Dispatch(const CommonHeader& header,
766 const SctpPacket::ChunkDescriptor& descriptor) {
767 switch (descriptor.type) {
768 case DataChunk::kType:
769 HandleData(header, descriptor);
770 break;
771 case InitChunk::kType:
772 HandleInit(header, descriptor);
773 break;
774 case InitAckChunk::kType:
775 HandleInitAck(header, descriptor);
776 break;
777 case SackChunk::kType:
778 HandleSack(header, descriptor);
779 break;
780 case HeartbeatRequestChunk::kType:
781 HandleHeartbeatRequest(header, descriptor);
782 break;
783 case HeartbeatAckChunk::kType:
784 HandleHeartbeatAck(header, descriptor);
785 break;
786 case AbortChunk::kType:
787 HandleAbort(header, descriptor);
788 break;
789 case ErrorChunk::kType:
790 HandleError(header, descriptor);
791 break;
792 case CookieEchoChunk::kType:
793 HandleCookieEcho(header, descriptor);
794 break;
795 case CookieAckChunk::kType:
796 HandleCookieAck(header, descriptor);
797 break;
798 case ShutdownChunk::kType:
799 HandleShutdown(header, descriptor);
800 break;
801 case ShutdownAckChunk::kType:
802 HandleShutdownAck(header, descriptor);
803 break;
804 case ShutdownCompleteChunk::kType:
805 HandleShutdownComplete(header, descriptor);
806 break;
807 case ReConfigChunk::kType:
808 HandleReconfig(header, descriptor);
809 break;
810 case ForwardTsnChunk::kType:
811 HandleForwardTsn(header, descriptor);
812 break;
813 case IDataChunk::kType:
814 HandleIData(header, descriptor);
815 break;
816 case IForwardTsnChunk::kType:
Victor Boivie69c83cd2022-03-05 08:18:26 +0100817 HandleIForwardTsn(header, descriptor);
Victor Boivieb6580cc2021-04-08 09:56:59 +0200818 break;
819 default:
820 return HandleUnrecognizedChunk(descriptor);
821 }
822 return true;
823}
824
825bool DcSctpSocket::HandleUnrecognizedChunk(
826 const SctpPacket::ChunkDescriptor& descriptor) {
827 bool report_as_error = (descriptor.type & 0x40) != 0;
828 bool continue_processing = (descriptor.type & 0x80) != 0;
829 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Received unknown chunk: "
830 << static_cast<int>(descriptor.type);
831 if (report_as_error) {
832 rtc::StringBuilder sb;
833 sb << "Received unknown chunk of type: "
834 << static_cast<int>(descriptor.type) << " with report-error bit set";
835 callbacks_.OnError(ErrorKind::kParseFailed, sb.str());
836 RTC_DLOG(LS_VERBOSE)
837 << log_prefix()
838 << "Unknown chunk, with type indicating it should be reported.";
839
840 // https://tools.ietf.org/html/rfc4960#section-3.2
841 // "... report in an ERROR chunk using the 'Unrecognized Chunk Type'
842 // cause."
843 if (tcb_ != nullptr) {
844 // Need TCB - this chunk must be sent with a correct verification tag.
Victor Boivieabf61882021-08-12 15:57:49 +0200845 packet_sender_.Send(tcb_->PacketBuilder().Add(
Victor Boivieb6580cc2021-04-08 09:56:59 +0200846 ErrorChunk(Parameters::Builder()
847 .Add(UnrecognizedChunkTypeCause(std::vector<uint8_t>(
848 descriptor.data.begin(), descriptor.data.end())))
849 .Build())));
850 }
851 }
852 if (!continue_processing) {
853 // https://tools.ietf.org/html/rfc4960#section-3.2
854 // "Stop processing this SCTP packet and discard it, do not process any
855 // further chunks within it."
856 RTC_DLOG(LS_VERBOSE) << log_prefix()
857 << "Unknown chunk, with type indicating not to "
858 "process any further chunks";
859 }
860
861 return continue_processing;
862}
863
864absl::optional<DurationMs> DcSctpSocket::OnInitTimerExpiry() {
865 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Timer " << t1_init_->name()
866 << " has expired: " << t1_init_->expiration_count()
Victor Boivie9680d292021-08-30 10:23:49 +0200867 << "/" << t1_init_->options().max_restarts.value_or(-1);
Victor Boivieb6580cc2021-04-08 09:56:59 +0200868 RTC_DCHECK(state_ == State::kCookieWait);
869
870 if (t1_init_->is_running()) {
871 SendInit();
872 } else {
873 InternalClose(ErrorKind::kTooManyRetries, "No INIT_ACK received");
874 }
875 RTC_DCHECK(IsConsistent());
876 return absl::nullopt;
877}
878
879absl::optional<DurationMs> DcSctpSocket::OnCookieTimerExpiry() {
880 // https://tools.ietf.org/html/rfc4960#section-4
881 // "If the T1-cookie timer expires, the endpoint MUST retransmit COOKIE
882 // ECHO and restart the T1-cookie timer without changing state. This MUST
883 // be repeated up to 'Max.Init.Retransmits' times. After that, the endpoint
884 // MUST abort the initialization process and report the error to the SCTP
885 // user."
886 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Timer " << t1_cookie_->name()
887 << " has expired: " << t1_cookie_->expiration_count()
Victor Boivie9680d292021-08-30 10:23:49 +0200888 << "/"
889 << t1_cookie_->options().max_restarts.value_or(-1);
Victor Boivieb6580cc2021-04-08 09:56:59 +0200890
891 RTC_DCHECK(state_ == State::kCookieEchoed);
892
893 if (t1_cookie_->is_running()) {
Victor Boiviec20f1562021-06-16 12:52:42 +0200894 tcb_->SendBufferedPackets(callbacks_.TimeMillis());
Victor Boivieb6580cc2021-04-08 09:56:59 +0200895 } else {
896 InternalClose(ErrorKind::kTooManyRetries, "No COOKIE_ACK received");
897 }
898
899 RTC_DCHECK(IsConsistent());
900 return absl::nullopt;
901}
902
903absl::optional<DurationMs> DcSctpSocket::OnShutdownTimerExpiry() {
904 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Timer " << t2_shutdown_->name()
905 << " has expired: " << t2_shutdown_->expiration_count()
Victor Boivie9680d292021-08-30 10:23:49 +0200906 << "/"
907 << t2_shutdown_->options().max_restarts.value_or(-1);
Victor Boivieb6580cc2021-04-08 09:56:59 +0200908
Victor Boivie914925f2021-05-07 11:22:50 +0200909 if (!t2_shutdown_->is_running()) {
Victor Boivieb6580cc2021-04-08 09:56:59 +0200910 // https://tools.ietf.org/html/rfc4960#section-9.2
911 // "An endpoint should limit the number of retransmissions of the SHUTDOWN
912 // chunk to the protocol parameter 'Association.Max.Retrans'. If this
913 // threshold is exceeded, the endpoint should destroy the TCB..."
914
Victor Boivieabf61882021-08-12 15:57:49 +0200915 packet_sender_.Send(tcb_->PacketBuilder().Add(
Victor Boivieb6580cc2021-04-08 09:56:59 +0200916 AbortChunk(true, Parameters::Builder()
917 .Add(UserInitiatedAbortCause(
918 "Too many retransmissions of SHUTDOWN"))
919 .Build())));
920
921 InternalClose(ErrorKind::kTooManyRetries, "No SHUTDOWN_ACK received");
Victor Boivie914925f2021-05-07 11:22:50 +0200922 RTC_DCHECK(IsConsistent());
923 return absl::nullopt;
Victor Boivieb6580cc2021-04-08 09:56:59 +0200924 }
Victor Boivie914925f2021-05-07 11:22:50 +0200925
926 // https://tools.ietf.org/html/rfc4960#section-9.2
927 // "If the timer expires, the endpoint must resend the SHUTDOWN with the
928 // updated last sequential TSN received from its peer."
929 SendShutdown();
Victor Boivieb6580cc2021-04-08 09:56:59 +0200930 RTC_DCHECK(IsConsistent());
931 return tcb_->current_rto();
932}
933
Victor Boivieabf61882021-08-12 15:57:49 +0200934void DcSctpSocket::OnSentPacket(rtc::ArrayView<const uint8_t> packet,
935 SendPacketStatus status) {
936 // The packet observer is invoked even if the packet was failed to be sent, to
937 // indicate an attempt was made.
Victor Boivieb6580cc2021-04-08 09:56:59 +0200938 if (packet_observer_ != nullptr) {
Victor Boivieabf61882021-08-12 15:57:49 +0200939 packet_observer_->OnSentPacket(callbacks_.TimeMillis(), packet);
Victor Boivieb6580cc2021-04-08 09:56:59 +0200940 }
Victor Boivieabf61882021-08-12 15:57:49 +0200941
942 if (status == SendPacketStatus::kSuccess) {
943 if (RTC_DLOG_IS_ON) {
944 DebugPrintOutgoing(packet);
945 }
946
947 // The heartbeat interval timer is restarted for every sent packet, to
948 // fire when the outgoing channel is inactive.
949 if (tcb_ != nullptr) {
950 tcb_->heartbeat_handler().RestartTimer();
951 }
952
953 ++metrics_.tx_packets_count;
954 }
Victor Boivieb6580cc2021-04-08 09:56:59 +0200955}
956
957bool DcSctpSocket::ValidateHasTCB() {
958 if (tcb_ != nullptr) {
959 return true;
960 }
961
962 callbacks_.OnError(
963 ErrorKind::kNotConnected,
964 "Received unexpected commands on socket that is not connected");
965 return false;
966}
967
968void DcSctpSocket::ReportFailedToParseChunk(int chunk_type) {
969 rtc::StringBuilder sb;
970 sb << "Failed to parse chunk of type: " << chunk_type;
971 callbacks_.OnError(ErrorKind::kParseFailed, sb.str());
972}
973
974void DcSctpSocket::HandleData(const CommonHeader& header,
975 const SctpPacket::ChunkDescriptor& descriptor) {
976 absl::optional<DataChunk> chunk = DataChunk::Parse(descriptor.data);
977 if (ValidateParseSuccess(chunk) && ValidateHasTCB()) {
978 HandleDataCommon(*chunk);
979 }
980}
981
982void DcSctpSocket::HandleIData(const CommonHeader& header,
983 const SctpPacket::ChunkDescriptor& descriptor) {
984 absl::optional<IDataChunk> chunk = IDataChunk::Parse(descriptor.data);
985 if (ValidateParseSuccess(chunk) && ValidateHasTCB()) {
986 HandleDataCommon(*chunk);
987 }
988}
989
990void DcSctpSocket::HandleDataCommon(AnyDataChunk& chunk) {
991 TSN tsn = chunk.tsn();
992 AnyDataChunk::ImmediateAckFlag immediate_ack = chunk.options().immediate_ack;
993 Data data = std::move(chunk).extract();
994
Victor Boivie4b7024b2021-12-01 18:57:22 +0000995 if (data.payload.empty()) {
Victor Boivieb6580cc2021-04-08 09:56:59 +0200996 // Empty DATA chunks are illegal.
Victor Boivieabf61882021-08-12 15:57:49 +0200997 packet_sender_.Send(tcb_->PacketBuilder().Add(
Victor Boivieb6580cc2021-04-08 09:56:59 +0200998 ErrorChunk(Parameters::Builder().Add(NoUserDataCause(tsn)).Build())));
999 callbacks_.OnError(ErrorKind::kProtocolViolation,
1000 "Received DATA chunk with no user data");
1001 return;
1002 }
1003
1004 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Handle DATA, queue_size="
1005 << tcb_->reassembly_queue().queued_bytes()
1006 << ", water_mark="
1007 << tcb_->reassembly_queue().watermark_bytes()
1008 << ", full=" << tcb_->reassembly_queue().is_full()
1009 << ", above="
1010 << tcb_->reassembly_queue().is_above_watermark();
1011
1012 if (tcb_->reassembly_queue().is_full()) {
1013 // If the reassembly queue is full, there is nothing that can be done. The
1014 // specification only allows dropping gap-ack-blocks, and that's not
1015 // likely to help as the socket has been trying to fill gaps since the
1016 // watermark was reached.
Victor Boivieabf61882021-08-12 15:57:49 +02001017 packet_sender_.Send(tcb_->PacketBuilder().Add(AbortChunk(
Victor Boivieb6580cc2021-04-08 09:56:59 +02001018 true, Parameters::Builder().Add(OutOfResourceErrorCause()).Build())));
1019 InternalClose(ErrorKind::kResourceExhaustion,
1020 "Reassembly Queue is exhausted");
1021 return;
1022 }
1023
1024 if (tcb_->reassembly_queue().is_above_watermark()) {
1025 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Is above high watermark";
1026 // If the reassembly queue is above its high watermark, only accept data
1027 // chunks that increase its cumulative ack tsn in an attempt to fill gaps
1028 // to deliver messages.
1029 if (!tcb_->data_tracker().will_increase_cum_ack_tsn(tsn)) {
1030 RTC_DLOG(LS_VERBOSE) << log_prefix()
1031 << "Rejected data because of exceeding watermark";
1032 tcb_->data_tracker().ForceImmediateSack();
1033 return;
1034 }
1035 }
1036
1037 if (!tcb_->data_tracker().IsTSNValid(tsn)) {
1038 RTC_DLOG(LS_VERBOSE) << log_prefix()
1039 << "Rejected data because of failing TSN validity";
1040 return;
1041 }
1042
Victor Boivie568bc232022-03-20 19:59:03 +01001043 if (tcb_->data_tracker().Observe(tsn, immediate_ack)) {
1044 tcb_->reassembly_queue().MaybeResetStreamsDeferred(
1045 tcb_->data_tracker().last_cumulative_acked_tsn());
1046 tcb_->reassembly_queue().Add(tsn, std::move(data));
1047 DeliverReassembledMessages();
1048 }
Victor Boivieb6580cc2021-04-08 09:56:59 +02001049}
1050
1051void DcSctpSocket::HandleInit(const CommonHeader& header,
1052 const SctpPacket::ChunkDescriptor& descriptor) {
1053 absl::optional<InitChunk> chunk = InitChunk::Parse(descriptor.data);
1054 if (!ValidateParseSuccess(chunk)) {
1055 return;
1056 }
1057
1058 if (chunk->initiate_tag() == VerificationTag(0) ||
1059 chunk->nbr_outbound_streams() == 0 || chunk->nbr_inbound_streams() == 0) {
1060 // https://tools.ietf.org/html/rfc4960#section-3.3.2
1061 // "If the value of the Initiate Tag in a received INIT chunk is found
1062 // to be 0, the receiver MUST treat it as an error and close the
1063 // association by transmitting an ABORT."
1064
1065 // "A receiver of an INIT with the OS value set to 0 SHOULD abort the
1066 // association."
1067
1068 // "A receiver of an INIT with the MIS value of 0 SHOULD abort the
1069 // association."
1070
Victor Boivieabf61882021-08-12 15:57:49 +02001071 packet_sender_.Send(
1072 SctpPacket::Builder(VerificationTag(0), options_)
1073 .Add(AbortChunk(
1074 /*filled_in_verification_tag=*/false,
1075 Parameters::Builder()
1076 .Add(ProtocolViolationCause("INIT malformed"))
1077 .Build())));
Victor Boivieb6580cc2021-04-08 09:56:59 +02001078 InternalClose(ErrorKind::kProtocolViolation, "Received invalid INIT");
1079 return;
1080 }
1081
1082 if (state_ == State::kShutdownAckSent) {
1083 // https://tools.ietf.org/html/rfc4960#section-9.2
1084 // "If an endpoint is in the SHUTDOWN-ACK-SENT state and receives an
1085 // INIT chunk (e.g., if the SHUTDOWN COMPLETE was lost) with source and
1086 // destination transport addresses (either in the IP addresses or in the
1087 // INIT chunk) that belong to this association, it should discard the INIT
1088 // chunk and retransmit the SHUTDOWN ACK chunk."
1089 RTC_DLOG(LS_VERBOSE) << log_prefix()
1090 << "Received Init indicating lost ShutdownComplete";
1091 SendShutdownAck();
1092 return;
1093 }
1094
1095 TieTag tie_tag(0);
1096 if (state_ == State::kClosed) {
1097 RTC_DLOG(LS_VERBOSE) << log_prefix()
1098 << "Received Init in closed state (normal)";
1099
1100 MakeConnectionParameters();
1101 } else if (state_ == State::kCookieWait || state_ == State::kCookieEchoed) {
1102 // https://tools.ietf.org/html/rfc4960#section-5.2.1
1103 // "This usually indicates an initialization collision, i.e., each
1104 // endpoint is attempting, at about the same time, to establish an
1105 // association with the other endpoint. Upon receipt of an INIT in the
1106 // COOKIE-WAIT state, an endpoint MUST respond with an INIT ACK using the
1107 // same parameters it sent in its original INIT chunk (including its
1108 // Initiate Tag, unchanged). When responding, the endpoint MUST send the
1109 // INIT ACK back to the same address that the original INIT (sent by this
1110 // endpoint) was sent."
1111 RTC_DLOG(LS_VERBOSE) << log_prefix()
1112 << "Received Init indicating simultaneous connections";
1113 } else {
1114 RTC_DCHECK(tcb_ != nullptr);
1115 // https://tools.ietf.org/html/rfc4960#section-5.2.2
1116 // "The outbound SCTP packet containing this INIT ACK MUST carry a
1117 // Verification Tag value equal to the Initiate Tag found in the
1118 // unexpected INIT. And the INIT ACK MUST contain a new Initiate Tag
1119 // (randomly generated; see Section 5.3.1). Other parameters for the
1120 // endpoint SHOULD be copied from the existing parameters of the
1121 // association (e.g., number of outbound streams) into the INIT ACK and
1122 // cookie."
1123 RTC_DLOG(LS_VERBOSE) << log_prefix()
1124 << "Received Init indicating restarted connection";
1125 // Create a new verification tag - different from the previous one.
1126 for (int tries = 0; tries < 10; ++tries) {
1127 connect_params_.verification_tag = VerificationTag(
1128 callbacks_.GetRandomInt(kMinVerificationTag, kMaxVerificationTag));
1129 if (connect_params_.verification_tag != tcb_->my_verification_tag()) {
1130 break;
1131 }
1132 }
1133
1134 // Make the initial TSN make a large jump, so that there is no overlap
1135 // with the old and new association.
1136 connect_params_.initial_tsn =
1137 TSN(*tcb_->retransmission_queue().next_tsn() + 1000000);
1138 tie_tag = tcb_->tie_tag();
1139 }
1140
1141 RTC_DLOG(LS_VERBOSE)
1142 << log_prefix()
1143 << rtc::StringFormat(
1144 "Proceeding with connection. my_verification_tag=%08x, "
1145 "my_initial_tsn=%u, peer_verification_tag=%08x, "
1146 "peer_initial_tsn=%u",
1147 *connect_params_.verification_tag, *connect_params_.initial_tsn,
1148 *chunk->initiate_tag(), *chunk->initial_tsn());
1149
1150 Capabilities capabilities = GetCapabilities(options_, chunk->parameters());
1151
1152 SctpPacket::Builder b(chunk->initiate_tag(), options_);
1153 Parameters::Builder params_builder =
1154 Parameters::Builder().Add(StateCookieParameter(
1155 StateCookie(chunk->initiate_tag(), chunk->initial_tsn(),
1156 chunk->a_rwnd(), tie_tag, capabilities)
1157 .Serialize()));
1158 AddCapabilityParameters(options_, params_builder);
1159
1160 InitAckChunk init_ack(/*initiate_tag=*/connect_params_.verification_tag,
1161 options_.max_receiver_window_buffer_size,
1162 options_.announced_maximum_outgoing_streams,
1163 options_.announced_maximum_incoming_streams,
1164 connect_params_.initial_tsn, params_builder.Build());
1165 b.Add(init_ack);
Victor Boivieabf61882021-08-12 15:57:49 +02001166 packet_sender_.Send(b);
Victor Boivieb6580cc2021-04-08 09:56:59 +02001167}
1168
Victor Boivieb6580cc2021-04-08 09:56:59 +02001169void DcSctpSocket::HandleInitAck(
1170 const CommonHeader& header,
1171 const SctpPacket::ChunkDescriptor& descriptor) {
1172 absl::optional<InitAckChunk> chunk = InitAckChunk::Parse(descriptor.data);
1173 if (!ValidateParseSuccess(chunk)) {
1174 return;
1175 }
1176
1177 if (state_ != State::kCookieWait) {
1178 // https://tools.ietf.org/html/rfc4960#section-5.2.3
1179 // "If an INIT ACK is received by an endpoint in any state other than
1180 // the COOKIE-WAIT state, the endpoint should discard the INIT ACK chunk."
1181 RTC_DLOG(LS_VERBOSE) << log_prefix()
1182 << "Received INIT_ACK in unexpected state";
1183 return;
1184 }
1185
1186 auto cookie = chunk->parameters().get<StateCookieParameter>();
1187 if (!cookie.has_value()) {
Victor Boivieabf61882021-08-12 15:57:49 +02001188 packet_sender_.Send(
1189 SctpPacket::Builder(connect_params_.verification_tag, options_)
1190 .Add(AbortChunk(
1191 /*filled_in_verification_tag=*/false,
1192 Parameters::Builder()
1193 .Add(ProtocolViolationCause("INIT-ACK malformed"))
1194 .Build())));
Victor Boivieb6580cc2021-04-08 09:56:59 +02001195 InternalClose(ErrorKind::kProtocolViolation,
1196 "InitAck chunk doesn't contain a cookie");
1197 return;
1198 }
1199 Capabilities capabilities = GetCapabilities(options_, chunk->parameters());
1200 t1_init_->Stop();
1201
Victor Boivief7fc71d2022-05-13 14:27:55 +02001202 metrics_.peer_implementation = DeterminePeerImplementation(cookie->data());
Victor Boivief4fa1662021-09-24 23:01:21 +02001203
Victor Boivieb6580cc2021-04-08 09:56:59 +02001204 tcb_ = std::make_unique<TransmissionControlBlock>(
1205 timer_manager_, log_prefix_, options_, capabilities, callbacks_,
1206 send_queue_, connect_params_.verification_tag,
1207 connect_params_.initial_tsn, chunk->initiate_tag(), chunk->initial_tsn(),
Victor Boivieabf61882021-08-12 15:57:49 +02001208 chunk->a_rwnd(), MakeTieTag(callbacks_), packet_sender_,
1209 [this]() { return state_ == State::kEstablished; });
Victor Boivieb6580cc2021-04-08 09:56:59 +02001210 RTC_DLOG(LS_VERBOSE) << log_prefix()
1211 << "Created peer TCB: " << tcb_->ToString();
1212
1213 SetState(State::kCookieEchoed, "INIT_ACK received");
1214
1215 // The connection isn't fully established just yet.
Victor Boiviec20f1562021-06-16 12:52:42 +02001216 tcb_->SetCookieEchoChunk(CookieEchoChunk(cookie->data()));
1217 tcb_->SendBufferedPackets(callbacks_.TimeMillis());
Victor Boivieb6580cc2021-04-08 09:56:59 +02001218 t1_cookie_->Start();
1219}
1220
1221void DcSctpSocket::HandleCookieEcho(
1222 const CommonHeader& header,
1223 const SctpPacket::ChunkDescriptor& descriptor) {
1224 absl::optional<CookieEchoChunk> chunk =
1225 CookieEchoChunk::Parse(descriptor.data);
1226 if (!ValidateParseSuccess(chunk)) {
1227 return;
1228 }
1229
1230 absl::optional<StateCookie> cookie =
1231 StateCookie::Deserialize(chunk->cookie());
1232 if (!cookie.has_value()) {
1233 callbacks_.OnError(ErrorKind::kParseFailed, "Failed to parse state cookie");
1234 return;
1235 }
1236
1237 if (tcb_ != nullptr) {
1238 if (!HandleCookieEchoWithTCB(header, *cookie)) {
1239 return;
1240 }
1241 } else {
1242 if (header.verification_tag != connect_params_.verification_tag) {
1243 callbacks_.OnError(
1244 ErrorKind::kParseFailed,
1245 rtc::StringFormat(
1246 "Received CookieEcho with invalid verification tag: %08x, "
1247 "expected %08x",
1248 *header.verification_tag, *connect_params_.verification_tag));
1249 return;
1250 }
1251 }
1252
1253 // The init timer can be running on simultaneous connections.
1254 t1_init_->Stop();
1255 t1_cookie_->Stop();
1256 if (state_ != State::kEstablished) {
Victor Boiviec20f1562021-06-16 12:52:42 +02001257 if (tcb_ != nullptr) {
1258 tcb_->ClearCookieEchoChunk();
1259 }
Victor Boivieb6580cc2021-04-08 09:56:59 +02001260 SetState(State::kEstablished, "COOKIE_ECHO received");
1261 callbacks_.OnConnected();
1262 }
1263
1264 if (tcb_ == nullptr) {
1265 tcb_ = std::make_unique<TransmissionControlBlock>(
1266 timer_manager_, log_prefix_, options_, cookie->capabilities(),
1267 callbacks_, send_queue_, connect_params_.verification_tag,
1268 connect_params_.initial_tsn, cookie->initiate_tag(),
1269 cookie->initial_tsn(), cookie->a_rwnd(), MakeTieTag(callbacks_),
Victor Boivieabf61882021-08-12 15:57:49 +02001270 packet_sender_, [this]() { return state_ == State::kEstablished; });
Victor Boivieb6580cc2021-04-08 09:56:59 +02001271 RTC_DLOG(LS_VERBOSE) << log_prefix()
1272 << "Created peer TCB: " << tcb_->ToString();
1273 }
1274
1275 SctpPacket::Builder b = tcb_->PacketBuilder();
1276 b.Add(CookieAckChunk());
1277
1278 // https://tools.ietf.org/html/rfc4960#section-5.1
1279 // "A COOKIE ACK chunk may be bundled with any pending DATA chunks (and/or
1280 // SACK chunks), but the COOKIE ACK chunk MUST be the first chunk in the
1281 // packet."
Victor Boivied3b186e2021-05-05 16:22:29 +02001282 tcb_->SendBufferedPackets(b, callbacks_.TimeMillis());
Victor Boivieb6580cc2021-04-08 09:56:59 +02001283}
1284
1285bool DcSctpSocket::HandleCookieEchoWithTCB(const CommonHeader& header,
1286 const StateCookie& cookie) {
1287 RTC_DLOG(LS_VERBOSE) << log_prefix()
1288 << "Handling CookieEchoChunk with TCB. local_tag="
1289 << *tcb_->my_verification_tag()
1290 << ", peer_tag=" << *header.verification_tag
1291 << ", tcb_tag=" << *tcb_->peer_verification_tag()
1292 << ", cookie_tag=" << *cookie.initiate_tag()
1293 << ", local_tie_tag=" << *tcb_->tie_tag()
1294 << ", peer_tie_tag=" << *cookie.tie_tag();
1295 // https://tools.ietf.org/html/rfc4960#section-5.2.4
1296 // "Handle a COOKIE ECHO when a TCB Exists"
1297 if (header.verification_tag != tcb_->my_verification_tag() &&
1298 tcb_->peer_verification_tag() != cookie.initiate_tag() &&
1299 cookie.tie_tag() == tcb_->tie_tag()) {
1300 // "A) In this case, the peer may have restarted."
1301 if (state_ == State::kShutdownAckSent) {
1302 // "If the endpoint is in the SHUTDOWN-ACK-SENT state and recognizes
1303 // that the peer has restarted ... it MUST NOT set up a new association
1304 // but instead resend the SHUTDOWN ACK and send an ERROR chunk with a
1305 // "Cookie Received While Shutting Down" error cause to its peer."
1306 SctpPacket::Builder b(cookie.initiate_tag(), options_);
1307 b.Add(ShutdownAckChunk());
1308 b.Add(ErrorChunk(Parameters::Builder()
1309 .Add(CookieReceivedWhileShuttingDownCause())
1310 .Build()));
Victor Boivieabf61882021-08-12 15:57:49 +02001311 packet_sender_.Send(b);
Victor Boivieb6580cc2021-04-08 09:56:59 +02001312 callbacks_.OnError(ErrorKind::kWrongSequence,
1313 "Received COOKIE-ECHO while shutting down");
1314 return false;
1315 }
1316
1317 RTC_DLOG(LS_VERBOSE) << log_prefix()
1318 << "Received COOKIE-ECHO indicating a restarted peer";
1319
Victor Boivieb6580cc2021-04-08 09:56:59 +02001320 tcb_ = nullptr;
1321 callbacks_.OnConnectionRestarted();
1322 } else if (header.verification_tag == tcb_->my_verification_tag() &&
1323 tcb_->peer_verification_tag() != cookie.initiate_tag()) {
1324 // TODO(boivie): Handle the peer_tag == 0?
1325 // "B) In this case, both sides may be attempting to start an
1326 // association at about the same time, but the peer endpoint started its
1327 // INIT after responding to the local endpoint's INIT."
1328 RTC_DLOG(LS_VERBOSE)
1329 << log_prefix()
1330 << "Received COOKIE-ECHO indicating simultaneous connections";
1331 tcb_ = nullptr;
1332 } else if (header.verification_tag != tcb_->my_verification_tag() &&
1333 tcb_->peer_verification_tag() == cookie.initiate_tag() &&
1334 cookie.tie_tag() == TieTag(0)) {
1335 // "C) In this case, the local endpoint's cookie has arrived late.
1336 // Before it arrived, the local endpoint sent an INIT and received an
1337 // INIT ACK and finally sent a COOKIE ECHO with the peer's same tag but
1338 // a new tag of its own. The cookie should be silently discarded. The
1339 // endpoint SHOULD NOT change states and should leave any timers
1340 // running."
1341 RTC_DLOG(LS_VERBOSE)
1342 << log_prefix()
1343 << "Received COOKIE-ECHO indicating a late COOKIE-ECHO. Discarding";
1344 return false;
1345 } else if (header.verification_tag == tcb_->my_verification_tag() &&
1346 tcb_->peer_verification_tag() == cookie.initiate_tag()) {
1347 // "D) When both local and remote tags match, the endpoint should enter
1348 // the ESTABLISHED state, if it is in the COOKIE-ECHOED state. It
1349 // should stop any cookie timer that may be running and send a COOKIE
1350 // ACK."
1351 RTC_DLOG(LS_VERBOSE)
1352 << log_prefix()
1353 << "Received duplicate COOKIE-ECHO, probably because of peer not "
1354 "receiving COOKIE-ACK and retransmitting COOKIE-ECHO. Continuing.";
1355 }
1356 return true;
1357}
1358
1359void DcSctpSocket::HandleCookieAck(
1360 const CommonHeader& header,
1361 const SctpPacket::ChunkDescriptor& descriptor) {
1362 absl::optional<CookieAckChunk> chunk = CookieAckChunk::Parse(descriptor.data);
1363 if (!ValidateParseSuccess(chunk)) {
1364 return;
1365 }
1366
1367 if (state_ != State::kCookieEchoed) {
1368 // https://tools.ietf.org/html/rfc4960#section-5.2.5
1369 // "At any state other than COOKIE-ECHOED, an endpoint should silently
1370 // discard a received COOKIE ACK chunk."
1371 RTC_DLOG(LS_VERBOSE) << log_prefix()
1372 << "Received COOKIE_ACK not in COOKIE_ECHOED state";
1373 return;
1374 }
1375
1376 // RFC 4960, Errata ID: 4400
1377 t1_cookie_->Stop();
Victor Boiviec20f1562021-06-16 12:52:42 +02001378 tcb_->ClearCookieEchoChunk();
Victor Boivieb6580cc2021-04-08 09:56:59 +02001379 SetState(State::kEstablished, "COOKIE_ACK received");
Victor Boivied3b186e2021-05-05 16:22:29 +02001380 tcb_->SendBufferedPackets(callbacks_.TimeMillis());
Victor Boivieb6580cc2021-04-08 09:56:59 +02001381 callbacks_.OnConnected();
1382}
1383
1384void DcSctpSocket::DeliverReassembledMessages() {
1385 if (tcb_->reassembly_queue().HasMessages()) {
1386 for (auto& message : tcb_->reassembly_queue().FlushMessages()) {
Victor Boivied4716ea2021-08-09 12:26:32 +02001387 ++metrics_.rx_messages_count;
Victor Boivieb6580cc2021-04-08 09:56:59 +02001388 callbacks_.OnMessageReceived(std::move(message));
1389 }
1390 }
1391}
1392
1393void DcSctpSocket::HandleSack(const CommonHeader& header,
1394 const SctpPacket::ChunkDescriptor& descriptor) {
1395 absl::optional<SackChunk> chunk = SackChunk::Parse(descriptor.data);
1396
1397 if (ValidateParseSuccess(chunk) && ValidateHasTCB()) {
Victor Boivied3b186e2021-05-05 16:22:29 +02001398 TimeMs now = callbacks_.TimeMillis();
Victor Boivieb6580cc2021-04-08 09:56:59 +02001399 SackChunk sack = ChunkValidators::Clean(*std::move(chunk));
1400
Victor Boivied3b186e2021-05-05 16:22:29 +02001401 if (tcb_->retransmission_queue().HandleSack(now, sack)) {
Victor Boivieb6580cc2021-04-08 09:56:59 +02001402 MaybeSendShutdownOrAck();
Victor Boivie5e354d92022-04-22 16:28:33 +02001403 // Receiving an ACK may make the socket go into fast recovery mode.
1404 // https://datatracker.ietf.org/doc/html/rfc4960#section-7.2.4
1405 // "Determine how many of the earliest (i.e., lowest TSN) DATA chunks
1406 // marked for retransmission will fit into a single packet, subject to
1407 // constraint of the path MTU of the destination transport address to
1408 // which the packet is being sent. Call this value K. Retransmit those K
1409 // DATA chunks in a single packet. When a Fast Retransmit is being
1410 // performed, the sender SHOULD ignore the value of cwnd and SHOULD NOT
1411 // delay retransmission for this single packet."
1412 tcb_->MaybeSendFastRetransmit();
1413
Victor Boivieb6580cc2021-04-08 09:56:59 +02001414 // Receiving an ACK will decrease outstanding bytes (maybe now below
1415 // cwnd?) or indicate packet loss that may result in sending FORWARD-TSN.
Victor Boivied3b186e2021-05-05 16:22:29 +02001416 tcb_->SendBufferedPackets(now);
Victor Boivieb6580cc2021-04-08 09:56:59 +02001417 } else {
1418 RTC_DLOG(LS_VERBOSE) << log_prefix()
1419 << "Dropping out-of-order SACK with TSN "
1420 << *sack.cumulative_tsn_ack();
1421 }
1422 }
1423}
1424
1425void DcSctpSocket::HandleHeartbeatRequest(
1426 const CommonHeader& header,
1427 const SctpPacket::ChunkDescriptor& descriptor) {
1428 absl::optional<HeartbeatRequestChunk> chunk =
1429 HeartbeatRequestChunk::Parse(descriptor.data);
1430
1431 if (ValidateParseSuccess(chunk) && ValidateHasTCB()) {
1432 tcb_->heartbeat_handler().HandleHeartbeatRequest(*std::move(chunk));
1433 }
1434}
1435
1436void DcSctpSocket::HandleHeartbeatAck(
1437 const CommonHeader& header,
1438 const SctpPacket::ChunkDescriptor& descriptor) {
1439 absl::optional<HeartbeatAckChunk> chunk =
1440 HeartbeatAckChunk::Parse(descriptor.data);
1441
1442 if (ValidateParseSuccess(chunk) && ValidateHasTCB()) {
1443 tcb_->heartbeat_handler().HandleHeartbeatAck(*std::move(chunk));
1444 }
1445}
1446
1447void DcSctpSocket::HandleAbort(const CommonHeader& header,
1448 const SctpPacket::ChunkDescriptor& descriptor) {
1449 absl::optional<AbortChunk> chunk = AbortChunk::Parse(descriptor.data);
1450 if (ValidateParseSuccess(chunk)) {
1451 std::string error_string = ErrorCausesToString(chunk->error_causes());
1452 if (tcb_ == nullptr) {
1453 // https://tools.ietf.org/html/rfc4960#section-3.3.7
1454 // "If an endpoint receives an ABORT with a format error or no TCB is
1455 // found, it MUST silently discard it."
1456 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Received ABORT (" << error_string
1457 << ") on a connection with no TCB. Ignoring";
1458 return;
1459 }
1460
1461 RTC_DLOG(LS_WARNING) << log_prefix() << "Received ABORT (" << error_string
1462 << ") - closing connection.";
1463 InternalClose(ErrorKind::kPeerReported, error_string);
1464 }
1465}
1466
1467void DcSctpSocket::HandleError(const CommonHeader& header,
1468 const SctpPacket::ChunkDescriptor& descriptor) {
1469 absl::optional<ErrorChunk> chunk = ErrorChunk::Parse(descriptor.data);
1470 if (ValidateParseSuccess(chunk)) {
1471 std::string error_string = ErrorCausesToString(chunk->error_causes());
1472 if (tcb_ == nullptr) {
1473 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Received ERROR (" << error_string
1474 << ") on a connection with no TCB. Ignoring";
1475 return;
1476 }
1477
1478 RTC_DLOG(LS_WARNING) << log_prefix() << "Received ERROR: " << error_string;
1479 callbacks_.OnError(ErrorKind::kPeerReported,
1480 "Peer reported error: " + error_string);
1481 }
1482}
1483
1484void DcSctpSocket::HandleReconfig(
1485 const CommonHeader& header,
1486 const SctpPacket::ChunkDescriptor& descriptor) {
1487 absl::optional<ReConfigChunk> chunk = ReConfigChunk::Parse(descriptor.data);
1488 if (ValidateParseSuccess(chunk) && ValidateHasTCB()) {
1489 tcb_->stream_reset_handler().HandleReConfig(*std::move(chunk));
Victor Boivief9e116f2022-03-31 17:15:03 +02001490 // Handling this response may result in outgoing stream resets finishing
1491 // (either successfully or with failure). If there still are pending streams
1492 // that were waiting for this request to finish, continue resetting them.
1493 MaybeSendResetStreamsRequest();
Victor Boivieb6580cc2021-04-08 09:56:59 +02001494 }
1495}
1496
1497void DcSctpSocket::HandleShutdown(
1498 const CommonHeader& header,
1499 const SctpPacket::ChunkDescriptor& descriptor) {
1500 if (!ValidateParseSuccess(ShutdownChunk::Parse(descriptor.data))) {
1501 return;
1502 }
1503
1504 if (state_ == State::kClosed) {
1505 return;
1506 } else if (state_ == State::kCookieWait || state_ == State::kCookieEchoed) {
1507 // https://tools.ietf.org/html/rfc4960#section-9.2
1508 // "If a SHUTDOWN is received in the COOKIE-WAIT or COOKIE ECHOED state,
1509 // the SHUTDOWN chunk SHOULD be silently discarded."
1510 } else if (state_ == State::kShutdownSent) {
1511 // https://tools.ietf.org/html/rfc4960#section-9.2
1512 // "If an endpoint is in the SHUTDOWN-SENT state and receives a
1513 // SHUTDOWN chunk from its peer, the endpoint shall respond immediately
1514 // with a SHUTDOWN ACK to its peer, and move into the SHUTDOWN-ACK-SENT
1515 // state restarting its T2-shutdown timer."
1516 SendShutdownAck();
1517 SetState(State::kShutdownAckSent, "SHUTDOWN received");
Victor Boivie50a0b122021-05-06 21:07:49 +02001518 } else if (state_ == State::kShutdownAckSent) {
1519 // TODO(webrtc:12739): This condition should be removed and handled by the
1520 // next (state_ != State::kShutdownReceived).
1521 return;
Victor Boivieb6580cc2021-04-08 09:56:59 +02001522 } else if (state_ != State::kShutdownReceived) {
1523 RTC_DLOG(LS_VERBOSE) << log_prefix()
1524 << "Received SHUTDOWN - shutting down the socket";
1525 // https://tools.ietf.org/html/rfc4960#section-9.2
1526 // "Upon reception of the SHUTDOWN, the peer endpoint shall enter the
1527 // SHUTDOWN-RECEIVED state, stop accepting new data from its SCTP user,
1528 // and verify, by checking the Cumulative TSN Ack field of the chunk, that
1529 // all its outstanding DATA chunks have been received by the SHUTDOWN
1530 // sender."
1531 SetState(State::kShutdownReceived, "SHUTDOWN received");
1532 MaybeSendShutdownOrAck();
1533 }
1534}
1535
1536void DcSctpSocket::HandleShutdownAck(
1537 const CommonHeader& header,
1538 const SctpPacket::ChunkDescriptor& descriptor) {
1539 if (!ValidateParseSuccess(ShutdownAckChunk::Parse(descriptor.data))) {
1540 return;
1541 }
1542
1543 if (state_ == State::kShutdownSent || state_ == State::kShutdownAckSent) {
1544 // https://tools.ietf.org/html/rfc4960#section-9.2
1545 // "Upon the receipt of the SHUTDOWN ACK, the SHUTDOWN sender shall stop
1546 // the T2-shutdown timer, send a SHUTDOWN COMPLETE chunk to its peer, and
1547 // remove all record of the association."
1548
1549 // "If an endpoint is in the SHUTDOWN-ACK-SENT state and receives a
1550 // SHUTDOWN ACK, it shall stop the T2-shutdown timer, send a SHUTDOWN
1551 // COMPLETE chunk to its peer, and remove all record of the association."
1552
1553 SctpPacket::Builder b = tcb_->PacketBuilder();
1554 b.Add(ShutdownCompleteChunk(/*tag_reflected=*/false));
Victor Boivieabf61882021-08-12 15:57:49 +02001555 packet_sender_.Send(b);
Victor Boivieb6580cc2021-04-08 09:56:59 +02001556 InternalClose(ErrorKind::kNoError, "");
1557 } else {
1558 // https://tools.ietf.org/html/rfc4960#section-8.5.1
1559 // "If the receiver is in COOKIE-ECHOED or COOKIE-WAIT state
1560 // the procedures in Section 8.4 SHOULD be followed; in other words, it
1561 // should be treated as an Out Of The Blue packet."
1562
1563 // https://tools.ietf.org/html/rfc4960#section-8.4
1564 // "If the packet contains a SHUTDOWN ACK chunk, the receiver
1565 // should respond to the sender of the OOTB packet with a SHUTDOWN
1566 // COMPLETE. When sending the SHUTDOWN COMPLETE, the receiver of the OOTB
1567 // packet must fill in the Verification Tag field of the outbound packet
1568 // with the Verification Tag received in the SHUTDOWN ACK and set the T
1569 // bit in the Chunk Flags to indicate that the Verification Tag is
1570 // reflected."
1571
1572 SctpPacket::Builder b(header.verification_tag, options_);
1573 b.Add(ShutdownCompleteChunk(/*tag_reflected=*/true));
Victor Boivieabf61882021-08-12 15:57:49 +02001574 packet_sender_.Send(b);
Victor Boivieb6580cc2021-04-08 09:56:59 +02001575 }
1576}
1577
1578void DcSctpSocket::HandleShutdownComplete(
1579 const CommonHeader& header,
1580 const SctpPacket::ChunkDescriptor& descriptor) {
1581 if (!ValidateParseSuccess(ShutdownCompleteChunk::Parse(descriptor.data))) {
1582 return;
1583 }
1584
1585 if (state_ == State::kShutdownAckSent) {
1586 // https://tools.ietf.org/html/rfc4960#section-9.2
1587 // "Upon reception of the SHUTDOWN COMPLETE chunk, the endpoint will
1588 // verify that it is in the SHUTDOWN-ACK-SENT state; if it is not, the
1589 // chunk should be discarded. If the endpoint is in the SHUTDOWN-ACK-SENT
1590 // state, the endpoint should stop the T2-shutdown timer and remove all
1591 // knowledge of the association (and thus the association enters the
1592 // CLOSED state)."
1593 InternalClose(ErrorKind::kNoError, "");
1594 }
1595}
1596
1597void DcSctpSocket::HandleForwardTsn(
1598 const CommonHeader& header,
1599 const SctpPacket::ChunkDescriptor& descriptor) {
1600 absl::optional<ForwardTsnChunk> chunk =
1601 ForwardTsnChunk::Parse(descriptor.data);
1602 if (ValidateParseSuccess(chunk) && ValidateHasTCB()) {
1603 HandleForwardTsnCommon(*chunk);
1604 }
1605}
1606
1607void DcSctpSocket::HandleIForwardTsn(
1608 const CommonHeader& header,
1609 const SctpPacket::ChunkDescriptor& descriptor) {
1610 absl::optional<IForwardTsnChunk> chunk =
1611 IForwardTsnChunk::Parse(descriptor.data);
1612 if (ValidateParseSuccess(chunk) && ValidateHasTCB()) {
1613 HandleForwardTsnCommon(*chunk);
1614 }
1615}
1616
1617void DcSctpSocket::HandleForwardTsnCommon(const AnyForwardTsnChunk& chunk) {
1618 if (!tcb_->capabilities().partial_reliability) {
1619 SctpPacket::Builder b = tcb_->PacketBuilder();
1620 b.Add(AbortChunk(/*filled_in_verification_tag=*/true,
1621 Parameters::Builder()
1622 .Add(ProtocolViolationCause(
1623 "I-FORWARD-TSN received, but not indicated "
1624 "during connection establishment"))
1625 .Build()));
Victor Boivieabf61882021-08-12 15:57:49 +02001626 packet_sender_.Send(b);
Victor Boivieb6580cc2021-04-08 09:56:59 +02001627
1628 callbacks_.OnError(ErrorKind::kProtocolViolation,
1629 "Received a FORWARD_TSN without announced peer support");
1630 return;
1631 }
1632 tcb_->data_tracker().HandleForwardTsn(chunk.new_cumulative_tsn());
1633 tcb_->reassembly_queue().Handle(chunk);
1634 // A forward TSN - for ordered streams - may allow messages to be
1635 // delivered.
1636 DeliverReassembledMessages();
1637
1638 // Processing a FORWARD_TSN might result in sending a SACK.
1639 tcb_->MaybeSendSack();
1640}
1641
1642void DcSctpSocket::MaybeSendShutdownOrAck() {
1643 if (tcb_->retransmission_queue().outstanding_bytes() != 0) {
1644 return;
1645 }
1646
1647 if (state_ == State::kShutdownPending) {
1648 // https://tools.ietf.org/html/rfc4960#section-9.2
1649 // "Once all its outstanding data has been acknowledged, the endpoint
1650 // shall send a SHUTDOWN chunk to its peer including in the Cumulative TSN
1651 // Ack field the last sequential TSN it has received from the peer. It
1652 // shall then start the T2-shutdown timer and enter the SHUTDOWN-SENT
1653 // state.""
1654
1655 SendShutdown();
1656 t2_shutdown_->set_duration(tcb_->current_rto());
1657 t2_shutdown_->Start();
1658 SetState(State::kShutdownSent, "No more outstanding data");
1659 } else if (state_ == State::kShutdownReceived) {
1660 // https://tools.ietf.org/html/rfc4960#section-9.2
1661 // "If the receiver of the SHUTDOWN has no more outstanding DATA
1662 // chunks, the SHUTDOWN receiver MUST send a SHUTDOWN ACK and start a
1663 // T2-shutdown timer of its own, entering the SHUTDOWN-ACK-SENT state. If
1664 // the timer expires, the endpoint must resend the SHUTDOWN ACK."
1665
1666 SendShutdownAck();
1667 SetState(State::kShutdownAckSent, "No more outstanding data");
1668 }
1669}
1670
1671void DcSctpSocket::SendShutdown() {
1672 SctpPacket::Builder b = tcb_->PacketBuilder();
1673 b.Add(ShutdownChunk(tcb_->data_tracker().last_cumulative_acked_tsn()));
Victor Boivieabf61882021-08-12 15:57:49 +02001674 packet_sender_.Send(b);
Victor Boivieb6580cc2021-04-08 09:56:59 +02001675}
1676
1677void DcSctpSocket::SendShutdownAck() {
Victor Boivieabf61882021-08-12 15:57:49 +02001678 packet_sender_.Send(tcb_->PacketBuilder().Add(ShutdownAckChunk()));
Victor Boivieb6580cc2021-04-08 09:56:59 +02001679 t2_shutdown_->set_duration(tcb_->current_rto());
1680 t2_shutdown_->Start();
1681}
1682
Sergey Sukhanov43972812021-09-17 15:32:48 +02001683HandoverReadinessStatus DcSctpSocket::GetHandoverReadiness() const {
Victor Boivie5755f3e2021-09-29 22:23:15 +02001684 RTC_DCHECK_RUN_ON(&thread_checker_);
Sergey Sukhanov43972812021-09-17 15:32:48 +02001685 HandoverReadinessStatus status;
1686 if (state_ != State::kClosed && state_ != State::kEstablished) {
1687 status.Add(HandoverUnreadinessReason::kWrongConnectionState);
1688 }
Sergey Sukhanov72435322021-09-21 13:31:09 +02001689 status.Add(send_queue_.GetHandoverReadiness());
Sergey Sukhanov43972812021-09-17 15:32:48 +02001690 if (tcb_) {
1691 status.Add(tcb_->GetHandoverReadiness());
1692 }
1693 return status;
1694}
1695
1696absl::optional<DcSctpSocketHandoverState>
1697DcSctpSocket::GetHandoverStateAndClose() {
Victor Boivie5755f3e2021-09-29 22:23:15 +02001698 RTC_DCHECK_RUN_ON(&thread_checker_);
Victor Boivie15a0c882021-09-28 21:38:34 +02001699 CallbackDeferrer::ScopedDeferrer deferrer(callbacks_);
1700
Sergey Sukhanov43972812021-09-17 15:32:48 +02001701 if (!GetHandoverReadiness().IsReady()) {
1702 return absl::nullopt;
1703 }
1704
1705 DcSctpSocketHandoverState state;
1706
1707 if (state_ == State::kClosed) {
1708 state.socket_state = DcSctpSocketHandoverState::SocketState::kClosed;
1709 } else if (state_ == State::kEstablished) {
1710 state.socket_state = DcSctpSocketHandoverState::SocketState::kConnected;
1711 tcb_->AddHandoverState(state);
Sergey Sukhanov72435322021-09-21 13:31:09 +02001712 send_queue_.AddHandoverState(state);
Sergey Sukhanov43972812021-09-17 15:32:48 +02001713 InternalClose(ErrorKind::kNoError, "handover");
Sergey Sukhanov43972812021-09-17 15:32:48 +02001714 }
1715
1716 return std::move(state);
1717}
1718
Victor Boivieb6580cc2021-04-08 09:56:59 +02001719} // namespace dcsctp