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