blob: 9287b869ac157a7a4682a2084368426e86119484 [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
Victor Boivie2cffde72022-06-27 20:35:37 +0000309void DcSctpSocket::CreateTransmissionControlBlock(
310 const Capabilities& capabilities,
311 VerificationTag my_verification_tag,
312 TSN my_initial_tsn,
313 VerificationTag peer_verification_tag,
314 TSN peer_initial_tsn,
315 size_t a_rwnd,
316 TieTag tie_tag) {
Victor Boivie5b2556e2022-05-13 15:31:14 +0200317 metrics_.uses_message_interleaving = capabilities.message_interleaving;
Victor Boivie2cffde72022-06-27 20:35:37 +0000318 tcb_ = std::make_unique<TransmissionControlBlock>(
319 timer_manager_, log_prefix_, options_, capabilities, callbacks_,
320 send_queue_, my_verification_tag, my_initial_tsn, peer_verification_tag,
321 peer_initial_tsn, a_rwnd, tie_tag, packet_sender_,
322 [this]() { return state_ == State::kEstablished; });
323 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Created TCB: " << tcb_->ToString();
324}
325
Sergey Sukhanov43972812021-09-17 15:32:48 +0200326void DcSctpSocket::RestoreFromState(const DcSctpSocketHandoverState& state) {
Victor Boivie5755f3e2021-09-29 22:23:15 +0200327 RTC_DCHECK_RUN_ON(&thread_checker_);
Victor Boivie15a0c882021-09-28 21:38:34 +0200328 CallbackDeferrer::ScopedDeferrer deferrer(callbacks_);
329
Sergey Sukhanov43972812021-09-17 15:32:48 +0200330 if (state_ != State::kClosed) {
331 callbacks_.OnError(ErrorKind::kUnsupportedOperation,
332 "Only closed socket can be restored from state");
333 } else {
334 if (state.socket_state ==
335 DcSctpSocketHandoverState::SocketState::kConnected) {
336 VerificationTag my_verification_tag =
337 VerificationTag(state.my_verification_tag);
338 connect_params_.verification_tag = my_verification_tag;
339
340 Capabilities capabilities;
341 capabilities.partial_reliability = state.capabilities.partial_reliability;
342 capabilities.message_interleaving =
343 state.capabilities.message_interleaving;
344 capabilities.reconfig = state.capabilities.reconfig;
345
Sergey Sukhanov72435322021-09-21 13:31:09 +0200346 send_queue_.RestoreFromState(state);
347
Victor Boivie2cffde72022-06-27 20:35:37 +0000348 CreateTransmissionControlBlock(
349 capabilities, my_verification_tag, TSN(state.my_initial_tsn),
Sergey Sukhanov43972812021-09-17 15:32:48 +0200350 VerificationTag(state.peer_verification_tag),
351 TSN(state.peer_initial_tsn), static_cast<size_t>(0),
Victor Boivie2cffde72022-06-27 20:35:37 +0000352 TieTag(state.tie_tag));
353
354 tcb_->RestoreFromState(state);
Sergey Sukhanov43972812021-09-17 15:32:48 +0200355
356 SetState(State::kEstablished, "restored from handover state");
357 callbacks_.OnConnected();
358 }
359 }
360
361 RTC_DCHECK(IsConsistent());
Sergey Sukhanov43972812021-09-17 15:32:48 +0200362}
363
Victor Boivieb6580cc2021-04-08 09:56:59 +0200364void DcSctpSocket::Shutdown() {
Victor Boivie5755f3e2021-09-29 22:23:15 +0200365 RTC_DCHECK_RUN_ON(&thread_checker_);
Victor Boivie15a0c882021-09-28 21:38:34 +0200366 CallbackDeferrer::ScopedDeferrer deferrer(callbacks_);
367
Victor Boivieb6580cc2021-04-08 09:56:59 +0200368 if (tcb_ != nullptr) {
369 // https://tools.ietf.org/html/rfc4960#section-9.2
370 // "Upon receipt of the SHUTDOWN primitive from its upper layer, the
371 // endpoint enters the SHUTDOWN-PENDING state and remains there until all
372 // outstanding data has been acknowledged by its peer."
Victor Boivie50a0b122021-05-06 21:07:49 +0200373
374 // TODO(webrtc:12739): Remove this check, as it just hides the problem that
375 // the socket can transition from ShutdownSent to ShutdownPending, or
376 // ShutdownAckSent to ShutdownPending which is illegal.
377 if (state_ != State::kShutdownSent && state_ != State::kShutdownAckSent) {
378 SetState(State::kShutdownPending, "Shutdown called");
379 t1_init_->Stop();
380 t1_cookie_->Stop();
381 MaybeSendShutdownOrAck();
382 }
Victor Boivieb6580cc2021-04-08 09:56:59 +0200383 } else {
384 // Connection closed before even starting to connect, or during the initial
385 // connection phase. There is no outstanding data, so the socket can just
386 // be closed (stopping any connection timers, if any), as this is the
387 // client's intention, by calling Shutdown.
388 InternalClose(ErrorKind::kNoError, "");
389 }
390 RTC_DCHECK(IsConsistent());
Victor Boivieb6580cc2021-04-08 09:56:59 +0200391}
392
393void DcSctpSocket::Close() {
Victor Boivie5755f3e2021-09-29 22:23:15 +0200394 RTC_DCHECK_RUN_ON(&thread_checker_);
Victor Boivie15a0c882021-09-28 21:38:34 +0200395 CallbackDeferrer::ScopedDeferrer deferrer(callbacks_);
396
Victor Boivieb6580cc2021-04-08 09:56:59 +0200397 if (state_ != State::kClosed) {
398 if (tcb_ != nullptr) {
399 SctpPacket::Builder b = tcb_->PacketBuilder();
400 b.Add(AbortChunk(/*filled_in_verification_tag=*/true,
401 Parameters::Builder()
402 .Add(UserInitiatedAbortCause("Close called"))
403 .Build()));
Victor Boivieabf61882021-08-12 15:57:49 +0200404 packet_sender_.Send(b);
Victor Boivieb6580cc2021-04-08 09:56:59 +0200405 }
406 InternalClose(ErrorKind::kNoError, "");
407 } else {
408 RTC_DLOG(LS_INFO) << log_prefix() << "Called Close on a closed socket";
409 }
410 RTC_DCHECK(IsConsistent());
Victor Boivieb6580cc2021-04-08 09:56:59 +0200411}
412
413void DcSctpSocket::CloseConnectionBecauseOfTooManyTransmissionErrors() {
Victor Boivieabf61882021-08-12 15:57:49 +0200414 packet_sender_.Send(tcb_->PacketBuilder().Add(AbortChunk(
Victor Boivieb6580cc2021-04-08 09:56:59 +0200415 true, Parameters::Builder()
416 .Add(UserInitiatedAbortCause("Too many retransmissions"))
417 .Build())));
418 InternalClose(ErrorKind::kTooManyRetries, "Too many retransmissions");
419}
420
421void DcSctpSocket::InternalClose(ErrorKind error, absl::string_view message) {
422 if (state_ != State::kClosed) {
423 t1_init_->Stop();
424 t1_cookie_->Stop();
425 t2_shutdown_->Stop();
426 tcb_ = nullptr;
Victor Boivieb6580cc2021-04-08 09:56:59 +0200427
428 if (error == ErrorKind::kNoError) {
429 callbacks_.OnClosed();
430 } else {
431 callbacks_.OnAborted(error, message);
432 }
433 SetState(State::kClosed, message);
434 }
435 // This method's purpose is to abort/close and make it consistent by ensuring
436 // that e.g. all timers really are stopped.
437 RTC_DCHECK(IsConsistent());
438}
439
Victor Boivie7e897ae2022-05-02 13:04:37 +0200440void DcSctpSocket::SetStreamPriority(StreamID stream_id,
441 StreamPriority priority) {
442 RTC_DCHECK_RUN_ON(&thread_checker_);
443 send_queue_.SetStreamPriority(stream_id, priority);
444}
445StreamPriority DcSctpSocket::GetStreamPriority(StreamID stream_id) const {
446 RTC_DCHECK_RUN_ON(&thread_checker_);
447 return send_queue_.GetStreamPriority(stream_id);
448}
449
Victor Boivieb6580cc2021-04-08 09:56:59 +0200450SendStatus DcSctpSocket::Send(DcSctpMessage message,
451 const SendOptions& send_options) {
Victor Boivie5755f3e2021-09-29 22:23:15 +0200452 RTC_DCHECK_RUN_ON(&thread_checker_);
Victor Boivie15a0c882021-09-28 21:38:34 +0200453 CallbackDeferrer::ScopedDeferrer deferrer(callbacks_);
454
Victor Boivieb6580cc2021-04-08 09:56:59 +0200455 if (message.payload().empty()) {
456 callbacks_.OnError(ErrorKind::kProtocolViolation,
457 "Unable to send empty message");
458 return SendStatus::kErrorMessageEmpty;
459 }
460 if (message.payload().size() > options_.max_message_size) {
461 callbacks_.OnError(ErrorKind::kProtocolViolation,
462 "Unable to send too large message");
463 return SendStatus::kErrorMessageTooLarge;
464 }
465 if (state_ == State::kShutdownPending || state_ == State::kShutdownSent ||
466 state_ == State::kShutdownReceived || state_ == State::kShutdownAckSent) {
467 // https://tools.ietf.org/html/rfc4960#section-9.2
468 // "An endpoint should reject any new data request from its upper layer
469 // if it is in the SHUTDOWN-PENDING, SHUTDOWN-SENT, SHUTDOWN-RECEIVED, or
470 // SHUTDOWN-ACK-SENT state."
471 callbacks_.OnError(ErrorKind::kWrongSequence,
472 "Unable to send message as the socket is shutting down");
473 return SendStatus::kErrorShuttingDown;
474 }
475 if (send_queue_.IsFull()) {
476 callbacks_.OnError(ErrorKind::kResourceExhaustion,
477 "Unable to send message as the send queue is full");
478 return SendStatus::kErrorResourceExhaustion;
479 }
480
Victor Boivied3b186e2021-05-05 16:22:29 +0200481 TimeMs now = callbacks_.TimeMillis();
Victor Boivied4716ea2021-08-09 12:26:32 +0200482 ++metrics_.tx_messages_count;
Victor Boivied3b186e2021-05-05 16:22:29 +0200483 send_queue_.Add(now, std::move(message), send_options);
Victor Boivieb6580cc2021-04-08 09:56:59 +0200484 if (tcb_ != nullptr) {
Victor Boivied3b186e2021-05-05 16:22:29 +0200485 tcb_->SendBufferedPackets(now);
Victor Boivieb6580cc2021-04-08 09:56:59 +0200486 }
487
488 RTC_DCHECK(IsConsistent());
Victor Boivieb6580cc2021-04-08 09:56:59 +0200489 return SendStatus::kSuccess;
490}
491
492ResetStreamsStatus DcSctpSocket::ResetStreams(
493 rtc::ArrayView<const StreamID> outgoing_streams) {
Victor Boivie5755f3e2021-09-29 22:23:15 +0200494 RTC_DCHECK_RUN_ON(&thread_checker_);
Victor Boivie15a0c882021-09-28 21:38:34 +0200495 CallbackDeferrer::ScopedDeferrer deferrer(callbacks_);
496
Victor Boivieb6580cc2021-04-08 09:56:59 +0200497 if (tcb_ == nullptr) {
498 callbacks_.OnError(ErrorKind::kWrongSequence,
499 "Can't reset streams as the socket is not connected");
500 return ResetStreamsStatus::kNotConnected;
501 }
502 if (!tcb_->capabilities().reconfig) {
503 callbacks_.OnError(ErrorKind::kUnsupportedOperation,
504 "Can't reset streams as the peer doesn't support it");
505 return ResetStreamsStatus::kNotSupported;
506 }
507
508 tcb_->stream_reset_handler().ResetStreams(outgoing_streams);
Victor Boivief9e116f2022-03-31 17:15:03 +0200509 MaybeSendResetStreamsRequest();
Victor Boivieb6580cc2021-04-08 09:56:59 +0200510
511 RTC_DCHECK(IsConsistent());
Victor Boivieb6580cc2021-04-08 09:56:59 +0200512 return ResetStreamsStatus::kPerformed;
513}
514
515SocketState DcSctpSocket::state() const {
Victor Boivie5755f3e2021-09-29 22:23:15 +0200516 RTC_DCHECK_RUN_ON(&thread_checker_);
Victor Boivieb6580cc2021-04-08 09:56:59 +0200517 switch (state_) {
518 case State::kClosed:
519 return SocketState::kClosed;
520 case State::kCookieWait:
Victor Boivieb6580cc2021-04-08 09:56:59 +0200521 case State::kCookieEchoed:
522 return SocketState::kConnecting;
523 case State::kEstablished:
524 return SocketState::kConnected;
525 case State::kShutdownPending:
Victor Boivieb6580cc2021-04-08 09:56:59 +0200526 case State::kShutdownSent:
Victor Boivieb6580cc2021-04-08 09:56:59 +0200527 case State::kShutdownReceived:
Victor Boivieb6580cc2021-04-08 09:56:59 +0200528 case State::kShutdownAckSent:
529 return SocketState::kShuttingDown;
530 }
531}
532
Florent Castelli0810b052021-05-04 20:12:52 +0200533void DcSctpSocket::SetMaxMessageSize(size_t max_message_size) {
Victor Boivie5755f3e2021-09-29 22:23:15 +0200534 RTC_DCHECK_RUN_ON(&thread_checker_);
Florent Castelli0810b052021-05-04 20:12:52 +0200535 options_.max_message_size = max_message_size;
536}
537
Victor Boivie236ac502021-05-20 19:34:18 +0200538size_t DcSctpSocket::buffered_amount(StreamID stream_id) const {
Victor Boivie5755f3e2021-09-29 22:23:15 +0200539 RTC_DCHECK_RUN_ON(&thread_checker_);
Victor Boivie236ac502021-05-20 19:34:18 +0200540 return send_queue_.buffered_amount(stream_id);
541}
542
543size_t DcSctpSocket::buffered_amount_low_threshold(StreamID stream_id) const {
Victor Boivie5755f3e2021-09-29 22:23:15 +0200544 RTC_DCHECK_RUN_ON(&thread_checker_);
Victor Boivie236ac502021-05-20 19:34:18 +0200545 return send_queue_.buffered_amount_low_threshold(stream_id);
546}
547
548void DcSctpSocket::SetBufferedAmountLowThreshold(StreamID stream_id,
549 size_t bytes) {
Victor Boivie5755f3e2021-09-29 22:23:15 +0200550 RTC_DCHECK_RUN_ON(&thread_checker_);
Victor Boivie236ac502021-05-20 19:34:18 +0200551 send_queue_.SetBufferedAmountLowThreshold(stream_id, bytes);
552}
553
Victor Boivief7fc71d2022-05-13 14:27:55 +0200554absl::optional<Metrics> DcSctpSocket::GetMetrics() const {
Victor Boivie5755f3e2021-09-29 22:23:15 +0200555 RTC_DCHECK_RUN_ON(&thread_checker_);
Victor Boivied4716ea2021-08-09 12:26:32 +0200556
Victor Boivief7fc71d2022-05-13 14:27:55 +0200557 if (tcb_ == nullptr) {
558 return absl::nullopt;
Victor Boivied4716ea2021-08-09 12:26:32 +0200559 }
560
Victor Boivief7fc71d2022-05-13 14:27:55 +0200561 Metrics metrics = metrics_;
562 metrics.cwnd_bytes = tcb_->cwnd();
563 metrics.srtt_ms = tcb_->current_srtt().value();
564 size_t packet_payload_size =
565 options_.mtu - SctpPacket::kHeaderSize - DataChunk::kHeaderSize;
566 metrics.unack_data_count =
567 tcb_->retransmission_queue().outstanding_items() +
568 (send_queue_.total_buffered_amount() + packet_payload_size - 1) /
569 packet_payload_size;
570 metrics.peer_rwnd_bytes = tcb_->retransmission_queue().rwnd();
571
Victor Boivied4716ea2021-08-09 12:26:32 +0200572 return metrics;
573}
574
Victor Boivieb6580cc2021-04-08 09:56:59 +0200575void DcSctpSocket::MaybeSendShutdownOnPacketReceived(const SctpPacket& packet) {
576 if (state_ == State::kShutdownSent) {
577 bool has_data_chunk =
578 std::find_if(packet.descriptors().begin(), packet.descriptors().end(),
579 [](const SctpPacket::ChunkDescriptor& descriptor) {
580 return descriptor.type == DataChunk::kType;
581 }) != packet.descriptors().end();
582 if (has_data_chunk) {
583 // https://tools.ietf.org/html/rfc4960#section-9.2
584 // "While in the SHUTDOWN-SENT state, the SHUTDOWN sender MUST immediately
585 // respond to each received packet containing one or more DATA chunks with
586 // a SHUTDOWN chunk and restart the T2-shutdown timer.""
587 SendShutdown();
588 t2_shutdown_->set_duration(tcb_->current_rto());
589 t2_shutdown_->Start();
590 }
591 }
592}
593
Victor Boivief9e116f2022-03-31 17:15:03 +0200594void DcSctpSocket::MaybeSendResetStreamsRequest() {
595 absl::optional<ReConfigChunk> reconfig =
596 tcb_->stream_reset_handler().MakeStreamResetRequest();
597 if (reconfig.has_value()) {
598 SctpPacket::Builder builder = tcb_->PacketBuilder();
599 builder.Add(*reconfig);
600 packet_sender_.Send(builder);
601 }
602}
603
Victor Boivieb6580cc2021-04-08 09:56:59 +0200604bool DcSctpSocket::ValidatePacket(const SctpPacket& packet) {
605 const CommonHeader& header = packet.common_header();
606 VerificationTag my_verification_tag =
607 tcb_ != nullptr ? tcb_->my_verification_tag() : VerificationTag(0);
608
609 if (header.verification_tag == VerificationTag(0)) {
610 if (packet.descriptors().size() == 1 &&
611 packet.descriptors()[0].type == InitChunk::kType) {
612 // https://tools.ietf.org/html/rfc4960#section-8.5.1
613 // "When an endpoint receives an SCTP packet with the Verification Tag
614 // set to 0, it should verify that the packet contains only an INIT chunk.
615 // Otherwise, the receiver MUST silently discard the packet.""
616 return true;
617 }
618 callbacks_.OnError(
619 ErrorKind::kParseFailed,
620 "Only a single INIT chunk can be present in packets sent on "
621 "verification_tag = 0");
622 return false;
623 }
624
625 if (packet.descriptors().size() == 1 &&
626 packet.descriptors()[0].type == AbortChunk::kType) {
627 // https://tools.ietf.org/html/rfc4960#section-8.5.1
628 // "The receiver of an ABORT MUST accept the packet if the Verification
629 // Tag field of the packet matches its own tag and the T bit is not set OR
630 // if it is set to its peer's tag and the T bit is set in the Chunk Flags.
631 // Otherwise, the receiver MUST silently discard the packet and take no
632 // further action."
633 bool t_bit = (packet.descriptors()[0].flags & 0x01) != 0;
634 if (t_bit && tcb_ == nullptr) {
635 // Can't verify the tag - assume it's okey.
636 return true;
637 }
638 if ((!t_bit && header.verification_tag == my_verification_tag) ||
639 (t_bit && header.verification_tag == tcb_->peer_verification_tag())) {
640 return true;
641 }
642 callbacks_.OnError(ErrorKind::kParseFailed,
643 "ABORT chunk verification tag was wrong");
644 return false;
645 }
646
647 if (packet.descriptors()[0].type == InitAckChunk::kType) {
648 if (header.verification_tag == connect_params_.verification_tag) {
649 return true;
650 }
651 callbacks_.OnError(
652 ErrorKind::kParseFailed,
653 rtc::StringFormat(
654 "Packet has invalid verification tag: %08x, expected %08x",
655 *header.verification_tag, *connect_params_.verification_tag));
656 return false;
657 }
658
659 if (packet.descriptors()[0].type == CookieEchoChunk::kType) {
660 // Handled in chunk handler (due to RFC 4960, section 5.2.4).
661 return true;
662 }
663
664 if (packet.descriptors().size() == 1 &&
665 packet.descriptors()[0].type == ShutdownCompleteChunk::kType) {
666 // https://tools.ietf.org/html/rfc4960#section-8.5.1
667 // "The receiver of a SHUTDOWN COMPLETE shall accept the packet if the
668 // Verification Tag field of the packet matches its own tag and the T bit is
669 // not set OR if it is set to its peer's tag and the T bit is set in the
670 // Chunk Flags. Otherwise, the receiver MUST silently discard the packet
671 // and take no further action."
672 bool t_bit = (packet.descriptors()[0].flags & 0x01) != 0;
673 if (t_bit && tcb_ == nullptr) {
674 // Can't verify the tag - assume it's okey.
675 return true;
676 }
677 if ((!t_bit && header.verification_tag == my_verification_tag) ||
678 (t_bit && header.verification_tag == tcb_->peer_verification_tag())) {
679 return true;
680 }
681 callbacks_.OnError(ErrorKind::kParseFailed,
682 "SHUTDOWN_COMPLETE chunk verification tag was wrong");
683 return false;
684 }
685
686 // https://tools.ietf.org/html/rfc4960#section-8.5
687 // "When receiving an SCTP packet, the endpoint MUST ensure that the value
688 // in the Verification Tag field of the received SCTP packet matches its own
689 // tag. If the received Verification Tag value does not match the receiver's
690 // own tag value, the receiver shall silently discard the packet and shall not
691 // process it any further..."
692 if (header.verification_tag == my_verification_tag) {
693 return true;
694 }
695
696 callbacks_.OnError(
697 ErrorKind::kParseFailed,
698 rtc::StringFormat(
699 "Packet has invalid verification tag: %08x, expected %08x",
700 *header.verification_tag, *my_verification_tag));
701 return false;
702}
703
704void DcSctpSocket::HandleTimeout(TimeoutID timeout_id) {
Victor Boivie5755f3e2021-09-29 22:23:15 +0200705 RTC_DCHECK_RUN_ON(&thread_checker_);
Victor Boivie15a0c882021-09-28 21:38:34 +0200706 CallbackDeferrer::ScopedDeferrer deferrer(callbacks_);
707
Victor Boivieb6580cc2021-04-08 09:56:59 +0200708 timer_manager_.HandleTimeout(timeout_id);
709
710 if (tcb_ != nullptr && tcb_->HasTooManyTxErrors()) {
711 // Tearing down the TCB has to be done outside the handlers.
712 CloseConnectionBecauseOfTooManyTransmissionErrors();
713 }
714
715 RTC_DCHECK(IsConsistent());
Victor Boivieb6580cc2021-04-08 09:56:59 +0200716}
717
718void DcSctpSocket::ReceivePacket(rtc::ArrayView<const uint8_t> data) {
Victor Boivie5755f3e2021-09-29 22:23:15 +0200719 RTC_DCHECK_RUN_ON(&thread_checker_);
Victor Boivie15a0c882021-09-28 21:38:34 +0200720 CallbackDeferrer::ScopedDeferrer deferrer(callbacks_);
721
Victor Boivied4716ea2021-08-09 12:26:32 +0200722 ++metrics_.rx_packets_count;
723
Victor Boivieb6580cc2021-04-08 09:56:59 +0200724 if (packet_observer_ != nullptr) {
725 packet_observer_->OnReceivedPacket(callbacks_.TimeMillis(), data);
726 }
727
728 absl::optional<SctpPacket> packet =
729 SctpPacket::Parse(data, options_.disable_checksum_verification);
730 if (!packet.has_value()) {
731 // https://tools.ietf.org/html/rfc4960#section-6.8
732 // "The default procedure for handling invalid SCTP packets is to
733 // silently discard them."
734 callbacks_.OnError(ErrorKind::kParseFailed,
735 "Failed to parse received SCTP packet");
736 RTC_DCHECK(IsConsistent());
Victor Boivieb6580cc2021-04-08 09:56:59 +0200737 return;
738 }
739
740 if (RTC_DLOG_IS_ON) {
741 for (const auto& descriptor : packet->descriptors()) {
742 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Received "
743 << DebugConvertChunkToString(descriptor.data);
744 }
745 }
746
747 if (!ValidatePacket(*packet)) {
748 RTC_DLOG(LS_VERBOSE) << log_prefix()
749 << "Packet failed verification tag check - dropping";
750 RTC_DCHECK(IsConsistent());
Victor Boivieb6580cc2021-04-08 09:56:59 +0200751 return;
752 }
753
754 MaybeSendShutdownOnPacketReceived(*packet);
755
756 for (const auto& descriptor : packet->descriptors()) {
757 if (!Dispatch(packet->common_header(), descriptor)) {
758 break;
759 }
760 }
761
762 if (tcb_ != nullptr) {
763 tcb_->data_tracker().ObservePacketEnd();
764 tcb_->MaybeSendSack();
765 }
766
767 RTC_DCHECK(IsConsistent());
Victor Boivieb6580cc2021-04-08 09:56:59 +0200768}
769
770void DcSctpSocket::DebugPrintOutgoing(rtc::ArrayView<const uint8_t> payload) {
771 auto packet = SctpPacket::Parse(payload);
772 RTC_DCHECK(packet.has_value());
773
774 for (const auto& desc : packet->descriptors()) {
775 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Sent "
776 << DebugConvertChunkToString(desc.data);
777 }
778}
779
780bool DcSctpSocket::Dispatch(const CommonHeader& header,
781 const SctpPacket::ChunkDescriptor& descriptor) {
782 switch (descriptor.type) {
783 case DataChunk::kType:
784 HandleData(header, descriptor);
785 break;
786 case InitChunk::kType:
787 HandleInit(header, descriptor);
788 break;
789 case InitAckChunk::kType:
790 HandleInitAck(header, descriptor);
791 break;
792 case SackChunk::kType:
793 HandleSack(header, descriptor);
794 break;
795 case HeartbeatRequestChunk::kType:
796 HandleHeartbeatRequest(header, descriptor);
797 break;
798 case HeartbeatAckChunk::kType:
799 HandleHeartbeatAck(header, descriptor);
800 break;
801 case AbortChunk::kType:
802 HandleAbort(header, descriptor);
803 break;
804 case ErrorChunk::kType:
805 HandleError(header, descriptor);
806 break;
807 case CookieEchoChunk::kType:
808 HandleCookieEcho(header, descriptor);
809 break;
810 case CookieAckChunk::kType:
811 HandleCookieAck(header, descriptor);
812 break;
813 case ShutdownChunk::kType:
814 HandleShutdown(header, descriptor);
815 break;
816 case ShutdownAckChunk::kType:
817 HandleShutdownAck(header, descriptor);
818 break;
819 case ShutdownCompleteChunk::kType:
820 HandleShutdownComplete(header, descriptor);
821 break;
822 case ReConfigChunk::kType:
823 HandleReconfig(header, descriptor);
824 break;
825 case ForwardTsnChunk::kType:
826 HandleForwardTsn(header, descriptor);
827 break;
828 case IDataChunk::kType:
829 HandleIData(header, descriptor);
830 break;
831 case IForwardTsnChunk::kType:
Victor Boivie69c83cd2022-03-05 08:18:26 +0100832 HandleIForwardTsn(header, descriptor);
Victor Boivieb6580cc2021-04-08 09:56:59 +0200833 break;
834 default:
835 return HandleUnrecognizedChunk(descriptor);
836 }
837 return true;
838}
839
840bool DcSctpSocket::HandleUnrecognizedChunk(
841 const SctpPacket::ChunkDescriptor& descriptor) {
842 bool report_as_error = (descriptor.type & 0x40) != 0;
843 bool continue_processing = (descriptor.type & 0x80) != 0;
844 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Received unknown chunk: "
845 << static_cast<int>(descriptor.type);
846 if (report_as_error) {
847 rtc::StringBuilder sb;
848 sb << "Received unknown chunk of type: "
849 << static_cast<int>(descriptor.type) << " with report-error bit set";
850 callbacks_.OnError(ErrorKind::kParseFailed, sb.str());
851 RTC_DLOG(LS_VERBOSE)
852 << log_prefix()
853 << "Unknown chunk, with type indicating it should be reported.";
854
855 // https://tools.ietf.org/html/rfc4960#section-3.2
856 // "... report in an ERROR chunk using the 'Unrecognized Chunk Type'
857 // cause."
858 if (tcb_ != nullptr) {
859 // Need TCB - this chunk must be sent with a correct verification tag.
Victor Boivieabf61882021-08-12 15:57:49 +0200860 packet_sender_.Send(tcb_->PacketBuilder().Add(
Victor Boivieb6580cc2021-04-08 09:56:59 +0200861 ErrorChunk(Parameters::Builder()
862 .Add(UnrecognizedChunkTypeCause(std::vector<uint8_t>(
863 descriptor.data.begin(), descriptor.data.end())))
864 .Build())));
865 }
866 }
867 if (!continue_processing) {
868 // https://tools.ietf.org/html/rfc4960#section-3.2
869 // "Stop processing this SCTP packet and discard it, do not process any
870 // further chunks within it."
871 RTC_DLOG(LS_VERBOSE) << log_prefix()
872 << "Unknown chunk, with type indicating not to "
873 "process any further chunks";
874 }
875
876 return continue_processing;
877}
878
879absl::optional<DurationMs> DcSctpSocket::OnInitTimerExpiry() {
880 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Timer " << t1_init_->name()
881 << " has expired: " << t1_init_->expiration_count()
Victor Boivie9680d292021-08-30 10:23:49 +0200882 << "/" << t1_init_->options().max_restarts.value_or(-1);
Victor Boivieb6580cc2021-04-08 09:56:59 +0200883 RTC_DCHECK(state_ == State::kCookieWait);
884
885 if (t1_init_->is_running()) {
886 SendInit();
887 } else {
888 InternalClose(ErrorKind::kTooManyRetries, "No INIT_ACK received");
889 }
890 RTC_DCHECK(IsConsistent());
891 return absl::nullopt;
892}
893
894absl::optional<DurationMs> DcSctpSocket::OnCookieTimerExpiry() {
895 // https://tools.ietf.org/html/rfc4960#section-4
896 // "If the T1-cookie timer expires, the endpoint MUST retransmit COOKIE
897 // ECHO and restart the T1-cookie timer without changing state. This MUST
898 // be repeated up to 'Max.Init.Retransmits' times. After that, the endpoint
899 // MUST abort the initialization process and report the error to the SCTP
900 // user."
901 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Timer " << t1_cookie_->name()
902 << " has expired: " << t1_cookie_->expiration_count()
Victor Boivie9680d292021-08-30 10:23:49 +0200903 << "/"
904 << t1_cookie_->options().max_restarts.value_or(-1);
Victor Boivieb6580cc2021-04-08 09:56:59 +0200905
906 RTC_DCHECK(state_ == State::kCookieEchoed);
907
908 if (t1_cookie_->is_running()) {
Victor Boiviec20f1562021-06-16 12:52:42 +0200909 tcb_->SendBufferedPackets(callbacks_.TimeMillis());
Victor Boivieb6580cc2021-04-08 09:56:59 +0200910 } else {
911 InternalClose(ErrorKind::kTooManyRetries, "No COOKIE_ACK received");
912 }
913
914 RTC_DCHECK(IsConsistent());
915 return absl::nullopt;
916}
917
918absl::optional<DurationMs> DcSctpSocket::OnShutdownTimerExpiry() {
919 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Timer " << t2_shutdown_->name()
920 << " has expired: " << t2_shutdown_->expiration_count()
Victor Boivie9680d292021-08-30 10:23:49 +0200921 << "/"
922 << t2_shutdown_->options().max_restarts.value_or(-1);
Victor Boivieb6580cc2021-04-08 09:56:59 +0200923
Victor Boivie914925f2021-05-07 11:22:50 +0200924 if (!t2_shutdown_->is_running()) {
Victor Boivieb6580cc2021-04-08 09:56:59 +0200925 // https://tools.ietf.org/html/rfc4960#section-9.2
926 // "An endpoint should limit the number of retransmissions of the SHUTDOWN
927 // chunk to the protocol parameter 'Association.Max.Retrans'. If this
928 // threshold is exceeded, the endpoint should destroy the TCB..."
929
Victor Boivieabf61882021-08-12 15:57:49 +0200930 packet_sender_.Send(tcb_->PacketBuilder().Add(
Victor Boivieb6580cc2021-04-08 09:56:59 +0200931 AbortChunk(true, Parameters::Builder()
932 .Add(UserInitiatedAbortCause(
933 "Too many retransmissions of SHUTDOWN"))
934 .Build())));
935
936 InternalClose(ErrorKind::kTooManyRetries, "No SHUTDOWN_ACK received");
Victor Boivie914925f2021-05-07 11:22:50 +0200937 RTC_DCHECK(IsConsistent());
938 return absl::nullopt;
Victor Boivieb6580cc2021-04-08 09:56:59 +0200939 }
Victor Boivie914925f2021-05-07 11:22:50 +0200940
941 // https://tools.ietf.org/html/rfc4960#section-9.2
942 // "If the timer expires, the endpoint must resend the SHUTDOWN with the
943 // updated last sequential TSN received from its peer."
944 SendShutdown();
Victor Boivieb6580cc2021-04-08 09:56:59 +0200945 RTC_DCHECK(IsConsistent());
946 return tcb_->current_rto();
947}
948
Victor Boivieabf61882021-08-12 15:57:49 +0200949void DcSctpSocket::OnSentPacket(rtc::ArrayView<const uint8_t> packet,
950 SendPacketStatus status) {
951 // The packet observer is invoked even if the packet was failed to be sent, to
952 // indicate an attempt was made.
Victor Boivieb6580cc2021-04-08 09:56:59 +0200953 if (packet_observer_ != nullptr) {
Victor Boivieabf61882021-08-12 15:57:49 +0200954 packet_observer_->OnSentPacket(callbacks_.TimeMillis(), packet);
Victor Boivieb6580cc2021-04-08 09:56:59 +0200955 }
Victor Boivieabf61882021-08-12 15:57:49 +0200956
957 if (status == SendPacketStatus::kSuccess) {
958 if (RTC_DLOG_IS_ON) {
959 DebugPrintOutgoing(packet);
960 }
961
962 // The heartbeat interval timer is restarted for every sent packet, to
963 // fire when the outgoing channel is inactive.
964 if (tcb_ != nullptr) {
965 tcb_->heartbeat_handler().RestartTimer();
966 }
967
968 ++metrics_.tx_packets_count;
969 }
Victor Boivieb6580cc2021-04-08 09:56:59 +0200970}
971
972bool DcSctpSocket::ValidateHasTCB() {
973 if (tcb_ != nullptr) {
974 return true;
975 }
976
977 callbacks_.OnError(
978 ErrorKind::kNotConnected,
979 "Received unexpected commands on socket that is not connected");
980 return false;
981}
982
983void DcSctpSocket::ReportFailedToParseChunk(int chunk_type) {
984 rtc::StringBuilder sb;
985 sb << "Failed to parse chunk of type: " << chunk_type;
986 callbacks_.OnError(ErrorKind::kParseFailed, sb.str());
987}
988
989void DcSctpSocket::HandleData(const CommonHeader& header,
990 const SctpPacket::ChunkDescriptor& descriptor) {
991 absl::optional<DataChunk> chunk = DataChunk::Parse(descriptor.data);
992 if (ValidateParseSuccess(chunk) && ValidateHasTCB()) {
993 HandleDataCommon(*chunk);
994 }
995}
996
997void DcSctpSocket::HandleIData(const CommonHeader& header,
998 const SctpPacket::ChunkDescriptor& descriptor) {
999 absl::optional<IDataChunk> chunk = IDataChunk::Parse(descriptor.data);
1000 if (ValidateParseSuccess(chunk) && ValidateHasTCB()) {
1001 HandleDataCommon(*chunk);
1002 }
1003}
1004
1005void DcSctpSocket::HandleDataCommon(AnyDataChunk& chunk) {
1006 TSN tsn = chunk.tsn();
1007 AnyDataChunk::ImmediateAckFlag immediate_ack = chunk.options().immediate_ack;
1008 Data data = std::move(chunk).extract();
1009
Victor Boivie4b7024b2021-12-01 18:57:22 +00001010 if (data.payload.empty()) {
Victor Boivieb6580cc2021-04-08 09:56:59 +02001011 // Empty DATA chunks are illegal.
Victor Boivieabf61882021-08-12 15:57:49 +02001012 packet_sender_.Send(tcb_->PacketBuilder().Add(
Victor Boivieb6580cc2021-04-08 09:56:59 +02001013 ErrorChunk(Parameters::Builder().Add(NoUserDataCause(tsn)).Build())));
1014 callbacks_.OnError(ErrorKind::kProtocolViolation,
1015 "Received DATA chunk with no user data");
1016 return;
1017 }
1018
1019 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Handle DATA, queue_size="
1020 << tcb_->reassembly_queue().queued_bytes()
1021 << ", water_mark="
1022 << tcb_->reassembly_queue().watermark_bytes()
1023 << ", full=" << tcb_->reassembly_queue().is_full()
1024 << ", above="
1025 << tcb_->reassembly_queue().is_above_watermark();
1026
1027 if (tcb_->reassembly_queue().is_full()) {
1028 // If the reassembly queue is full, there is nothing that can be done. The
1029 // specification only allows dropping gap-ack-blocks, and that's not
1030 // likely to help as the socket has been trying to fill gaps since the
1031 // watermark was reached.
Victor Boivieabf61882021-08-12 15:57:49 +02001032 packet_sender_.Send(tcb_->PacketBuilder().Add(AbortChunk(
Victor Boivieb6580cc2021-04-08 09:56:59 +02001033 true, Parameters::Builder().Add(OutOfResourceErrorCause()).Build())));
1034 InternalClose(ErrorKind::kResourceExhaustion,
1035 "Reassembly Queue is exhausted");
1036 return;
1037 }
1038
1039 if (tcb_->reassembly_queue().is_above_watermark()) {
1040 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Is above high watermark";
1041 // If the reassembly queue is above its high watermark, only accept data
1042 // chunks that increase its cumulative ack tsn in an attempt to fill gaps
1043 // to deliver messages.
1044 if (!tcb_->data_tracker().will_increase_cum_ack_tsn(tsn)) {
1045 RTC_DLOG(LS_VERBOSE) << log_prefix()
1046 << "Rejected data because of exceeding watermark";
1047 tcb_->data_tracker().ForceImmediateSack();
1048 return;
1049 }
1050 }
1051
1052 if (!tcb_->data_tracker().IsTSNValid(tsn)) {
1053 RTC_DLOG(LS_VERBOSE) << log_prefix()
1054 << "Rejected data because of failing TSN validity";
1055 return;
1056 }
1057
Victor Boivie568bc232022-03-20 19:59:03 +01001058 if (tcb_->data_tracker().Observe(tsn, immediate_ack)) {
1059 tcb_->reassembly_queue().MaybeResetStreamsDeferred(
1060 tcb_->data_tracker().last_cumulative_acked_tsn());
1061 tcb_->reassembly_queue().Add(tsn, std::move(data));
1062 DeliverReassembledMessages();
1063 }
Victor Boivieb6580cc2021-04-08 09:56:59 +02001064}
1065
1066void DcSctpSocket::HandleInit(const CommonHeader& header,
1067 const SctpPacket::ChunkDescriptor& descriptor) {
1068 absl::optional<InitChunk> chunk = InitChunk::Parse(descriptor.data);
1069 if (!ValidateParseSuccess(chunk)) {
1070 return;
1071 }
1072
1073 if (chunk->initiate_tag() == VerificationTag(0) ||
1074 chunk->nbr_outbound_streams() == 0 || chunk->nbr_inbound_streams() == 0) {
1075 // https://tools.ietf.org/html/rfc4960#section-3.3.2
1076 // "If the value of the Initiate Tag in a received INIT chunk is found
1077 // to be 0, the receiver MUST treat it as an error and close the
1078 // association by transmitting an ABORT."
1079
1080 // "A receiver of an INIT with the OS value set to 0 SHOULD abort the
1081 // association."
1082
1083 // "A receiver of an INIT with the MIS value of 0 SHOULD abort the
1084 // association."
1085
Victor Boivieabf61882021-08-12 15:57:49 +02001086 packet_sender_.Send(
1087 SctpPacket::Builder(VerificationTag(0), options_)
1088 .Add(AbortChunk(
1089 /*filled_in_verification_tag=*/false,
1090 Parameters::Builder()
1091 .Add(ProtocolViolationCause("INIT malformed"))
1092 .Build())));
Victor Boivieb6580cc2021-04-08 09:56:59 +02001093 InternalClose(ErrorKind::kProtocolViolation, "Received invalid INIT");
1094 return;
1095 }
1096
1097 if (state_ == State::kShutdownAckSent) {
1098 // https://tools.ietf.org/html/rfc4960#section-9.2
1099 // "If an endpoint is in the SHUTDOWN-ACK-SENT state and receives an
1100 // INIT chunk (e.g., if the SHUTDOWN COMPLETE was lost) with source and
1101 // destination transport addresses (either in the IP addresses or in the
1102 // INIT chunk) that belong to this association, it should discard the INIT
1103 // chunk and retransmit the SHUTDOWN ACK chunk."
1104 RTC_DLOG(LS_VERBOSE) << log_prefix()
1105 << "Received Init indicating lost ShutdownComplete";
1106 SendShutdownAck();
1107 return;
1108 }
1109
1110 TieTag tie_tag(0);
1111 if (state_ == State::kClosed) {
1112 RTC_DLOG(LS_VERBOSE) << log_prefix()
1113 << "Received Init in closed state (normal)";
1114
1115 MakeConnectionParameters();
1116 } else if (state_ == State::kCookieWait || state_ == State::kCookieEchoed) {
1117 // https://tools.ietf.org/html/rfc4960#section-5.2.1
1118 // "This usually indicates an initialization collision, i.e., each
1119 // endpoint is attempting, at about the same time, to establish an
1120 // association with the other endpoint. Upon receipt of an INIT in the
1121 // COOKIE-WAIT state, an endpoint MUST respond with an INIT ACK using the
1122 // same parameters it sent in its original INIT chunk (including its
1123 // Initiate Tag, unchanged). When responding, the endpoint MUST send the
1124 // INIT ACK back to the same address that the original INIT (sent by this
1125 // endpoint) was sent."
1126 RTC_DLOG(LS_VERBOSE) << log_prefix()
1127 << "Received Init indicating simultaneous connections";
1128 } else {
1129 RTC_DCHECK(tcb_ != nullptr);
1130 // https://tools.ietf.org/html/rfc4960#section-5.2.2
1131 // "The outbound SCTP packet containing this INIT ACK MUST carry a
1132 // Verification Tag value equal to the Initiate Tag found in the
1133 // unexpected INIT. And the INIT ACK MUST contain a new Initiate Tag
1134 // (randomly generated; see Section 5.3.1). Other parameters for the
1135 // endpoint SHOULD be copied from the existing parameters of the
1136 // association (e.g., number of outbound streams) into the INIT ACK and
1137 // cookie."
1138 RTC_DLOG(LS_VERBOSE) << log_prefix()
1139 << "Received Init indicating restarted connection";
1140 // Create a new verification tag - different from the previous one.
1141 for (int tries = 0; tries < 10; ++tries) {
1142 connect_params_.verification_tag = VerificationTag(
1143 callbacks_.GetRandomInt(kMinVerificationTag, kMaxVerificationTag));
1144 if (connect_params_.verification_tag != tcb_->my_verification_tag()) {
1145 break;
1146 }
1147 }
1148
1149 // Make the initial TSN make a large jump, so that there is no overlap
1150 // with the old and new association.
1151 connect_params_.initial_tsn =
1152 TSN(*tcb_->retransmission_queue().next_tsn() + 1000000);
1153 tie_tag = tcb_->tie_tag();
1154 }
1155
1156 RTC_DLOG(LS_VERBOSE)
1157 << log_prefix()
1158 << rtc::StringFormat(
1159 "Proceeding with connection. my_verification_tag=%08x, "
1160 "my_initial_tsn=%u, peer_verification_tag=%08x, "
1161 "peer_initial_tsn=%u",
1162 *connect_params_.verification_tag, *connect_params_.initial_tsn,
1163 *chunk->initiate_tag(), *chunk->initial_tsn());
1164
1165 Capabilities capabilities = GetCapabilities(options_, chunk->parameters());
1166
1167 SctpPacket::Builder b(chunk->initiate_tag(), options_);
1168 Parameters::Builder params_builder =
1169 Parameters::Builder().Add(StateCookieParameter(
1170 StateCookie(chunk->initiate_tag(), chunk->initial_tsn(),
1171 chunk->a_rwnd(), tie_tag, capabilities)
1172 .Serialize()));
1173 AddCapabilityParameters(options_, params_builder);
1174
1175 InitAckChunk init_ack(/*initiate_tag=*/connect_params_.verification_tag,
1176 options_.max_receiver_window_buffer_size,
1177 options_.announced_maximum_outgoing_streams,
1178 options_.announced_maximum_incoming_streams,
1179 connect_params_.initial_tsn, params_builder.Build());
1180 b.Add(init_ack);
Victor Boivieabf61882021-08-12 15:57:49 +02001181 packet_sender_.Send(b);
Victor Boivieb6580cc2021-04-08 09:56:59 +02001182}
1183
Victor Boivieb6580cc2021-04-08 09:56:59 +02001184void DcSctpSocket::HandleInitAck(
1185 const CommonHeader& header,
1186 const SctpPacket::ChunkDescriptor& descriptor) {
1187 absl::optional<InitAckChunk> chunk = InitAckChunk::Parse(descriptor.data);
1188 if (!ValidateParseSuccess(chunk)) {
1189 return;
1190 }
1191
1192 if (state_ != State::kCookieWait) {
1193 // https://tools.ietf.org/html/rfc4960#section-5.2.3
1194 // "If an INIT ACK is received by an endpoint in any state other than
1195 // the COOKIE-WAIT state, the endpoint should discard the INIT ACK chunk."
1196 RTC_DLOG(LS_VERBOSE) << log_prefix()
1197 << "Received INIT_ACK in unexpected state";
1198 return;
1199 }
1200
1201 auto cookie = chunk->parameters().get<StateCookieParameter>();
1202 if (!cookie.has_value()) {
Victor Boivieabf61882021-08-12 15:57:49 +02001203 packet_sender_.Send(
1204 SctpPacket::Builder(connect_params_.verification_tag, options_)
1205 .Add(AbortChunk(
1206 /*filled_in_verification_tag=*/false,
1207 Parameters::Builder()
1208 .Add(ProtocolViolationCause("INIT-ACK malformed"))
1209 .Build())));
Victor Boivieb6580cc2021-04-08 09:56:59 +02001210 InternalClose(ErrorKind::kProtocolViolation,
1211 "InitAck chunk doesn't contain a cookie");
1212 return;
1213 }
1214 Capabilities capabilities = GetCapabilities(options_, chunk->parameters());
1215 t1_init_->Stop();
1216
Victor Boivief7fc71d2022-05-13 14:27:55 +02001217 metrics_.peer_implementation = DeterminePeerImplementation(cookie->data());
Victor Boivief4fa1662021-09-24 23:01:21 +02001218
Victor Boivie2cffde72022-06-27 20:35:37 +00001219 // If the connection is re-established (peer restarted, but re-used old
1220 // connection), make sure that all message identifiers are reset and any
1221 // partly sent message is re-sent in full. The same is true when the socket
1222 // is closed and later re-opened, which never happens in WebRTC, but is a
1223 // valid operation on the SCTP level. Note that in case of handover, the
1224 // send queue is already re-configured, and shouldn't be reset.
1225 send_queue_.Reset();
1226
1227 CreateTransmissionControlBlock(capabilities, connect_params_.verification_tag,
1228 connect_params_.initial_tsn,
1229 chunk->initiate_tag(), chunk->initial_tsn(),
1230 chunk->a_rwnd(), MakeTieTag(callbacks_));
Victor Boivieb6580cc2021-04-08 09:56:59 +02001231
1232 SetState(State::kCookieEchoed, "INIT_ACK received");
1233
1234 // The connection isn't fully established just yet.
Victor Boiviec20f1562021-06-16 12:52:42 +02001235 tcb_->SetCookieEchoChunk(CookieEchoChunk(cookie->data()));
1236 tcb_->SendBufferedPackets(callbacks_.TimeMillis());
Victor Boivieb6580cc2021-04-08 09:56:59 +02001237 t1_cookie_->Start();
1238}
1239
1240void DcSctpSocket::HandleCookieEcho(
1241 const CommonHeader& header,
1242 const SctpPacket::ChunkDescriptor& descriptor) {
1243 absl::optional<CookieEchoChunk> chunk =
1244 CookieEchoChunk::Parse(descriptor.data);
1245 if (!ValidateParseSuccess(chunk)) {
1246 return;
1247 }
1248
1249 absl::optional<StateCookie> cookie =
1250 StateCookie::Deserialize(chunk->cookie());
1251 if (!cookie.has_value()) {
1252 callbacks_.OnError(ErrorKind::kParseFailed, "Failed to parse state cookie");
1253 return;
1254 }
1255
1256 if (tcb_ != nullptr) {
1257 if (!HandleCookieEchoWithTCB(header, *cookie)) {
1258 return;
1259 }
1260 } else {
1261 if (header.verification_tag != connect_params_.verification_tag) {
1262 callbacks_.OnError(
1263 ErrorKind::kParseFailed,
1264 rtc::StringFormat(
1265 "Received CookieEcho with invalid verification tag: %08x, "
1266 "expected %08x",
1267 *header.verification_tag, *connect_params_.verification_tag));
1268 return;
1269 }
1270 }
1271
1272 // The init timer can be running on simultaneous connections.
1273 t1_init_->Stop();
1274 t1_cookie_->Stop();
1275 if (state_ != State::kEstablished) {
Victor Boiviec20f1562021-06-16 12:52:42 +02001276 if (tcb_ != nullptr) {
1277 tcb_->ClearCookieEchoChunk();
1278 }
Victor Boivieb6580cc2021-04-08 09:56:59 +02001279 SetState(State::kEstablished, "COOKIE_ECHO received");
1280 callbacks_.OnConnected();
1281 }
1282
1283 if (tcb_ == nullptr) {
Victor Boivie2cffde72022-06-27 20:35:37 +00001284 // If the connection is re-established (peer restarted, but re-used old
1285 // connection), make sure that all message identifiers are reset and any
1286 // partly sent message is re-sent in full. The same is true when the socket
1287 // is closed and later re-opened, which never happens in WebRTC, but is a
1288 // valid operation on the SCTP level. Note that in case of handover, the
1289 // send queue is already re-configured, and shouldn't be reset.
1290 send_queue_.Reset();
1291
1292 CreateTransmissionControlBlock(
1293 cookie->capabilities(), connect_params_.verification_tag,
Victor Boivieb6580cc2021-04-08 09:56:59 +02001294 connect_params_.initial_tsn, cookie->initiate_tag(),
Victor Boivie2cffde72022-06-27 20:35:37 +00001295 cookie->initial_tsn(), cookie->a_rwnd(), MakeTieTag(callbacks_));
Victor Boivieb6580cc2021-04-08 09:56:59 +02001296 }
1297
1298 SctpPacket::Builder b = tcb_->PacketBuilder();
1299 b.Add(CookieAckChunk());
1300
1301 // https://tools.ietf.org/html/rfc4960#section-5.1
1302 // "A COOKIE ACK chunk may be bundled with any pending DATA chunks (and/or
1303 // SACK chunks), but the COOKIE ACK chunk MUST be the first chunk in the
1304 // packet."
Victor Boivied3b186e2021-05-05 16:22:29 +02001305 tcb_->SendBufferedPackets(b, callbacks_.TimeMillis());
Victor Boivieb6580cc2021-04-08 09:56:59 +02001306}
1307
1308bool DcSctpSocket::HandleCookieEchoWithTCB(const CommonHeader& header,
1309 const StateCookie& cookie) {
1310 RTC_DLOG(LS_VERBOSE) << log_prefix()
1311 << "Handling CookieEchoChunk with TCB. local_tag="
1312 << *tcb_->my_verification_tag()
1313 << ", peer_tag=" << *header.verification_tag
1314 << ", tcb_tag=" << *tcb_->peer_verification_tag()
1315 << ", cookie_tag=" << *cookie.initiate_tag()
1316 << ", local_tie_tag=" << *tcb_->tie_tag()
1317 << ", peer_tie_tag=" << *cookie.tie_tag();
1318 // https://tools.ietf.org/html/rfc4960#section-5.2.4
1319 // "Handle a COOKIE ECHO when a TCB Exists"
1320 if (header.verification_tag != tcb_->my_verification_tag() &&
1321 tcb_->peer_verification_tag() != cookie.initiate_tag() &&
1322 cookie.tie_tag() == tcb_->tie_tag()) {
1323 // "A) In this case, the peer may have restarted."
1324 if (state_ == State::kShutdownAckSent) {
1325 // "If the endpoint is in the SHUTDOWN-ACK-SENT state and recognizes
1326 // that the peer has restarted ... it MUST NOT set up a new association
1327 // but instead resend the SHUTDOWN ACK and send an ERROR chunk with a
1328 // "Cookie Received While Shutting Down" error cause to its peer."
1329 SctpPacket::Builder b(cookie.initiate_tag(), options_);
1330 b.Add(ShutdownAckChunk());
1331 b.Add(ErrorChunk(Parameters::Builder()
1332 .Add(CookieReceivedWhileShuttingDownCause())
1333 .Build()));
Victor Boivieabf61882021-08-12 15:57:49 +02001334 packet_sender_.Send(b);
Victor Boivieb6580cc2021-04-08 09:56:59 +02001335 callbacks_.OnError(ErrorKind::kWrongSequence,
1336 "Received COOKIE-ECHO while shutting down");
1337 return false;
1338 }
1339
1340 RTC_DLOG(LS_VERBOSE) << log_prefix()
1341 << "Received COOKIE-ECHO indicating a restarted peer";
1342
Victor Boivieb6580cc2021-04-08 09:56:59 +02001343 tcb_ = nullptr;
1344 callbacks_.OnConnectionRestarted();
1345 } else if (header.verification_tag == tcb_->my_verification_tag() &&
1346 tcb_->peer_verification_tag() != cookie.initiate_tag()) {
1347 // TODO(boivie): Handle the peer_tag == 0?
1348 // "B) In this case, both sides may be attempting to start an
1349 // association at about the same time, but the peer endpoint started its
1350 // INIT after responding to the local endpoint's INIT."
1351 RTC_DLOG(LS_VERBOSE)
1352 << log_prefix()
1353 << "Received COOKIE-ECHO indicating simultaneous connections";
1354 tcb_ = nullptr;
1355 } else if (header.verification_tag != tcb_->my_verification_tag() &&
1356 tcb_->peer_verification_tag() == cookie.initiate_tag() &&
1357 cookie.tie_tag() == TieTag(0)) {
1358 // "C) In this case, the local endpoint's cookie has arrived late.
1359 // Before it arrived, the local endpoint sent an INIT and received an
1360 // INIT ACK and finally sent a COOKIE ECHO with the peer's same tag but
1361 // a new tag of its own. The cookie should be silently discarded. The
1362 // endpoint SHOULD NOT change states and should leave any timers
1363 // running."
1364 RTC_DLOG(LS_VERBOSE)
1365 << log_prefix()
1366 << "Received COOKIE-ECHO indicating a late COOKIE-ECHO. Discarding";
1367 return false;
1368 } else if (header.verification_tag == tcb_->my_verification_tag() &&
1369 tcb_->peer_verification_tag() == cookie.initiate_tag()) {
1370 // "D) When both local and remote tags match, the endpoint should enter
1371 // the ESTABLISHED state, if it is in the COOKIE-ECHOED state. It
1372 // should stop any cookie timer that may be running and send a COOKIE
1373 // ACK."
1374 RTC_DLOG(LS_VERBOSE)
1375 << log_prefix()
1376 << "Received duplicate COOKIE-ECHO, probably because of peer not "
1377 "receiving COOKIE-ACK and retransmitting COOKIE-ECHO. Continuing.";
1378 }
1379 return true;
1380}
1381
1382void DcSctpSocket::HandleCookieAck(
1383 const CommonHeader& header,
1384 const SctpPacket::ChunkDescriptor& descriptor) {
1385 absl::optional<CookieAckChunk> chunk = CookieAckChunk::Parse(descriptor.data);
1386 if (!ValidateParseSuccess(chunk)) {
1387 return;
1388 }
1389
1390 if (state_ != State::kCookieEchoed) {
1391 // https://tools.ietf.org/html/rfc4960#section-5.2.5
1392 // "At any state other than COOKIE-ECHOED, an endpoint should silently
1393 // discard a received COOKIE ACK chunk."
1394 RTC_DLOG(LS_VERBOSE) << log_prefix()
1395 << "Received COOKIE_ACK not in COOKIE_ECHOED state";
1396 return;
1397 }
1398
1399 // RFC 4960, Errata ID: 4400
1400 t1_cookie_->Stop();
Victor Boiviec20f1562021-06-16 12:52:42 +02001401 tcb_->ClearCookieEchoChunk();
Victor Boivieb6580cc2021-04-08 09:56:59 +02001402 SetState(State::kEstablished, "COOKIE_ACK received");
Victor Boivied3b186e2021-05-05 16:22:29 +02001403 tcb_->SendBufferedPackets(callbacks_.TimeMillis());
Victor Boivieb6580cc2021-04-08 09:56:59 +02001404 callbacks_.OnConnected();
1405}
1406
1407void DcSctpSocket::DeliverReassembledMessages() {
1408 if (tcb_->reassembly_queue().HasMessages()) {
1409 for (auto& message : tcb_->reassembly_queue().FlushMessages()) {
Victor Boivied4716ea2021-08-09 12:26:32 +02001410 ++metrics_.rx_messages_count;
Victor Boivieb6580cc2021-04-08 09:56:59 +02001411 callbacks_.OnMessageReceived(std::move(message));
1412 }
1413 }
1414}
1415
1416void DcSctpSocket::HandleSack(const CommonHeader& header,
1417 const SctpPacket::ChunkDescriptor& descriptor) {
1418 absl::optional<SackChunk> chunk = SackChunk::Parse(descriptor.data);
1419
1420 if (ValidateParseSuccess(chunk) && ValidateHasTCB()) {
Victor Boivied3b186e2021-05-05 16:22:29 +02001421 TimeMs now = callbacks_.TimeMillis();
Victor Boivieb6580cc2021-04-08 09:56:59 +02001422 SackChunk sack = ChunkValidators::Clean(*std::move(chunk));
1423
Victor Boivied3b186e2021-05-05 16:22:29 +02001424 if (tcb_->retransmission_queue().HandleSack(now, sack)) {
Victor Boivieb6580cc2021-04-08 09:56:59 +02001425 MaybeSendShutdownOrAck();
Victor Boivie5e354d92022-04-22 16:28:33 +02001426 // Receiving an ACK may make the socket go into fast recovery mode.
1427 // https://datatracker.ietf.org/doc/html/rfc4960#section-7.2.4
1428 // "Determine how many of the earliest (i.e., lowest TSN) DATA chunks
1429 // marked for retransmission will fit into a single packet, subject to
1430 // constraint of the path MTU of the destination transport address to
1431 // which the packet is being sent. Call this value K. Retransmit those K
1432 // DATA chunks in a single packet. When a Fast Retransmit is being
1433 // performed, the sender SHOULD ignore the value of cwnd and SHOULD NOT
1434 // delay retransmission for this single packet."
1435 tcb_->MaybeSendFastRetransmit();
1436
Victor Boivieb6580cc2021-04-08 09:56:59 +02001437 // Receiving an ACK will decrease outstanding bytes (maybe now below
1438 // cwnd?) or indicate packet loss that may result in sending FORWARD-TSN.
Victor Boivied3b186e2021-05-05 16:22:29 +02001439 tcb_->SendBufferedPackets(now);
Victor Boivieb6580cc2021-04-08 09:56:59 +02001440 } else {
1441 RTC_DLOG(LS_VERBOSE) << log_prefix()
1442 << "Dropping out-of-order SACK with TSN "
1443 << *sack.cumulative_tsn_ack();
1444 }
1445 }
1446}
1447
1448void DcSctpSocket::HandleHeartbeatRequest(
1449 const CommonHeader& header,
1450 const SctpPacket::ChunkDescriptor& descriptor) {
1451 absl::optional<HeartbeatRequestChunk> chunk =
1452 HeartbeatRequestChunk::Parse(descriptor.data);
1453
1454 if (ValidateParseSuccess(chunk) && ValidateHasTCB()) {
1455 tcb_->heartbeat_handler().HandleHeartbeatRequest(*std::move(chunk));
1456 }
1457}
1458
1459void DcSctpSocket::HandleHeartbeatAck(
1460 const CommonHeader& header,
1461 const SctpPacket::ChunkDescriptor& descriptor) {
1462 absl::optional<HeartbeatAckChunk> chunk =
1463 HeartbeatAckChunk::Parse(descriptor.data);
1464
1465 if (ValidateParseSuccess(chunk) && ValidateHasTCB()) {
1466 tcb_->heartbeat_handler().HandleHeartbeatAck(*std::move(chunk));
1467 }
1468}
1469
1470void DcSctpSocket::HandleAbort(const CommonHeader& header,
1471 const SctpPacket::ChunkDescriptor& descriptor) {
1472 absl::optional<AbortChunk> chunk = AbortChunk::Parse(descriptor.data);
1473 if (ValidateParseSuccess(chunk)) {
1474 std::string error_string = ErrorCausesToString(chunk->error_causes());
1475 if (tcb_ == nullptr) {
1476 // https://tools.ietf.org/html/rfc4960#section-3.3.7
1477 // "If an endpoint receives an ABORT with a format error or no TCB is
1478 // found, it MUST silently discard it."
1479 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Received ABORT (" << error_string
1480 << ") on a connection with no TCB. Ignoring";
1481 return;
1482 }
1483
1484 RTC_DLOG(LS_WARNING) << log_prefix() << "Received ABORT (" << error_string
1485 << ") - closing connection.";
1486 InternalClose(ErrorKind::kPeerReported, error_string);
1487 }
1488}
1489
1490void DcSctpSocket::HandleError(const CommonHeader& header,
1491 const SctpPacket::ChunkDescriptor& descriptor) {
1492 absl::optional<ErrorChunk> chunk = ErrorChunk::Parse(descriptor.data);
1493 if (ValidateParseSuccess(chunk)) {
1494 std::string error_string = ErrorCausesToString(chunk->error_causes());
1495 if (tcb_ == nullptr) {
1496 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Received ERROR (" << error_string
1497 << ") on a connection with no TCB. Ignoring";
1498 return;
1499 }
1500
1501 RTC_DLOG(LS_WARNING) << log_prefix() << "Received ERROR: " << error_string;
1502 callbacks_.OnError(ErrorKind::kPeerReported,
1503 "Peer reported error: " + error_string);
1504 }
1505}
1506
1507void DcSctpSocket::HandleReconfig(
1508 const CommonHeader& header,
1509 const SctpPacket::ChunkDescriptor& descriptor) {
1510 absl::optional<ReConfigChunk> chunk = ReConfigChunk::Parse(descriptor.data);
1511 if (ValidateParseSuccess(chunk) && ValidateHasTCB()) {
1512 tcb_->stream_reset_handler().HandleReConfig(*std::move(chunk));
Victor Boivief9e116f2022-03-31 17:15:03 +02001513 // Handling this response may result in outgoing stream resets finishing
1514 // (either successfully or with failure). If there still are pending streams
1515 // that were waiting for this request to finish, continue resetting them.
1516 MaybeSendResetStreamsRequest();
Victor Boivieb6580cc2021-04-08 09:56:59 +02001517 }
1518}
1519
1520void DcSctpSocket::HandleShutdown(
1521 const CommonHeader& header,
1522 const SctpPacket::ChunkDescriptor& descriptor) {
1523 if (!ValidateParseSuccess(ShutdownChunk::Parse(descriptor.data))) {
1524 return;
1525 }
1526
1527 if (state_ == State::kClosed) {
1528 return;
1529 } else if (state_ == State::kCookieWait || state_ == State::kCookieEchoed) {
1530 // https://tools.ietf.org/html/rfc4960#section-9.2
1531 // "If a SHUTDOWN is received in the COOKIE-WAIT or COOKIE ECHOED state,
1532 // the SHUTDOWN chunk SHOULD be silently discarded."
1533 } else if (state_ == State::kShutdownSent) {
1534 // https://tools.ietf.org/html/rfc4960#section-9.2
1535 // "If an endpoint is in the SHUTDOWN-SENT state and receives a
1536 // SHUTDOWN chunk from its peer, the endpoint shall respond immediately
1537 // with a SHUTDOWN ACK to its peer, and move into the SHUTDOWN-ACK-SENT
1538 // state restarting its T2-shutdown timer."
1539 SendShutdownAck();
1540 SetState(State::kShutdownAckSent, "SHUTDOWN received");
Victor Boivie50a0b122021-05-06 21:07:49 +02001541 } else if (state_ == State::kShutdownAckSent) {
1542 // TODO(webrtc:12739): This condition should be removed and handled by the
1543 // next (state_ != State::kShutdownReceived).
1544 return;
Victor Boivieb6580cc2021-04-08 09:56:59 +02001545 } else if (state_ != State::kShutdownReceived) {
1546 RTC_DLOG(LS_VERBOSE) << log_prefix()
1547 << "Received SHUTDOWN - shutting down the socket";
1548 // https://tools.ietf.org/html/rfc4960#section-9.2
1549 // "Upon reception of the SHUTDOWN, the peer endpoint shall enter the
1550 // SHUTDOWN-RECEIVED state, stop accepting new data from its SCTP user,
1551 // and verify, by checking the Cumulative TSN Ack field of the chunk, that
1552 // all its outstanding DATA chunks have been received by the SHUTDOWN
1553 // sender."
1554 SetState(State::kShutdownReceived, "SHUTDOWN received");
1555 MaybeSendShutdownOrAck();
1556 }
1557}
1558
1559void DcSctpSocket::HandleShutdownAck(
1560 const CommonHeader& header,
1561 const SctpPacket::ChunkDescriptor& descriptor) {
1562 if (!ValidateParseSuccess(ShutdownAckChunk::Parse(descriptor.data))) {
1563 return;
1564 }
1565
1566 if (state_ == State::kShutdownSent || state_ == State::kShutdownAckSent) {
1567 // https://tools.ietf.org/html/rfc4960#section-9.2
1568 // "Upon the receipt of the SHUTDOWN ACK, the SHUTDOWN sender shall stop
1569 // the T2-shutdown timer, send a SHUTDOWN COMPLETE chunk to its peer, and
1570 // remove all record of the association."
1571
1572 // "If an endpoint is in the SHUTDOWN-ACK-SENT state and receives a
1573 // SHUTDOWN ACK, it shall stop the T2-shutdown timer, send a SHUTDOWN
1574 // COMPLETE chunk to its peer, and remove all record of the association."
1575
1576 SctpPacket::Builder b = tcb_->PacketBuilder();
1577 b.Add(ShutdownCompleteChunk(/*tag_reflected=*/false));
Victor Boivieabf61882021-08-12 15:57:49 +02001578 packet_sender_.Send(b);
Victor Boivieb6580cc2021-04-08 09:56:59 +02001579 InternalClose(ErrorKind::kNoError, "");
1580 } else {
1581 // https://tools.ietf.org/html/rfc4960#section-8.5.1
1582 // "If the receiver is in COOKIE-ECHOED or COOKIE-WAIT state
1583 // the procedures in Section 8.4 SHOULD be followed; in other words, it
1584 // should be treated as an Out Of The Blue packet."
1585
1586 // https://tools.ietf.org/html/rfc4960#section-8.4
1587 // "If the packet contains a SHUTDOWN ACK chunk, the receiver
1588 // should respond to the sender of the OOTB packet with a SHUTDOWN
1589 // COMPLETE. When sending the SHUTDOWN COMPLETE, the receiver of the OOTB
1590 // packet must fill in the Verification Tag field of the outbound packet
1591 // with the Verification Tag received in the SHUTDOWN ACK and set the T
1592 // bit in the Chunk Flags to indicate that the Verification Tag is
1593 // reflected."
1594
1595 SctpPacket::Builder b(header.verification_tag, options_);
1596 b.Add(ShutdownCompleteChunk(/*tag_reflected=*/true));
Victor Boivieabf61882021-08-12 15:57:49 +02001597 packet_sender_.Send(b);
Victor Boivieb6580cc2021-04-08 09:56:59 +02001598 }
1599}
1600
1601void DcSctpSocket::HandleShutdownComplete(
1602 const CommonHeader& header,
1603 const SctpPacket::ChunkDescriptor& descriptor) {
1604 if (!ValidateParseSuccess(ShutdownCompleteChunk::Parse(descriptor.data))) {
1605 return;
1606 }
1607
1608 if (state_ == State::kShutdownAckSent) {
1609 // https://tools.ietf.org/html/rfc4960#section-9.2
1610 // "Upon reception of the SHUTDOWN COMPLETE chunk, the endpoint will
1611 // verify that it is in the SHUTDOWN-ACK-SENT state; if it is not, the
1612 // chunk should be discarded. If the endpoint is in the SHUTDOWN-ACK-SENT
1613 // state, the endpoint should stop the T2-shutdown timer and remove all
1614 // knowledge of the association (and thus the association enters the
1615 // CLOSED state)."
1616 InternalClose(ErrorKind::kNoError, "");
1617 }
1618}
1619
1620void DcSctpSocket::HandleForwardTsn(
1621 const CommonHeader& header,
1622 const SctpPacket::ChunkDescriptor& descriptor) {
1623 absl::optional<ForwardTsnChunk> chunk =
1624 ForwardTsnChunk::Parse(descriptor.data);
1625 if (ValidateParseSuccess(chunk) && ValidateHasTCB()) {
1626 HandleForwardTsnCommon(*chunk);
1627 }
1628}
1629
1630void DcSctpSocket::HandleIForwardTsn(
1631 const CommonHeader& header,
1632 const SctpPacket::ChunkDescriptor& descriptor) {
1633 absl::optional<IForwardTsnChunk> chunk =
1634 IForwardTsnChunk::Parse(descriptor.data);
1635 if (ValidateParseSuccess(chunk) && ValidateHasTCB()) {
1636 HandleForwardTsnCommon(*chunk);
1637 }
1638}
1639
1640void DcSctpSocket::HandleForwardTsnCommon(const AnyForwardTsnChunk& chunk) {
1641 if (!tcb_->capabilities().partial_reliability) {
1642 SctpPacket::Builder b = tcb_->PacketBuilder();
1643 b.Add(AbortChunk(/*filled_in_verification_tag=*/true,
1644 Parameters::Builder()
1645 .Add(ProtocolViolationCause(
1646 "I-FORWARD-TSN received, but not indicated "
1647 "during connection establishment"))
1648 .Build()));
Victor Boivieabf61882021-08-12 15:57:49 +02001649 packet_sender_.Send(b);
Victor Boivieb6580cc2021-04-08 09:56:59 +02001650
1651 callbacks_.OnError(ErrorKind::kProtocolViolation,
1652 "Received a FORWARD_TSN without announced peer support");
1653 return;
1654 }
1655 tcb_->data_tracker().HandleForwardTsn(chunk.new_cumulative_tsn());
1656 tcb_->reassembly_queue().Handle(chunk);
1657 // A forward TSN - for ordered streams - may allow messages to be
1658 // delivered.
1659 DeliverReassembledMessages();
1660
1661 // Processing a FORWARD_TSN might result in sending a SACK.
1662 tcb_->MaybeSendSack();
1663}
1664
1665void DcSctpSocket::MaybeSendShutdownOrAck() {
1666 if (tcb_->retransmission_queue().outstanding_bytes() != 0) {
1667 return;
1668 }
1669
1670 if (state_ == State::kShutdownPending) {
1671 // https://tools.ietf.org/html/rfc4960#section-9.2
1672 // "Once all its outstanding data has been acknowledged, the endpoint
1673 // shall send a SHUTDOWN chunk to its peer including in the Cumulative TSN
1674 // Ack field the last sequential TSN it has received from the peer. It
1675 // shall then start the T2-shutdown timer and enter the SHUTDOWN-SENT
1676 // state.""
1677
1678 SendShutdown();
1679 t2_shutdown_->set_duration(tcb_->current_rto());
1680 t2_shutdown_->Start();
1681 SetState(State::kShutdownSent, "No more outstanding data");
1682 } else if (state_ == State::kShutdownReceived) {
1683 // https://tools.ietf.org/html/rfc4960#section-9.2
1684 // "If the receiver of the SHUTDOWN has no more outstanding DATA
1685 // chunks, the SHUTDOWN receiver MUST send a SHUTDOWN ACK and start a
1686 // T2-shutdown timer of its own, entering the SHUTDOWN-ACK-SENT state. If
1687 // the timer expires, the endpoint must resend the SHUTDOWN ACK."
1688
1689 SendShutdownAck();
1690 SetState(State::kShutdownAckSent, "No more outstanding data");
1691 }
1692}
1693
1694void DcSctpSocket::SendShutdown() {
1695 SctpPacket::Builder b = tcb_->PacketBuilder();
1696 b.Add(ShutdownChunk(tcb_->data_tracker().last_cumulative_acked_tsn()));
Victor Boivieabf61882021-08-12 15:57:49 +02001697 packet_sender_.Send(b);
Victor Boivieb6580cc2021-04-08 09:56:59 +02001698}
1699
1700void DcSctpSocket::SendShutdownAck() {
Victor Boivieabf61882021-08-12 15:57:49 +02001701 packet_sender_.Send(tcb_->PacketBuilder().Add(ShutdownAckChunk()));
Victor Boivieb6580cc2021-04-08 09:56:59 +02001702 t2_shutdown_->set_duration(tcb_->current_rto());
1703 t2_shutdown_->Start();
1704}
1705
Sergey Sukhanov43972812021-09-17 15:32:48 +02001706HandoverReadinessStatus DcSctpSocket::GetHandoverReadiness() const {
Victor Boivie5755f3e2021-09-29 22:23:15 +02001707 RTC_DCHECK_RUN_ON(&thread_checker_);
Sergey Sukhanov43972812021-09-17 15:32:48 +02001708 HandoverReadinessStatus status;
1709 if (state_ != State::kClosed && state_ != State::kEstablished) {
1710 status.Add(HandoverUnreadinessReason::kWrongConnectionState);
1711 }
Sergey Sukhanov72435322021-09-21 13:31:09 +02001712 status.Add(send_queue_.GetHandoverReadiness());
Sergey Sukhanov43972812021-09-17 15:32:48 +02001713 if (tcb_) {
1714 status.Add(tcb_->GetHandoverReadiness());
1715 }
1716 return status;
1717}
1718
1719absl::optional<DcSctpSocketHandoverState>
1720DcSctpSocket::GetHandoverStateAndClose() {
Victor Boivie5755f3e2021-09-29 22:23:15 +02001721 RTC_DCHECK_RUN_ON(&thread_checker_);
Victor Boivie15a0c882021-09-28 21:38:34 +02001722 CallbackDeferrer::ScopedDeferrer deferrer(callbacks_);
1723
Sergey Sukhanov43972812021-09-17 15:32:48 +02001724 if (!GetHandoverReadiness().IsReady()) {
1725 return absl::nullopt;
1726 }
1727
1728 DcSctpSocketHandoverState state;
1729
1730 if (state_ == State::kClosed) {
1731 state.socket_state = DcSctpSocketHandoverState::SocketState::kClosed;
1732 } else if (state_ == State::kEstablished) {
1733 state.socket_state = DcSctpSocketHandoverState::SocketState::kConnected;
1734 tcb_->AddHandoverState(state);
Sergey Sukhanov72435322021-09-21 13:31:09 +02001735 send_queue_.AddHandoverState(state);
Sergey Sukhanov43972812021-09-17 15:32:48 +02001736 InternalClose(ErrorKind::kNoError, "handover");
Sergey Sukhanov43972812021-09-17 15:32:48 +02001737 }
1738
1739 return std::move(state);
1740}
1741
Victor Boivieb6580cc2021-04-08 09:56:59 +02001742} // namespace dcsctp