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