blob: aa48649fb63c8b1e3b52fa44b96770de830ba0c3 [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 Boivie00c61422022-05-27 09:55:41 +0200189 send_queue_(log_prefix_,
190 &callbacks_,
191 options_.max_send_buffer_size,
192 options_.mtu,
193 options_.default_stream_priority,
194 options_.total_buffered_amount_low_threshold) {}
Victor Boivieb6580cc2021-04-08 09:56:59 +0200195
196std::string DcSctpSocket::log_prefix() const {
Florent Castelli29ff3ef2022-02-17 16:23:56 +0100197 return log_prefix_ + "[" + std::string(ToString(state_)) + "] ";
Victor Boivieb6580cc2021-04-08 09:56:59 +0200198}
199
200bool DcSctpSocket::IsConsistent() const {
Victor Boivie54e4e352021-09-15 10:42:26 +0200201 if (tcb_ != nullptr && tcb_->reassembly_queue().HasMessages()) {
202 return false;
203 }
Victor Boivieb6580cc2021-04-08 09:56:59 +0200204 switch (state_) {
205 case State::kClosed:
206 return (tcb_ == nullptr && !t1_init_->is_running() &&
207 !t1_cookie_->is_running() && !t2_shutdown_->is_running());
208 case State::kCookieWait:
209 return (tcb_ == nullptr && t1_init_->is_running() &&
210 !t1_cookie_->is_running() && !t2_shutdown_->is_running());
211 case State::kCookieEchoed:
212 return (tcb_ != nullptr && !t1_init_->is_running() &&
213 t1_cookie_->is_running() && !t2_shutdown_->is_running() &&
Victor Boiviec20f1562021-06-16 12:52:42 +0200214 tcb_->has_cookie_echo_chunk());
Victor Boivieb6580cc2021-04-08 09:56:59 +0200215 case State::kEstablished:
216 return (tcb_ != nullptr && !t1_init_->is_running() &&
217 !t1_cookie_->is_running() && !t2_shutdown_->is_running());
218 case State::kShutdownPending:
219 return (tcb_ != nullptr && !t1_init_->is_running() &&
220 !t1_cookie_->is_running() && !t2_shutdown_->is_running());
221 case State::kShutdownSent:
222 return (tcb_ != nullptr && !t1_init_->is_running() &&
223 !t1_cookie_->is_running() && t2_shutdown_->is_running());
224 case State::kShutdownReceived:
225 return (tcb_ != nullptr && !t1_init_->is_running() &&
226 !t1_cookie_->is_running() && !t2_shutdown_->is_running());
227 case State::kShutdownAckSent:
228 return (tcb_ != nullptr && !t1_init_->is_running() &&
229 !t1_cookie_->is_running() && t2_shutdown_->is_running());
230 }
231}
232
233constexpr absl::string_view DcSctpSocket::ToString(DcSctpSocket::State state) {
234 switch (state) {
235 case DcSctpSocket::State::kClosed:
236 return "CLOSED";
237 case DcSctpSocket::State::kCookieWait:
238 return "COOKIE_WAIT";
239 case DcSctpSocket::State::kCookieEchoed:
240 return "COOKIE_ECHOED";
241 case DcSctpSocket::State::kEstablished:
242 return "ESTABLISHED";
243 case DcSctpSocket::State::kShutdownPending:
244 return "SHUTDOWN_PENDING";
245 case DcSctpSocket::State::kShutdownSent:
246 return "SHUTDOWN_SENT";
247 case DcSctpSocket::State::kShutdownReceived:
248 return "SHUTDOWN_RECEIVED";
249 case DcSctpSocket::State::kShutdownAckSent:
250 return "SHUTDOWN_ACK_SENT";
251 }
252}
253
254void DcSctpSocket::SetState(State state, absl::string_view reason) {
255 if (state_ != state) {
256 RTC_DLOG(LS_VERBOSE) << log_prefix_ << "Socket state changed from "
257 << ToString(state_) << " to " << ToString(state)
258 << " due to " << reason;
259 state_ = state;
260 }
261}
262
263void DcSctpSocket::SendInit() {
264 Parameters::Builder params_builder;
265 AddCapabilityParameters(options_, params_builder);
266 InitChunk init(/*initiate_tag=*/connect_params_.verification_tag,
267 /*a_rwnd=*/options_.max_receiver_window_buffer_size,
268 options_.announced_maximum_outgoing_streams,
269 options_.announced_maximum_incoming_streams,
270 connect_params_.initial_tsn, params_builder.Build());
271 SctpPacket::Builder b(VerificationTag(0), options_);
272 b.Add(init);
Victor Boivieabf61882021-08-12 15:57:49 +0200273 packet_sender_.Send(b);
Victor Boivieb6580cc2021-04-08 09:56:59 +0200274}
275
276void DcSctpSocket::MakeConnectionParameters() {
277 VerificationTag new_verification_tag(
278 callbacks_.GetRandomInt(kMinVerificationTag, kMaxVerificationTag));
279 TSN initial_tsn(callbacks_.GetRandomInt(kMinInitialTsn, kMaxInitialTsn));
280 connect_params_.initial_tsn = initial_tsn;
281 connect_params_.verification_tag = new_verification_tag;
282}
283
284void DcSctpSocket::Connect() {
Victor Boivie5755f3e2021-09-29 22:23:15 +0200285 RTC_DCHECK_RUN_ON(&thread_checker_);
Victor Boivie15a0c882021-09-28 21:38:34 +0200286 CallbackDeferrer::ScopedDeferrer deferrer(callbacks_);
287
Victor Boivieb6580cc2021-04-08 09:56:59 +0200288 if (state_ == State::kClosed) {
289 MakeConnectionParameters();
290 RTC_DLOG(LS_INFO)
291 << log_prefix()
292 << rtc::StringFormat(
293 "Connecting. my_verification_tag=%08x, my_initial_tsn=%u",
294 *connect_params_.verification_tag, *connect_params_.initial_tsn);
295 SendInit();
296 t1_init_->Start();
297 SetState(State::kCookieWait, "Connect called");
298 } else {
299 RTC_DLOG(LS_WARNING) << log_prefix()
300 << "Called Connect on a socket that is not closed";
301 }
302 RTC_DCHECK(IsConsistent());
Victor Boivieb6580cc2021-04-08 09:56:59 +0200303}
304
Victor Boivie2cffde72022-06-27 20:35:37 +0000305void DcSctpSocket::CreateTransmissionControlBlock(
306 const Capabilities& capabilities,
307 VerificationTag my_verification_tag,
308 TSN my_initial_tsn,
309 VerificationTag peer_verification_tag,
310 TSN peer_initial_tsn,
311 size_t a_rwnd,
312 TieTag tie_tag) {
Victor Boivie5b2556e2022-05-13 15:31:14 +0200313 metrics_.uses_message_interleaving = capabilities.message_interleaving;
Victor Boivie2cffde72022-06-27 20:35:37 +0000314 tcb_ = std::make_unique<TransmissionControlBlock>(
315 timer_manager_, log_prefix_, options_, capabilities, callbacks_,
316 send_queue_, my_verification_tag, my_initial_tsn, peer_verification_tag,
317 peer_initial_tsn, a_rwnd, tie_tag, packet_sender_,
318 [this]() { return state_ == State::kEstablished; });
319 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Created TCB: " << tcb_->ToString();
320}
321
Sergey Sukhanov43972812021-09-17 15:32:48 +0200322void DcSctpSocket::RestoreFromState(const DcSctpSocketHandoverState& state) {
Victor Boivie5755f3e2021-09-29 22:23:15 +0200323 RTC_DCHECK_RUN_ON(&thread_checker_);
Victor Boivie15a0c882021-09-28 21:38:34 +0200324 CallbackDeferrer::ScopedDeferrer deferrer(callbacks_);
325
Sergey Sukhanov43972812021-09-17 15:32:48 +0200326 if (state_ != State::kClosed) {
327 callbacks_.OnError(ErrorKind::kUnsupportedOperation,
328 "Only closed socket can be restored from state");
329 } else {
330 if (state.socket_state ==
331 DcSctpSocketHandoverState::SocketState::kConnected) {
332 VerificationTag my_verification_tag =
333 VerificationTag(state.my_verification_tag);
334 connect_params_.verification_tag = my_verification_tag;
335
336 Capabilities capabilities;
337 capabilities.partial_reliability = state.capabilities.partial_reliability;
338 capabilities.message_interleaving =
339 state.capabilities.message_interleaving;
340 capabilities.reconfig = state.capabilities.reconfig;
341
Sergey Sukhanov72435322021-09-21 13:31:09 +0200342 send_queue_.RestoreFromState(state);
343
Victor Boivie2cffde72022-06-27 20:35:37 +0000344 CreateTransmissionControlBlock(
345 capabilities, my_verification_tag, TSN(state.my_initial_tsn),
Sergey Sukhanov43972812021-09-17 15:32:48 +0200346 VerificationTag(state.peer_verification_tag),
347 TSN(state.peer_initial_tsn), static_cast<size_t>(0),
Victor Boivie2cffde72022-06-27 20:35:37 +0000348 TieTag(state.tie_tag));
349
350 tcb_->RestoreFromState(state);
Sergey Sukhanov43972812021-09-17 15:32:48 +0200351
352 SetState(State::kEstablished, "restored from handover state");
353 callbacks_.OnConnected();
354 }
355 }
356
357 RTC_DCHECK(IsConsistent());
Sergey Sukhanov43972812021-09-17 15:32:48 +0200358}
359
Victor Boivieb6580cc2021-04-08 09:56:59 +0200360void DcSctpSocket::Shutdown() {
Victor Boivie5755f3e2021-09-29 22:23:15 +0200361 RTC_DCHECK_RUN_ON(&thread_checker_);
Victor Boivie15a0c882021-09-28 21:38:34 +0200362 CallbackDeferrer::ScopedDeferrer deferrer(callbacks_);
363
Victor Boivieb6580cc2021-04-08 09:56:59 +0200364 if (tcb_ != nullptr) {
365 // https://tools.ietf.org/html/rfc4960#section-9.2
366 // "Upon receipt of the SHUTDOWN primitive from its upper layer, the
367 // endpoint enters the SHUTDOWN-PENDING state and remains there until all
368 // outstanding data has been acknowledged by its peer."
Victor Boivie50a0b122021-05-06 21:07:49 +0200369
370 // TODO(webrtc:12739): Remove this check, as it just hides the problem that
371 // the socket can transition from ShutdownSent to ShutdownPending, or
372 // ShutdownAckSent to ShutdownPending which is illegal.
373 if (state_ != State::kShutdownSent && state_ != State::kShutdownAckSent) {
374 SetState(State::kShutdownPending, "Shutdown called");
375 t1_init_->Stop();
376 t1_cookie_->Stop();
377 MaybeSendShutdownOrAck();
378 }
Victor Boivieb6580cc2021-04-08 09:56:59 +0200379 } else {
380 // Connection closed before even starting to connect, or during the initial
381 // connection phase. There is no outstanding data, so the socket can just
382 // be closed (stopping any connection timers, if any), as this is the
383 // client's intention, by calling Shutdown.
384 InternalClose(ErrorKind::kNoError, "");
385 }
386 RTC_DCHECK(IsConsistent());
Victor Boivieb6580cc2021-04-08 09:56:59 +0200387}
388
389void DcSctpSocket::Close() {
Victor Boivie5755f3e2021-09-29 22:23:15 +0200390 RTC_DCHECK_RUN_ON(&thread_checker_);
Victor Boivie15a0c882021-09-28 21:38:34 +0200391 CallbackDeferrer::ScopedDeferrer deferrer(callbacks_);
392
Victor Boivieb6580cc2021-04-08 09:56:59 +0200393 if (state_ != State::kClosed) {
394 if (tcb_ != nullptr) {
395 SctpPacket::Builder b = tcb_->PacketBuilder();
396 b.Add(AbortChunk(/*filled_in_verification_tag=*/true,
397 Parameters::Builder()
398 .Add(UserInitiatedAbortCause("Close called"))
399 .Build()));
Victor Boivieabf61882021-08-12 15:57:49 +0200400 packet_sender_.Send(b);
Victor Boivieb6580cc2021-04-08 09:56:59 +0200401 }
402 InternalClose(ErrorKind::kNoError, "");
403 } else {
404 RTC_DLOG(LS_INFO) << log_prefix() << "Called Close on a closed socket";
405 }
406 RTC_DCHECK(IsConsistent());
Victor Boivieb6580cc2021-04-08 09:56:59 +0200407}
408
409void DcSctpSocket::CloseConnectionBecauseOfTooManyTransmissionErrors() {
Victor Boivieabf61882021-08-12 15:57:49 +0200410 packet_sender_.Send(tcb_->PacketBuilder().Add(AbortChunk(
Victor Boivieb6580cc2021-04-08 09:56:59 +0200411 true, Parameters::Builder()
412 .Add(UserInitiatedAbortCause("Too many retransmissions"))
413 .Build())));
414 InternalClose(ErrorKind::kTooManyRetries, "Too many retransmissions");
415}
416
417void DcSctpSocket::InternalClose(ErrorKind error, absl::string_view message) {
418 if (state_ != State::kClosed) {
419 t1_init_->Stop();
420 t1_cookie_->Stop();
421 t2_shutdown_->Stop();
422 tcb_ = nullptr;
Victor Boivieb6580cc2021-04-08 09:56:59 +0200423
424 if (error == ErrorKind::kNoError) {
425 callbacks_.OnClosed();
426 } else {
427 callbacks_.OnAborted(error, message);
428 }
429 SetState(State::kClosed, message);
430 }
431 // This method's purpose is to abort/close and make it consistent by ensuring
432 // that e.g. all timers really are stopped.
433 RTC_DCHECK(IsConsistent());
434}
435
Victor Boivie7e897ae2022-05-02 13:04:37 +0200436void DcSctpSocket::SetStreamPriority(StreamID stream_id,
437 StreamPriority priority) {
438 RTC_DCHECK_RUN_ON(&thread_checker_);
439 send_queue_.SetStreamPriority(stream_id, priority);
440}
441StreamPriority DcSctpSocket::GetStreamPriority(StreamID stream_id) const {
442 RTC_DCHECK_RUN_ON(&thread_checker_);
443 return send_queue_.GetStreamPriority(stream_id);
444}
445
Victor Boivieb6580cc2021-04-08 09:56:59 +0200446SendStatus DcSctpSocket::Send(DcSctpMessage message,
447 const SendOptions& send_options) {
Victor Boivie5755f3e2021-09-29 22:23:15 +0200448 RTC_DCHECK_RUN_ON(&thread_checker_);
Victor Boivie15a0c882021-09-28 21:38:34 +0200449 CallbackDeferrer::ScopedDeferrer deferrer(callbacks_);
450
Victor Boivieb6580cc2021-04-08 09:56:59 +0200451 if (message.payload().empty()) {
452 callbacks_.OnError(ErrorKind::kProtocolViolation,
453 "Unable to send empty message");
454 return SendStatus::kErrorMessageEmpty;
455 }
456 if (message.payload().size() > options_.max_message_size) {
457 callbacks_.OnError(ErrorKind::kProtocolViolation,
458 "Unable to send too large message");
459 return SendStatus::kErrorMessageTooLarge;
460 }
461 if (state_ == State::kShutdownPending || state_ == State::kShutdownSent ||
462 state_ == State::kShutdownReceived || state_ == State::kShutdownAckSent) {
463 // https://tools.ietf.org/html/rfc4960#section-9.2
464 // "An endpoint should reject any new data request from its upper layer
465 // if it is in the SHUTDOWN-PENDING, SHUTDOWN-SENT, SHUTDOWN-RECEIVED, or
466 // SHUTDOWN-ACK-SENT state."
467 callbacks_.OnError(ErrorKind::kWrongSequence,
468 "Unable to send message as the socket is shutting down");
469 return SendStatus::kErrorShuttingDown;
470 }
471 if (send_queue_.IsFull()) {
472 callbacks_.OnError(ErrorKind::kResourceExhaustion,
473 "Unable to send message as the send queue is full");
474 return SendStatus::kErrorResourceExhaustion;
475 }
476
Victor Boivied3b186e2021-05-05 16:22:29 +0200477 TimeMs now = callbacks_.TimeMillis();
Victor Boivied4716ea2021-08-09 12:26:32 +0200478 ++metrics_.tx_messages_count;
Victor Boivied3b186e2021-05-05 16:22:29 +0200479 send_queue_.Add(now, std::move(message), send_options);
Victor Boivieb6580cc2021-04-08 09:56:59 +0200480 if (tcb_ != nullptr) {
Victor Boivied3b186e2021-05-05 16:22:29 +0200481 tcb_->SendBufferedPackets(now);
Victor Boivieb6580cc2021-04-08 09:56:59 +0200482 }
483
484 RTC_DCHECK(IsConsistent());
Victor Boivieb6580cc2021-04-08 09:56:59 +0200485 return SendStatus::kSuccess;
486}
487
488ResetStreamsStatus DcSctpSocket::ResetStreams(
489 rtc::ArrayView<const StreamID> outgoing_streams) {
Victor Boivie5755f3e2021-09-29 22:23:15 +0200490 RTC_DCHECK_RUN_ON(&thread_checker_);
Victor Boivie15a0c882021-09-28 21:38:34 +0200491 CallbackDeferrer::ScopedDeferrer deferrer(callbacks_);
492
Victor Boivieb6580cc2021-04-08 09:56:59 +0200493 if (tcb_ == nullptr) {
494 callbacks_.OnError(ErrorKind::kWrongSequence,
495 "Can't reset streams as the socket is not connected");
496 return ResetStreamsStatus::kNotConnected;
497 }
498 if (!tcb_->capabilities().reconfig) {
499 callbacks_.OnError(ErrorKind::kUnsupportedOperation,
500 "Can't reset streams as the peer doesn't support it");
501 return ResetStreamsStatus::kNotSupported;
502 }
503
504 tcb_->stream_reset_handler().ResetStreams(outgoing_streams);
Victor Boivief9e116f2022-03-31 17:15:03 +0200505 MaybeSendResetStreamsRequest();
Victor Boivieb6580cc2021-04-08 09:56:59 +0200506
507 RTC_DCHECK(IsConsistent());
Victor Boivieb6580cc2021-04-08 09:56:59 +0200508 return ResetStreamsStatus::kPerformed;
509}
510
511SocketState DcSctpSocket::state() const {
Victor Boivie5755f3e2021-09-29 22:23:15 +0200512 RTC_DCHECK_RUN_ON(&thread_checker_);
Victor Boivieb6580cc2021-04-08 09:56:59 +0200513 switch (state_) {
514 case State::kClosed:
515 return SocketState::kClosed;
516 case State::kCookieWait:
Victor Boivieb6580cc2021-04-08 09:56:59 +0200517 case State::kCookieEchoed:
518 return SocketState::kConnecting;
519 case State::kEstablished:
520 return SocketState::kConnected;
521 case State::kShutdownPending:
Victor Boivieb6580cc2021-04-08 09:56:59 +0200522 case State::kShutdownSent:
Victor Boivieb6580cc2021-04-08 09:56:59 +0200523 case State::kShutdownReceived:
Victor Boivieb6580cc2021-04-08 09:56:59 +0200524 case State::kShutdownAckSent:
525 return SocketState::kShuttingDown;
526 }
527}
528
Florent Castelli0810b052021-05-04 20:12:52 +0200529void DcSctpSocket::SetMaxMessageSize(size_t max_message_size) {
Victor Boivie5755f3e2021-09-29 22:23:15 +0200530 RTC_DCHECK_RUN_ON(&thread_checker_);
Florent Castelli0810b052021-05-04 20:12:52 +0200531 options_.max_message_size = max_message_size;
532}
533
Victor Boivie236ac502021-05-20 19:34:18 +0200534size_t DcSctpSocket::buffered_amount(StreamID stream_id) const {
Victor Boivie5755f3e2021-09-29 22:23:15 +0200535 RTC_DCHECK_RUN_ON(&thread_checker_);
Victor Boivie236ac502021-05-20 19:34:18 +0200536 return send_queue_.buffered_amount(stream_id);
537}
538
539size_t DcSctpSocket::buffered_amount_low_threshold(StreamID stream_id) const {
Victor Boivie5755f3e2021-09-29 22:23:15 +0200540 RTC_DCHECK_RUN_ON(&thread_checker_);
Victor Boivie236ac502021-05-20 19:34:18 +0200541 return send_queue_.buffered_amount_low_threshold(stream_id);
542}
543
544void DcSctpSocket::SetBufferedAmountLowThreshold(StreamID stream_id,
545 size_t bytes) {
Victor Boivie5755f3e2021-09-29 22:23:15 +0200546 RTC_DCHECK_RUN_ON(&thread_checker_);
Victor Boivie236ac502021-05-20 19:34:18 +0200547 send_queue_.SetBufferedAmountLowThreshold(stream_id, bytes);
548}
549
Victor Boivief7fc71d2022-05-13 14:27:55 +0200550absl::optional<Metrics> DcSctpSocket::GetMetrics() const {
Victor Boivie5755f3e2021-09-29 22:23:15 +0200551 RTC_DCHECK_RUN_ON(&thread_checker_);
Victor Boivied4716ea2021-08-09 12:26:32 +0200552
Victor Boivief7fc71d2022-05-13 14:27:55 +0200553 if (tcb_ == nullptr) {
554 return absl::nullopt;
Victor Boivied4716ea2021-08-09 12:26:32 +0200555 }
556
Victor Boivief7fc71d2022-05-13 14:27:55 +0200557 Metrics metrics = metrics_;
558 metrics.cwnd_bytes = tcb_->cwnd();
559 metrics.srtt_ms = tcb_->current_srtt().value();
560 size_t packet_payload_size =
561 options_.mtu - SctpPacket::kHeaderSize - DataChunk::kHeaderSize;
562 metrics.unack_data_count =
563 tcb_->retransmission_queue().outstanding_items() +
564 (send_queue_.total_buffered_amount() + packet_payload_size - 1) /
565 packet_payload_size;
566 metrics.peer_rwnd_bytes = tcb_->retransmission_queue().rwnd();
567
Victor Boivied4716ea2021-08-09 12:26:32 +0200568 return metrics;
569}
570
Victor Boivieb6580cc2021-04-08 09:56:59 +0200571void DcSctpSocket::MaybeSendShutdownOnPacketReceived(const SctpPacket& packet) {
572 if (state_ == State::kShutdownSent) {
573 bool has_data_chunk =
574 std::find_if(packet.descriptors().begin(), packet.descriptors().end(),
575 [](const SctpPacket::ChunkDescriptor& descriptor) {
576 return descriptor.type == DataChunk::kType;
577 }) != packet.descriptors().end();
578 if (has_data_chunk) {
579 // https://tools.ietf.org/html/rfc4960#section-9.2
580 // "While in the SHUTDOWN-SENT state, the SHUTDOWN sender MUST immediately
581 // respond to each received packet containing one or more DATA chunks with
582 // a SHUTDOWN chunk and restart the T2-shutdown timer.""
583 SendShutdown();
584 t2_shutdown_->set_duration(tcb_->current_rto());
585 t2_shutdown_->Start();
586 }
587 }
588}
589
Victor Boivief9e116f2022-03-31 17:15:03 +0200590void DcSctpSocket::MaybeSendResetStreamsRequest() {
591 absl::optional<ReConfigChunk> reconfig =
592 tcb_->stream_reset_handler().MakeStreamResetRequest();
593 if (reconfig.has_value()) {
594 SctpPacket::Builder builder = tcb_->PacketBuilder();
595 builder.Add(*reconfig);
596 packet_sender_.Send(builder);
597 }
598}
599
Victor Boivieb6580cc2021-04-08 09:56:59 +0200600bool DcSctpSocket::ValidatePacket(const SctpPacket& packet) {
601 const CommonHeader& header = packet.common_header();
602 VerificationTag my_verification_tag =
603 tcb_ != nullptr ? tcb_->my_verification_tag() : VerificationTag(0);
604
605 if (header.verification_tag == VerificationTag(0)) {
606 if (packet.descriptors().size() == 1 &&
607 packet.descriptors()[0].type == InitChunk::kType) {
608 // https://tools.ietf.org/html/rfc4960#section-8.5.1
609 // "When an endpoint receives an SCTP packet with the Verification Tag
610 // set to 0, it should verify that the packet contains only an INIT chunk.
611 // Otherwise, the receiver MUST silently discard the packet.""
612 return true;
613 }
614 callbacks_.OnError(
615 ErrorKind::kParseFailed,
616 "Only a single INIT chunk can be present in packets sent on "
617 "verification_tag = 0");
618 return false;
619 }
620
621 if (packet.descriptors().size() == 1 &&
622 packet.descriptors()[0].type == AbortChunk::kType) {
623 // https://tools.ietf.org/html/rfc4960#section-8.5.1
624 // "The receiver of an ABORT MUST accept the packet if the Verification
625 // Tag field of the packet matches its own tag and the T bit is not set OR
626 // if it is set to its peer's tag and the T bit is set in the Chunk Flags.
627 // Otherwise, the receiver MUST silently discard the packet and take no
628 // further action."
629 bool t_bit = (packet.descriptors()[0].flags & 0x01) != 0;
630 if (t_bit && tcb_ == nullptr) {
631 // Can't verify the tag - assume it's okey.
632 return true;
633 }
634 if ((!t_bit && header.verification_tag == my_verification_tag) ||
635 (t_bit && header.verification_tag == tcb_->peer_verification_tag())) {
636 return true;
637 }
638 callbacks_.OnError(ErrorKind::kParseFailed,
639 "ABORT chunk verification tag was wrong");
640 return false;
641 }
642
643 if (packet.descriptors()[0].type == InitAckChunk::kType) {
644 if (header.verification_tag == connect_params_.verification_tag) {
645 return true;
646 }
647 callbacks_.OnError(
648 ErrorKind::kParseFailed,
649 rtc::StringFormat(
650 "Packet has invalid verification tag: %08x, expected %08x",
651 *header.verification_tag, *connect_params_.verification_tag));
652 return false;
653 }
654
655 if (packet.descriptors()[0].type == CookieEchoChunk::kType) {
656 // Handled in chunk handler (due to RFC 4960, section 5.2.4).
657 return true;
658 }
659
660 if (packet.descriptors().size() == 1 &&
661 packet.descriptors()[0].type == ShutdownCompleteChunk::kType) {
662 // https://tools.ietf.org/html/rfc4960#section-8.5.1
663 // "The receiver of a SHUTDOWN COMPLETE shall accept the packet if the
664 // Verification Tag field of the packet matches its own tag and the T bit is
665 // not set OR if it is set to its peer's tag and the T bit is set in the
666 // Chunk Flags. Otherwise, the receiver MUST silently discard the packet
667 // and take no further action."
668 bool t_bit = (packet.descriptors()[0].flags & 0x01) != 0;
669 if (t_bit && tcb_ == nullptr) {
670 // Can't verify the tag - assume it's okey.
671 return true;
672 }
673 if ((!t_bit && header.verification_tag == my_verification_tag) ||
674 (t_bit && header.verification_tag == tcb_->peer_verification_tag())) {
675 return true;
676 }
677 callbacks_.OnError(ErrorKind::kParseFailed,
678 "SHUTDOWN_COMPLETE chunk verification tag was wrong");
679 return false;
680 }
681
682 // https://tools.ietf.org/html/rfc4960#section-8.5
683 // "When receiving an SCTP packet, the endpoint MUST ensure that the value
684 // in the Verification Tag field of the received SCTP packet matches its own
685 // tag. If the received Verification Tag value does not match the receiver's
686 // own tag value, the receiver shall silently discard the packet and shall not
687 // process it any further..."
688 if (header.verification_tag == my_verification_tag) {
689 return true;
690 }
691
692 callbacks_.OnError(
693 ErrorKind::kParseFailed,
694 rtc::StringFormat(
695 "Packet has invalid verification tag: %08x, expected %08x",
696 *header.verification_tag, *my_verification_tag));
697 return false;
698}
699
700void DcSctpSocket::HandleTimeout(TimeoutID timeout_id) {
Victor Boivie5755f3e2021-09-29 22:23:15 +0200701 RTC_DCHECK_RUN_ON(&thread_checker_);
Victor Boivie15a0c882021-09-28 21:38:34 +0200702 CallbackDeferrer::ScopedDeferrer deferrer(callbacks_);
703
Victor Boivieb6580cc2021-04-08 09:56:59 +0200704 timer_manager_.HandleTimeout(timeout_id);
705
706 if (tcb_ != nullptr && tcb_->HasTooManyTxErrors()) {
707 // Tearing down the TCB has to be done outside the handlers.
708 CloseConnectionBecauseOfTooManyTransmissionErrors();
709 }
710
711 RTC_DCHECK(IsConsistent());
Victor Boivieb6580cc2021-04-08 09:56:59 +0200712}
713
714void DcSctpSocket::ReceivePacket(rtc::ArrayView<const uint8_t> data) {
Victor Boivie5755f3e2021-09-29 22:23:15 +0200715 RTC_DCHECK_RUN_ON(&thread_checker_);
Victor Boivie15a0c882021-09-28 21:38:34 +0200716 CallbackDeferrer::ScopedDeferrer deferrer(callbacks_);
717
Victor Boivied4716ea2021-08-09 12:26:32 +0200718 ++metrics_.rx_packets_count;
719
Victor Boivieb6580cc2021-04-08 09:56:59 +0200720 if (packet_observer_ != nullptr) {
721 packet_observer_->OnReceivedPacket(callbacks_.TimeMillis(), data);
722 }
723
724 absl::optional<SctpPacket> packet =
725 SctpPacket::Parse(data, options_.disable_checksum_verification);
726 if (!packet.has_value()) {
727 // https://tools.ietf.org/html/rfc4960#section-6.8
728 // "The default procedure for handling invalid SCTP packets is to
729 // silently discard them."
730 callbacks_.OnError(ErrorKind::kParseFailed,
731 "Failed to parse received SCTP packet");
732 RTC_DCHECK(IsConsistent());
Victor Boivieb6580cc2021-04-08 09:56:59 +0200733 return;
734 }
735
736 if (RTC_DLOG_IS_ON) {
737 for (const auto& descriptor : packet->descriptors()) {
738 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Received "
739 << DebugConvertChunkToString(descriptor.data);
740 }
741 }
742
743 if (!ValidatePacket(*packet)) {
744 RTC_DLOG(LS_VERBOSE) << log_prefix()
745 << "Packet failed verification tag check - dropping";
746 RTC_DCHECK(IsConsistent());
Victor Boivieb6580cc2021-04-08 09:56:59 +0200747 return;
748 }
749
750 MaybeSendShutdownOnPacketReceived(*packet);
751
752 for (const auto& descriptor : packet->descriptors()) {
753 if (!Dispatch(packet->common_header(), descriptor)) {
754 break;
755 }
756 }
757
758 if (tcb_ != nullptr) {
759 tcb_->data_tracker().ObservePacketEnd();
760 tcb_->MaybeSendSack();
761 }
762
763 RTC_DCHECK(IsConsistent());
Victor Boivieb6580cc2021-04-08 09:56:59 +0200764}
765
766void DcSctpSocket::DebugPrintOutgoing(rtc::ArrayView<const uint8_t> payload) {
767 auto packet = SctpPacket::Parse(payload);
768 RTC_DCHECK(packet.has_value());
769
770 for (const auto& desc : packet->descriptors()) {
771 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Sent "
772 << DebugConvertChunkToString(desc.data);
773 }
774}
775
776bool DcSctpSocket::Dispatch(const CommonHeader& header,
777 const SctpPacket::ChunkDescriptor& descriptor) {
778 switch (descriptor.type) {
779 case DataChunk::kType:
780 HandleData(header, descriptor);
781 break;
782 case InitChunk::kType:
783 HandleInit(header, descriptor);
784 break;
785 case InitAckChunk::kType:
786 HandleInitAck(header, descriptor);
787 break;
788 case SackChunk::kType:
789 HandleSack(header, descriptor);
790 break;
791 case HeartbeatRequestChunk::kType:
792 HandleHeartbeatRequest(header, descriptor);
793 break;
794 case HeartbeatAckChunk::kType:
795 HandleHeartbeatAck(header, descriptor);
796 break;
797 case AbortChunk::kType:
798 HandleAbort(header, descriptor);
799 break;
800 case ErrorChunk::kType:
801 HandleError(header, descriptor);
802 break;
803 case CookieEchoChunk::kType:
804 HandleCookieEcho(header, descriptor);
805 break;
806 case CookieAckChunk::kType:
807 HandleCookieAck(header, descriptor);
808 break;
809 case ShutdownChunk::kType:
810 HandleShutdown(header, descriptor);
811 break;
812 case ShutdownAckChunk::kType:
813 HandleShutdownAck(header, descriptor);
814 break;
815 case ShutdownCompleteChunk::kType:
816 HandleShutdownComplete(header, descriptor);
817 break;
818 case ReConfigChunk::kType:
819 HandleReconfig(header, descriptor);
820 break;
821 case ForwardTsnChunk::kType:
822 HandleForwardTsn(header, descriptor);
823 break;
824 case IDataChunk::kType:
825 HandleIData(header, descriptor);
826 break;
827 case IForwardTsnChunk::kType:
Victor Boivie69c83cd2022-03-05 08:18:26 +0100828 HandleIForwardTsn(header, descriptor);
Victor Boivieb6580cc2021-04-08 09:56:59 +0200829 break;
830 default:
831 return HandleUnrecognizedChunk(descriptor);
832 }
833 return true;
834}
835
836bool DcSctpSocket::HandleUnrecognizedChunk(
837 const SctpPacket::ChunkDescriptor& descriptor) {
838 bool report_as_error = (descriptor.type & 0x40) != 0;
839 bool continue_processing = (descriptor.type & 0x80) != 0;
840 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Received unknown chunk: "
841 << static_cast<int>(descriptor.type);
842 if (report_as_error) {
843 rtc::StringBuilder sb;
844 sb << "Received unknown chunk of type: "
845 << static_cast<int>(descriptor.type) << " with report-error bit set";
846 callbacks_.OnError(ErrorKind::kParseFailed, sb.str());
847 RTC_DLOG(LS_VERBOSE)
848 << log_prefix()
849 << "Unknown chunk, with type indicating it should be reported.";
850
851 // https://tools.ietf.org/html/rfc4960#section-3.2
852 // "... report in an ERROR chunk using the 'Unrecognized Chunk Type'
853 // cause."
854 if (tcb_ != nullptr) {
855 // Need TCB - this chunk must be sent with a correct verification tag.
Victor Boivieabf61882021-08-12 15:57:49 +0200856 packet_sender_.Send(tcb_->PacketBuilder().Add(
Victor Boivieb6580cc2021-04-08 09:56:59 +0200857 ErrorChunk(Parameters::Builder()
858 .Add(UnrecognizedChunkTypeCause(std::vector<uint8_t>(
859 descriptor.data.begin(), descriptor.data.end())))
860 .Build())));
861 }
862 }
863 if (!continue_processing) {
864 // https://tools.ietf.org/html/rfc4960#section-3.2
865 // "Stop processing this SCTP packet and discard it, do not process any
866 // further chunks within it."
867 RTC_DLOG(LS_VERBOSE) << log_prefix()
868 << "Unknown chunk, with type indicating not to "
869 "process any further chunks";
870 }
871
872 return continue_processing;
873}
874
875absl::optional<DurationMs> DcSctpSocket::OnInitTimerExpiry() {
876 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Timer " << t1_init_->name()
877 << " has expired: " << t1_init_->expiration_count()
Victor Boivie9680d292021-08-30 10:23:49 +0200878 << "/" << t1_init_->options().max_restarts.value_or(-1);
Victor Boivieb6580cc2021-04-08 09:56:59 +0200879 RTC_DCHECK(state_ == State::kCookieWait);
880
881 if (t1_init_->is_running()) {
882 SendInit();
883 } else {
884 InternalClose(ErrorKind::kTooManyRetries, "No INIT_ACK received");
885 }
886 RTC_DCHECK(IsConsistent());
887 return absl::nullopt;
888}
889
890absl::optional<DurationMs> DcSctpSocket::OnCookieTimerExpiry() {
891 // https://tools.ietf.org/html/rfc4960#section-4
892 // "If the T1-cookie timer expires, the endpoint MUST retransmit COOKIE
893 // ECHO and restart the T1-cookie timer without changing state. This MUST
894 // be repeated up to 'Max.Init.Retransmits' times. After that, the endpoint
895 // MUST abort the initialization process and report the error to the SCTP
896 // user."
897 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Timer " << t1_cookie_->name()
898 << " has expired: " << t1_cookie_->expiration_count()
Victor Boivie9680d292021-08-30 10:23:49 +0200899 << "/"
900 << t1_cookie_->options().max_restarts.value_or(-1);
Victor Boivieb6580cc2021-04-08 09:56:59 +0200901
902 RTC_DCHECK(state_ == State::kCookieEchoed);
903
904 if (t1_cookie_->is_running()) {
Victor Boiviec20f1562021-06-16 12:52:42 +0200905 tcb_->SendBufferedPackets(callbacks_.TimeMillis());
Victor Boivieb6580cc2021-04-08 09:56:59 +0200906 } else {
907 InternalClose(ErrorKind::kTooManyRetries, "No COOKIE_ACK received");
908 }
909
910 RTC_DCHECK(IsConsistent());
911 return absl::nullopt;
912}
913
914absl::optional<DurationMs> DcSctpSocket::OnShutdownTimerExpiry() {
915 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Timer " << t2_shutdown_->name()
916 << " has expired: " << t2_shutdown_->expiration_count()
Victor Boivie9680d292021-08-30 10:23:49 +0200917 << "/"
918 << t2_shutdown_->options().max_restarts.value_or(-1);
Victor Boivieb6580cc2021-04-08 09:56:59 +0200919
Victor Boivie914925f2021-05-07 11:22:50 +0200920 if (!t2_shutdown_->is_running()) {
Victor Boivieb6580cc2021-04-08 09:56:59 +0200921 // https://tools.ietf.org/html/rfc4960#section-9.2
922 // "An endpoint should limit the number of retransmissions of the SHUTDOWN
923 // chunk to the protocol parameter 'Association.Max.Retrans'. If this
924 // threshold is exceeded, the endpoint should destroy the TCB..."
925
Victor Boivieabf61882021-08-12 15:57:49 +0200926 packet_sender_.Send(tcb_->PacketBuilder().Add(
Victor Boivieb6580cc2021-04-08 09:56:59 +0200927 AbortChunk(true, Parameters::Builder()
928 .Add(UserInitiatedAbortCause(
929 "Too many retransmissions of SHUTDOWN"))
930 .Build())));
931
932 InternalClose(ErrorKind::kTooManyRetries, "No SHUTDOWN_ACK received");
Victor Boivie914925f2021-05-07 11:22:50 +0200933 RTC_DCHECK(IsConsistent());
934 return absl::nullopt;
Victor Boivieb6580cc2021-04-08 09:56:59 +0200935 }
Victor Boivie914925f2021-05-07 11:22:50 +0200936
937 // https://tools.ietf.org/html/rfc4960#section-9.2
938 // "If the timer expires, the endpoint must resend the SHUTDOWN with the
939 // updated last sequential TSN received from its peer."
940 SendShutdown();
Victor Boivieb6580cc2021-04-08 09:56:59 +0200941 RTC_DCHECK(IsConsistent());
942 return tcb_->current_rto();
943}
944
Victor Boivieabf61882021-08-12 15:57:49 +0200945void DcSctpSocket::OnSentPacket(rtc::ArrayView<const uint8_t> packet,
946 SendPacketStatus status) {
947 // The packet observer is invoked even if the packet was failed to be sent, to
948 // indicate an attempt was made.
Victor Boivieb6580cc2021-04-08 09:56:59 +0200949 if (packet_observer_ != nullptr) {
Victor Boivieabf61882021-08-12 15:57:49 +0200950 packet_observer_->OnSentPacket(callbacks_.TimeMillis(), packet);
Victor Boivieb6580cc2021-04-08 09:56:59 +0200951 }
Victor Boivieabf61882021-08-12 15:57:49 +0200952
953 if (status == SendPacketStatus::kSuccess) {
954 if (RTC_DLOG_IS_ON) {
955 DebugPrintOutgoing(packet);
956 }
957
958 // The heartbeat interval timer is restarted for every sent packet, to
959 // fire when the outgoing channel is inactive.
960 if (tcb_ != nullptr) {
961 tcb_->heartbeat_handler().RestartTimer();
962 }
963
964 ++metrics_.tx_packets_count;
965 }
Victor Boivieb6580cc2021-04-08 09:56:59 +0200966}
967
968bool DcSctpSocket::ValidateHasTCB() {
969 if (tcb_ != nullptr) {
970 return true;
971 }
972
973 callbacks_.OnError(
974 ErrorKind::kNotConnected,
975 "Received unexpected commands on socket that is not connected");
976 return false;
977}
978
979void DcSctpSocket::ReportFailedToParseChunk(int chunk_type) {
980 rtc::StringBuilder sb;
981 sb << "Failed to parse chunk of type: " << chunk_type;
982 callbacks_.OnError(ErrorKind::kParseFailed, sb.str());
983}
984
985void DcSctpSocket::HandleData(const CommonHeader& header,
986 const SctpPacket::ChunkDescriptor& descriptor) {
987 absl::optional<DataChunk> chunk = DataChunk::Parse(descriptor.data);
988 if (ValidateParseSuccess(chunk) && ValidateHasTCB()) {
989 HandleDataCommon(*chunk);
990 }
991}
992
993void DcSctpSocket::HandleIData(const CommonHeader& header,
994 const SctpPacket::ChunkDescriptor& descriptor) {
995 absl::optional<IDataChunk> chunk = IDataChunk::Parse(descriptor.data);
996 if (ValidateParseSuccess(chunk) && ValidateHasTCB()) {
997 HandleDataCommon(*chunk);
998 }
999}
1000
1001void DcSctpSocket::HandleDataCommon(AnyDataChunk& chunk) {
1002 TSN tsn = chunk.tsn();
1003 AnyDataChunk::ImmediateAckFlag immediate_ack = chunk.options().immediate_ack;
1004 Data data = std::move(chunk).extract();
1005
Victor Boivie4b7024b2021-12-01 18:57:22 +00001006 if (data.payload.empty()) {
Victor Boivieb6580cc2021-04-08 09:56:59 +02001007 // Empty DATA chunks are illegal.
Victor Boivieabf61882021-08-12 15:57:49 +02001008 packet_sender_.Send(tcb_->PacketBuilder().Add(
Victor Boivieb6580cc2021-04-08 09:56:59 +02001009 ErrorChunk(Parameters::Builder().Add(NoUserDataCause(tsn)).Build())));
1010 callbacks_.OnError(ErrorKind::kProtocolViolation,
1011 "Received DATA chunk with no user data");
1012 return;
1013 }
1014
1015 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Handle DATA, queue_size="
1016 << tcb_->reassembly_queue().queued_bytes()
1017 << ", water_mark="
1018 << tcb_->reassembly_queue().watermark_bytes()
1019 << ", full=" << tcb_->reassembly_queue().is_full()
1020 << ", above="
1021 << tcb_->reassembly_queue().is_above_watermark();
1022
1023 if (tcb_->reassembly_queue().is_full()) {
1024 // If the reassembly queue is full, there is nothing that can be done. The
1025 // specification only allows dropping gap-ack-blocks, and that's not
1026 // likely to help as the socket has been trying to fill gaps since the
1027 // watermark was reached.
Victor Boivieabf61882021-08-12 15:57:49 +02001028 packet_sender_.Send(tcb_->PacketBuilder().Add(AbortChunk(
Victor Boivieb6580cc2021-04-08 09:56:59 +02001029 true, Parameters::Builder().Add(OutOfResourceErrorCause()).Build())));
1030 InternalClose(ErrorKind::kResourceExhaustion,
1031 "Reassembly Queue is exhausted");
1032 return;
1033 }
1034
1035 if (tcb_->reassembly_queue().is_above_watermark()) {
1036 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Is above high watermark";
1037 // If the reassembly queue is above its high watermark, only accept data
1038 // chunks that increase its cumulative ack tsn in an attempt to fill gaps
1039 // to deliver messages.
1040 if (!tcb_->data_tracker().will_increase_cum_ack_tsn(tsn)) {
1041 RTC_DLOG(LS_VERBOSE) << log_prefix()
1042 << "Rejected data because of exceeding watermark";
1043 tcb_->data_tracker().ForceImmediateSack();
1044 return;
1045 }
1046 }
1047
1048 if (!tcb_->data_tracker().IsTSNValid(tsn)) {
1049 RTC_DLOG(LS_VERBOSE) << log_prefix()
1050 << "Rejected data because of failing TSN validity";
1051 return;
1052 }
1053
Victor Boivie568bc232022-03-20 19:59:03 +01001054 if (tcb_->data_tracker().Observe(tsn, immediate_ack)) {
1055 tcb_->reassembly_queue().MaybeResetStreamsDeferred(
1056 tcb_->data_tracker().last_cumulative_acked_tsn());
1057 tcb_->reassembly_queue().Add(tsn, std::move(data));
1058 DeliverReassembledMessages();
1059 }
Victor Boivieb6580cc2021-04-08 09:56:59 +02001060}
1061
1062void DcSctpSocket::HandleInit(const CommonHeader& header,
1063 const SctpPacket::ChunkDescriptor& descriptor) {
1064 absl::optional<InitChunk> chunk = InitChunk::Parse(descriptor.data);
1065 if (!ValidateParseSuccess(chunk)) {
1066 return;
1067 }
1068
1069 if (chunk->initiate_tag() == VerificationTag(0) ||
1070 chunk->nbr_outbound_streams() == 0 || chunk->nbr_inbound_streams() == 0) {
1071 // https://tools.ietf.org/html/rfc4960#section-3.3.2
1072 // "If the value of the Initiate Tag in a received INIT chunk is found
1073 // to be 0, the receiver MUST treat it as an error and close the
1074 // association by transmitting an ABORT."
1075
1076 // "A receiver of an INIT with the OS value set to 0 SHOULD abort the
1077 // association."
1078
1079 // "A receiver of an INIT with the MIS value of 0 SHOULD abort the
1080 // association."
1081
Victor Boivieabf61882021-08-12 15:57:49 +02001082 packet_sender_.Send(
1083 SctpPacket::Builder(VerificationTag(0), options_)
1084 .Add(AbortChunk(
1085 /*filled_in_verification_tag=*/false,
1086 Parameters::Builder()
1087 .Add(ProtocolViolationCause("INIT malformed"))
1088 .Build())));
Victor Boivieb6580cc2021-04-08 09:56:59 +02001089 InternalClose(ErrorKind::kProtocolViolation, "Received invalid INIT");
1090 return;
1091 }
1092
1093 if (state_ == State::kShutdownAckSent) {
1094 // https://tools.ietf.org/html/rfc4960#section-9.2
1095 // "If an endpoint is in the SHUTDOWN-ACK-SENT state and receives an
1096 // INIT chunk (e.g., if the SHUTDOWN COMPLETE was lost) with source and
1097 // destination transport addresses (either in the IP addresses or in the
1098 // INIT chunk) that belong to this association, it should discard the INIT
1099 // chunk and retransmit the SHUTDOWN ACK chunk."
1100 RTC_DLOG(LS_VERBOSE) << log_prefix()
1101 << "Received Init indicating lost ShutdownComplete";
1102 SendShutdownAck();
1103 return;
1104 }
1105
1106 TieTag tie_tag(0);
1107 if (state_ == State::kClosed) {
1108 RTC_DLOG(LS_VERBOSE) << log_prefix()
1109 << "Received Init in closed state (normal)";
1110
1111 MakeConnectionParameters();
1112 } else if (state_ == State::kCookieWait || state_ == State::kCookieEchoed) {
1113 // https://tools.ietf.org/html/rfc4960#section-5.2.1
1114 // "This usually indicates an initialization collision, i.e., each
1115 // endpoint is attempting, at about the same time, to establish an
1116 // association with the other endpoint. Upon receipt of an INIT in the
1117 // COOKIE-WAIT state, an endpoint MUST respond with an INIT ACK using the
1118 // same parameters it sent in its original INIT chunk (including its
1119 // Initiate Tag, unchanged). When responding, the endpoint MUST send the
1120 // INIT ACK back to the same address that the original INIT (sent by this
1121 // endpoint) was sent."
1122 RTC_DLOG(LS_VERBOSE) << log_prefix()
1123 << "Received Init indicating simultaneous connections";
1124 } else {
1125 RTC_DCHECK(tcb_ != nullptr);
1126 // https://tools.ietf.org/html/rfc4960#section-5.2.2
1127 // "The outbound SCTP packet containing this INIT ACK MUST carry a
1128 // Verification Tag value equal to the Initiate Tag found in the
1129 // unexpected INIT. And the INIT ACK MUST contain a new Initiate Tag
1130 // (randomly generated; see Section 5.3.1). Other parameters for the
1131 // endpoint SHOULD be copied from the existing parameters of the
1132 // association (e.g., number of outbound streams) into the INIT ACK and
1133 // cookie."
1134 RTC_DLOG(LS_VERBOSE) << log_prefix()
1135 << "Received Init indicating restarted connection";
1136 // Create a new verification tag - different from the previous one.
1137 for (int tries = 0; tries < 10; ++tries) {
1138 connect_params_.verification_tag = VerificationTag(
1139 callbacks_.GetRandomInt(kMinVerificationTag, kMaxVerificationTag));
1140 if (connect_params_.verification_tag != tcb_->my_verification_tag()) {
1141 break;
1142 }
1143 }
1144
1145 // Make the initial TSN make a large jump, so that there is no overlap
1146 // with the old and new association.
1147 connect_params_.initial_tsn =
1148 TSN(*tcb_->retransmission_queue().next_tsn() + 1000000);
1149 tie_tag = tcb_->tie_tag();
1150 }
1151
1152 RTC_DLOG(LS_VERBOSE)
1153 << log_prefix()
1154 << rtc::StringFormat(
1155 "Proceeding with connection. my_verification_tag=%08x, "
1156 "my_initial_tsn=%u, peer_verification_tag=%08x, "
1157 "peer_initial_tsn=%u",
1158 *connect_params_.verification_tag, *connect_params_.initial_tsn,
1159 *chunk->initiate_tag(), *chunk->initial_tsn());
1160
1161 Capabilities capabilities = GetCapabilities(options_, chunk->parameters());
1162
1163 SctpPacket::Builder b(chunk->initiate_tag(), options_);
1164 Parameters::Builder params_builder =
1165 Parameters::Builder().Add(StateCookieParameter(
1166 StateCookie(chunk->initiate_tag(), chunk->initial_tsn(),
1167 chunk->a_rwnd(), tie_tag, capabilities)
1168 .Serialize()));
1169 AddCapabilityParameters(options_, params_builder);
1170
1171 InitAckChunk init_ack(/*initiate_tag=*/connect_params_.verification_tag,
1172 options_.max_receiver_window_buffer_size,
1173 options_.announced_maximum_outgoing_streams,
1174 options_.announced_maximum_incoming_streams,
1175 connect_params_.initial_tsn, params_builder.Build());
1176 b.Add(init_ack);
Victor Boivieabf61882021-08-12 15:57:49 +02001177 packet_sender_.Send(b);
Victor Boivieb6580cc2021-04-08 09:56:59 +02001178}
1179
Victor Boivieb6580cc2021-04-08 09:56:59 +02001180void DcSctpSocket::HandleInitAck(
1181 const CommonHeader& header,
1182 const SctpPacket::ChunkDescriptor& descriptor) {
1183 absl::optional<InitAckChunk> chunk = InitAckChunk::Parse(descriptor.data);
1184 if (!ValidateParseSuccess(chunk)) {
1185 return;
1186 }
1187
1188 if (state_ != State::kCookieWait) {
1189 // https://tools.ietf.org/html/rfc4960#section-5.2.3
1190 // "If an INIT ACK is received by an endpoint in any state other than
1191 // the COOKIE-WAIT state, the endpoint should discard the INIT ACK chunk."
1192 RTC_DLOG(LS_VERBOSE) << log_prefix()
1193 << "Received INIT_ACK in unexpected state";
1194 return;
1195 }
1196
1197 auto cookie = chunk->parameters().get<StateCookieParameter>();
1198 if (!cookie.has_value()) {
Victor Boivieabf61882021-08-12 15:57:49 +02001199 packet_sender_.Send(
1200 SctpPacket::Builder(connect_params_.verification_tag, options_)
1201 .Add(AbortChunk(
1202 /*filled_in_verification_tag=*/false,
1203 Parameters::Builder()
1204 .Add(ProtocolViolationCause("INIT-ACK malformed"))
1205 .Build())));
Victor Boivieb6580cc2021-04-08 09:56:59 +02001206 InternalClose(ErrorKind::kProtocolViolation,
1207 "InitAck chunk doesn't contain a cookie");
1208 return;
1209 }
1210 Capabilities capabilities = GetCapabilities(options_, chunk->parameters());
1211 t1_init_->Stop();
1212
Victor Boivief7fc71d2022-05-13 14:27:55 +02001213 metrics_.peer_implementation = DeterminePeerImplementation(cookie->data());
Victor Boivief4fa1662021-09-24 23:01:21 +02001214
Victor Boivie2cffde72022-06-27 20:35:37 +00001215 // If the connection is re-established (peer restarted, but re-used old
1216 // connection), make sure that all message identifiers are reset and any
1217 // partly sent message is re-sent in full. The same is true when the socket
1218 // is closed and later re-opened, which never happens in WebRTC, but is a
1219 // valid operation on the SCTP level. Note that in case of handover, the
1220 // send queue is already re-configured, and shouldn't be reset.
1221 send_queue_.Reset();
1222
1223 CreateTransmissionControlBlock(capabilities, connect_params_.verification_tag,
1224 connect_params_.initial_tsn,
1225 chunk->initiate_tag(), chunk->initial_tsn(),
1226 chunk->a_rwnd(), MakeTieTag(callbacks_));
Victor Boivieb6580cc2021-04-08 09:56:59 +02001227
1228 SetState(State::kCookieEchoed, "INIT_ACK received");
1229
1230 // The connection isn't fully established just yet.
Victor Boiviec20f1562021-06-16 12:52:42 +02001231 tcb_->SetCookieEchoChunk(CookieEchoChunk(cookie->data()));
1232 tcb_->SendBufferedPackets(callbacks_.TimeMillis());
Victor Boivieb6580cc2021-04-08 09:56:59 +02001233 t1_cookie_->Start();
1234}
1235
1236void DcSctpSocket::HandleCookieEcho(
1237 const CommonHeader& header,
1238 const SctpPacket::ChunkDescriptor& descriptor) {
1239 absl::optional<CookieEchoChunk> chunk =
1240 CookieEchoChunk::Parse(descriptor.data);
1241 if (!ValidateParseSuccess(chunk)) {
1242 return;
1243 }
1244
1245 absl::optional<StateCookie> cookie =
1246 StateCookie::Deserialize(chunk->cookie());
1247 if (!cookie.has_value()) {
1248 callbacks_.OnError(ErrorKind::kParseFailed, "Failed to parse state cookie");
1249 return;
1250 }
1251
1252 if (tcb_ != nullptr) {
1253 if (!HandleCookieEchoWithTCB(header, *cookie)) {
1254 return;
1255 }
1256 } else {
1257 if (header.verification_tag != connect_params_.verification_tag) {
1258 callbacks_.OnError(
1259 ErrorKind::kParseFailed,
1260 rtc::StringFormat(
1261 "Received CookieEcho with invalid verification tag: %08x, "
1262 "expected %08x",
1263 *header.verification_tag, *connect_params_.verification_tag));
1264 return;
1265 }
1266 }
1267
1268 // The init timer can be running on simultaneous connections.
1269 t1_init_->Stop();
1270 t1_cookie_->Stop();
1271 if (state_ != State::kEstablished) {
Victor Boiviec20f1562021-06-16 12:52:42 +02001272 if (tcb_ != nullptr) {
1273 tcb_->ClearCookieEchoChunk();
1274 }
Victor Boivieb6580cc2021-04-08 09:56:59 +02001275 SetState(State::kEstablished, "COOKIE_ECHO received");
1276 callbacks_.OnConnected();
1277 }
1278
1279 if (tcb_ == nullptr) {
Victor Boivie2cffde72022-06-27 20:35:37 +00001280 // If the connection is re-established (peer restarted, but re-used old
1281 // connection), make sure that all message identifiers are reset and any
1282 // partly sent message is re-sent in full. The same is true when the socket
1283 // is closed and later re-opened, which never happens in WebRTC, but is a
1284 // valid operation on the SCTP level. Note that in case of handover, the
1285 // send queue is already re-configured, and shouldn't be reset.
1286 send_queue_.Reset();
1287
1288 CreateTransmissionControlBlock(
1289 cookie->capabilities(), connect_params_.verification_tag,
Victor Boivieb6580cc2021-04-08 09:56:59 +02001290 connect_params_.initial_tsn, cookie->initiate_tag(),
Victor Boivie2cffde72022-06-27 20:35:37 +00001291 cookie->initial_tsn(), cookie->a_rwnd(), MakeTieTag(callbacks_));
Victor Boivieb6580cc2021-04-08 09:56:59 +02001292 }
1293
1294 SctpPacket::Builder b = tcb_->PacketBuilder();
1295 b.Add(CookieAckChunk());
1296
1297 // https://tools.ietf.org/html/rfc4960#section-5.1
1298 // "A COOKIE ACK chunk may be bundled with any pending DATA chunks (and/or
1299 // SACK chunks), but the COOKIE ACK chunk MUST be the first chunk in the
1300 // packet."
Victor Boivied3b186e2021-05-05 16:22:29 +02001301 tcb_->SendBufferedPackets(b, callbacks_.TimeMillis());
Victor Boivieb6580cc2021-04-08 09:56:59 +02001302}
1303
1304bool DcSctpSocket::HandleCookieEchoWithTCB(const CommonHeader& header,
1305 const StateCookie& cookie) {
1306 RTC_DLOG(LS_VERBOSE) << log_prefix()
1307 << "Handling CookieEchoChunk with TCB. local_tag="
1308 << *tcb_->my_verification_tag()
1309 << ", peer_tag=" << *header.verification_tag
1310 << ", tcb_tag=" << *tcb_->peer_verification_tag()
1311 << ", cookie_tag=" << *cookie.initiate_tag()
1312 << ", local_tie_tag=" << *tcb_->tie_tag()
1313 << ", peer_tie_tag=" << *cookie.tie_tag();
1314 // https://tools.ietf.org/html/rfc4960#section-5.2.4
1315 // "Handle a COOKIE ECHO when a TCB Exists"
1316 if (header.verification_tag != tcb_->my_verification_tag() &&
1317 tcb_->peer_verification_tag() != cookie.initiate_tag() &&
1318 cookie.tie_tag() == tcb_->tie_tag()) {
1319 // "A) In this case, the peer may have restarted."
1320 if (state_ == State::kShutdownAckSent) {
1321 // "If the endpoint is in the SHUTDOWN-ACK-SENT state and recognizes
1322 // that the peer has restarted ... it MUST NOT set up a new association
1323 // but instead resend the SHUTDOWN ACK and send an ERROR chunk with a
1324 // "Cookie Received While Shutting Down" error cause to its peer."
1325 SctpPacket::Builder b(cookie.initiate_tag(), options_);
1326 b.Add(ShutdownAckChunk());
1327 b.Add(ErrorChunk(Parameters::Builder()
1328 .Add(CookieReceivedWhileShuttingDownCause())
1329 .Build()));
Victor Boivieabf61882021-08-12 15:57:49 +02001330 packet_sender_.Send(b);
Victor Boivieb6580cc2021-04-08 09:56:59 +02001331 callbacks_.OnError(ErrorKind::kWrongSequence,
1332 "Received COOKIE-ECHO while shutting down");
1333 return false;
1334 }
1335
1336 RTC_DLOG(LS_VERBOSE) << log_prefix()
1337 << "Received COOKIE-ECHO indicating a restarted peer";
1338
Victor Boivieb6580cc2021-04-08 09:56:59 +02001339 tcb_ = nullptr;
1340 callbacks_.OnConnectionRestarted();
1341 } else if (header.verification_tag == tcb_->my_verification_tag() &&
1342 tcb_->peer_verification_tag() != cookie.initiate_tag()) {
1343 // TODO(boivie): Handle the peer_tag == 0?
1344 // "B) In this case, both sides may be attempting to start an
1345 // association at about the same time, but the peer endpoint started its
1346 // INIT after responding to the local endpoint's INIT."
1347 RTC_DLOG(LS_VERBOSE)
1348 << log_prefix()
1349 << "Received COOKIE-ECHO indicating simultaneous connections";
1350 tcb_ = nullptr;
1351 } else if (header.verification_tag != tcb_->my_verification_tag() &&
1352 tcb_->peer_verification_tag() == cookie.initiate_tag() &&
1353 cookie.tie_tag() == TieTag(0)) {
1354 // "C) In this case, the local endpoint's cookie has arrived late.
1355 // Before it arrived, the local endpoint sent an INIT and received an
1356 // INIT ACK and finally sent a COOKIE ECHO with the peer's same tag but
1357 // a new tag of its own. The cookie should be silently discarded. The
1358 // endpoint SHOULD NOT change states and should leave any timers
1359 // running."
1360 RTC_DLOG(LS_VERBOSE)
1361 << log_prefix()
1362 << "Received COOKIE-ECHO indicating a late COOKIE-ECHO. Discarding";
1363 return false;
1364 } else if (header.verification_tag == tcb_->my_verification_tag() &&
1365 tcb_->peer_verification_tag() == cookie.initiate_tag()) {
1366 // "D) When both local and remote tags match, the endpoint should enter
1367 // the ESTABLISHED state, if it is in the COOKIE-ECHOED state. It
1368 // should stop any cookie timer that may be running and send a COOKIE
1369 // ACK."
1370 RTC_DLOG(LS_VERBOSE)
1371 << log_prefix()
1372 << "Received duplicate COOKIE-ECHO, probably because of peer not "
1373 "receiving COOKIE-ACK and retransmitting COOKIE-ECHO. Continuing.";
1374 }
1375 return true;
1376}
1377
1378void DcSctpSocket::HandleCookieAck(
1379 const CommonHeader& header,
1380 const SctpPacket::ChunkDescriptor& descriptor) {
1381 absl::optional<CookieAckChunk> chunk = CookieAckChunk::Parse(descriptor.data);
1382 if (!ValidateParseSuccess(chunk)) {
1383 return;
1384 }
1385
1386 if (state_ != State::kCookieEchoed) {
1387 // https://tools.ietf.org/html/rfc4960#section-5.2.5
1388 // "At any state other than COOKIE-ECHOED, an endpoint should silently
1389 // discard a received COOKIE ACK chunk."
1390 RTC_DLOG(LS_VERBOSE) << log_prefix()
1391 << "Received COOKIE_ACK not in COOKIE_ECHOED state";
1392 return;
1393 }
1394
1395 // RFC 4960, Errata ID: 4400
1396 t1_cookie_->Stop();
Victor Boiviec20f1562021-06-16 12:52:42 +02001397 tcb_->ClearCookieEchoChunk();
Victor Boivieb6580cc2021-04-08 09:56:59 +02001398 SetState(State::kEstablished, "COOKIE_ACK received");
Victor Boivied3b186e2021-05-05 16:22:29 +02001399 tcb_->SendBufferedPackets(callbacks_.TimeMillis());
Victor Boivieb6580cc2021-04-08 09:56:59 +02001400 callbacks_.OnConnected();
1401}
1402
1403void DcSctpSocket::DeliverReassembledMessages() {
1404 if (tcb_->reassembly_queue().HasMessages()) {
1405 for (auto& message : tcb_->reassembly_queue().FlushMessages()) {
Victor Boivied4716ea2021-08-09 12:26:32 +02001406 ++metrics_.rx_messages_count;
Victor Boivieb6580cc2021-04-08 09:56:59 +02001407 callbacks_.OnMessageReceived(std::move(message));
1408 }
1409 }
1410}
1411
1412void DcSctpSocket::HandleSack(const CommonHeader& header,
1413 const SctpPacket::ChunkDescriptor& descriptor) {
1414 absl::optional<SackChunk> chunk = SackChunk::Parse(descriptor.data);
1415
1416 if (ValidateParseSuccess(chunk) && ValidateHasTCB()) {
Victor Boivied3b186e2021-05-05 16:22:29 +02001417 TimeMs now = callbacks_.TimeMillis();
Victor Boivieb6580cc2021-04-08 09:56:59 +02001418 SackChunk sack = ChunkValidators::Clean(*std::move(chunk));
1419
Victor Boivied3b186e2021-05-05 16:22:29 +02001420 if (tcb_->retransmission_queue().HandleSack(now, sack)) {
Victor Boivieb6580cc2021-04-08 09:56:59 +02001421 MaybeSendShutdownOrAck();
Victor Boivie5e354d92022-04-22 16:28:33 +02001422 // Receiving an ACK may make the socket go into fast recovery mode.
1423 // https://datatracker.ietf.org/doc/html/rfc4960#section-7.2.4
1424 // "Determine how many of the earliest (i.e., lowest TSN) DATA chunks
1425 // marked for retransmission will fit into a single packet, subject to
1426 // constraint of the path MTU of the destination transport address to
1427 // which the packet is being sent. Call this value K. Retransmit those K
1428 // DATA chunks in a single packet. When a Fast Retransmit is being
1429 // performed, the sender SHOULD ignore the value of cwnd and SHOULD NOT
1430 // delay retransmission for this single packet."
1431 tcb_->MaybeSendFastRetransmit();
1432
Victor Boivieb6580cc2021-04-08 09:56:59 +02001433 // Receiving an ACK will decrease outstanding bytes (maybe now below
1434 // cwnd?) or indicate packet loss that may result in sending FORWARD-TSN.
Victor Boivied3b186e2021-05-05 16:22:29 +02001435 tcb_->SendBufferedPackets(now);
Victor Boivieb6580cc2021-04-08 09:56:59 +02001436 } else {
1437 RTC_DLOG(LS_VERBOSE) << log_prefix()
1438 << "Dropping out-of-order SACK with TSN "
1439 << *sack.cumulative_tsn_ack();
1440 }
1441 }
1442}
1443
1444void DcSctpSocket::HandleHeartbeatRequest(
1445 const CommonHeader& header,
1446 const SctpPacket::ChunkDescriptor& descriptor) {
1447 absl::optional<HeartbeatRequestChunk> chunk =
1448 HeartbeatRequestChunk::Parse(descriptor.data);
1449
1450 if (ValidateParseSuccess(chunk) && ValidateHasTCB()) {
1451 tcb_->heartbeat_handler().HandleHeartbeatRequest(*std::move(chunk));
1452 }
1453}
1454
1455void DcSctpSocket::HandleHeartbeatAck(
1456 const CommonHeader& header,
1457 const SctpPacket::ChunkDescriptor& descriptor) {
1458 absl::optional<HeartbeatAckChunk> chunk =
1459 HeartbeatAckChunk::Parse(descriptor.data);
1460
1461 if (ValidateParseSuccess(chunk) && ValidateHasTCB()) {
1462 tcb_->heartbeat_handler().HandleHeartbeatAck(*std::move(chunk));
1463 }
1464}
1465
1466void DcSctpSocket::HandleAbort(const CommonHeader& header,
1467 const SctpPacket::ChunkDescriptor& descriptor) {
1468 absl::optional<AbortChunk> chunk = AbortChunk::Parse(descriptor.data);
1469 if (ValidateParseSuccess(chunk)) {
1470 std::string error_string = ErrorCausesToString(chunk->error_causes());
1471 if (tcb_ == nullptr) {
1472 // https://tools.ietf.org/html/rfc4960#section-3.3.7
1473 // "If an endpoint receives an ABORT with a format error or no TCB is
1474 // found, it MUST silently discard it."
1475 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Received ABORT (" << error_string
1476 << ") on a connection with no TCB. Ignoring";
1477 return;
1478 }
1479
1480 RTC_DLOG(LS_WARNING) << log_prefix() << "Received ABORT (" << error_string
1481 << ") - closing connection.";
1482 InternalClose(ErrorKind::kPeerReported, error_string);
1483 }
1484}
1485
1486void DcSctpSocket::HandleError(const CommonHeader& header,
1487 const SctpPacket::ChunkDescriptor& descriptor) {
1488 absl::optional<ErrorChunk> chunk = ErrorChunk::Parse(descriptor.data);
1489 if (ValidateParseSuccess(chunk)) {
1490 std::string error_string = ErrorCausesToString(chunk->error_causes());
1491 if (tcb_ == nullptr) {
1492 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Received ERROR (" << error_string
1493 << ") on a connection with no TCB. Ignoring";
1494 return;
1495 }
1496
1497 RTC_DLOG(LS_WARNING) << log_prefix() << "Received ERROR: " << error_string;
1498 callbacks_.OnError(ErrorKind::kPeerReported,
1499 "Peer reported error: " + error_string);
1500 }
1501}
1502
1503void DcSctpSocket::HandleReconfig(
1504 const CommonHeader& header,
1505 const SctpPacket::ChunkDescriptor& descriptor) {
1506 absl::optional<ReConfigChunk> chunk = ReConfigChunk::Parse(descriptor.data);
1507 if (ValidateParseSuccess(chunk) && ValidateHasTCB()) {
1508 tcb_->stream_reset_handler().HandleReConfig(*std::move(chunk));
Victor Boivief9e116f2022-03-31 17:15:03 +02001509 // Handling this response may result in outgoing stream resets finishing
1510 // (either successfully or with failure). If there still are pending streams
1511 // that were waiting for this request to finish, continue resetting them.
1512 MaybeSendResetStreamsRequest();
Victor Boivieb6580cc2021-04-08 09:56:59 +02001513 }
1514}
1515
1516void DcSctpSocket::HandleShutdown(
1517 const CommonHeader& header,
1518 const SctpPacket::ChunkDescriptor& descriptor) {
1519 if (!ValidateParseSuccess(ShutdownChunk::Parse(descriptor.data))) {
1520 return;
1521 }
1522
1523 if (state_ == State::kClosed) {
1524 return;
1525 } else if (state_ == State::kCookieWait || state_ == State::kCookieEchoed) {
1526 // https://tools.ietf.org/html/rfc4960#section-9.2
1527 // "If a SHUTDOWN is received in the COOKIE-WAIT or COOKIE ECHOED state,
1528 // the SHUTDOWN chunk SHOULD be silently discarded."
1529 } else if (state_ == State::kShutdownSent) {
1530 // https://tools.ietf.org/html/rfc4960#section-9.2
1531 // "If an endpoint is in the SHUTDOWN-SENT state and receives a
1532 // SHUTDOWN chunk from its peer, the endpoint shall respond immediately
1533 // with a SHUTDOWN ACK to its peer, and move into the SHUTDOWN-ACK-SENT
1534 // state restarting its T2-shutdown timer."
1535 SendShutdownAck();
1536 SetState(State::kShutdownAckSent, "SHUTDOWN received");
Victor Boivie50a0b122021-05-06 21:07:49 +02001537 } else if (state_ == State::kShutdownAckSent) {
1538 // TODO(webrtc:12739): This condition should be removed and handled by the
1539 // next (state_ != State::kShutdownReceived).
1540 return;
Victor Boivieb6580cc2021-04-08 09:56:59 +02001541 } else if (state_ != State::kShutdownReceived) {
1542 RTC_DLOG(LS_VERBOSE) << log_prefix()
1543 << "Received SHUTDOWN - shutting down the socket";
1544 // https://tools.ietf.org/html/rfc4960#section-9.2
1545 // "Upon reception of the SHUTDOWN, the peer endpoint shall enter the
1546 // SHUTDOWN-RECEIVED state, stop accepting new data from its SCTP user,
1547 // and verify, by checking the Cumulative TSN Ack field of the chunk, that
1548 // all its outstanding DATA chunks have been received by the SHUTDOWN
1549 // sender."
1550 SetState(State::kShutdownReceived, "SHUTDOWN received");
1551 MaybeSendShutdownOrAck();
1552 }
1553}
1554
1555void DcSctpSocket::HandleShutdownAck(
1556 const CommonHeader& header,
1557 const SctpPacket::ChunkDescriptor& descriptor) {
1558 if (!ValidateParseSuccess(ShutdownAckChunk::Parse(descriptor.data))) {
1559 return;
1560 }
1561
1562 if (state_ == State::kShutdownSent || state_ == State::kShutdownAckSent) {
1563 // https://tools.ietf.org/html/rfc4960#section-9.2
1564 // "Upon the receipt of the SHUTDOWN ACK, the SHUTDOWN sender shall stop
1565 // the T2-shutdown timer, send a SHUTDOWN COMPLETE chunk to its peer, and
1566 // remove all record of the association."
1567
1568 // "If an endpoint is in the SHUTDOWN-ACK-SENT state and receives a
1569 // SHUTDOWN ACK, it shall stop the T2-shutdown timer, send a SHUTDOWN
1570 // COMPLETE chunk to its peer, and remove all record of the association."
1571
1572 SctpPacket::Builder b = tcb_->PacketBuilder();
1573 b.Add(ShutdownCompleteChunk(/*tag_reflected=*/false));
Victor Boivieabf61882021-08-12 15:57:49 +02001574 packet_sender_.Send(b);
Victor Boivieb6580cc2021-04-08 09:56:59 +02001575 InternalClose(ErrorKind::kNoError, "");
1576 } else {
1577 // https://tools.ietf.org/html/rfc4960#section-8.5.1
1578 // "If the receiver is in COOKIE-ECHOED or COOKIE-WAIT state
1579 // the procedures in Section 8.4 SHOULD be followed; in other words, it
1580 // should be treated as an Out Of The Blue packet."
1581
1582 // https://tools.ietf.org/html/rfc4960#section-8.4
1583 // "If the packet contains a SHUTDOWN ACK chunk, the receiver
1584 // should respond to the sender of the OOTB packet with a SHUTDOWN
1585 // COMPLETE. When sending the SHUTDOWN COMPLETE, the receiver of the OOTB
1586 // packet must fill in the Verification Tag field of the outbound packet
1587 // with the Verification Tag received in the SHUTDOWN ACK and set the T
1588 // bit in the Chunk Flags to indicate that the Verification Tag is
1589 // reflected."
1590
1591 SctpPacket::Builder b(header.verification_tag, options_);
1592 b.Add(ShutdownCompleteChunk(/*tag_reflected=*/true));
Victor Boivieabf61882021-08-12 15:57:49 +02001593 packet_sender_.Send(b);
Victor Boivieb6580cc2021-04-08 09:56:59 +02001594 }
1595}
1596
1597void DcSctpSocket::HandleShutdownComplete(
1598 const CommonHeader& header,
1599 const SctpPacket::ChunkDescriptor& descriptor) {
1600 if (!ValidateParseSuccess(ShutdownCompleteChunk::Parse(descriptor.data))) {
1601 return;
1602 }
1603
1604 if (state_ == State::kShutdownAckSent) {
1605 // https://tools.ietf.org/html/rfc4960#section-9.2
1606 // "Upon reception of the SHUTDOWN COMPLETE chunk, the endpoint will
1607 // verify that it is in the SHUTDOWN-ACK-SENT state; if it is not, the
1608 // chunk should be discarded. If the endpoint is in the SHUTDOWN-ACK-SENT
1609 // state, the endpoint should stop the T2-shutdown timer and remove all
1610 // knowledge of the association (and thus the association enters the
1611 // CLOSED state)."
1612 InternalClose(ErrorKind::kNoError, "");
1613 }
1614}
1615
1616void DcSctpSocket::HandleForwardTsn(
1617 const CommonHeader& header,
1618 const SctpPacket::ChunkDescriptor& descriptor) {
1619 absl::optional<ForwardTsnChunk> chunk =
1620 ForwardTsnChunk::Parse(descriptor.data);
1621 if (ValidateParseSuccess(chunk) && ValidateHasTCB()) {
1622 HandleForwardTsnCommon(*chunk);
1623 }
1624}
1625
1626void DcSctpSocket::HandleIForwardTsn(
1627 const CommonHeader& header,
1628 const SctpPacket::ChunkDescriptor& descriptor) {
1629 absl::optional<IForwardTsnChunk> chunk =
1630 IForwardTsnChunk::Parse(descriptor.data);
1631 if (ValidateParseSuccess(chunk) && ValidateHasTCB()) {
1632 HandleForwardTsnCommon(*chunk);
1633 }
1634}
1635
1636void DcSctpSocket::HandleForwardTsnCommon(const AnyForwardTsnChunk& chunk) {
1637 if (!tcb_->capabilities().partial_reliability) {
1638 SctpPacket::Builder b = tcb_->PacketBuilder();
1639 b.Add(AbortChunk(/*filled_in_verification_tag=*/true,
1640 Parameters::Builder()
1641 .Add(ProtocolViolationCause(
1642 "I-FORWARD-TSN received, but not indicated "
1643 "during connection establishment"))
1644 .Build()));
Victor Boivieabf61882021-08-12 15:57:49 +02001645 packet_sender_.Send(b);
Victor Boivieb6580cc2021-04-08 09:56:59 +02001646
1647 callbacks_.OnError(ErrorKind::kProtocolViolation,
1648 "Received a FORWARD_TSN without announced peer support");
1649 return;
1650 }
1651 tcb_->data_tracker().HandleForwardTsn(chunk.new_cumulative_tsn());
1652 tcb_->reassembly_queue().Handle(chunk);
1653 // A forward TSN - for ordered streams - may allow messages to be
1654 // delivered.
1655 DeliverReassembledMessages();
1656
1657 // Processing a FORWARD_TSN might result in sending a SACK.
1658 tcb_->MaybeSendSack();
1659}
1660
1661void DcSctpSocket::MaybeSendShutdownOrAck() {
1662 if (tcb_->retransmission_queue().outstanding_bytes() != 0) {
1663 return;
1664 }
1665
1666 if (state_ == State::kShutdownPending) {
1667 // https://tools.ietf.org/html/rfc4960#section-9.2
1668 // "Once all its outstanding data has been acknowledged, the endpoint
1669 // shall send a SHUTDOWN chunk to its peer including in the Cumulative TSN
1670 // Ack field the last sequential TSN it has received from the peer. It
1671 // shall then start the T2-shutdown timer and enter the SHUTDOWN-SENT
1672 // state.""
1673
1674 SendShutdown();
1675 t2_shutdown_->set_duration(tcb_->current_rto());
1676 t2_shutdown_->Start();
1677 SetState(State::kShutdownSent, "No more outstanding data");
1678 } else if (state_ == State::kShutdownReceived) {
1679 // https://tools.ietf.org/html/rfc4960#section-9.2
1680 // "If the receiver of the SHUTDOWN has no more outstanding DATA
1681 // chunks, the SHUTDOWN receiver MUST send a SHUTDOWN ACK and start a
1682 // T2-shutdown timer of its own, entering the SHUTDOWN-ACK-SENT state. If
1683 // the timer expires, the endpoint must resend the SHUTDOWN ACK."
1684
1685 SendShutdownAck();
1686 SetState(State::kShutdownAckSent, "No more outstanding data");
1687 }
1688}
1689
1690void DcSctpSocket::SendShutdown() {
1691 SctpPacket::Builder b = tcb_->PacketBuilder();
1692 b.Add(ShutdownChunk(tcb_->data_tracker().last_cumulative_acked_tsn()));
Victor Boivieabf61882021-08-12 15:57:49 +02001693 packet_sender_.Send(b);
Victor Boivieb6580cc2021-04-08 09:56:59 +02001694}
1695
1696void DcSctpSocket::SendShutdownAck() {
Victor Boivieabf61882021-08-12 15:57:49 +02001697 packet_sender_.Send(tcb_->PacketBuilder().Add(ShutdownAckChunk()));
Victor Boivieb6580cc2021-04-08 09:56:59 +02001698 t2_shutdown_->set_duration(tcb_->current_rto());
1699 t2_shutdown_->Start();
1700}
1701
Sergey Sukhanov43972812021-09-17 15:32:48 +02001702HandoverReadinessStatus DcSctpSocket::GetHandoverReadiness() const {
Victor Boivie5755f3e2021-09-29 22:23:15 +02001703 RTC_DCHECK_RUN_ON(&thread_checker_);
Sergey Sukhanov43972812021-09-17 15:32:48 +02001704 HandoverReadinessStatus status;
1705 if (state_ != State::kClosed && state_ != State::kEstablished) {
1706 status.Add(HandoverUnreadinessReason::kWrongConnectionState);
1707 }
Sergey Sukhanov72435322021-09-21 13:31:09 +02001708 status.Add(send_queue_.GetHandoverReadiness());
Sergey Sukhanov43972812021-09-17 15:32:48 +02001709 if (tcb_) {
1710 status.Add(tcb_->GetHandoverReadiness());
1711 }
1712 return status;
1713}
1714
1715absl::optional<DcSctpSocketHandoverState>
1716DcSctpSocket::GetHandoverStateAndClose() {
Victor Boivie5755f3e2021-09-29 22:23:15 +02001717 RTC_DCHECK_RUN_ON(&thread_checker_);
Victor Boivie15a0c882021-09-28 21:38:34 +02001718 CallbackDeferrer::ScopedDeferrer deferrer(callbacks_);
1719
Sergey Sukhanov43972812021-09-17 15:32:48 +02001720 if (!GetHandoverReadiness().IsReady()) {
1721 return absl::nullopt;
1722 }
1723
1724 DcSctpSocketHandoverState state;
1725
1726 if (state_ == State::kClosed) {
1727 state.socket_state = DcSctpSocketHandoverState::SocketState::kClosed;
1728 } else if (state_ == State::kEstablished) {
1729 state.socket_state = DcSctpSocketHandoverState::SocketState::kConnected;
1730 tcb_->AddHandoverState(state);
Sergey Sukhanov72435322021-09-21 13:31:09 +02001731 send_queue_.AddHandoverState(state);
Sergey Sukhanov43972812021-09-17 15:32:48 +02001732 InternalClose(ErrorKind::kNoError, "handover");
Sergey Sukhanov43972812021-09-17 15:32:48 +02001733 }
1734
1735 return std::move(state);
1736}
1737
Victor Boivieb6580cc2021-04-08 09:56:59 +02001738} // namespace dcsctp